mirror of
https://github.com/esphome/esphome.git
synced 2024-12-26 17:17:46 +01:00
commit
c32fec7432
38
.clang-tidy
38
.clang-tidy
@ -4,14 +4,35 @@ Checks: >-
|
||||
-abseil-*,
|
||||
-android-*,
|
||||
-boost-*,
|
||||
-bugprone-branch-clone,
|
||||
-bugprone-macro-parentheses,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-reserved-identifier,
|
||||
-bugprone-signed-char-misuse,
|
||||
-bugprone-suspicious-include,
|
||||
-bugprone-too-small-loop-variable,
|
||||
-bugprone-unhandled-self-assignment,
|
||||
-cert-dcl37-c,
|
||||
-cert-dcl50-cpp,
|
||||
-cert-dcl51-cpp,
|
||||
-cert-err58-cpp,
|
||||
-cert-oop54-cpp,
|
||||
-cert-oop57-cpp,
|
||||
-cert-str34-c,
|
||||
-clang-analyzer-core.CallAndMessage,
|
||||
-clang-analyzer-optin.*,
|
||||
-clang-analyzer-osx.*,
|
||||
-clang-analyzer-security.*,
|
||||
-clang-diagnostic-shadow-field,
|
||||
-cppcoreguidelines-avoid-c-arrays,
|
||||
-cppcoreguidelines-avoid-goto,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
-cppcoreguidelines-avoid-non-const-global-variables,
|
||||
-cppcoreguidelines-c-copy-assignment-signature,
|
||||
-cppcoreguidelines-init-variables,
|
||||
-cppcoreguidelines-macro-usage,
|
||||
-cppcoreguidelines-narrowing-conversions,
|
||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||
-cppcoreguidelines-owning-memory,
|
||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||
@ -37,10 +58,16 @@ Checks: >-
|
||||
-google-runtime-int,
|
||||
-google-runtime-references,
|
||||
-hicpp-*,
|
||||
-llvm-else-after-return,
|
||||
-llvm-header-guard,
|
||||
-llvm-include-order,
|
||||
-llvm-qualified-auto,
|
||||
-llvmlibc-*,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
-misc-no-recursion,
|
||||
-misc-unconventional-assign-operator,
|
||||
-misc-unused-parameters,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-deprecated-headers,
|
||||
-modernize-pass-by-value,
|
||||
-modernize-pass-by-value,
|
||||
@ -48,14 +75,25 @@ Checks: >-
|
||||
-modernize-use-auto,
|
||||
-modernize-use-default-member-init,
|
||||
-modernize-use-equals-default,
|
||||
-modernize-use-trailing-return-type,
|
||||
-mpi-*,
|
||||
-objc-*,
|
||||
-performance-unnecessary-value-param,
|
||||
-readability-braces-around-statements,
|
||||
-readability-const-return-type,
|
||||
-readability-convert-member-functions-to-static,
|
||||
-readability-else-after-return,
|
||||
-readability-implicit-bool-conversion,
|
||||
-readability-isolate-declaration,
|
||||
-readability-magic-numbers,
|
||||
-readability-make-member-function-const,
|
||||
-readability-named-parameter,
|
||||
-readability-qualified-auto,
|
||||
-readability-redundant-access-specifiers,
|
||||
-readability-redundant-member-init,
|
||||
-readability-redundant-string-init,
|
||||
-readability-uppercase-literal-suffix,
|
||||
-readability-use-anyofallof,
|
||||
-warnings-as-errors,
|
||||
-zircon-*
|
||||
WarningsAsErrors: '*'
|
||||
|
14
.github/PULL_REQUEST_TEMPLATE.md
vendored
14
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,25 +1,22 @@
|
||||
# What does this implement/fix?
|
||||
|
||||
Quick description
|
||||
Quick description and explanation of changes
|
||||
|
||||
## Types of changes
|
||||
|
||||
- [ ] Bugfix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] Configuration change (this will require users to update their yaml configuration files to keep working)
|
||||
- [ ] Other
|
||||
|
||||
**Related issue or feature (if applicable):** fixes <link to issue>
|
||||
|
||||
**Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs#<esphome-docs PR number goes here>
|
||||
|
||||
# Test Environment
|
||||
## Test Environment
|
||||
|
||||
- [ ] ESP32
|
||||
- [ ] ESP8266
|
||||
- [ ] Windows
|
||||
- [ ] Mac OS
|
||||
- [ ] Linux
|
||||
|
||||
## Example entry for `config.yaml`:
|
||||
<!--
|
||||
@ -34,11 +31,6 @@ Quick description
|
||||
|
||||
```
|
||||
|
||||
# Explain your changes
|
||||
|
||||
Describe your changes here to communicate to the maintainers **why we should accept this pull request**.
|
||||
Very important to fill if no issue linked
|
||||
|
||||
## Checklist:
|
||||
- [ ] The code change is tested and works locally.
|
||||
- [ ] Tests have been added to verify that the new code works (under `tests/` folder).
|
||||
|
2
.github/workflows/ci-docker.yml
vendored
2
.github/workflows/ci-docker.yml
vendored
@ -26,7 +26,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up env variables
|
||||
run: |
|
||||
base_version="3.0.0"
|
||||
base_version="3.4.0"
|
||||
|
||||
if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
|
||||
build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
|
||||
|
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
# cpp lint job runs with esphome-lint docker image so that clang-format-*
|
||||
# doesn't have to be installed
|
||||
container: esphome/esphome-lint:latest
|
||||
container: esphome/esphome-lint:1.1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
# Set up the pio project so that the cpp checks know how files are compiled
|
||||
@ -32,7 +32,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
# cpp lint job runs with esphome-lint docker image so that clang-format-*
|
||||
# doesn't have to be installed
|
||||
container: esphome/esphome-lint:latest
|
||||
container: esphome/esphome-lint:1.1
|
||||
# Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@ -97,6 +97,7 @@ jobs:
|
||||
- test2
|
||||
- test3
|
||||
- test4
|
||||
- test5
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
@ -126,7 +127,7 @@ jobs:
|
||||
run: |
|
||||
echo "::add-matcher::.github/workflows/matchers/gcc.json"
|
||||
echo "::add-matcher::.github/workflows/matchers/python.json"
|
||||
- run: esphome tests/${{ matrix.test }}.yaml compile
|
||||
- run: esphome compile tests/${{ matrix.test }}.yaml
|
||||
|
||||
pytest:
|
||||
runs-on: ubuntu-latest
|
||||
|
6
.github/workflows/docker-lint-build.yml
vendored
6
.github/workflows/docker-lint-build.yml
vendored
@ -7,6 +7,7 @@ on:
|
||||
paths:
|
||||
- 'docker/Dockerfile.lint'
|
||||
- 'requirements.txt'
|
||||
- 'requirements_optional.txt'
|
||||
- 'requirements_test.txt'
|
||||
- 'platformio.ini'
|
||||
- '.github/workflows/docker-lint-build.yml'
|
||||
@ -17,6 +18,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set TAG
|
||||
run: |
|
||||
echo "TAG=1.1" >> $GITHUB_ENV
|
||||
- name: Pull for cache
|
||||
run: |
|
||||
docker pull "esphome/esphome-lint:latest" || true
|
||||
@ -26,6 +30,7 @@ jobs:
|
||||
--cache-from "esphome/esphome-lint:latest" \
|
||||
--file "docker/Dockerfile.lint" \
|
||||
--tag "esphome/esphome-lint:latest" \
|
||||
--tag "esphome/esphome-lint:${TAG}" \
|
||||
.
|
||||
- name: Log in to docker hub
|
||||
env:
|
||||
@ -33,4 +38,5 @@ jobs:
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
run: docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}"
|
||||
- run: |
|
||||
docker push "esphome/esphome-lint:${TAG}"
|
||||
docker push "esphome/esphome-lint:latest"
|
||||
|
9
.github/workflows/release-dev.yml
vendored
9
.github/workflows/release-dev.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
# cpp lint job runs with esphome-lint docker image so that clang-format-*
|
||||
# doesn't have to be installed
|
||||
container: esphome/esphome-lint:latest
|
||||
container: esphome/esphome-lint:1.1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
# Set up the pio project so that the cpp checks know how files are compiled
|
||||
@ -29,7 +29,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
# cpp lint job runs with esphome-lint docker image so that clang-format-*
|
||||
# doesn't have to be installed
|
||||
container: esphome/esphome-lint:latest
|
||||
container: esphome/esphome-lint:1.1
|
||||
# Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@ -94,6 +94,7 @@ jobs:
|
||||
- test2
|
||||
- test3
|
||||
- test4
|
||||
- test5
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
@ -123,7 +124,7 @@ jobs:
|
||||
run: |
|
||||
echo "::add-matcher::.github/workflows/matchers/gcc.json"
|
||||
echo "::add-matcher::.github/workflows/matchers/python.json"
|
||||
- run: esphome tests/${{ matrix.test }}.yaml compile
|
||||
- run: esphome compile tests/${{ matrix.test }}.yaml
|
||||
|
||||
pytest:
|
||||
runs-on: ubuntu-latest
|
||||
@ -174,7 +175,7 @@ jobs:
|
||||
echo "TAG=${TAG}" >> $GITHUB_ENV
|
||||
- name: Set up env variables
|
||||
run: |
|
||||
base_version="3.0.0"
|
||||
base_version="3.4.0"
|
||||
|
||||
if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
|
||||
build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
|
||||
|
9
.github/workflows/release.yml
vendored
9
.github/workflows/release.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
# cpp lint job runs with esphome-lint docker image so that clang-format-*
|
||||
# doesn't have to be installed
|
||||
container: esphome/esphome-lint:latest
|
||||
container: esphome/esphome-lint:1.1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
# Set up the pio project so that the cpp checks know how files are compiled
|
||||
@ -28,7 +28,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
# cpp lint job runs with esphome-lint docker image so that clang-format-*
|
||||
# doesn't have to be installed
|
||||
container: esphome/esphome-lint:latest
|
||||
container: esphome/esphome-lint:1.1
|
||||
# Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@ -93,6 +93,7 @@ jobs:
|
||||
- test2
|
||||
- test3
|
||||
- test4
|
||||
- test5
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
@ -121,7 +122,7 @@ jobs:
|
||||
run: |
|
||||
echo "::add-matcher::.github/workflows/matchers/gcc.json"
|
||||
echo "::add-matcher::.github/workflows/matchers/python.json"
|
||||
- run: esphome tests/${{ matrix.test }}.yaml compile
|
||||
- run: esphome compile tests/${{ matrix.test }}.yaml
|
||||
|
||||
pytest:
|
||||
runs-on: ubuntu-latest
|
||||
@ -194,7 +195,7 @@ jobs:
|
||||
echo "TAG=${TAG}" >> $GITHUB_ENV
|
||||
- name: Set up env variables
|
||||
run: |
|
||||
base_version="3.0.0"
|
||||
base_version="3.4.0"
|
||||
|
||||
if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
|
||||
build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -100,6 +100,8 @@ CMakeLists.txt
|
||||
|
||||
# CMake
|
||||
cmake-build-debug/
|
||||
cmake-build-livingroom8266/
|
||||
cmake-build-livingroom32/
|
||||
cmake-build-release/
|
||||
|
||||
CMakeCache.txt
|
||||
|
2
.vscode/tasks.json
vendored
2
.vscode/tasks.json
vendored
@ -4,7 +4,7 @@
|
||||
{
|
||||
"label": "run",
|
||||
"type": "shell",
|
||||
"command": "python3 -m esphome config dashboard",
|
||||
"command": "python3 -m esphome dashboard config",
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
|
@ -29,11 +29,14 @@ esphome/components/climate/* @esphome/core
|
||||
esphome/components/climate_ir/* @glmnet
|
||||
esphome/components/coolix/* @glmnet
|
||||
esphome/components/cover/* @esphome/core
|
||||
esphome/components/cs5460a/* @balrog-kun
|
||||
esphome/components/ct_clamp/* @jesserockz
|
||||
esphome/components/debug/* @OttoWinter
|
||||
esphome/components/dfplayer/* @glmnet
|
||||
esphome/components/dht/* @OttoWinter
|
||||
esphome/components/ds1307/* @badbadc0ffee
|
||||
esphome/components/esp32_ble/* @jesserockz
|
||||
esphome/components/esp32_improv/* @jesserockz
|
||||
esphome/components/exposure_notifications/* @OttoWinter
|
||||
esphome/components/ezo/* @ssieb
|
||||
esphome/components/fastled_base/* @OttoWinter
|
||||
@ -43,6 +46,7 @@ esphome/components/gpio/* @esphome/core
|
||||
esphome/components/gps/* @coogle
|
||||
esphome/components/homeassistant/* @OttoWinter
|
||||
esphome/components/i2c/* @esphome/core
|
||||
esphome/components/improv/* @jesserockz
|
||||
esphome/components/inkbird_ibsth1_mini/* @fkirill
|
||||
esphome/components/inkplate6/* @jesserockz
|
||||
esphome/components/integration/* @OttoWinter
|
||||
@ -63,6 +67,7 @@ esphome/components/mcp2515/* @danielschramm @mvturnho
|
||||
esphome/components/mcp9808/* @k7hpn
|
||||
esphome/components/midea_ac/* @dudanov
|
||||
esphome/components/midea_dongle/* @dudanov
|
||||
esphome/components/mitsubishi/* @RubyBailey
|
||||
esphome/components/network/* @esphome/core
|
||||
esphome/components/nfc/* @jesserockz
|
||||
esphome/components/ota/* @esphome/core
|
||||
@ -80,6 +85,7 @@ esphome/components/restart/* @esphome/core
|
||||
esphome/components/rf_bridge/* @jesserockz
|
||||
esphome/components/rtttl/* @glmnet
|
||||
esphome/components/script/* @esphome/core
|
||||
esphome/components/sdm_meter/* @jesserockz @polyfaces
|
||||
esphome/components/sensor/* @esphome/core
|
||||
esphome/components/sgp40/* @SenexCrenshaw
|
||||
esphome/components/sht4x/* @sjtrny
|
||||
@ -122,3 +128,4 @@ esphome/components/web_server_base/* @OttoWinter
|
||||
esphome/components/whirlpool/* @glmnet
|
||||
esphome/components/xiaomi_lywsd03mmc/* @ahpohl
|
||||
esphome/components/xiaomi_mhoc401/* @vevsvevs
|
||||
esphome/components/xpt2046/* @numo68
|
||||
|
@ -1,10 +1,10 @@
|
||||
ARG BUILD_FROM=esphome/esphome-base-amd64:3.0.0
|
||||
ARG BUILD_FROM=esphome/esphome-base-amd64:3.4.0
|
||||
FROM ${BUILD_FROM}
|
||||
|
||||
# First install requirements to leverage caching when requirements don't change
|
||||
COPY requirements.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 \
|
||||
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
|
||||
&& /platformio_install_deps.py /platformio.ini
|
||||
|
||||
# Then copy esphome and install
|
||||
@ -27,4 +27,4 @@ WORKDIR /config
|
||||
# in every docker command twice
|
||||
ENTRYPOINT ["esphome"]
|
||||
# When no arguments given, start the dashboard in the workdir
|
||||
CMD ["/config", "dashboard"]
|
||||
CMD ["dashboard", "/config"]
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM esphome/esphome-base-amd64:3.0.0
|
||||
FROM esphome/esphome-base-amd64:3.4.0
|
||||
|
||||
COPY . .
|
||||
|
||||
|
@ -2,9 +2,9 @@ ARG BUILD_FROM
|
||||
FROM ${BUILD_FROM}
|
||||
|
||||
# First install requirements to leverage caching when requirements don't change
|
||||
COPY requirements.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 \
|
||||
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
|
||||
&& /platformio_install_deps.py /platformio.ini
|
||||
|
||||
# Copy root filesystem
|
||||
|
@ -1,8 +1,8 @@
|
||||
FROM esphome/esphome-lint-base:3.0.0
|
||||
FROM esphome/esphome-lint-base:3.4.0
|
||||
|
||||
COPY requirements.txt requirements_test.txt docker/platformio_install_deps.py platformio.ini /
|
||||
COPY requirements.txt requirements_optional.txt requirements_test.txt docker/platformio_install_deps.py platformio.ini /
|
||||
RUN \
|
||||
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_test.txt \
|
||||
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt -r /requirements_test.txt \
|
||||
&& /platformio_install_deps.py /platformio.ini
|
||||
|
||||
VOLUME ["/esphome"]
|
||||
|
@ -23,4 +23,4 @@ if bashio::config.has_value 'relative_url'; then
|
||||
fi
|
||||
|
||||
bashio::log.info "Starting ESPHome dashboard..."
|
||||
exec esphome /config/esphome dashboard --socket /var/run/esphome.sock --hassio
|
||||
exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --hassio
|
||||
|
@ -18,7 +18,7 @@ from esphome.const import (
|
||||
CONF_ESPHOME,
|
||||
CONF_PLATFORMIO_OPTIONS,
|
||||
)
|
||||
from esphome.core import CORE, EsphomeError, coroutine, coroutine_with_priority
|
||||
from esphome.core import CORE, EsphomeError, coroutine
|
||||
from esphome.helpers import indent
|
||||
from esphome.util import (
|
||||
run_external_command,
|
||||
@ -127,15 +127,16 @@ def wrap_to_code(name, comp):
|
||||
coro = coroutine(comp.to_code)
|
||||
|
||||
@functools.wraps(comp.to_code)
|
||||
@coroutine_with_priority(coro.priority)
|
||||
def wrapped(conf):
|
||||
async def wrapped(conf):
|
||||
cg.add(cg.LineComment(f"{name}:"))
|
||||
if comp.config_schema is not None:
|
||||
conf_str = yaml_util.dump(conf)
|
||||
conf_str = conf_str.replace("//", "")
|
||||
cg.add(cg.LineComment(indent(conf_str)))
|
||||
yield coro(conf)
|
||||
await coro(conf)
|
||||
|
||||
if hasattr(coro, "priority"):
|
||||
wrapped.priority = coro.priority
|
||||
return wrapped
|
||||
|
||||
|
||||
@ -267,7 +268,7 @@ def clean_mqtt(config, args):
|
||||
def command_wizard(args):
|
||||
from esphome import wizard
|
||||
|
||||
return wizard.wizard(args.configuration[0])
|
||||
return wizard.wizard(args.configuration)
|
||||
|
||||
|
||||
def command_config(args, config):
|
||||
@ -283,7 +284,7 @@ def command_vscode(args):
|
||||
|
||||
logging.disable(logging.INFO)
|
||||
logging.disable(logging.WARNING)
|
||||
CORE.config_path = args.configuration[0]
|
||||
CORE.config_path = args.configuration
|
||||
vscode.read_config(args)
|
||||
|
||||
|
||||
@ -303,7 +304,7 @@ def command_compile(args, config):
|
||||
|
||||
def command_upload(args, config):
|
||||
port = choose_upload_log_host(
|
||||
default=args.upload_port,
|
||||
default=args.device,
|
||||
check_default=None,
|
||||
show_ota=True,
|
||||
show_mqtt=False,
|
||||
@ -318,7 +319,7 @@ def command_upload(args, config):
|
||||
|
||||
def command_logs(args, config):
|
||||
port = choose_upload_log_host(
|
||||
default=args.serial_port,
|
||||
default=args.device,
|
||||
check_default=None,
|
||||
show_ota=False,
|
||||
show_mqtt=True,
|
||||
@ -336,7 +337,7 @@ def command_run(args, config):
|
||||
return exit_code
|
||||
_LOGGER.info("Successfully compiled program.")
|
||||
port = choose_upload_log_host(
|
||||
default=args.upload_port,
|
||||
default=args.device,
|
||||
check_default=None,
|
||||
show_ota=True,
|
||||
show_mqtt=False,
|
||||
@ -349,7 +350,7 @@ def command_run(args, config):
|
||||
if args.no_logs:
|
||||
return 0
|
||||
port = choose_upload_log_host(
|
||||
default=args.upload_port,
|
||||
default=args.device,
|
||||
check_default=port,
|
||||
show_ota=False,
|
||||
show_mqtt=True,
|
||||
@ -393,7 +394,7 @@ def command_update_all(args):
|
||||
import click
|
||||
|
||||
success = {}
|
||||
files = list_yaml_files(args.configuration[0])
|
||||
files = list_yaml_files(args.configuration)
|
||||
twidth = 60
|
||||
|
||||
def print_bar(middle_text):
|
||||
@ -407,7 +408,7 @@ def command_update_all(args):
|
||||
print("-" * twidth)
|
||||
print()
|
||||
rc = run_external_process(
|
||||
"esphome", "--dashboard", f, "run", "--no-logs", "--upload-port", "OTA"
|
||||
"esphome", "--dashboard", "run", f, "--no-logs", "--device", "OTA"
|
||||
)
|
||||
if rc == 0:
|
||||
print_bar("[{}] {}".format(color(Fore.BOLD_GREEN, "SUCCESS"), f))
|
||||
@ -452,15 +453,17 @@ POST_CONFIG_ACTIONS = {
|
||||
|
||||
|
||||
def parse_args(argv):
|
||||
parser = argparse.ArgumentParser(description=f"ESPHome v{const.__version__}")
|
||||
parser.add_argument(
|
||||
"-v", "--verbose", help="Enable verbose esphome logs.", action="store_true"
|
||||
options_parser = argparse.ArgumentParser(add_help=False)
|
||||
options_parser.add_argument(
|
||||
"-v", "--verbose", help="Enable verbose ESPHome logs.", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-q", "--quiet", help="Disable all esphome logs.", action="store_true"
|
||||
options_parser.add_argument(
|
||||
"-q", "--quiet", help="Disable all ESPHome logs.", action="store_true"
|
||||
)
|
||||
parser.add_argument("--dashboard", help=argparse.SUPPRESS, action="store_true")
|
||||
parser.add_argument(
|
||||
options_parser.add_argument(
|
||||
"--dashboard", help=argparse.SUPPRESS, action="store_true"
|
||||
)
|
||||
options_parser.add_argument(
|
||||
"-s",
|
||||
"--substitution",
|
||||
nargs=2,
|
||||
@ -468,17 +471,87 @@ def parse_args(argv):
|
||||
help="Add a substitution",
|
||||
metavar=("key", "value"),
|
||||
)
|
||||
parser.add_argument(
|
||||
"configuration", help="Your YAML configuration file.", nargs="*"
|
||||
|
||||
# Keep backward compatibility with the old command line format of
|
||||
# esphome <config> <command>.
|
||||
#
|
||||
# Unfortunately this can't be done by adding another configuration argument to the
|
||||
# main config parser, as argparse is greedy when parsing arguments, so in regular
|
||||
# usage it'll eat the command as the configuration argument and error out out
|
||||
# because it can't parse the configuration as a command.
|
||||
#
|
||||
# Instead, construct an ad-hoc parser for the old format that doesn't actually
|
||||
# process the arguments, but parses them enough to let us figure out if the old
|
||||
# format is used. In that case, swap the command and configuration in the arguments
|
||||
# and continue on with the normal parser (after raising a deprecation warning).
|
||||
#
|
||||
# Disable argparse's built-in help option and add it manually to prevent this
|
||||
# parser from printing the help messagefor the old format when invoked with -h.
|
||||
compat_parser = argparse.ArgumentParser(parents=[options_parser], add_help=False)
|
||||
compat_parser.add_argument("-h", "--help")
|
||||
compat_parser.add_argument("configuration", nargs="*")
|
||||
compat_parser.add_argument(
|
||||
"command",
|
||||
choices=[
|
||||
"config",
|
||||
"compile",
|
||||
"upload",
|
||||
"logs",
|
||||
"run",
|
||||
"clean-mqtt",
|
||||
"wizard",
|
||||
"mqtt-fingerprint",
|
||||
"version",
|
||||
"clean",
|
||||
"dashboard",
|
||||
],
|
||||
)
|
||||
|
||||
subparsers = parser.add_subparsers(help="Commands", dest="command")
|
||||
# on Python 3.9+ we can simply set exit_on_error=False in the constructor
|
||||
def _raise(x):
|
||||
raise argparse.ArgumentError(None, x)
|
||||
|
||||
compat_parser.error = _raise
|
||||
|
||||
try:
|
||||
result, unparsed = compat_parser.parse_known_args(argv[1:])
|
||||
last_option = len(argv) - len(unparsed) - 1 - len(result.configuration)
|
||||
argv = argv[0:last_option] + [result.command] + result.configuration + unparsed
|
||||
deprecated_argv_suggestion = argv
|
||||
except argparse.ArgumentError:
|
||||
# This is not an old-style command line, so we don't have to do anything.
|
||||
deprecated_argv_suggestion = None
|
||||
|
||||
# And continue on with regular parsing
|
||||
parser = argparse.ArgumentParser(
|
||||
description=f"ESPHome v{const.__version__}", parents=[options_parser]
|
||||
)
|
||||
parser.set_defaults(deprecated_argv_suggestion=deprecated_argv_suggestion)
|
||||
|
||||
mqtt_options = argparse.ArgumentParser(add_help=False)
|
||||
mqtt_options.add_argument("--topic", help="Manually set the MQTT topic.")
|
||||
mqtt_options.add_argument("--username", help="Manually set the MQTT username.")
|
||||
mqtt_options.add_argument("--password", help="Manually set the MQTT password.")
|
||||
mqtt_options.add_argument("--client-id", help="Manually set the MQTT client id.")
|
||||
|
||||
subparsers = parser.add_subparsers(
|
||||
help="Command to run:", dest="command", metavar="command"
|
||||
)
|
||||
subparsers.required = True
|
||||
subparsers.add_parser("config", help="Validate the configuration and spit it out.")
|
||||
|
||||
parser_config = subparsers.add_parser(
|
||||
"config", help="Validate the configuration and spit it out."
|
||||
)
|
||||
parser_config.add_argument(
|
||||
"configuration", help="Your YAML configuration file(s).", nargs="+"
|
||||
)
|
||||
|
||||
parser_compile = subparsers.add_parser(
|
||||
"compile", help="Read the configuration and compile a program."
|
||||
)
|
||||
parser_compile.add_argument(
|
||||
"configuration", help="Your YAML configuration file(s).", nargs="+"
|
||||
)
|
||||
parser_compile.add_argument(
|
||||
"--only-generate",
|
||||
help="Only generate source code, do not compile.",
|
||||
@ -486,106 +559,124 @@ def parse_args(argv):
|
||||
)
|
||||
|
||||
parser_upload = subparsers.add_parser(
|
||||
"upload", help="Validate the configuration " "and upload the latest binary."
|
||||
"upload", help="Validate the configuration and upload the latest binary."
|
||||
)
|
||||
parser_upload.add_argument(
|
||||
"--upload-port",
|
||||
help="Manually specify the upload port to use. "
|
||||
"For example /dev/cu.SLAB_USBtoUART.",
|
||||
"configuration", help="Your YAML configuration file(s).", nargs="+"
|
||||
)
|
||||
parser_upload.add_argument(
|
||||
"--device",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
|
||||
)
|
||||
|
||||
parser_logs = subparsers.add_parser(
|
||||
"logs", help="Validate the configuration " "and show all MQTT logs."
|
||||
"logs",
|
||||
help="Validate the configuration and show all logs.",
|
||||
parents=[mqtt_options],
|
||||
)
|
||||
parser_logs.add_argument("--topic", help="Manually set the topic to subscribe to.")
|
||||
parser_logs.add_argument("--username", help="Manually set the username.")
|
||||
parser_logs.add_argument("--password", help="Manually set the password.")
|
||||
parser_logs.add_argument("--client-id", help="Manually set the client id.")
|
||||
parser_logs.add_argument(
|
||||
"--serial-port",
|
||||
help="Manually specify a serial port to use"
|
||||
"For example /dev/cu.SLAB_USBtoUART.",
|
||||
"configuration", help="Your YAML configuration file.", nargs=1
|
||||
)
|
||||
parser_logs.add_argument(
|
||||
"--device",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
|
||||
)
|
||||
|
||||
parser_run = subparsers.add_parser(
|
||||
"run",
|
||||
help="Validate the configuration, create a binary, "
|
||||
"upload it, and start MQTT logs.",
|
||||
help="Validate the configuration, create a binary, upload it, and start logs.",
|
||||
parents=[mqtt_options],
|
||||
)
|
||||
parser_run.add_argument(
|
||||
"--upload-port",
|
||||
help="Manually specify the upload port/ip to use. "
|
||||
"For example /dev/cu.SLAB_USBtoUART.",
|
||||
"configuration", help="Your YAML configuration file(s).", nargs="+"
|
||||
)
|
||||
parser_run.add_argument(
|
||||
"--no-logs", help="Disable starting MQTT logs.", action="store_true"
|
||||
"--device",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
|
||||
)
|
||||
parser_run.add_argument(
|
||||
"--topic", help="Manually set the topic to subscribe to for logs."
|
||||
"--no-logs", help="Disable starting logs.", action="store_true"
|
||||
)
|
||||
parser_run.add_argument(
|
||||
"--username", help="Manually set the MQTT username for logs."
|
||||
)
|
||||
parser_run.add_argument(
|
||||
"--password", help="Manually set the MQTT password for logs."
|
||||
)
|
||||
parser_run.add_argument("--client-id", help="Manually set the client id for logs.")
|
||||
|
||||
parser_clean = subparsers.add_parser(
|
||||
"clean-mqtt", help="Helper to clear an MQTT topic from " "retain messages."
|
||||
"clean-mqtt",
|
||||
help="Helper to clear retained messages from an MQTT topic.",
|
||||
parents=[mqtt_options],
|
||||
)
|
||||
parser_clean.add_argument(
|
||||
"configuration", help="Your YAML configuration file(s).", nargs="+"
|
||||
)
|
||||
parser_clean.add_argument("--topic", help="Manually set the topic to subscribe to.")
|
||||
parser_clean.add_argument("--username", help="Manually set the username.")
|
||||
parser_clean.add_argument("--password", help="Manually set the password.")
|
||||
parser_clean.add_argument("--client-id", help="Manually set the client id.")
|
||||
|
||||
subparsers.add_parser(
|
||||
parser_wizard = subparsers.add_parser(
|
||||
"wizard",
|
||||
help="A helpful setup wizard that will guide "
|
||||
"you through setting up esphome.",
|
||||
help="A helpful setup wizard that will guide you through setting up ESPHome.",
|
||||
)
|
||||
parser_wizard.add_argument(
|
||||
"configuration",
|
||||
help="Your YAML configuration file.",
|
||||
)
|
||||
|
||||
subparsers.add_parser(
|
||||
parser_fingerprint = subparsers.add_parser(
|
||||
"mqtt-fingerprint", help="Get the SSL fingerprint from a MQTT broker."
|
||||
)
|
||||
parser_fingerprint.add_argument(
|
||||
"configuration", help="Your YAML configuration file(s).", nargs="+"
|
||||
)
|
||||
|
||||
subparsers.add_parser("version", help="Print the esphome version and exit.")
|
||||
subparsers.add_parser("version", help="Print the ESPHome version and exit.")
|
||||
|
||||
subparsers.add_parser("clean", help="Delete all temporary build files.")
|
||||
parser_clean = subparsers.add_parser(
|
||||
"clean", help="Delete all temporary build files."
|
||||
)
|
||||
parser_clean.add_argument(
|
||||
"configuration", help="Your YAML configuration file(s).", nargs="+"
|
||||
)
|
||||
|
||||
dashboard = subparsers.add_parser(
|
||||
parser_dashboard = subparsers.add_parser(
|
||||
"dashboard", help="Create a simple web server for a dashboard."
|
||||
)
|
||||
dashboard.add_argument(
|
||||
parser_dashboard.add_argument(
|
||||
"configuration",
|
||||
help="Your YAML configuration file directory.",
|
||||
)
|
||||
parser_dashboard.add_argument(
|
||||
"--port",
|
||||
help="The HTTP port to open connections on. Defaults to 6052.",
|
||||
type=int,
|
||||
default=6052,
|
||||
)
|
||||
dashboard.add_argument(
|
||||
parser_dashboard.add_argument(
|
||||
"--username",
|
||||
help="The optional username to require " "for authentication.",
|
||||
help="The optional username to require for authentication.",
|
||||
type=str,
|
||||
default="",
|
||||
)
|
||||
dashboard.add_argument(
|
||||
parser_dashboard.add_argument(
|
||||
"--password",
|
||||
help="The optional password to require " "for authentication.",
|
||||
help="The optional password to require for authentication.",
|
||||
type=str,
|
||||
default="",
|
||||
)
|
||||
dashboard.add_argument(
|
||||
parser_dashboard.add_argument(
|
||||
"--open-ui", help="Open the dashboard UI in a browser.", action="store_true"
|
||||
)
|
||||
dashboard.add_argument("--hassio", help=argparse.SUPPRESS, action="store_true")
|
||||
dashboard.add_argument(
|
||||
parser_dashboard.add_argument(
|
||||
"--hassio", help=argparse.SUPPRESS, action="store_true"
|
||||
)
|
||||
parser_dashboard.add_argument(
|
||||
"--socket", help="Make the dashboard serve under a unix socket", type=str
|
||||
)
|
||||
|
||||
vscode = subparsers.add_parser("vscode", help=argparse.SUPPRESS)
|
||||
vscode.add_argument("--ace", action="store_true")
|
||||
parser_vscode = subparsers.add_parser("vscode")
|
||||
parser_vscode.add_argument(
|
||||
"configuration", help="Your YAML configuration file.", nargs=1
|
||||
)
|
||||
parser_vscode.add_argument("--ace", action="store_true")
|
||||
|
||||
subparsers.add_parser("update-all", help=argparse.SUPPRESS)
|
||||
parser_update = subparsers.add_parser("update-all")
|
||||
parser_update.add_argument(
|
||||
"configuration", help="Your YAML configuration file directory.", nargs=1
|
||||
)
|
||||
|
||||
return parser.parse_args(argv[1:])
|
||||
|
||||
@ -595,9 +686,13 @@ def run_esphome(argv):
|
||||
CORE.dashboard = args.dashboard
|
||||
|
||||
setup_log(args.verbose, args.quiet)
|
||||
if args.command != "version" and not args.configuration:
|
||||
_LOGGER.error("Missing configuration parameter, see esphome --help.")
|
||||
return 1
|
||||
if args.deprecated_argv_suggestion is not None:
|
||||
_LOGGER.warning(
|
||||
"Calling ESPHome with the configuration before the command is deprecated "
|
||||
"and will be removed in the future. "
|
||||
)
|
||||
_LOGGER.warning("Please instead use:")
|
||||
_LOGGER.warning(" esphome %s", " ".join(args.deprecated_argv_suggestion[1:]))
|
||||
|
||||
if sys.version_info < (3, 7, 0):
|
||||
_LOGGER.error(
|
||||
@ -610,7 +705,7 @@ def run_esphome(argv):
|
||||
try:
|
||||
return PRE_CONFIG_ACTIONS[args.command](args)
|
||||
except EsphomeError as e:
|
||||
_LOGGER.error(e)
|
||||
_LOGGER.error(e, exc_info=args.verbose)
|
||||
return 1
|
||||
|
||||
for conf_path in args.configuration:
|
||||
@ -628,7 +723,7 @@ def run_esphome(argv):
|
||||
try:
|
||||
rc = POST_CONFIG_ACTIONS[args.command](args, config)
|
||||
except EsphomeError as e:
|
||||
_LOGGER.error(e)
|
||||
_LOGGER.error(e, exc_info=args.verbose)
|
||||
return 1
|
||||
if rc != 0:
|
||||
return rc
|
||||
|
@ -10,7 +10,6 @@ from esphome.const import (
|
||||
CONF_TYPE_ID,
|
||||
CONF_TIME,
|
||||
)
|
||||
from esphome.core import coroutine
|
||||
from esphome.jsonschema import jschema_extractor
|
||||
from esphome.util import Registry
|
||||
|
||||
@ -142,27 +141,27 @@ NotCondition = cg.esphome_ns.class_("NotCondition", Condition)
|
||||
|
||||
|
||||
@register_condition("and", AndCondition, validate_condition_list)
|
||||
def and_condition_to_code(config, condition_id, template_arg, args):
|
||||
conditions = yield build_condition_list(config, template_arg, args)
|
||||
yield cg.new_Pvariable(condition_id, template_arg, conditions)
|
||||
async def and_condition_to_code(config, condition_id, template_arg, args):
|
||||
conditions = await build_condition_list(config, template_arg, args)
|
||||
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
||||
|
||||
|
||||
@register_condition("or", OrCondition, validate_condition_list)
|
||||
def or_condition_to_code(config, condition_id, template_arg, args):
|
||||
conditions = yield build_condition_list(config, template_arg, args)
|
||||
yield cg.new_Pvariable(condition_id, template_arg, conditions)
|
||||
async def or_condition_to_code(config, condition_id, template_arg, args):
|
||||
conditions = await build_condition_list(config, template_arg, args)
|
||||
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
||||
|
||||
|
||||
@register_condition("not", NotCondition, validate_potentially_and_condition)
|
||||
def not_condition_to_code(config, condition_id, template_arg, args):
|
||||
condition = yield build_condition(config, template_arg, args)
|
||||
yield cg.new_Pvariable(condition_id, template_arg, condition)
|
||||
async def not_condition_to_code(config, condition_id, template_arg, args):
|
||||
condition = await build_condition(config, template_arg, args)
|
||||
return cg.new_Pvariable(condition_id, template_arg, condition)
|
||||
|
||||
|
||||
@register_condition("lambda", LambdaCondition, cv.lambda_)
|
||||
def lambda_condition_to_code(config, condition_id, template_arg, args):
|
||||
lambda_ = yield cg.process_lambda(config, args, return_type=bool)
|
||||
yield cg.new_Pvariable(condition_id, template_arg, lambda_)
|
||||
@register_condition("lambda", LambdaCondition, cv.returning_lambda)
|
||||
async def lambda_condition_to_code(config, condition_id, template_arg, args):
|
||||
lambda_ = await cg.process_lambda(config, args, return_type=bool)
|
||||
return cg.new_Pvariable(condition_id, template_arg, lambda_)
|
||||
|
||||
|
||||
@register_condition(
|
||||
@ -177,26 +176,26 @@ def lambda_condition_to_code(config, condition_id, template_arg, args):
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
)
|
||||
def for_condition_to_code(config, condition_id, template_arg, args):
|
||||
condition = yield build_condition(
|
||||
async def for_condition_to_code(config, condition_id, template_arg, args):
|
||||
condition = await build_condition(
|
||||
config[CONF_CONDITION], cg.TemplateArguments(), []
|
||||
)
|
||||
var = cg.new_Pvariable(condition_id, template_arg, condition)
|
||||
yield cg.register_component(var, config)
|
||||
templ = yield cg.templatable(config[CONF_TIME], args, cg.uint32)
|
||||
await cg.register_component(var, config)
|
||||
templ = await cg.templatable(config[CONF_TIME], args, cg.uint32)
|
||||
cg.add(var.set_time(templ))
|
||||
yield var
|
||||
return var
|
||||
|
||||
|
||||
@register_action(
|
||||
"delay", DelayAction, cv.templatable(cv.positive_time_period_milliseconds)
|
||||
)
|
||||
def delay_action_to_code(config, action_id, template_arg, args):
|
||||
async def delay_action_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_component(var, {})
|
||||
template_ = yield cg.templatable(config, args, cg.uint32)
|
||||
await cg.register_component(var, {})
|
||||
template_ = await cg.templatable(config, args, cg.uint32)
|
||||
cg.add(var.set_delay(template_))
|
||||
yield var
|
||||
return var
|
||||
|
||||
|
||||
@register_action(
|
||||
@ -211,16 +210,16 @@ def delay_action_to_code(config, action_id, template_arg, args):
|
||||
cv.has_at_least_one_key(CONF_THEN, CONF_ELSE),
|
||||
),
|
||||
)
|
||||
def if_action_to_code(config, action_id, template_arg, args):
|
||||
conditions = yield build_condition(config[CONF_CONDITION], template_arg, args)
|
||||
async def if_action_to_code(config, action_id, template_arg, args):
|
||||
conditions = await build_condition(config[CONF_CONDITION], template_arg, args)
|
||||
var = cg.new_Pvariable(action_id, template_arg, conditions)
|
||||
if CONF_THEN in config:
|
||||
actions = yield build_action_list(config[CONF_THEN], template_arg, args)
|
||||
actions = await build_action_list(config[CONF_THEN], template_arg, args)
|
||||
cg.add(var.add_then(actions))
|
||||
if CONF_ELSE in config:
|
||||
actions = yield build_action_list(config[CONF_ELSE], template_arg, args)
|
||||
actions = await build_action_list(config[CONF_ELSE], template_arg, args)
|
||||
cg.add(var.add_else(actions))
|
||||
yield var
|
||||
return var
|
||||
|
||||
|
||||
@register_action(
|
||||
@ -233,12 +232,12 @@ def if_action_to_code(config, action_id, template_arg, args):
|
||||
}
|
||||
),
|
||||
)
|
||||
def while_action_to_code(config, action_id, template_arg, args):
|
||||
conditions = yield build_condition(config[CONF_CONDITION], template_arg, args)
|
||||
async def while_action_to_code(config, action_id, template_arg, args):
|
||||
conditions = await build_condition(config[CONF_CONDITION], template_arg, args)
|
||||
var = cg.new_Pvariable(action_id, template_arg, conditions)
|
||||
actions = yield build_action_list(config[CONF_THEN], template_arg, args)
|
||||
actions = await build_action_list(config[CONF_THEN], template_arg, args)
|
||||
cg.add(var.add_then(actions))
|
||||
yield var
|
||||
return var
|
||||
|
||||
|
||||
def validate_wait_until(value):
|
||||
@ -253,17 +252,17 @@ def validate_wait_until(value):
|
||||
|
||||
|
||||
@register_action("wait_until", WaitUntilAction, validate_wait_until)
|
||||
def wait_until_action_to_code(config, action_id, template_arg, args):
|
||||
conditions = yield build_condition(config[CONF_CONDITION], template_arg, args)
|
||||
async def wait_until_action_to_code(config, action_id, template_arg, args):
|
||||
conditions = await build_condition(config[CONF_CONDITION], template_arg, args)
|
||||
var = cg.new_Pvariable(action_id, template_arg, conditions)
|
||||
yield cg.register_component(var, {})
|
||||
yield var
|
||||
await cg.register_component(var, {})
|
||||
return var
|
||||
|
||||
|
||||
@register_action("lambda", LambdaAction, cv.lambda_)
|
||||
def lambda_action_to_code(config, action_id, template_arg, args):
|
||||
lambda_ = yield cg.process_lambda(config, args, return_type=cg.void)
|
||||
yield cg.new_Pvariable(action_id, template_arg, lambda_)
|
||||
async def lambda_action_to_code(config, action_id, template_arg, args):
|
||||
lambda_ = await cg.process_lambda(config, args, return_type=cg.void)
|
||||
return cg.new_Pvariable(action_id, template_arg, lambda_)
|
||||
|
||||
|
||||
@register_action(
|
||||
@ -275,54 +274,51 @@ def lambda_action_to_code(config, action_id, template_arg, args):
|
||||
}
|
||||
),
|
||||
)
|
||||
def component_update_action_to_code(config, action_id, template_arg, args):
|
||||
comp = yield cg.get_variable(config[CONF_ID])
|
||||
yield cg.new_Pvariable(action_id, template_arg, comp)
|
||||
async def component_update_action_to_code(config, action_id, template_arg, args):
|
||||
comp = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, comp)
|
||||
|
||||
|
||||
@coroutine
|
||||
def build_action(full_config, template_arg, args):
|
||||
async def build_action(full_config, template_arg, args):
|
||||
registry_entry, config = cg.extract_registry_entry_config(
|
||||
ACTION_REGISTRY, full_config
|
||||
)
|
||||
action_id = full_config[CONF_TYPE_ID]
|
||||
builder = registry_entry.coroutine_fun
|
||||
yield builder(config, action_id, template_arg, args)
|
||||
ret = await builder(config, action_id, template_arg, args)
|
||||
return ret
|
||||
|
||||
|
||||
@coroutine
|
||||
def build_action_list(config, templ, arg_type):
|
||||
async def build_action_list(config, templ, arg_type):
|
||||
actions = []
|
||||
for conf in config:
|
||||
action = yield build_action(conf, templ, arg_type)
|
||||
action = await build_action(conf, templ, arg_type)
|
||||
actions.append(action)
|
||||
yield actions
|
||||
return actions
|
||||
|
||||
|
||||
@coroutine
|
||||
def build_condition(full_config, template_arg, args):
|
||||
async def build_condition(full_config, template_arg, args):
|
||||
registry_entry, config = cg.extract_registry_entry_config(
|
||||
CONDITION_REGISTRY, full_config
|
||||
)
|
||||
action_id = full_config[CONF_TYPE_ID]
|
||||
builder = registry_entry.coroutine_fun
|
||||
yield builder(config, action_id, template_arg, args)
|
||||
ret = await builder(config, action_id, template_arg, args)
|
||||
return ret
|
||||
|
||||
|
||||
@coroutine
|
||||
def build_condition_list(config, templ, args):
|
||||
async def build_condition_list(config, templ, args):
|
||||
conditions = []
|
||||
for conf in config:
|
||||
condition = yield build_condition(conf, templ, args)
|
||||
condition = await build_condition(conf, templ, args)
|
||||
conditions.append(condition)
|
||||
yield conditions
|
||||
return conditions
|
||||
|
||||
|
||||
@coroutine
|
||||
def build_automation(trigger, args, config):
|
||||
async def build_automation(trigger, args, config):
|
||||
arg_types = [arg[0] for arg in args]
|
||||
templ = cg.TemplateArguments(*arg_types)
|
||||
obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ, trigger)
|
||||
actions = yield build_action_list(config[CONF_THEN], templ, args)
|
||||
actions = await build_action_list(config[CONF_THEN], templ, args)
|
||||
cg.add(obj.add_actions(actions))
|
||||
yield obj
|
||||
return obj
|
||||
|
@ -19,6 +19,7 @@ from esphome.cpp_generator import ( # noqa
|
||||
Statement,
|
||||
LineComment,
|
||||
progmem_array,
|
||||
static_const_array,
|
||||
statement,
|
||||
variable,
|
||||
new_variable,
|
||||
|
@ -18,16 +18,16 @@ CONFIG_SCHEMA = stepper.STEPPER_SCHEMA.extend(
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield stepper.register_stepper(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await stepper.register_stepper(var, config)
|
||||
|
||||
step_pin = yield cg.gpio_pin_expression(config[CONF_STEP_PIN])
|
||||
step_pin = await cg.gpio_pin_expression(config[CONF_STEP_PIN])
|
||||
cg.add(var.set_step_pin(step_pin))
|
||||
dir_pin = yield cg.gpio_pin_expression(config[CONF_DIR_PIN])
|
||||
dir_pin = await cg.gpio_pin_expression(config[CONF_DIR_PIN])
|
||||
cg.add(var.set_dir_pin(dir_pin))
|
||||
|
||||
if CONF_SLEEP_PIN in config:
|
||||
sleep_pin = yield cg.gpio_pin_expression(config[CONF_SLEEP_PIN])
|
||||
sleep_pin = await cg.gpio_pin_expression(config[CONF_SLEEP_PIN])
|
||||
cg.add(var.set_sleep_pin(sleep_pin))
|
||||
|
@ -32,18 +32,18 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend(
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
await cg.register_component(var, config)
|
||||
|
||||
# override default min power to 10%
|
||||
if CONF_MIN_POWER not in config:
|
||||
config[CONF_MIN_POWER] = 0.1
|
||||
yield output.register_output(var, config)
|
||||
await output.register_output(var, config)
|
||||
|
||||
pin = yield cg.gpio_pin_expression(config[CONF_GATE_PIN])
|
||||
pin = await cg.gpio_pin_expression(config[CONF_GATE_PIN])
|
||||
cg.add(var.set_gate_pin(pin))
|
||||
pin = yield cg.gpio_pin_expression(config[CONF_ZERO_CROSS_PIN])
|
||||
pin = await cg.gpio_pin_expression(config[CONF_ZERO_CROSS_PIN])
|
||||
cg.add(var.set_zero_cross_pin(pin))
|
||||
cg.add(var.set_init_with_half_cycle(config[CONF_INIT_WITH_HALF_CYCLE]))
|
||||
cg.add(var.set_method(config[CONF_METHOD]))
|
||||
|
@ -21,8 +21,7 @@ CONFIG_SCHEMA = cv.Schema({})
|
||||
"Adalight",
|
||||
{cv.GenerateID(CONF_UART_ID): cv.use_id(uart.UARTComponent)},
|
||||
)
|
||||
def adalight_light_effect_to_code(config, effect_id):
|
||||
async def adalight_light_effect_to_code(config, effect_id):
|
||||
effect = cg.new_Pvariable(effect_id, config[CONF_NAME])
|
||||
yield uart.register_uart_device(effect, config)
|
||||
|
||||
yield effect
|
||||
await uart.register_uart_device(effect, config)
|
||||
return effect
|
||||
|
@ -8,6 +8,7 @@ from esphome.const import (
|
||||
CONF_PIN,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
ICON_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_VOLT,
|
||||
)
|
||||
|
||||
@ -35,7 +36,9 @@ ADCSensor = adc_ns.class_(
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
sensor.sensor_schema(UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE)
|
||||
sensor.sensor_schema(
|
||||
UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
|
||||
)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ADCSensor),
|
||||
@ -49,10 +52,10 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield sensor.register_sensor(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await sensor.register_sensor(var, config)
|
||||
|
||||
if config[CONF_PIN] == "VCC":
|
||||
cg.add_define("USE_ADC_SENSOR_VCC")
|
||||
|
@ -38,18 +38,18 @@ CONFIG_SCHEMA = cv.All(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
wrapped_light = yield cg.get_variable(config[CONF_ADDRESSABLE_LIGHT_ID])
|
||||
wrapped_light = await cg.get_variable(config[CONF_ADDRESSABLE_LIGHT_ID])
|
||||
cg.add(var.set_width(config[CONF_WIDTH]))
|
||||
cg.add(var.set_height(config[CONF_HEIGHT]))
|
||||
cg.add(var.set_light(wrapped_light))
|
||||
|
||||
yield cg.register_component(var, config)
|
||||
yield display.register_display(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await display.register_display(var, config)
|
||||
|
||||
if CONF_PIXEL_MAPPER in config:
|
||||
pixel_mapper_template_ = yield cg.process_lambda(
|
||||
pixel_mapper_template_ = await cg.process_lambda(
|
||||
config[CONF_PIXEL_MAPPER],
|
||||
[(int, "x"), (int, "y")],
|
||||
return_type=cg.int_,
|
||||
@ -57,7 +57,7 @@ def to_code(config):
|
||||
cg.add(var.set_pixel_mapper(pixel_mapper_template_))
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
lambda_ = yield cg.process_lambda(
|
||||
lambda_ = await cg.process_lambda(
|
||||
config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void
|
||||
)
|
||||
cg.add(var.set_writer(lambda_))
|
||||
|
@ -9,6 +9,7 @@ from esphome.const import (
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
ICON_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_VOLT,
|
||||
UNIT_AMPERE,
|
||||
UNIT_WATT,
|
||||
@ -31,19 +32,27 @@ CONFIG_SCHEMA = (
|
||||
cv.GenerateID(): cv.declare_id(ADE7953),
|
||||
cv.Optional(CONF_IRQ_PIN): pins.input_pin,
|
||||
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
|
||||
UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
|
||||
UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
|
||||
),
|
||||
cv.Optional(CONF_CURRENT_A): sensor.sensor_schema(
|
||||
UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT
|
||||
UNIT_AMPERE,
|
||||
ICON_EMPTY,
|
||||
2,
|
||||
DEVICE_CLASS_CURRENT,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_CURRENT_B): sensor.sensor_schema(
|
||||
UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT
|
||||
UNIT_AMPERE,
|
||||
ICON_EMPTY,
|
||||
2,
|
||||
DEVICE_CLASS_CURRENT,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_ACTIVE_POWER_A): sensor.sensor_schema(
|
||||
UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER
|
||||
UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
|
||||
),
|
||||
cv.Optional(CONF_ACTIVE_POWER_B): sensor.sensor_schema(
|
||||
UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER
|
||||
UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
|
||||
),
|
||||
}
|
||||
)
|
||||
@ -52,10 +61,10 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
if CONF_IRQ_PIN in config:
|
||||
cg.add(var.set_irq_pin(config[CONF_IRQ_PIN]))
|
||||
@ -70,5 +79,5 @@ def to_code(config):
|
||||
if key not in config:
|
||||
continue
|
||||
conf = config[key]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(getattr(var, f"set_{key}_sensor")(sens))
|
||||
|
@ -23,9 +23,9 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
cg.add(var.set_continuous_mode(config[CONF_CONTINUOUS_MODE]))
|
||||
|
@ -6,6 +6,7 @@ from esphome.const import (
|
||||
CONF_MULTIPLEXER,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
ICON_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_VOLT,
|
||||
CONF_ID,
|
||||
)
|
||||
@ -51,7 +52,9 @@ ADS1115Sensor = ads1115_ns.class_(
|
||||
|
||||
CONF_ADS1115_ID = "ads1115_id"
|
||||
CONFIG_SCHEMA = (
|
||||
sensor.sensor_schema(UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE)
|
||||
sensor.sensor_schema(
|
||||
UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
|
||||
)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ADS1115Sensor),
|
||||
@ -64,11 +67,11 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
paren = yield cg.get_variable(config[CONF_ADS1115_ID])
|
||||
async def to_code(config):
|
||||
paren = await cg.get_variable(config[CONF_ADS1115_ID])
|
||||
var = cg.new_Pvariable(config[CONF_ID], paren)
|
||||
yield sensor.register_sensor(var, config)
|
||||
yield cg.register_component(var, config)
|
||||
await sensor.register_sensor(var, config)
|
||||
await cg.register_component(var, config)
|
||||
|
||||
cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
|
||||
cg.add(var.set_gain(config[CONF_GAIN]))
|
||||
|
@ -60,6 +60,7 @@ void AHT10Component::update() {
|
||||
delay = AHT10_HUMIDITY_DELAY;
|
||||
for (int i = 0; i < AHT10_ATTEMPS; ++i) {
|
||||
ESP_LOGVV(TAG, "Attemps %u at %6ld", i, millis());
|
||||
delay_microseconds_accurate(4);
|
||||
if (!this->read_bytes(0, data, 6, delay)) {
|
||||
ESP_LOGD(TAG, "Communication with AHT10 failed, waiting...");
|
||||
} else if ((data[0] & 0x80) == 0x80) { // Bit[7] = 0b1, device is busy
|
||||
|
@ -8,6 +8,7 @@ from esphome.const import (
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
ICON_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_PERCENT,
|
||||
)
|
||||
@ -22,10 +23,18 @@ CONFIG_SCHEMA = (
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(AHT10Component),
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
UNIT_CELSIUS, ICON_EMPTY, 2, DEVICE_CLASS_TEMPERATURE
|
||||
UNIT_CELSIUS,
|
||||
ICON_EMPTY,
|
||||
2,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
|
||||
UNIT_PERCENT, ICON_EMPTY, 2, DEVICE_CLASS_HUMIDITY
|
||||
UNIT_PERCENT,
|
||||
ICON_EMPTY,
|
||||
2,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
}
|
||||
)
|
||||
@ -34,15 +43,15 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
if CONF_TEMPERATURE in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
|
||||
sens = await sensor.new_sensor(config[CONF_TEMPERATURE])
|
||||
cg.add(var.set_temperature_sensor(sens))
|
||||
|
||||
if CONF_HUMIDITY in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_HUMIDITY])
|
||||
sens = await sensor.new_sensor(config[CONF_HUMIDITY])
|
||||
cg.add(var.set_humidity_sensor(sens))
|
||||
|
@ -7,6 +7,7 @@ from esphome.const import (
|
||||
CONF_TEMPERATURE,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
ICON_EMPTY,
|
||||
UNIT_PERCENT,
|
||||
@ -24,10 +25,18 @@ CONFIG_SCHEMA = (
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(AM2320Component),
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
|
||||
UNIT_CELSIUS,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
|
||||
UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY
|
||||
UNIT_PERCENT,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
}
|
||||
)
|
||||
@ -36,15 +45,15 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
if CONF_TEMPERATURE in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
|
||||
sens = await sensor.new_sensor(config[CONF_TEMPERATURE])
|
||||
cg.add(var.set_temperature_sensor(sens))
|
||||
|
||||
if CONF_HUMIDITY in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_HUMIDITY])
|
||||
sens = await sensor.new_sensor(config[CONF_HUMIDITY])
|
||||
cg.add(var.set_humidity_sensor(sens))
|
||||
|
@ -34,7 +34,7 @@ CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, ANIMATION_SCHEMA)
|
||||
CODEOWNERS = ["@syndlex"]
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
from PIL import Image
|
||||
|
||||
path = CORE.relative_config_path(config[CONF_FILE])
|
||||
|
@ -23,7 +23,7 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
@ -24,8 +24,8 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = yield cg.get_variable(config[CONF_APDS9960_ID])
|
||||
var = yield binary_sensor.new_binary_sensor(config)
|
||||
async def to_code(config):
|
||||
hub = await cg.get_variable(config[CONF_APDS9960_ID])
|
||||
var = await binary_sensor.new_binary_sensor(config)
|
||||
func = getattr(hub, DIRECTIONS[config[CONF_DIRECTION]])
|
||||
cg.add(func(var))
|
||||
|
@ -1,7 +1,13 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor
|
||||
from esphome.const import CONF_TYPE, DEVICE_CLASS_EMPTY, UNIT_PERCENT, ICON_LIGHTBULB
|
||||
from esphome.const import (
|
||||
CONF_TYPE,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_PERCENT,
|
||||
ICON_LIGHTBULB,
|
||||
)
|
||||
from . import APDS9960, CONF_APDS9960_ID
|
||||
|
||||
DEPENDENCIES = ["apds9960"]
|
||||
@ -15,7 +21,7 @@ TYPES = {
|
||||
}
|
||||
|
||||
CONFIG_SCHEMA = sensor.sensor_schema(
|
||||
UNIT_PERCENT, ICON_LIGHTBULB, 1, DEVICE_CLASS_EMPTY
|
||||
UNIT_PERCENT, ICON_LIGHTBULB, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT
|
||||
).extend(
|
||||
{
|
||||
cv.Required(CONF_TYPE): cv.one_of(*TYPES, upper=True),
|
||||
@ -24,8 +30,8 @@ CONFIG_SCHEMA = sensor.sensor_schema(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = yield cg.get_variable(config[CONF_APDS9960_ID])
|
||||
var = yield sensor.new_sensor(config)
|
||||
async def to_code(config):
|
||||
hub = await cg.get_variable(config[CONF_APDS9960_ID])
|
||||
var = await sensor.new_sensor(config)
|
||||
func = getattr(hub, TYPES[config[CONF_TYPE]])
|
||||
cg.add(func(var))
|
||||
|
@ -68,9 +68,9 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
|
||||
|
||||
@coroutine_with_priority(40.0)
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
await cg.register_component(var, config)
|
||||
|
||||
cg.add(var.set_port(config[CONF_PORT]))
|
||||
cg.add(var.set_password(config[CONF_PASSWORD]))
|
||||
@ -90,7 +90,7 @@ def to_code(config):
|
||||
conf[CONF_TRIGGER_ID], templ, conf[CONF_SERVICE], service_arg_names
|
||||
)
|
||||
cg.add(var.register_user_service(trigger))
|
||||
yield automation.build_automation(trigger, func_args, conf)
|
||||
await automation.build_automation(trigger, func_args, conf)
|
||||
|
||||
cg.add_define("USE_API")
|
||||
cg.add_global(api_ns.using)
|
||||
@ -116,21 +116,21 @@ HOMEASSISTANT_SERVICE_ACTION_SCHEMA = cv.Schema(
|
||||
HomeAssistantServiceCallAction,
|
||||
HOMEASSISTANT_SERVICE_ACTION_SCHEMA,
|
||||
)
|
||||
def homeassistant_service_to_code(config, action_id, template_arg, args):
|
||||
serv = yield cg.get_variable(config[CONF_ID])
|
||||
async def homeassistant_service_to_code(config, action_id, template_arg, args):
|
||||
serv = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, serv, False)
|
||||
templ = yield cg.templatable(config[CONF_SERVICE], args, None)
|
||||
templ = await cg.templatable(config[CONF_SERVICE], args, None)
|
||||
cg.add(var.set_service(templ))
|
||||
for key, value in config[CONF_DATA].items():
|
||||
templ = yield cg.templatable(value, args, None)
|
||||
templ = await cg.templatable(value, args, None)
|
||||
cg.add(var.add_data(key, templ))
|
||||
for key, value in config[CONF_DATA_TEMPLATE].items():
|
||||
templ = yield cg.templatable(value, args, None)
|
||||
templ = await cg.templatable(value, args, None)
|
||||
cg.add(var.add_data_template(key, templ))
|
||||
for key, value in config[CONF_VARIABLES].items():
|
||||
templ = yield cg.templatable(value, args, None)
|
||||
templ = await cg.templatable(value, args, None)
|
||||
cg.add(var.add_variable(key, templ))
|
||||
yield var
|
||||
return var
|
||||
|
||||
|
||||
def validate_homeassistant_event(value):
|
||||
@ -159,21 +159,21 @@ HOMEASSISTANT_EVENT_ACTION_SCHEMA = cv.Schema(
|
||||
HomeAssistantServiceCallAction,
|
||||
HOMEASSISTANT_EVENT_ACTION_SCHEMA,
|
||||
)
|
||||
def homeassistant_event_to_code(config, action_id, template_arg, args):
|
||||
serv = yield cg.get_variable(config[CONF_ID])
|
||||
async def homeassistant_event_to_code(config, action_id, template_arg, args):
|
||||
serv = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, serv, True)
|
||||
templ = yield cg.templatable(config[CONF_EVENT], args, None)
|
||||
templ = await cg.templatable(config[CONF_EVENT], args, None)
|
||||
cg.add(var.set_service(templ))
|
||||
for key, value in config[CONF_DATA].items():
|
||||
templ = yield cg.templatable(value, args, None)
|
||||
templ = await cg.templatable(value, args, None)
|
||||
cg.add(var.add_data(key, templ))
|
||||
for key, value in config[CONF_DATA_TEMPLATE].items():
|
||||
templ = yield cg.templatable(value, args, None)
|
||||
templ = await cg.templatable(value, args, None)
|
||||
cg.add(var.add_data_template(key, templ))
|
||||
for key, value in config[CONF_VARIABLES].items():
|
||||
templ = yield cg.templatable(value, args, None)
|
||||
templ = await cg.templatable(value, args, None)
|
||||
cg.add(var.add_variable(key, templ))
|
||||
yield var
|
||||
return var
|
||||
|
||||
|
||||
HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA = cv.maybe_simple_value(
|
||||
@ -190,15 +190,15 @@ HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA = cv.maybe_simple_value(
|
||||
HomeAssistantServiceCallAction,
|
||||
HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA,
|
||||
)
|
||||
def homeassistant_tag_scanned_to_code(config, action_id, template_arg, args):
|
||||
serv = yield cg.get_variable(config[CONF_ID])
|
||||
async def homeassistant_tag_scanned_to_code(config, action_id, template_arg, args):
|
||||
serv = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, serv, True)
|
||||
cg.add(var.set_service("esphome.tag_scanned"))
|
||||
templ = yield cg.templatable(config[CONF_TAG], args, cg.std_string)
|
||||
templ = await cg.templatable(config[CONF_TAG], args, cg.std_string)
|
||||
cg.add(var.add_data("tag_id", templ))
|
||||
yield var
|
||||
return var
|
||||
|
||||
|
||||
@automation.register_condition("api.connected", APIConnectedCondition, {})
|
||||
def api_connected_to_code(config, condition_id, template_arg, args):
|
||||
yield cg.new_Pvariable(condition_id, template_arg)
|
||||
async def api_connected_to_code(config, condition_id, template_arg, args):
|
||||
return cg.new_Pvariable(condition_id, template_arg)
|
||||
|
@ -176,6 +176,10 @@ message DeviceInfoResponse {
|
||||
string model = 6;
|
||||
|
||||
bool has_deep_sleep = 7;
|
||||
|
||||
// The esphome project details if set
|
||||
string project_name = 8;
|
||||
string project_version = 9;
|
||||
}
|
||||
|
||||
message ListEntitiesRequest {
|
||||
@ -409,6 +413,11 @@ message LightCommandRequest {
|
||||
}
|
||||
|
||||
// ==================== SENSOR ====================
|
||||
enum SensorStateClass {
|
||||
STATE_CLASS_NONE = 0;
|
||||
STATE_CLASS_MEASUREMENT = 1;
|
||||
}
|
||||
|
||||
message ListEntitiesSensorResponse {
|
||||
option (id) = 16;
|
||||
option (source) = SOURCE_SERVER;
|
||||
@ -424,6 +433,7 @@ message ListEntitiesSensorResponse {
|
||||
int32 accuracy_decimals = 7;
|
||||
bool force_update = 8;
|
||||
string device_class = 9;
|
||||
SensorStateClass state_class = 10;
|
||||
}
|
||||
message SensorStateResponse {
|
||||
option (id) = 25;
|
||||
@ -561,6 +571,7 @@ message SubscribeHomeAssistantStateResponse {
|
||||
option (id) = 39;
|
||||
option (source) = SOURCE_SERVER;
|
||||
string entity_id = 1;
|
||||
string attribute = 2;
|
||||
}
|
||||
|
||||
message HomeAssistantStateResponse {
|
||||
@ -570,6 +581,7 @@ message HomeAssistantStateResponse {
|
||||
|
||||
string entity_id = 1;
|
||||
string state = 2;
|
||||
string attribute = 3;
|
||||
}
|
||||
|
||||
// ==================== IMPORT TIME ====================
|
||||
@ -664,11 +676,12 @@ message CameraImageRequest {
|
||||
// ==================== CLIMATE ====================
|
||||
enum ClimateMode {
|
||||
CLIMATE_MODE_OFF = 0;
|
||||
CLIMATE_MODE_AUTO = 1;
|
||||
CLIMATE_MODE_HEAT_COOL = 1;
|
||||
CLIMATE_MODE_COOL = 2;
|
||||
CLIMATE_MODE_HEAT = 3;
|
||||
CLIMATE_MODE_FAN_ONLY = 4;
|
||||
CLIMATE_MODE_DRY = 5;
|
||||
CLIMATE_MODE_AUTO = 6;
|
||||
}
|
||||
enum ClimateFanMode {
|
||||
CLIMATE_FAN_ON = 0;
|
||||
@ -696,6 +709,15 @@ enum ClimateAction {
|
||||
CLIMATE_ACTION_DRYING = 5;
|
||||
CLIMATE_ACTION_FAN = 6;
|
||||
}
|
||||
enum ClimatePreset {
|
||||
CLIMATE_PRESET_ECO = 0;
|
||||
CLIMATE_PRESET_AWAY = 1;
|
||||
CLIMATE_PRESET_BOOST = 2;
|
||||
CLIMATE_PRESET_COMFORT = 3;
|
||||
CLIMATE_PRESET_HOME = 4;
|
||||
CLIMATE_PRESET_SLEEP = 5;
|
||||
CLIMATE_PRESET_ACTIVITY = 6;
|
||||
}
|
||||
message ListEntitiesClimateResponse {
|
||||
option (id) = 46;
|
||||
option (source) = SOURCE_SERVER;
|
||||
@ -716,6 +738,9 @@ message ListEntitiesClimateResponse {
|
||||
bool supports_action = 12;
|
||||
repeated ClimateFanMode supported_fan_modes = 13;
|
||||
repeated ClimateSwingMode supported_swing_modes = 14;
|
||||
repeated string supported_custom_fan_modes = 15;
|
||||
repeated ClimatePreset supported_presets = 16;
|
||||
repeated string supported_custom_presets = 17;
|
||||
}
|
||||
message ClimateStateResponse {
|
||||
option (id) = 47;
|
||||
@ -733,6 +758,9 @@ message ClimateStateResponse {
|
||||
ClimateAction action = 8;
|
||||
ClimateFanMode fan_mode = 9;
|
||||
ClimateSwingMode swing_mode = 10;
|
||||
string custom_fan_mode = 11;
|
||||
ClimatePreset preset = 12;
|
||||
string custom_preset = 13;
|
||||
}
|
||||
message ClimateCommandRequest {
|
||||
option (id) = 48;
|
||||
@ -755,4 +783,10 @@ message ClimateCommandRequest {
|
||||
ClimateFanMode fan_mode = 13;
|
||||
bool has_swing_mode = 14;
|
||||
ClimateSwingMode swing_mode = 15;
|
||||
bool has_custom_fan_mode = 16;
|
||||
string custom_fan_mode = 17;
|
||||
bool has_preset = 18;
|
||||
ClimatePreset preset = 19;
|
||||
bool has_custom_preset = 20;
|
||||
string custom_preset = 21;
|
||||
}
|
||||
|
@ -395,6 +395,8 @@ bool APIConnection::send_sensor_info(sensor::Sensor *sensor) {
|
||||
msg.accuracy_decimals = sensor->get_accuracy_decimals();
|
||||
msg.force_update = sensor->get_force_update();
|
||||
msg.device_class = sensor->get_device_class();
|
||||
msg.state_class = static_cast<enums::SensorStateClass>(sensor->state_class);
|
||||
|
||||
return this->send_list_entities_sensor_response(msg);
|
||||
}
|
||||
#endif
|
||||
@ -475,8 +477,14 @@ bool APIConnection::send_climate_state(climate::Climate *climate) {
|
||||
}
|
||||
if (traits.get_supports_away())
|
||||
resp.away = climate->away;
|
||||
if (traits.get_supports_fan_modes())
|
||||
resp.fan_mode = static_cast<enums::ClimateFanMode>(climate->fan_mode);
|
||||
if (traits.get_supports_fan_modes() && climate->fan_mode.has_value())
|
||||
resp.fan_mode = static_cast<enums::ClimateFanMode>(climate->fan_mode.value());
|
||||
if (!traits.get_supported_custom_fan_modes().empty() && climate->custom_fan_mode.has_value())
|
||||
resp.custom_fan_mode = climate->custom_fan_mode.value();
|
||||
if (traits.get_supports_presets() && climate->preset.has_value())
|
||||
resp.preset = static_cast<enums::ClimatePreset>(climate->preset.value());
|
||||
if (!traits.get_supported_custom_presets().empty() && climate->custom_preset.has_value())
|
||||
resp.custom_preset = climate->custom_preset.value();
|
||||
if (traits.get_supports_swing_modes())
|
||||
resp.swing_mode = static_cast<enums::ClimateSwingMode>(climate->swing_mode);
|
||||
return this->send_climate_state_response(resp);
|
||||
@ -490,8 +498,9 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
|
||||
msg.unique_id = get_default_unique_id("climate", climate);
|
||||
msg.supports_current_temperature = traits.get_supports_current_temperature();
|
||||
msg.supports_two_point_target_temperature = traits.get_supports_two_point_target_temperature();
|
||||
for (auto mode : {climate::CLIMATE_MODE_AUTO, climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL,
|
||||
climate::CLIMATE_MODE_HEAT, climate::CLIMATE_MODE_DRY, climate::CLIMATE_MODE_FAN_ONLY}) {
|
||||
for (auto mode :
|
||||
{climate::CLIMATE_MODE_AUTO, climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL, climate::CLIMATE_MODE_HEAT,
|
||||
climate::CLIMATE_MODE_DRY, climate::CLIMATE_MODE_FAN_ONLY, climate::CLIMATE_MODE_HEAT_COOL}) {
|
||||
if (traits.supports_mode(mode))
|
||||
msg.supported_modes.push_back(static_cast<enums::ClimateMode>(mode));
|
||||
}
|
||||
@ -506,6 +515,18 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
|
||||
if (traits.supports_fan_mode(fan_mode))
|
||||
msg.supported_fan_modes.push_back(static_cast<enums::ClimateFanMode>(fan_mode));
|
||||
}
|
||||
for (auto const &custom_fan_mode : traits.get_supported_custom_fan_modes()) {
|
||||
msg.supported_custom_fan_modes.push_back(custom_fan_mode);
|
||||
}
|
||||
for (auto preset : {climate::CLIMATE_PRESET_ECO, climate::CLIMATE_PRESET_AWAY, climate::CLIMATE_PRESET_BOOST,
|
||||
climate::CLIMATE_PRESET_COMFORT, climate::CLIMATE_PRESET_HOME, climate::CLIMATE_PRESET_SLEEP,
|
||||
climate::CLIMATE_PRESET_ACTIVITY}) {
|
||||
if (traits.supports_preset(preset))
|
||||
msg.supported_presets.push_back(static_cast<enums::ClimatePreset>(preset));
|
||||
}
|
||||
for (auto const &custom_preset : traits.get_supported_custom_presets()) {
|
||||
msg.supported_custom_presets.push_back(custom_preset);
|
||||
}
|
||||
for (auto swing_mode : {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_BOTH, climate::CLIMATE_SWING_VERTICAL,
|
||||
climate::CLIMATE_SWING_HORIZONTAL}) {
|
||||
if (traits.supports_swing_mode(swing_mode))
|
||||
@ -531,6 +552,12 @@ void APIConnection::climate_command(const ClimateCommandRequest &msg) {
|
||||
call.set_away(msg.away);
|
||||
if (msg.has_fan_mode)
|
||||
call.set_fan_mode(static_cast<climate::ClimateFanMode>(msg.fan_mode));
|
||||
if (msg.has_custom_fan_mode)
|
||||
call.set_fan_mode(msg.custom_fan_mode);
|
||||
if (msg.has_preset)
|
||||
call.set_preset(static_cast<climate::ClimatePreset>(msg.preset));
|
||||
if (msg.has_custom_preset)
|
||||
call.set_preset(msg.custom_preset);
|
||||
if (msg.has_swing_mode)
|
||||
call.set_swing_mode(static_cast<climate::ClimateSwingMode>(msg.swing_mode));
|
||||
call.perform();
|
||||
@ -637,14 +664,19 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
|
||||
#endif
|
||||
#ifdef USE_DEEP_SLEEP
|
||||
resp.has_deep_sleep = deep_sleep::global_has_deep_sleep;
|
||||
#endif
|
||||
#ifdef ESPHOME_PROJECT_NAME
|
||||
resp.project_name = ESPHOME_PROJECT_NAME;
|
||||
resp.project_version = ESPHOME_PROJECT_VERSION;
|
||||
#endif
|
||||
return resp;
|
||||
}
|
||||
void APIConnection::on_home_assistant_state_response(const HomeAssistantStateResponse &msg) {
|
||||
for (auto &it : this->parent_->get_state_subs())
|
||||
if (it.entity_id == msg.entity_id)
|
||||
if (it.entity_id == msg.entity_id && it.attribute.value() == msg.attribute) {
|
||||
it.callback(msg.state);
|
||||
}
|
||||
}
|
||||
void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
|
||||
bool found = false;
|
||||
for (auto *service : this->parent_->get_user_services()) {
|
||||
@ -660,6 +692,7 @@ void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistant
|
||||
for (auto &it : this->parent_->get_state_subs()) {
|
||||
SubscribeHomeAssistantStateResponse resp;
|
||||
resp.entity_id = it.entity_id;
|
||||
resp.attribute = it.attribute.value();
|
||||
if (!this->send_subscribe_home_assistant_state_response(resp)) {
|
||||
this->on_fatal_error();
|
||||
return;
|
||||
|
@ -62,6 +62,16 @@ template<> const char *proto_enum_to_string<enums::FanDirection>(enums::FanDirec
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::SensorStateClass value) {
|
||||
switch (value) {
|
||||
case enums::STATE_CLASS_NONE:
|
||||
return "STATE_CLASS_NONE";
|
||||
case enums::STATE_CLASS_MEASUREMENT:
|
||||
return "STATE_CLASS_MEASUREMENT";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel value) {
|
||||
switch (value) {
|
||||
case enums::LOG_LEVEL_NONE:
|
||||
@ -108,8 +118,8 @@ template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMo
|
||||
switch (value) {
|
||||
case enums::CLIMATE_MODE_OFF:
|
||||
return "CLIMATE_MODE_OFF";
|
||||
case enums::CLIMATE_MODE_AUTO:
|
||||
return "CLIMATE_MODE_AUTO";
|
||||
case enums::CLIMATE_MODE_HEAT_COOL:
|
||||
return "CLIMATE_MODE_HEAT_COOL";
|
||||
case enums::CLIMATE_MODE_COOL:
|
||||
return "CLIMATE_MODE_COOL";
|
||||
case enums::CLIMATE_MODE_HEAT:
|
||||
@ -118,6 +128,8 @@ template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMo
|
||||
return "CLIMATE_MODE_FAN_ONLY";
|
||||
case enums::CLIMATE_MODE_DRY:
|
||||
return "CLIMATE_MODE_DRY";
|
||||
case enums::CLIMATE_MODE_AUTO:
|
||||
return "CLIMATE_MODE_AUTO";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@ -178,6 +190,26 @@ template<> const char *proto_enum_to_string<enums::ClimateAction>(enums::Climate
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::ClimatePreset value) {
|
||||
switch (value) {
|
||||
case enums::CLIMATE_PRESET_ECO:
|
||||
return "CLIMATE_PRESET_ECO";
|
||||
case enums::CLIMATE_PRESET_AWAY:
|
||||
return "CLIMATE_PRESET_AWAY";
|
||||
case enums::CLIMATE_PRESET_BOOST:
|
||||
return "CLIMATE_PRESET_BOOST";
|
||||
case enums::CLIMATE_PRESET_COMFORT:
|
||||
return "CLIMATE_PRESET_COMFORT";
|
||||
case enums::CLIMATE_PRESET_HOME:
|
||||
return "CLIMATE_PRESET_HOME";
|
||||
case enums::CLIMATE_PRESET_SLEEP:
|
||||
return "CLIMATE_PRESET_SLEEP";
|
||||
case enums::CLIMATE_PRESET_ACTIVITY:
|
||||
return "CLIMATE_PRESET_ACTIVITY";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||
switch (field_id) {
|
||||
case 1: {
|
||||
@ -328,6 +360,14 @@ bool DeviceInfoResponse::decode_length(uint32_t field_id, ProtoLengthDelimited v
|
||||
this->model = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 8: {
|
||||
this->project_name = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 9: {
|
||||
this->project_version = value.as_string();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -340,6 +380,8 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_string(5, this->compilation_time);
|
||||
buffer.encode_string(6, this->model);
|
||||
buffer.encode_bool(7, this->has_deep_sleep);
|
||||
buffer.encode_string(8, this->project_name);
|
||||
buffer.encode_string(9, this->project_version);
|
||||
}
|
||||
void DeviceInfoResponse::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
@ -371,6 +413,14 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
|
||||
out.append(" has_deep_sleep: ");
|
||||
out.append(YESNO(this->has_deep_sleep));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" project_name: ");
|
||||
out.append("'").append(this->project_name).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" project_version: ");
|
||||
out.append("'").append(this->project_version).append("'");
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
void ListEntitiesRequest::encode(ProtoWriteBuffer buffer) const {}
|
||||
@ -1507,6 +1557,10 @@ bool ListEntitiesSensorResponse::decode_varint(uint32_t field_id, ProtoVarInt va
|
||||
this->force_update = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 10: {
|
||||
this->state_class = value.as_enum<enums::SensorStateClass>();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -1561,6 +1615,7 @@ void ListEntitiesSensorResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_int32(7, this->accuracy_decimals);
|
||||
buffer.encode_bool(8, this->force_update);
|
||||
buffer.encode_string(9, this->device_class);
|
||||
buffer.encode_enum<enums::SensorStateClass>(10, this->state_class);
|
||||
}
|
||||
void ListEntitiesSensorResponse::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
@ -1602,6 +1657,10 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const {
|
||||
out.append(" device_class: ");
|
||||
out.append("'").append(this->device_class).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" state_class: ");
|
||||
out.append(proto_enum_to_string<enums::SensorStateClass>(this->state_class));
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
bool SensorStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
@ -2123,12 +2182,17 @@ bool SubscribeHomeAssistantStateResponse::decode_length(uint32_t field_id, Proto
|
||||
this->entity_id = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 2: {
|
||||
this->attribute = value.as_string();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_string(1, this->entity_id);
|
||||
buffer.encode_string(2, this->attribute);
|
||||
}
|
||||
void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
@ -2136,6 +2200,10 @@ void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const {
|
||||
out.append(" entity_id: ");
|
||||
out.append("'").append(this->entity_id).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" attribute: ");
|
||||
out.append("'").append(this->attribute).append("'");
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||
@ -2148,6 +2216,10 @@ bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDel
|
||||
this->state = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 3: {
|
||||
this->attribute = value.as_string();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -2155,6 +2227,7 @@ bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDel
|
||||
void HomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_string(1, this->entity_id);
|
||||
buffer.encode_string(2, this->state);
|
||||
buffer.encode_string(3, this->attribute);
|
||||
}
|
||||
void HomeAssistantStateResponse::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
@ -2166,6 +2239,10 @@ void HomeAssistantStateResponse::dump_to(std::string &out) const {
|
||||
out.append(" state: ");
|
||||
out.append("'").append(this->state).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" attribute: ");
|
||||
out.append("'").append(this->attribute).append("'");
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
void GetTimeRequest::encode(ProtoWriteBuffer buffer) const {}
|
||||
@ -2610,6 +2687,10 @@ bool ListEntitiesClimateResponse::decode_varint(uint32_t field_id, ProtoVarInt v
|
||||
this->supported_swing_modes.push_back(value.as_enum<enums::ClimateSwingMode>());
|
||||
return true;
|
||||
}
|
||||
case 16: {
|
||||
this->supported_presets.push_back(value.as_enum<enums::ClimatePreset>());
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -2628,6 +2709,14 @@ bool ListEntitiesClimateResponse::decode_length(uint32_t field_id, ProtoLengthDe
|
||||
this->unique_id = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 15: {
|
||||
this->supported_custom_fan_modes.push_back(value.as_string());
|
||||
return true;
|
||||
}
|
||||
case 17: {
|
||||
this->supported_custom_presets.push_back(value.as_string());
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -2675,6 +2764,15 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
for (auto &it : this->supported_swing_modes) {
|
||||
buffer.encode_enum<enums::ClimateSwingMode>(14, it, true);
|
||||
}
|
||||
for (auto &it : this->supported_custom_fan_modes) {
|
||||
buffer.encode_string(15, it, true);
|
||||
}
|
||||
for (auto &it : this->supported_presets) {
|
||||
buffer.encode_enum<enums::ClimatePreset>(16, it, true);
|
||||
}
|
||||
for (auto &it : this->supported_custom_presets) {
|
||||
buffer.encode_string(17, it, true);
|
||||
}
|
||||
}
|
||||
void ListEntitiesClimateResponse::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
@ -2744,6 +2842,24 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
|
||||
out.append(proto_enum_to_string<enums::ClimateSwingMode>(it));
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
for (const auto &it : this->supported_custom_fan_modes) {
|
||||
out.append(" supported_custom_fan_modes: ");
|
||||
out.append("'").append(it).append("'");
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
for (const auto &it : this->supported_presets) {
|
||||
out.append(" supported_presets: ");
|
||||
out.append(proto_enum_to_string<enums::ClimatePreset>(it));
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
for (const auto &it : this->supported_custom_presets) {
|
||||
out.append(" supported_custom_presets: ");
|
||||
out.append("'").append(it).append("'");
|
||||
out.append("\n");
|
||||
}
|
||||
out.append("}");
|
||||
}
|
||||
bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
@ -2768,6 +2884,24 @@ bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
this->swing_mode = value.as_enum<enums::ClimateSwingMode>();
|
||||
return true;
|
||||
}
|
||||
case 12: {
|
||||
this->preset = value.as_enum<enums::ClimatePreset>();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ClimateStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||
switch (field_id) {
|
||||
case 11: {
|
||||
this->custom_fan_mode = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 13: {
|
||||
this->custom_preset = value.as_string();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -2809,6 +2943,9 @@ void ClimateStateResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_enum<enums::ClimateAction>(8, this->action);
|
||||
buffer.encode_enum<enums::ClimateFanMode>(9, this->fan_mode);
|
||||
buffer.encode_enum<enums::ClimateSwingMode>(10, this->swing_mode);
|
||||
buffer.encode_string(11, this->custom_fan_mode);
|
||||
buffer.encode_enum<enums::ClimatePreset>(12, this->preset);
|
||||
buffer.encode_string(13, this->custom_preset);
|
||||
}
|
||||
void ClimateStateResponse::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
@ -2857,6 +2994,18 @@ void ClimateStateResponse::dump_to(std::string &out) const {
|
||||
out.append(" swing_mode: ");
|
||||
out.append(proto_enum_to_string<enums::ClimateSwingMode>(this->swing_mode));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" custom_fan_mode: ");
|
||||
out.append("'").append(this->custom_fan_mode).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" preset: ");
|
||||
out.append(proto_enum_to_string<enums::ClimatePreset>(this->preset));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" custom_preset: ");
|
||||
out.append("'").append(this->custom_preset).append("'");
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
@ -2905,6 +3054,36 @@ bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
|
||||
this->swing_mode = value.as_enum<enums::ClimateSwingMode>();
|
||||
return true;
|
||||
}
|
||||
case 16: {
|
||||
this->has_custom_fan_mode = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 18: {
|
||||
this->has_preset = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 19: {
|
||||
this->preset = value.as_enum<enums::ClimatePreset>();
|
||||
return true;
|
||||
}
|
||||
case 20: {
|
||||
this->has_custom_preset = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ClimateCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||
switch (field_id) {
|
||||
case 17: {
|
||||
this->custom_fan_mode = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 21: {
|
||||
this->custom_preset = value.as_string();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -2947,6 +3126,12 @@ void ClimateCommandRequest::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_enum<enums::ClimateFanMode>(13, this->fan_mode);
|
||||
buffer.encode_bool(14, this->has_swing_mode);
|
||||
buffer.encode_enum<enums::ClimateSwingMode>(15, this->swing_mode);
|
||||
buffer.encode_bool(16, this->has_custom_fan_mode);
|
||||
buffer.encode_string(17, this->custom_fan_mode);
|
||||
buffer.encode_bool(18, this->has_preset);
|
||||
buffer.encode_enum<enums::ClimatePreset>(19, this->preset);
|
||||
buffer.encode_bool(20, this->has_custom_preset);
|
||||
buffer.encode_string(21, this->custom_preset);
|
||||
}
|
||||
void ClimateCommandRequest::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
@ -3014,6 +3199,30 @@ void ClimateCommandRequest::dump_to(std::string &out) const {
|
||||
out.append(" swing_mode: ");
|
||||
out.append(proto_enum_to_string<enums::ClimateSwingMode>(this->swing_mode));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" has_custom_fan_mode: ");
|
||||
out.append(YESNO(this->has_custom_fan_mode));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" custom_fan_mode: ");
|
||||
out.append("'").append(this->custom_fan_mode).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" has_preset: ");
|
||||
out.append(YESNO(this->has_preset));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" preset: ");
|
||||
out.append(proto_enum_to_string<enums::ClimatePreset>(this->preset));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" has_custom_preset: ");
|
||||
out.append(YESNO(this->has_custom_preset));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" custom_preset: ");
|
||||
out.append("'").append(this->custom_preset).append("'");
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,10 @@ enum FanDirection : uint32_t {
|
||||
FAN_DIRECTION_FORWARD = 0,
|
||||
FAN_DIRECTION_REVERSE = 1,
|
||||
};
|
||||
enum SensorStateClass : uint32_t {
|
||||
STATE_CLASS_NONE = 0,
|
||||
STATE_CLASS_MEASUREMENT = 1,
|
||||
};
|
||||
enum LogLevel : uint32_t {
|
||||
LOG_LEVEL_NONE = 0,
|
||||
LOG_LEVEL_ERROR = 1,
|
||||
@ -53,11 +57,12 @@ enum ServiceArgType : uint32_t {
|
||||
};
|
||||
enum ClimateMode : uint32_t {
|
||||
CLIMATE_MODE_OFF = 0,
|
||||
CLIMATE_MODE_AUTO = 1,
|
||||
CLIMATE_MODE_HEAT_COOL = 1,
|
||||
CLIMATE_MODE_COOL = 2,
|
||||
CLIMATE_MODE_HEAT = 3,
|
||||
CLIMATE_MODE_FAN_ONLY = 4,
|
||||
CLIMATE_MODE_DRY = 5,
|
||||
CLIMATE_MODE_AUTO = 6,
|
||||
};
|
||||
enum ClimateFanMode : uint32_t {
|
||||
CLIMATE_FAN_ON = 0,
|
||||
@ -84,12 +89,21 @@ enum ClimateAction : uint32_t {
|
||||
CLIMATE_ACTION_DRYING = 5,
|
||||
CLIMATE_ACTION_FAN = 6,
|
||||
};
|
||||
enum ClimatePreset : uint32_t {
|
||||
CLIMATE_PRESET_ECO = 0,
|
||||
CLIMATE_PRESET_AWAY = 1,
|
||||
CLIMATE_PRESET_BOOST = 2,
|
||||
CLIMATE_PRESET_COMFORT = 3,
|
||||
CLIMATE_PRESET_HOME = 4,
|
||||
CLIMATE_PRESET_SLEEP = 5,
|
||||
CLIMATE_PRESET_ACTIVITY = 6,
|
||||
};
|
||||
|
||||
} // namespace enums
|
||||
|
||||
class HelloRequest : public ProtoMessage {
|
||||
public:
|
||||
std::string client_info{}; // NOLINT
|
||||
std::string client_info{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -98,9 +112,9 @@ class HelloRequest : public ProtoMessage {
|
||||
};
|
||||
class HelloResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t api_version_major{0}; // NOLINT
|
||||
uint32_t api_version_minor{0}; // NOLINT
|
||||
std::string server_info{}; // NOLINT
|
||||
uint32_t api_version_major{0};
|
||||
uint32_t api_version_minor{0};
|
||||
std::string server_info{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -110,7 +124,7 @@ class HelloResponse : public ProtoMessage {
|
||||
};
|
||||
class ConnectRequest : public ProtoMessage {
|
||||
public:
|
||||
std::string password{}; // NOLINT
|
||||
std::string password{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -119,7 +133,7 @@ class ConnectRequest : public ProtoMessage {
|
||||
};
|
||||
class ConnectResponse : public ProtoMessage {
|
||||
public:
|
||||
bool invalid_password{false}; // NOLINT
|
||||
bool invalid_password{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -163,13 +177,15 @@ class DeviceInfoRequest : public ProtoMessage {
|
||||
};
|
||||
class DeviceInfoResponse : public ProtoMessage {
|
||||
public:
|
||||
bool uses_password{false}; // NOLINT
|
||||
std::string name{}; // NOLINT
|
||||
std::string mac_address{}; // NOLINT
|
||||
std::string esphome_version{}; // NOLINT
|
||||
std::string compilation_time{}; // NOLINT
|
||||
std::string model{}; // NOLINT
|
||||
bool has_deep_sleep{false}; // NOLINT
|
||||
bool uses_password{false};
|
||||
std::string name{};
|
||||
std::string mac_address{};
|
||||
std::string esphome_version{};
|
||||
std::string compilation_time{};
|
||||
std::string model{};
|
||||
bool has_deep_sleep{false};
|
||||
std::string project_name{};
|
||||
std::string project_version{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -200,12 +216,12 @@ class SubscribeStatesRequest : public ProtoMessage {
|
||||
};
|
||||
class ListEntitiesBinarySensorResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string object_id{}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::string name{}; // NOLINT
|
||||
std::string unique_id{}; // NOLINT
|
||||
std::string device_class{}; // NOLINT
|
||||
bool is_status_binary_sensor{false}; // NOLINT
|
||||
std::string object_id{};
|
||||
uint32_t key{0};
|
||||
std::string name{};
|
||||
std::string unique_id{};
|
||||
std::string device_class{};
|
||||
bool is_status_binary_sensor{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -216,9 +232,9 @@ class ListEntitiesBinarySensorResponse : public ProtoMessage {
|
||||
};
|
||||
class BinarySensorStateResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool state{false}; // NOLINT
|
||||
bool missing_state{false}; // NOLINT
|
||||
uint32_t key{0};
|
||||
bool state{false};
|
||||
bool missing_state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -228,14 +244,14 @@ class BinarySensorStateResponse : public ProtoMessage {
|
||||
};
|
||||
class ListEntitiesCoverResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string object_id{}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::string name{}; // NOLINT
|
||||
std::string unique_id{}; // NOLINT
|
||||
bool assumed_state{false}; // NOLINT
|
||||
bool supports_position{false}; // NOLINT
|
||||
bool supports_tilt{false}; // NOLINT
|
||||
std::string device_class{}; // NOLINT
|
||||
std::string object_id{};
|
||||
uint32_t key{0};
|
||||
std::string name{};
|
||||
std::string unique_id{};
|
||||
bool assumed_state{false};
|
||||
bool supports_position{false};
|
||||
bool supports_tilt{false};
|
||||
std::string device_class{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -246,11 +262,11 @@ class ListEntitiesCoverResponse : public ProtoMessage {
|
||||
};
|
||||
class CoverStateResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
enums::LegacyCoverState legacy_state{}; // NOLINT
|
||||
float position{0.0f}; // NOLINT
|
||||
float tilt{0.0f}; // NOLINT
|
||||
enums::CoverOperation current_operation{}; // NOLINT
|
||||
uint32_t key{0};
|
||||
enums::LegacyCoverState legacy_state{};
|
||||
float position{0.0f};
|
||||
float tilt{0.0f};
|
||||
enums::CoverOperation current_operation{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -260,14 +276,14 @@ class CoverStateResponse : public ProtoMessage {
|
||||
};
|
||||
class CoverCommandRequest : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool has_legacy_command{false}; // NOLINT
|
||||
enums::LegacyCoverCommand legacy_command{}; // NOLINT
|
||||
bool has_position{false}; // NOLINT
|
||||
float position{0.0f}; // NOLINT
|
||||
bool has_tilt{false}; // NOLINT
|
||||
float tilt{0.0f}; // NOLINT
|
||||
bool stop{false}; // NOLINT
|
||||
uint32_t key{0};
|
||||
bool has_legacy_command{false};
|
||||
enums::LegacyCoverCommand legacy_command{};
|
||||
bool has_position{false};
|
||||
float position{0.0f};
|
||||
bool has_tilt{false};
|
||||
float tilt{0.0f};
|
||||
bool stop{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -277,14 +293,14 @@ class CoverCommandRequest : public ProtoMessage {
|
||||
};
|
||||
class ListEntitiesFanResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string object_id{}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::string name{}; // NOLINT
|
||||
std::string unique_id{}; // NOLINT
|
||||
bool supports_oscillation{false}; // NOLINT
|
||||
bool supports_speed{false}; // NOLINT
|
||||
bool supports_direction{false}; // NOLINT
|
||||
int32_t supported_speed_count{0}; // NOLINT
|
||||
std::string object_id{};
|
||||
uint32_t key{0};
|
||||
std::string name{};
|
||||
std::string unique_id{};
|
||||
bool supports_oscillation{false};
|
||||
bool supports_speed{false};
|
||||
bool supports_direction{false};
|
||||
int32_t supported_speed_count{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -295,12 +311,12 @@ class ListEntitiesFanResponse : public ProtoMessage {
|
||||
};
|
||||
class FanStateResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool state{false}; // NOLINT
|
||||
bool oscillating{false}; // NOLINT
|
||||
enums::FanSpeed speed{}; // NOLINT
|
||||
enums::FanDirection direction{}; // NOLINT
|
||||
int32_t speed_level{0}; // NOLINT
|
||||
uint32_t key{0};
|
||||
bool state{false};
|
||||
bool oscillating{false};
|
||||
enums::FanSpeed speed{};
|
||||
enums::FanDirection direction{};
|
||||
int32_t speed_level{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -310,17 +326,17 @@ class FanStateResponse : public ProtoMessage {
|
||||
};
|
||||
class FanCommandRequest : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool has_state{false}; // NOLINT
|
||||
bool state{false}; // NOLINT
|
||||
bool has_speed{false}; // NOLINT
|
||||
enums::FanSpeed speed{}; // NOLINT
|
||||
bool has_oscillating{false}; // NOLINT
|
||||
bool oscillating{false}; // NOLINT
|
||||
bool has_direction{false}; // NOLINT
|
||||
enums::FanDirection direction{}; // NOLINT
|
||||
bool has_speed_level{false}; // NOLINT
|
||||
int32_t speed_level{0}; // NOLINT
|
||||
uint32_t key{0};
|
||||
bool has_state{false};
|
||||
bool state{false};
|
||||
bool has_speed{false};
|
||||
enums::FanSpeed speed{};
|
||||
bool has_oscillating{false};
|
||||
bool oscillating{false};
|
||||
bool has_direction{false};
|
||||
enums::FanDirection direction{};
|
||||
bool has_speed_level{false};
|
||||
int32_t speed_level{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -330,17 +346,17 @@ class FanCommandRequest : public ProtoMessage {
|
||||
};
|
||||
class ListEntitiesLightResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string object_id{}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::string name{}; // NOLINT
|
||||
std::string unique_id{}; // NOLINT
|
||||
bool supports_brightness{false}; // NOLINT
|
||||
bool supports_rgb{false}; // NOLINT
|
||||
bool supports_white_value{false}; // NOLINT
|
||||
bool supports_color_temperature{false}; // NOLINT
|
||||
float min_mireds{0.0f}; // NOLINT
|
||||
float max_mireds{0.0f}; // NOLINT
|
||||
std::vector<std::string> effects{}; // NOLINT
|
||||
std::string object_id{};
|
||||
uint32_t key{0};
|
||||
std::string name{};
|
||||
std::string unique_id{};
|
||||
bool supports_brightness{false};
|
||||
bool supports_rgb{false};
|
||||
bool supports_white_value{false};
|
||||
bool supports_color_temperature{false};
|
||||
float min_mireds{0.0f};
|
||||
float max_mireds{0.0f};
|
||||
std::vector<std::string> effects{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -351,15 +367,15 @@ class ListEntitiesLightResponse : public ProtoMessage {
|
||||
};
|
||||
class LightStateResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool state{false}; // NOLINT
|
||||
float brightness{0.0f}; // NOLINT
|
||||
float red{0.0f}; // NOLINT
|
||||
float green{0.0f}; // NOLINT
|
||||
float blue{0.0f}; // NOLINT
|
||||
float white{0.0f}; // NOLINT
|
||||
float color_temperature{0.0f}; // NOLINT
|
||||
std::string effect{}; // NOLINT
|
||||
uint32_t key{0};
|
||||
bool state{false};
|
||||
float brightness{0.0f};
|
||||
float red{0.0f};
|
||||
float green{0.0f};
|
||||
float blue{0.0f};
|
||||
float white{0.0f};
|
||||
float color_temperature{0.0f};
|
||||
std::string effect{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -370,25 +386,25 @@ class LightStateResponse : public ProtoMessage {
|
||||
};
|
||||
class LightCommandRequest : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool has_state{false}; // NOLINT
|
||||
bool state{false}; // NOLINT
|
||||
bool has_brightness{false}; // NOLINT
|
||||
float brightness{0.0f}; // NOLINT
|
||||
bool has_rgb{false}; // NOLINT
|
||||
float red{0.0f}; // NOLINT
|
||||
float green{0.0f}; // NOLINT
|
||||
float blue{0.0f}; // NOLINT
|
||||
bool has_white{false}; // NOLINT
|
||||
float white{0.0f}; // NOLINT
|
||||
bool has_color_temperature{false}; // NOLINT
|
||||
float color_temperature{0.0f}; // NOLINT
|
||||
bool has_transition_length{false}; // NOLINT
|
||||
uint32_t transition_length{0}; // NOLINT
|
||||
bool has_flash_length{false}; // NOLINT
|
||||
uint32_t flash_length{0}; // NOLINT
|
||||
bool has_effect{false}; // NOLINT
|
||||
std::string effect{}; // NOLINT
|
||||
uint32_t key{0};
|
||||
bool has_state{false};
|
||||
bool state{false};
|
||||
bool has_brightness{false};
|
||||
float brightness{0.0f};
|
||||
bool has_rgb{false};
|
||||
float red{0.0f};
|
||||
float green{0.0f};
|
||||
float blue{0.0f};
|
||||
bool has_white{false};
|
||||
float white{0.0f};
|
||||
bool has_color_temperature{false};
|
||||
float color_temperature{0.0f};
|
||||
bool has_transition_length{false};
|
||||
uint32_t transition_length{0};
|
||||
bool has_flash_length{false};
|
||||
uint32_t flash_length{0};
|
||||
bool has_effect{false};
|
||||
std::string effect{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -399,15 +415,16 @@ class LightCommandRequest : public ProtoMessage {
|
||||
};
|
||||
class ListEntitiesSensorResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string object_id{}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::string name{}; // NOLINT
|
||||
std::string unique_id{}; // NOLINT
|
||||
std::string icon{}; // NOLINT
|
||||
std::string unit_of_measurement{}; // NOLINT
|
||||
int32_t accuracy_decimals{0}; // NOLINT
|
||||
bool force_update{false}; // NOLINT
|
||||
std::string device_class{}; // NOLINT
|
||||
std::string object_id{};
|
||||
uint32_t key{0};
|
||||
std::string name{};
|
||||
std::string unique_id{};
|
||||
std::string icon{};
|
||||
std::string unit_of_measurement{};
|
||||
int32_t accuracy_decimals{0};
|
||||
bool force_update{false};
|
||||
std::string device_class{};
|
||||
enums::SensorStateClass state_class{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -418,9 +435,9 @@ class ListEntitiesSensorResponse : public ProtoMessage {
|
||||
};
|
||||
class SensorStateResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
float state{0.0f}; // NOLINT
|
||||
bool missing_state{false}; // NOLINT
|
||||
uint32_t key{0};
|
||||
float state{0.0f};
|
||||
bool missing_state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -430,12 +447,12 @@ class SensorStateResponse : public ProtoMessage {
|
||||
};
|
||||
class ListEntitiesSwitchResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string object_id{}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::string name{}; // NOLINT
|
||||
std::string unique_id{}; // NOLINT
|
||||
std::string icon{}; // NOLINT
|
||||
bool assumed_state{false}; // NOLINT
|
||||
std::string object_id{};
|
||||
uint32_t key{0};
|
||||
std::string name{};
|
||||
std::string unique_id{};
|
||||
std::string icon{};
|
||||
bool assumed_state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -446,8 +463,8 @@ class ListEntitiesSwitchResponse : public ProtoMessage {
|
||||
};
|
||||
class SwitchStateResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool state{false}; // NOLINT
|
||||
uint32_t key{0};
|
||||
bool state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -457,8 +474,8 @@ class SwitchStateResponse : public ProtoMessage {
|
||||
};
|
||||
class SwitchCommandRequest : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool state{false}; // NOLINT
|
||||
uint32_t key{0};
|
||||
bool state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -468,11 +485,11 @@ class SwitchCommandRequest : public ProtoMessage {
|
||||
};
|
||||
class ListEntitiesTextSensorResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string object_id{}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::string name{}; // NOLINT
|
||||
std::string unique_id{}; // NOLINT
|
||||
std::string icon{}; // NOLINT
|
||||
std::string object_id{};
|
||||
uint32_t key{0};
|
||||
std::string name{};
|
||||
std::string unique_id{};
|
||||
std::string icon{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -482,9 +499,9 @@ class ListEntitiesTextSensorResponse : public ProtoMessage {
|
||||
};
|
||||
class TextSensorStateResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::string state{}; // NOLINT
|
||||
bool missing_state{false}; // NOLINT
|
||||
uint32_t key{0};
|
||||
std::string state{};
|
||||
bool missing_state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -495,8 +512,8 @@ class TextSensorStateResponse : public ProtoMessage {
|
||||
};
|
||||
class SubscribeLogsRequest : public ProtoMessage {
|
||||
public:
|
||||
enums::LogLevel level{}; // NOLINT
|
||||
bool dump_config{false}; // NOLINT
|
||||
enums::LogLevel level{};
|
||||
bool dump_config{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -505,10 +522,10 @@ class SubscribeLogsRequest : public ProtoMessage {
|
||||
};
|
||||
class SubscribeLogsResponse : public ProtoMessage {
|
||||
public:
|
||||
enums::LogLevel level{}; // NOLINT
|
||||
std::string tag{}; // NOLINT
|
||||
std::string message{}; // NOLINT
|
||||
bool send_failed{false}; // NOLINT
|
||||
enums::LogLevel level{};
|
||||
std::string tag{};
|
||||
std::string message{};
|
||||
bool send_failed{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -525,8 +542,8 @@ class SubscribeHomeassistantServicesRequest : public ProtoMessage {
|
||||
};
|
||||
class HomeassistantServiceMap : public ProtoMessage {
|
||||
public:
|
||||
std::string key{}; // NOLINT
|
||||
std::string value{}; // NOLINT
|
||||
std::string key{};
|
||||
std::string value{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -535,11 +552,11 @@ class HomeassistantServiceMap : public ProtoMessage {
|
||||
};
|
||||
class HomeassistantServiceResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string service{}; // NOLINT
|
||||
std::vector<HomeassistantServiceMap> data{}; // NOLINT
|
||||
std::vector<HomeassistantServiceMap> data_template{}; // NOLINT
|
||||
std::vector<HomeassistantServiceMap> variables{}; // NOLINT
|
||||
bool is_event{false}; // NOLINT
|
||||
std::string service{};
|
||||
std::vector<HomeassistantServiceMap> data{};
|
||||
std::vector<HomeassistantServiceMap> data_template{};
|
||||
std::vector<HomeassistantServiceMap> variables{};
|
||||
bool is_event{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -556,7 +573,8 @@ class SubscribeHomeAssistantStatesRequest : public ProtoMessage {
|
||||
};
|
||||
class SubscribeHomeAssistantStateResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string entity_id{}; // NOLINT
|
||||
std::string entity_id{};
|
||||
std::string attribute{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -565,8 +583,9 @@ class SubscribeHomeAssistantStateResponse : public ProtoMessage {
|
||||
};
|
||||
class HomeAssistantStateResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string entity_id{}; // NOLINT
|
||||
std::string state{}; // NOLINT
|
||||
std::string entity_id{};
|
||||
std::string state{};
|
||||
std::string attribute{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -582,7 +601,7 @@ class GetTimeRequest : public ProtoMessage {
|
||||
};
|
||||
class GetTimeResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t epoch_seconds{0}; // NOLINT
|
||||
uint32_t epoch_seconds{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -591,8 +610,8 @@ class GetTimeResponse : public ProtoMessage {
|
||||
};
|
||||
class ListEntitiesServicesArgument : public ProtoMessage {
|
||||
public:
|
||||
std::string name{}; // NOLINT
|
||||
enums::ServiceArgType type{}; // NOLINT
|
||||
std::string name{};
|
||||
enums::ServiceArgType type{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -602,9 +621,9 @@ class ListEntitiesServicesArgument : public ProtoMessage {
|
||||
};
|
||||
class ListEntitiesServicesResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string name{}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::vector<ListEntitiesServicesArgument> args{}; // NOLINT
|
||||
std::string name{};
|
||||
uint32_t key{0};
|
||||
std::vector<ListEntitiesServicesArgument> args{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -614,15 +633,15 @@ class ListEntitiesServicesResponse : public ProtoMessage {
|
||||
};
|
||||
class ExecuteServiceArgument : public ProtoMessage {
|
||||
public:
|
||||
bool bool_{false}; // NOLINT
|
||||
int32_t legacy_int{0}; // NOLINT
|
||||
float float_{0.0f}; // NOLINT
|
||||
std::string string_{}; // NOLINT
|
||||
int32_t int_{0}; // NOLINT
|
||||
std::vector<bool> bool_array{}; // NOLINT
|
||||
std::vector<int32_t> int_array{}; // NOLINT
|
||||
std::vector<float> float_array{}; // NOLINT
|
||||
std::vector<std::string> string_array{}; // NOLINT
|
||||
bool bool_{false};
|
||||
int32_t legacy_int{0};
|
||||
float float_{0.0f};
|
||||
std::string string_{};
|
||||
int32_t int_{0};
|
||||
std::vector<bool> bool_array{};
|
||||
std::vector<int32_t> int_array{};
|
||||
std::vector<float> float_array{};
|
||||
std::vector<std::string> string_array{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -633,8 +652,8 @@ class ExecuteServiceArgument : public ProtoMessage {
|
||||
};
|
||||
class ExecuteServiceRequest : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::vector<ExecuteServiceArgument> args{}; // NOLINT
|
||||
uint32_t key{0};
|
||||
std::vector<ExecuteServiceArgument> args{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -644,10 +663,10 @@ class ExecuteServiceRequest : public ProtoMessage {
|
||||
};
|
||||
class ListEntitiesCameraResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string object_id{}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::string name{}; // NOLINT
|
||||
std::string unique_id{}; // NOLINT
|
||||
std::string object_id{};
|
||||
uint32_t key{0};
|
||||
std::string name{};
|
||||
std::string unique_id{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -657,9 +676,9 @@ class ListEntitiesCameraResponse : public ProtoMessage {
|
||||
};
|
||||
class CameraImageResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::string data{}; // NOLINT
|
||||
bool done{false}; // NOLINT
|
||||
uint32_t key{0};
|
||||
std::string data{};
|
||||
bool done{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -670,8 +689,8 @@ class CameraImageResponse : public ProtoMessage {
|
||||
};
|
||||
class CameraImageRequest : public ProtoMessage {
|
||||
public:
|
||||
bool single{false}; // NOLINT
|
||||
bool stream{false}; // NOLINT
|
||||
bool single{false};
|
||||
bool stream{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -680,20 +699,23 @@ class CameraImageRequest : public ProtoMessage {
|
||||
};
|
||||
class ListEntitiesClimateResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string object_id{}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::string name{}; // NOLINT
|
||||
std::string unique_id{}; // NOLINT
|
||||
bool supports_current_temperature{false}; // NOLINT
|
||||
bool supports_two_point_target_temperature{false}; // NOLINT
|
||||
std::vector<enums::ClimateMode> supported_modes{}; // NOLINT
|
||||
float visual_min_temperature{0.0f}; // NOLINT
|
||||
float visual_max_temperature{0.0f}; // NOLINT
|
||||
float visual_temperature_step{0.0f}; // NOLINT
|
||||
bool supports_away{false}; // NOLINT
|
||||
bool supports_action{false}; // NOLINT
|
||||
std::vector<enums::ClimateFanMode> supported_fan_modes{}; // NOLINT
|
||||
std::vector<enums::ClimateSwingMode> supported_swing_modes{}; // NOLINT
|
||||
std::string object_id{};
|
||||
uint32_t key{0};
|
||||
std::string name{};
|
||||
std::string unique_id{};
|
||||
bool supports_current_temperature{false};
|
||||
bool supports_two_point_target_temperature{false};
|
||||
std::vector<enums::ClimateMode> supported_modes{};
|
||||
float visual_min_temperature{0.0f};
|
||||
float visual_max_temperature{0.0f};
|
||||
float visual_temperature_step{0.0f};
|
||||
bool supports_away{false};
|
||||
bool supports_action{false};
|
||||
std::vector<enums::ClimateFanMode> supported_fan_modes{};
|
||||
std::vector<enums::ClimateSwingMode> supported_swing_modes{};
|
||||
std::vector<std::string> supported_custom_fan_modes{};
|
||||
std::vector<enums::ClimatePreset> supported_presets{};
|
||||
std::vector<std::string> supported_custom_presets{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@ -704,45 +726,56 @@ class ListEntitiesClimateResponse : public ProtoMessage {
|
||||
};
|
||||
class ClimateStateResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
enums::ClimateMode mode{}; // NOLINT
|
||||
float current_temperature{0.0f}; // NOLINT
|
||||
float target_temperature{0.0f}; // NOLINT
|
||||
float target_temperature_low{0.0f}; // NOLINT
|
||||
float target_temperature_high{0.0f}; // NOLINT
|
||||
bool away{false}; // NOLINT
|
||||
enums::ClimateAction action{}; // NOLINT
|
||||
enums::ClimateFanMode fan_mode{}; // NOLINT
|
||||
enums::ClimateSwingMode swing_mode{}; // NOLINT
|
||||
uint32_t key{0};
|
||||
enums::ClimateMode mode{};
|
||||
float current_temperature{0.0f};
|
||||
float target_temperature{0.0f};
|
||||
float target_temperature_low{0.0f};
|
||||
float target_temperature_high{0.0f};
|
||||
bool away{false};
|
||||
enums::ClimateAction action{};
|
||||
enums::ClimateFanMode fan_mode{};
|
||||
enums::ClimateSwingMode swing_mode{};
|
||||
std::string custom_fan_mode{};
|
||||
enums::ClimatePreset preset{};
|
||||
std::string custom_preset{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
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 ClimateCommandRequest : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool has_mode{false}; // NOLINT
|
||||
enums::ClimateMode mode{}; // NOLINT
|
||||
bool has_target_temperature{false}; // NOLINT
|
||||
float target_temperature{0.0f}; // NOLINT
|
||||
bool has_target_temperature_low{false}; // NOLINT
|
||||
float target_temperature_low{0.0f}; // NOLINT
|
||||
bool has_target_temperature_high{false}; // NOLINT
|
||||
float target_temperature_high{0.0f}; // NOLINT
|
||||
bool has_away{false}; // NOLINT
|
||||
bool away{false}; // NOLINT
|
||||
bool has_fan_mode{false}; // NOLINT
|
||||
enums::ClimateFanMode fan_mode{}; // NOLINT
|
||||
bool has_swing_mode{false}; // NOLINT
|
||||
enums::ClimateSwingMode swing_mode{}; // NOLINT
|
||||
uint32_t key{0};
|
||||
bool has_mode{false};
|
||||
enums::ClimateMode mode{};
|
||||
bool has_target_temperature{false};
|
||||
float target_temperature{0.0f};
|
||||
bool has_target_temperature_low{false};
|
||||
float target_temperature_low{0.0f};
|
||||
bool has_target_temperature_high{false};
|
||||
float target_temperature_high{0.0f};
|
||||
bool has_away{false};
|
||||
bool away{false};
|
||||
bool has_fan_mode{false};
|
||||
enums::ClimateFanMode fan_mode{};
|
||||
bool has_swing_mode{false};
|
||||
enums::ClimateSwingMode swing_mode{};
|
||||
bool has_custom_fan_mode{false};
|
||||
std::string custom_fan_mode{};
|
||||
bool has_preset{false};
|
||||
enums::ClimatePreset preset{};
|
||||
bool has_custom_preset{false};
|
||||
std::string custom_preset{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -208,9 +208,11 @@ void APIServer::send_homeassistant_service_call(const HomeassistantServiceRespon
|
||||
}
|
||||
}
|
||||
APIServer::APIServer() { global_api_server = this; }
|
||||
void APIServer::subscribe_home_assistant_state(std::string entity_id, std::function<void(std::string)> f) {
|
||||
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(std::string)> f) {
|
||||
this->state_subs_.push_back(HomeAssistantStateSubscription{
|
||||
.entity_id = std::move(entity_id),
|
||||
.attribute = std::move(attribute),
|
||||
.callback = std::move(f),
|
||||
});
|
||||
}
|
||||
|
@ -71,10 +71,12 @@ class APIServer : public Component, public Controller {
|
||||
|
||||
struct HomeAssistantStateSubscription {
|
||||
std::string entity_id;
|
||||
optional<std::string> attribute;
|
||||
std::function<void(std::string)> callback;
|
||||
};
|
||||
|
||||
void subscribe_home_assistant_state(std::string entity_id, std::function<void(std::string)> f);
|
||||
void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(std::string)> f);
|
||||
const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
|
||||
const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }
|
||||
|
||||
|
@ -76,13 +76,13 @@ class CustomAPIDevice {
|
||||
global_api_server->register_user_service(service);
|
||||
}
|
||||
|
||||
/** Subscribe to the state of an entity from Home Assistant.
|
||||
/** Subscribe to the state (or attribute state) of an entity from Home Assistant.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* ```cpp
|
||||
* void setup() override {
|
||||
* subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast");
|
||||
* subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "climate.kitchen", "current_temperature");
|
||||
* }
|
||||
*
|
||||
* void on_state_changed(std::string state) {
|
||||
@ -93,17 +93,19 @@ class CustomAPIDevice {
|
||||
* @tparam T The class type creating the service, automatically deduced from the function pointer.
|
||||
* @param callback The member function to call when the entity state changes.
|
||||
* @param entity_id The entity_id to track.
|
||||
* @param attribute The entity state attribute to track.
|
||||
*/
|
||||
template<typename T>
|
||||
void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id) {
|
||||
void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id,
|
||||
const std::string &attribute = "") {
|
||||
auto f = std::bind(callback, (T *) this, std::placeholders::_1);
|
||||
global_api_server->subscribe_home_assistant_state(entity_id, f);
|
||||
global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute), f);
|
||||
}
|
||||
|
||||
/** Subscribe to the state of an entity from Home Assistant.
|
||||
/** Subscribe to the state (or attribute state) of an entity from Home Assistant.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
*å
|
||||
* ```cpp
|
||||
* void setup() override {
|
||||
* subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast");
|
||||
@ -117,11 +119,13 @@ class CustomAPIDevice {
|
||||
* @tparam T The class type creating the service, automatically deduced from the function pointer.
|
||||
* @param callback The member function to call when the entity state changes.
|
||||
* @param entity_id The entity_id to track.
|
||||
* @param attribute The entity state attribute to track.
|
||||
*/
|
||||
template<typename T>
|
||||
void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id) {
|
||||
void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id,
|
||||
const std::string &attribute = "") {
|
||||
auto f = std::bind(callback, (T *) this, entity_id, std::placeholders::_1);
|
||||
global_api_server->subscribe_home_assistant_state(entity_id, f);
|
||||
global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute), f);
|
||||
}
|
||||
|
||||
/** Call a Home Assistant service from ESPHome.
|
||||
|
@ -11,7 +11,6 @@ from esphome.const import (
|
||||
CONF_DIV_RATIO,
|
||||
CONF_CAPACITANCE,
|
||||
)
|
||||
from esphome.core import coroutine
|
||||
|
||||
AUTO_LOAD = ["sensor", "binary_sensor"]
|
||||
MULTI_CONF = True
|
||||
@ -40,11 +39,10 @@ AS3935_SCHEMA = cv.Schema(
|
||||
)
|
||||
|
||||
|
||||
@coroutine
|
||||
def setup_as3935(var, config):
|
||||
yield cg.register_component(var, config)
|
||||
async def setup_as3935(var, config):
|
||||
await cg.register_component(var, config)
|
||||
|
||||
irq_pin = yield cg.gpio_pin_expression(config[CONF_IRQ_PIN])
|
||||
irq_pin = await cg.gpio_pin_expression(config[CONF_IRQ_PIN])
|
||||
cg.add(var.set_irq_pin(irq_pin))
|
||||
cg.add(var.set_indoor(config[CONF_INDOOR]))
|
||||
cg.add(var.set_noise_level(config[CONF_NOISE_LEVEL]))
|
||||
|
@ -12,7 +12,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = yield cg.get_variable(config[CONF_AS3935_ID])
|
||||
var = yield binary_sensor.new_binary_sensor(config)
|
||||
async def to_code(config):
|
||||
hub = await cg.get_variable(config[CONF_AS3935_ID])
|
||||
var = await binary_sensor.new_binary_sensor(config)
|
||||
cg.add(hub.set_thunder_alert_binary_sensor(var))
|
||||
|
@ -5,6 +5,7 @@ from esphome.const import (
|
||||
CONF_DISTANCE,
|
||||
CONF_LIGHTNING_ENERGY,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
STATE_CLASS_NONE,
|
||||
UNIT_KILOMETER,
|
||||
UNIT_EMPTY,
|
||||
ICON_SIGNAL_DISTANCE_VARIANT,
|
||||
@ -18,24 +19,28 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_AS3935_ID): cv.use_id(AS3935),
|
||||
cv.Optional(CONF_DISTANCE): sensor.sensor_schema(
|
||||
UNIT_KILOMETER, ICON_SIGNAL_DISTANCE_VARIANT, 1, DEVICE_CLASS_EMPTY
|
||||
UNIT_KILOMETER,
|
||||
ICON_SIGNAL_DISTANCE_VARIANT,
|
||||
1,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
STATE_CLASS_NONE,
|
||||
),
|
||||
cv.Optional(CONF_LIGHTNING_ENERGY): sensor.sensor_schema(
|
||||
UNIT_EMPTY, ICON_FLASH, 1, DEVICE_CLASS_EMPTY
|
||||
UNIT_EMPTY, ICON_FLASH, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = yield cg.get_variable(config[CONF_AS3935_ID])
|
||||
async def to_code(config):
|
||||
hub = await cg.get_variable(config[CONF_AS3935_ID])
|
||||
|
||||
if CONF_DISTANCE in config:
|
||||
conf = config[CONF_DISTANCE]
|
||||
distance_sensor = yield sensor.new_sensor(conf)
|
||||
distance_sensor = await sensor.new_sensor(conf)
|
||||
cg.add(hub.set_distance_sensor(distance_sensor))
|
||||
|
||||
if CONF_LIGHTNING_ENERGY in config:
|
||||
conf = config[CONF_LIGHTNING_ENERGY]
|
||||
lightning_energy_sensor = yield sensor.new_sensor(conf)
|
||||
lightning_energy_sensor = await sensor.new_sensor(conf)
|
||||
cg.add(hub.set_energy_sensor(lightning_energy_sensor))
|
||||
|
@ -20,7 +20,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield as3935.setup_as3935(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await as3935.setup_as3935(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
@ -20,7 +20,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield as3935.setup_as3935(var, config)
|
||||
yield spi.register_spi_device(var, config)
|
||||
await as3935.setup_as3935(var, config)
|
||||
await spi.register_spi_device(var, config)
|
||||
|
@ -33,7 +33,7 @@ void SPIAS3935Component::write_register(uint8_t reg, uint8_t mask, uint8_t bits,
|
||||
uint8_t SPIAS3935Component::read_register(uint8_t reg) {
|
||||
uint8_t value = 0;
|
||||
this->enable();
|
||||
this->write_byte(reg |= SPI_READ_M);
|
||||
this->write_byte(reg | SPI_READ_M);
|
||||
value = this->read_byte();
|
||||
// According to datsheet, the chip select must be written HIGH, LOW, HIGH
|
||||
// to correctly end the READ command.
|
||||
|
@ -6,7 +6,7 @@ CODEOWNERS = ["@OttoWinter"]
|
||||
|
||||
|
||||
@coroutine_with_priority(200.0)
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
if CORE.is_esp32:
|
||||
# https://github.com/esphome/AsyncTCP/blob/master/library.json
|
||||
cg.add_library("esphome/AsyncTCP-esphome", "1.2.2")
|
||||
|
@ -13,6 +13,7 @@ from esphome.const import (
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
ICON_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_PERCENT,
|
||||
UNIT_VOLT,
|
||||
@ -33,16 +34,28 @@ CONFIG_SCHEMA = (
|
||||
cv.GenerateID(): cv.declare_id(ATCMiThermometer),
|
||||
cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
|
||||
UNIT_CELSIUS,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
|
||||
UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_HUMIDITY
|
||||
UNIT_PERCENT,
|
||||
ICON_EMPTY,
|
||||
0,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(
|
||||
UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY
|
||||
UNIT_PERCENT,
|
||||
ICON_EMPTY,
|
||||
0,
|
||||
DEVICE_CLASS_BATTERY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema(
|
||||
UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE
|
||||
UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
|
||||
),
|
||||
}
|
||||
)
|
||||
@ -51,22 +64,22 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield esp32_ble_tracker.register_ble_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await esp32_ble_tracker.register_ble_device(var, config)
|
||||
|
||||
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
|
||||
|
||||
if CONF_TEMPERATURE in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
|
||||
sens = await sensor.new_sensor(config[CONF_TEMPERATURE])
|
||||
cg.add(var.set_temperature(sens))
|
||||
if CONF_HUMIDITY in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_HUMIDITY])
|
||||
sens = await sensor.new_sensor(config[CONF_HUMIDITY])
|
||||
cg.add(var.set_humidity(sens))
|
||||
if CONF_BATTERY_LEVEL in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL])
|
||||
sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL])
|
||||
cg.add(var.set_battery_level(sens))
|
||||
if CONF_BATTERY_VOLTAGE in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_BATTERY_VOLTAGE])
|
||||
sens = await sensor.new_sensor(config[CONF_BATTERY_VOLTAGE])
|
||||
cg.add(var.set_battery_voltage(sens))
|
||||
|
@ -3,6 +3,7 @@ import esphome.config_validation as cv
|
||||
from esphome.components import sensor, spi
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_REACTIVE_POWER,
|
||||
CONF_VOLTAGE,
|
||||
CONF_CURRENT,
|
||||
CONF_POWER,
|
||||
@ -20,6 +21,7 @@ from esphome.const import (
|
||||
ICON_EMPTY,
|
||||
ICON_LIGHTBULB,
|
||||
ICON_CURRENT_AC,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_HERTZ,
|
||||
UNIT_VOLT,
|
||||
UNIT_AMPERE,
|
||||
@ -34,7 +36,6 @@ CONF_PHASE_A = "phase_a"
|
||||
CONF_PHASE_B = "phase_b"
|
||||
CONF_PHASE_C = "phase_c"
|
||||
|
||||
CONF_REACTIVE_POWER = "reactive_power"
|
||||
CONF_LINE_FREQUENCY = "line_frequency"
|
||||
CONF_CHIP_TEMPERATURE = "chip_temperature"
|
||||
CONF_GAIN_PGA = "gain_pga"
|
||||
@ -63,25 +64,37 @@ ATM90E32Component = atm90e32_ns.class_(
|
||||
ATM90E32_PHASE_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
|
||||
UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE
|
||||
UNIT_VOLT,
|
||||
ICON_EMPTY,
|
||||
2,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_CURRENT): sensor.sensor_schema(
|
||||
UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT
|
||||
UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT
|
||||
),
|
||||
cv.Optional(CONF_POWER): sensor.sensor_schema(
|
||||
UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER
|
||||
UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
|
||||
),
|
||||
cv.Optional(CONF_REACTIVE_POWER): sensor.sensor_schema(
|
||||
UNIT_VOLT_AMPS_REACTIVE, ICON_LIGHTBULB, 2, DEVICE_CLASS_EMPTY
|
||||
UNIT_VOLT_AMPS_REACTIVE,
|
||||
ICON_LIGHTBULB,
|
||||
2,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_POWER_FACTOR): sensor.sensor_schema(
|
||||
UNIT_EMPTY, ICON_EMPTY, 2, DEVICE_CLASS_POWER_FACTOR
|
||||
UNIT_EMPTY,
|
||||
ICON_EMPTY,
|
||||
2,
|
||||
DEVICE_CLASS_POWER_FACTOR,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_FORWARD_ACTIVE_ENERGY): sensor.sensor_schema(
|
||||
UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY
|
||||
UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY, STATE_CLASS_MEASUREMENT
|
||||
),
|
||||
cv.Optional(CONF_REVERSE_ACTIVE_ENERGY): sensor.sensor_schema(
|
||||
UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY
|
||||
UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY, STATE_CLASS_MEASUREMENT
|
||||
),
|
||||
cv.Optional(CONF_GAIN_VOLTAGE, default=7305): cv.uint16_t,
|
||||
cv.Optional(CONF_GAIN_CT, default=27961): cv.uint16_t,
|
||||
@ -96,10 +109,18 @@ CONFIG_SCHEMA = (
|
||||
cv.Optional(CONF_PHASE_B): ATM90E32_PHASE_SCHEMA,
|
||||
cv.Optional(CONF_PHASE_C): ATM90E32_PHASE_SCHEMA,
|
||||
cv.Optional(CONF_FREQUENCY): sensor.sensor_schema(
|
||||
UNIT_HERTZ, ICON_CURRENT_AC, 1, DEVICE_CLASS_EMPTY
|
||||
UNIT_HERTZ,
|
||||
ICON_CURRENT_AC,
|
||||
1,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_CHIP_TEMPERATURE): sensor.sensor_schema(
|
||||
UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
|
||||
UNIT_CELSIUS,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Required(CONF_LINE_FREQUENCY): cv.enum(LINE_FREQS, upper=True),
|
||||
cv.Optional(CONF_CURRENT_PHASES, default="3"): cv.enum(
|
||||
@ -113,10 +134,10 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield spi.register_spi_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await spi.register_spi_device(var, config)
|
||||
|
||||
for i, phase in enumerate([CONF_PHASE_A, CONF_PHASE_B, CONF_PHASE_C]):
|
||||
if phase not in config:
|
||||
@ -125,31 +146,31 @@ def to_code(config):
|
||||
cg.add(var.set_volt_gain(i, conf[CONF_GAIN_VOLTAGE]))
|
||||
cg.add(var.set_ct_gain(i, conf[CONF_GAIN_CT]))
|
||||
if CONF_VOLTAGE in conf:
|
||||
sens = yield sensor.new_sensor(conf[CONF_VOLTAGE])
|
||||
sens = await sensor.new_sensor(conf[CONF_VOLTAGE])
|
||||
cg.add(var.set_voltage_sensor(i, sens))
|
||||
if CONF_CURRENT in conf:
|
||||
sens = yield sensor.new_sensor(conf[CONF_CURRENT])
|
||||
sens = await sensor.new_sensor(conf[CONF_CURRENT])
|
||||
cg.add(var.set_current_sensor(i, sens))
|
||||
if CONF_POWER in conf:
|
||||
sens = yield sensor.new_sensor(conf[CONF_POWER])
|
||||
sens = await sensor.new_sensor(conf[CONF_POWER])
|
||||
cg.add(var.set_power_sensor(i, sens))
|
||||
if CONF_REACTIVE_POWER in conf:
|
||||
sens = yield sensor.new_sensor(conf[CONF_REACTIVE_POWER])
|
||||
sens = await sensor.new_sensor(conf[CONF_REACTIVE_POWER])
|
||||
cg.add(var.set_reactive_power_sensor(i, sens))
|
||||
if CONF_POWER_FACTOR in conf:
|
||||
sens = yield sensor.new_sensor(conf[CONF_POWER_FACTOR])
|
||||
sens = await sensor.new_sensor(conf[CONF_POWER_FACTOR])
|
||||
cg.add(var.set_power_factor_sensor(i, sens))
|
||||
if CONF_FORWARD_ACTIVE_ENERGY in conf:
|
||||
sens = yield sensor.new_sensor(conf[CONF_FORWARD_ACTIVE_ENERGY])
|
||||
sens = await sensor.new_sensor(conf[CONF_FORWARD_ACTIVE_ENERGY])
|
||||
cg.add(var.set_forward_active_energy_sensor(i, sens))
|
||||
if CONF_REVERSE_ACTIVE_ENERGY in conf:
|
||||
sens = yield sensor.new_sensor(conf[CONF_REVERSE_ACTIVE_ENERGY])
|
||||
sens = await sensor.new_sensor(conf[CONF_REVERSE_ACTIVE_ENERGY])
|
||||
cg.add(var.set_reverse_active_energy_sensor(i, sens))
|
||||
if CONF_FREQUENCY in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_FREQUENCY])
|
||||
sens = await sensor.new_sensor(config[CONF_FREQUENCY])
|
||||
cg.add(var.set_freq_sensor(sens))
|
||||
if CONF_CHIP_TEMPERATURE in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_CHIP_TEMPERATURE])
|
||||
sens = await sensor.new_sensor(config[CONF_CHIP_TEMPERATURE])
|
||||
cg.add(var.set_chip_temperature_sensor(sens))
|
||||
cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY]))
|
||||
cg.add(var.set_current_phases(config[CONF_CURRENT_PHASES]))
|
||||
|
@ -12,6 +12,7 @@ from esphome.const import (
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
ICON_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_PERCENT,
|
||||
UNIT_VOLT,
|
||||
@ -32,16 +33,28 @@ CONFIG_SCHEMA = (
|
||||
cv.GenerateID(): cv.declare_id(BParasite),
|
||||
cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
|
||||
UNIT_CELSIUS,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
|
||||
UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY
|
||||
UNIT_PERCENT,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema(
|
||||
UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE
|
||||
UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
|
||||
),
|
||||
cv.Optional(CONF_MOISTURE): sensor.sensor_schema(
|
||||
UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY
|
||||
UNIT_PERCENT,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
}
|
||||
)
|
||||
@ -50,10 +63,10 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield esp32_ble_tracker.register_ble_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await esp32_ble_tracker.register_ble_device(var, config)
|
||||
|
||||
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
|
||||
|
||||
@ -64,5 +77,5 @@ def to_code(config):
|
||||
(CONF_MOISTURE, var.set_soil_moisture),
|
||||
]:
|
||||
if config_key in config:
|
||||
sens = yield sensor.new_sensor(config[config_key])
|
||||
sens = await sensor.new_sensor(config[config_key])
|
||||
cg.add(setter(sens))
|
||||
|
@ -39,12 +39,12 @@ CONFIG_SCHEMA = cv.All(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield climate.register_climate(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await climate.register_climate(var, config)
|
||||
|
||||
sens = yield cg.get_variable(config[CONF_SENSOR])
|
||||
sens = await cg.get_variable(config[CONF_SENSOR])
|
||||
cg.add(var.set_sensor(sens))
|
||||
|
||||
normal_config = BangBangClimateTargetTempConfig(
|
||||
@ -53,17 +53,17 @@ def to_code(config):
|
||||
)
|
||||
cg.add(var.set_normal_config(normal_config))
|
||||
|
||||
yield automation.build_automation(
|
||||
await automation.build_automation(
|
||||
var.get_idle_trigger(), [], config[CONF_IDLE_ACTION]
|
||||
)
|
||||
|
||||
if CONF_COOL_ACTION in config:
|
||||
yield automation.build_automation(
|
||||
await automation.build_automation(
|
||||
var.get_cool_trigger(), [], config[CONF_COOL_ACTION]
|
||||
)
|
||||
cg.add(var.set_supports_cool(True))
|
||||
if CONF_HEAT_ACTION in config:
|
||||
yield automation.build_automation(
|
||||
await automation.build_automation(
|
||||
var.get_heat_trigger(), [], config[CONF_HEAT_ACTION]
|
||||
)
|
||||
cg.add(var.set_supports_heat(True))
|
||||
|
@ -6,6 +6,7 @@ from esphome.const import (
|
||||
CONF_RESOLUTION,
|
||||
DEVICE_CLASS_ILLUMINANCE,
|
||||
ICON_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_LUX,
|
||||
CONF_MEASUREMENT_DURATION,
|
||||
)
|
||||
@ -26,7 +27,9 @@ BH1750Sensor = bh1750_ns.class_(
|
||||
|
||||
CONF_MEASUREMENT_TIME = "measurement_time"
|
||||
CONFIG_SCHEMA = (
|
||||
sensor.sensor_schema(UNIT_LUX, ICON_EMPTY, 1, DEVICE_CLASS_ILLUMINANCE)
|
||||
sensor.sensor_schema(
|
||||
UNIT_LUX, ICON_EMPTY, 1, DEVICE_CLASS_ILLUMINANCE, STATE_CLASS_MEASUREMENT
|
||||
)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(BH1750Sensor),
|
||||
@ -46,11 +49,11 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield sensor.register_sensor(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await sensor.register_sensor(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
cg.add(var.set_resolution(config[CONF_RESOLUTION]))
|
||||
cg.add(var.set_measurement_duration(config[CONF_MEASUREMENT_DURATION]))
|
||||
|
@ -21,19 +21,19 @@ CONFIG_SCHEMA = fan.FAN_SCHEMA.extend(
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
|
||||
yield cg.register_component(var, config)
|
||||
await cg.register_component(var, config)
|
||||
|
||||
fan_ = yield fan.create_fan_state(config)
|
||||
fan_ = await fan.create_fan_state(config)
|
||||
cg.add(var.set_fan(fan_))
|
||||
output_ = yield cg.get_variable(config[CONF_OUTPUT])
|
||||
output_ = await cg.get_variable(config[CONF_OUTPUT])
|
||||
cg.add(var.set_output(output_))
|
||||
|
||||
if CONF_OSCILLATION_OUTPUT in config:
|
||||
oscillation_output = yield cg.get_variable(config[CONF_OSCILLATION_OUTPUT])
|
||||
oscillation_output = await cg.get_variable(config[CONF_OSCILLATION_OUTPUT])
|
||||
cg.add(var.set_oscillating(oscillation_output))
|
||||
|
||||
if CONF_DIRECTION_OUTPUT in config:
|
||||
direction_output = yield cg.get_variable(config[CONF_DIRECTION_OUTPUT])
|
||||
direction_output = await cg.get_variable(config[CONF_DIRECTION_OUTPUT])
|
||||
cg.add(var.set_direction(direction_output))
|
||||
|
@ -14,9 +14,9 @@ CONFIG_SCHEMA = light.BINARY_LIGHT_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
|
||||
yield light.register_light(var, config)
|
||||
await light.register_light(var, config)
|
||||
|
||||
out = yield cg.get_variable(config[CONF_OUTPUT])
|
||||
out = await cg.get_variable(config[CONF_OUTPUT])
|
||||
cg.add(var.set_output(out))
|
||||
|
@ -4,6 +4,7 @@ from esphome import automation, core
|
||||
from esphome.automation import Condition, maybe_simple_id
|
||||
from esphome.components import mqtt
|
||||
from esphome.const import (
|
||||
CONF_DELAY,
|
||||
CONF_DEVICE_CLASS,
|
||||
CONF_FILTERS,
|
||||
CONF_ID,
|
||||
@ -50,7 +51,7 @@ from esphome.const import (
|
||||
DEVICE_CLASS_VIBRATION,
|
||||
DEVICE_CLASS_WINDOW,
|
||||
)
|
||||
from esphome.core import CORE, coroutine, coroutine_with_priority
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.util import Registry
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
@ -120,6 +121,7 @@ DelayedOnOffFilter = binary_sensor_ns.class_("DelayedOnOffFilter", Filter, cg.Co
|
||||
DelayedOnFilter = binary_sensor_ns.class_("DelayedOnFilter", Filter, cg.Component)
|
||||
DelayedOffFilter = binary_sensor_ns.class_("DelayedOffFilter", Filter, cg.Component)
|
||||
InvertFilter = binary_sensor_ns.class_("InvertFilter", Filter)
|
||||
AutorepeatFilter = binary_sensor_ns.class_("AutorepeatFilter", Filter, cg.Component)
|
||||
LambdaFilter = binary_sensor_ns.class_("LambdaFilter", Filter)
|
||||
|
||||
FILTER_REGISTRY = Registry()
|
||||
@ -127,43 +129,88 @@ validate_filters = cv.validate_registry("filter", FILTER_REGISTRY)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register("invert", InvertFilter, {})
|
||||
def invert_filter_to_code(config, filter_id):
|
||||
yield cg.new_Pvariable(filter_id)
|
||||
async def invert_filter_to_code(config, filter_id):
|
||||
return cg.new_Pvariable(filter_id)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register(
|
||||
"delayed_on_off", DelayedOnOffFilter, cv.positive_time_period_milliseconds
|
||||
)
|
||||
def delayed_on_off_filter_to_code(config, filter_id):
|
||||
async def delayed_on_off_filter_to_code(config, filter_id):
|
||||
var = cg.new_Pvariable(filter_id, config)
|
||||
yield cg.register_component(var, {})
|
||||
yield var
|
||||
await cg.register_component(var, {})
|
||||
return var
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register(
|
||||
"delayed_on", DelayedOnFilter, cv.positive_time_period_milliseconds
|
||||
)
|
||||
def delayed_on_filter_to_code(config, filter_id):
|
||||
async def delayed_on_filter_to_code(config, filter_id):
|
||||
var = cg.new_Pvariable(filter_id, config)
|
||||
yield cg.register_component(var, {})
|
||||
yield var
|
||||
await cg.register_component(var, {})
|
||||
return var
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register(
|
||||
"delayed_off", DelayedOffFilter, cv.positive_time_period_milliseconds
|
||||
)
|
||||
def delayed_off_filter_to_code(config, filter_id):
|
||||
async def delayed_off_filter_to_code(config, filter_id):
|
||||
var = cg.new_Pvariable(filter_id, config)
|
||||
yield cg.register_component(var, {})
|
||||
yield var
|
||||
await cg.register_component(var, {})
|
||||
return var
|
||||
|
||||
|
||||
CONF_TIME_OFF = "time_off"
|
||||
CONF_TIME_ON = "time_on"
|
||||
|
||||
DEFAULT_DELAY = "1s"
|
||||
DEFAULT_TIME_OFF = "100ms"
|
||||
DEFAULT_TIME_ON = "900ms"
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register(
|
||||
"autorepeat",
|
||||
AutorepeatFilter,
|
||||
cv.All(
|
||||
cv.ensure_list(
|
||||
{
|
||||
cv.Optional(
|
||||
CONF_DELAY, default=DEFAULT_DELAY
|
||||
): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(
|
||||
CONF_TIME_OFF, default=DEFAULT_TIME_OFF
|
||||
): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(
|
||||
CONF_TIME_ON, default=DEFAULT_TIME_ON
|
||||
): cv.positive_time_period_milliseconds,
|
||||
}
|
||||
),
|
||||
),
|
||||
)
|
||||
async def autorepeat_filter_to_code(config, filter_id):
|
||||
timings = []
|
||||
if len(config) > 0:
|
||||
for conf in config:
|
||||
timings.append((conf[CONF_DELAY], conf[CONF_TIME_OFF], conf[CONF_TIME_ON]))
|
||||
else:
|
||||
timings.append(
|
||||
(
|
||||
cv.time_period_str_unit(DEFAULT_DELAY).total_milliseconds,
|
||||
cv.time_period_str_unit(DEFAULT_TIME_OFF).total_milliseconds,
|
||||
cv.time_period_str_unit(DEFAULT_TIME_ON).total_milliseconds,
|
||||
)
|
||||
)
|
||||
var = cg.new_Pvariable(filter_id, timings)
|
||||
await cg.register_component(var, {})
|
||||
return var
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register("lambda", LambdaFilter, cv.returning_lambda)
|
||||
def lambda_filter_to_code(config, filter_id):
|
||||
lambda_ = yield cg.process_lambda(
|
||||
async def lambda_filter_to_code(config, filter_id):
|
||||
lambda_ = await cg.process_lambda(
|
||||
config, [(bool, "x")], return_type=cg.optional.template(bool)
|
||||
)
|
||||
yield cg.new_Pvariable(filter_id, lambda_)
|
||||
return cg.new_Pvariable(filter_id, lambda_)
|
||||
|
||||
|
||||
MULTI_CLICK_TIMING_SCHEMA = cv.Schema(
|
||||
@ -334,8 +381,7 @@ BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
@coroutine
|
||||
def setup_binary_sensor_core_(var, config):
|
||||
async def setup_binary_sensor_core_(var, config):
|
||||
cg.add(var.set_name(config[CONF_NAME]))
|
||||
if CONF_INTERNAL in config:
|
||||
cg.add(var.set_internal(config[CONF_INTERNAL]))
|
||||
@ -344,28 +390,28 @@ def setup_binary_sensor_core_(var, config):
|
||||
if CONF_INVERTED in config:
|
||||
cg.add(var.set_inverted(config[CONF_INVERTED]))
|
||||
if CONF_FILTERS in config:
|
||||
filters = yield cg.build_registry_list(FILTER_REGISTRY, config[CONF_FILTERS])
|
||||
filters = await cg.build_registry_list(FILTER_REGISTRY, config[CONF_FILTERS])
|
||||
cg.add(var.add_filters(filters))
|
||||
|
||||
for conf in config.get(CONF_ON_PRESS, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(trigger, [], conf)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
for conf in config.get(CONF_ON_RELEASE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(trigger, [], conf)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
for conf in config.get(CONF_ON_CLICK, []):
|
||||
trigger = cg.new_Pvariable(
|
||||
conf[CONF_TRIGGER_ID], var, conf[CONF_MIN_LENGTH], conf[CONF_MAX_LENGTH]
|
||||
)
|
||||
yield automation.build_automation(trigger, [], conf)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
for conf in config.get(CONF_ON_DOUBLE_CLICK, []):
|
||||
trigger = cg.new_Pvariable(
|
||||
conf[CONF_TRIGGER_ID], var, conf[CONF_MIN_LENGTH], conf[CONF_MAX_LENGTH]
|
||||
)
|
||||
yield automation.build_automation(trigger, [], conf)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
for conf in config.get(CONF_ON_MULTI_CLICK, []):
|
||||
timings = []
|
||||
@ -381,31 +427,29 @@ def setup_binary_sensor_core_(var, config):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, timings)
|
||||
if CONF_INVALID_COOLDOWN in conf:
|
||||
cg.add(trigger.set_invalid_cooldown(conf[CONF_INVALID_COOLDOWN]))
|
||||
yield cg.register_component(trigger, conf)
|
||||
yield automation.build_automation(trigger, [], conf)
|
||||
await cg.register_component(trigger, conf)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
for conf in config.get(CONF_ON_STATE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(trigger, [(bool, "x")], conf)
|
||||
await automation.build_automation(trigger, [(bool, "x")], conf)
|
||||
|
||||
if CONF_MQTT_ID in config:
|
||||
mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var)
|
||||
yield mqtt.register_mqtt_component(mqtt_, config)
|
||||
await mqtt.register_mqtt_component(mqtt_, config)
|
||||
|
||||
|
||||
@coroutine
|
||||
def register_binary_sensor(var, config):
|
||||
async def register_binary_sensor(var, config):
|
||||
if not CORE.has_id(config[CONF_ID]):
|
||||
var = cg.Pvariable(config[CONF_ID], var)
|
||||
cg.add(cg.App.register_binary_sensor(var))
|
||||
yield setup_binary_sensor_core_(var, config)
|
||||
await setup_binary_sensor_core_(var, config)
|
||||
|
||||
|
||||
@coroutine
|
||||
def new_binary_sensor(config):
|
||||
async def new_binary_sensor(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
|
||||
yield register_binary_sensor(var, config)
|
||||
yield var
|
||||
await register_binary_sensor(var, config)
|
||||
return var
|
||||
|
||||
|
||||
BINARY_SENSOR_CONDITION_SCHEMA = maybe_simple_id(
|
||||
@ -422,20 +466,20 @@ BINARY_SENSOR_CONDITION_SCHEMA = maybe_simple_id(
|
||||
@automation.register_condition(
|
||||
"binary_sensor.is_on", BinarySensorCondition, BINARY_SENSOR_CONDITION_SCHEMA
|
||||
)
|
||||
def binary_sensor_is_on_to_code(config, condition_id, template_arg, args):
|
||||
paren = yield cg.get_variable(config[CONF_ID])
|
||||
yield cg.new_Pvariable(condition_id, template_arg, paren, True)
|
||||
async def binary_sensor_is_on_to_code(config, condition_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(condition_id, template_arg, paren, True)
|
||||
|
||||
|
||||
@automation.register_condition(
|
||||
"binary_sensor.is_off", BinarySensorCondition, BINARY_SENSOR_CONDITION_SCHEMA
|
||||
)
|
||||
def binary_sensor_is_off_to_code(config, condition_id, template_arg, args):
|
||||
paren = yield cg.get_variable(config[CONF_ID])
|
||||
yield cg.new_Pvariable(condition_id, template_arg, paren, False)
|
||||
async def binary_sensor_is_off_to_code(config, condition_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(condition_id, template_arg, paren, False)
|
||||
|
||||
|
||||
@coroutine_with_priority(100.0)
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
cg.add_define("USE_BINARY_SENSOR")
|
||||
cg.add_global(binary_sensor_ns.using)
|
||||
|
@ -64,6 +64,50 @@ float DelayedOffFilter::get_setup_priority() const { return setup_priority::HARD
|
||||
|
||||
optional<bool> InvertFilter::new_value(bool value, bool is_initial) { return !value; }
|
||||
|
||||
AutorepeatFilter::AutorepeatFilter(const std::vector<AutorepeatFilterTiming> &timings) : timings_(timings) {}
|
||||
|
||||
optional<bool> AutorepeatFilter::new_value(bool value, bool is_initial) {
|
||||
if (value) {
|
||||
// Ignore if already running
|
||||
if (this->active_timing_ != 0)
|
||||
return {};
|
||||
|
||||
this->next_timing_();
|
||||
return true;
|
||||
} else {
|
||||
this->cancel_timeout("TIMING");
|
||||
this->cancel_timeout("ON_OFF");
|
||||
this->active_timing_ = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AutorepeatFilter::next_timing_() {
|
||||
// Entering this method
|
||||
// 1st time: starts waiting the first delay
|
||||
// 2nd time: starts waiting the second delay and starts toggling with the first time_off / _on
|
||||
// last time: no delay to start but have to bump the index to reflect the last
|
||||
if (this->active_timing_ < this->timings_.size())
|
||||
this->set_timeout("TIMING", this->timings_[this->active_timing_].delay, [this]() { this->next_timing_(); });
|
||||
|
||||
if (this->active_timing_ <= this->timings_.size()) {
|
||||
this->active_timing_++;
|
||||
}
|
||||
|
||||
if (this->active_timing_ == 2)
|
||||
this->next_value_(false);
|
||||
|
||||
// Leaving this method: if the toggling is started, it has to use [active_timing_ - 2] for the intervals
|
||||
}
|
||||
|
||||
void AutorepeatFilter::next_value_(bool val) {
|
||||
const AutorepeatFilterTiming &timing = this->timings_[this->active_timing_ - 2];
|
||||
this->output(val, false); // This is at least the second one so not initial
|
||||
this->set_timeout("ON_OFF", val ? timing.time_on : timing.time_off, [this, val]() { this->next_value_(!val); });
|
||||
}
|
||||
|
||||
float AutorepeatFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
|
||||
LambdaFilter::LambdaFilter(const std::function<optional<bool>(bool)> &f) : f_(f) {}
|
||||
|
||||
optional<bool> LambdaFilter::new_value(bool value, bool is_initial) { return this->f_(value); }
|
||||
|
@ -66,6 +66,33 @@ class InvertFilter : public Filter {
|
||||
optional<bool> new_value(bool value, bool is_initial) override;
|
||||
};
|
||||
|
||||
struct AutorepeatFilterTiming {
|
||||
AutorepeatFilterTiming(uint32_t delay, uint32_t off, uint32_t on) {
|
||||
this->delay = delay;
|
||||
this->time_off = off;
|
||||
this->time_on = on;
|
||||
}
|
||||
uint32_t delay;
|
||||
uint32_t time_off;
|
||||
uint32_t time_on;
|
||||
};
|
||||
|
||||
class AutorepeatFilter : public Filter, public Component {
|
||||
public:
|
||||
explicit AutorepeatFilter(const std::vector<AutorepeatFilterTiming> &timings);
|
||||
|
||||
optional<bool> new_value(bool value, bool is_initial) override;
|
||||
|
||||
float get_setup_priority() const override;
|
||||
|
||||
protected:
|
||||
void next_timing_();
|
||||
void next_value_(bool val);
|
||||
|
||||
std::vector<AutorepeatFilterTiming> timings_;
|
||||
uint8_t active_timing_{0};
|
||||
};
|
||||
|
||||
class LambdaFilter : public Filter {
|
||||
public:
|
||||
explicit LambdaFilter(const std::function<optional<bool>(bool)> &f);
|
||||
|
@ -12,6 +12,7 @@ from esphome.const import (
|
||||
ICON_CHECK_CIRCLE_OUTLINE,
|
||||
CONF_BINARY_SENSOR,
|
||||
CONF_GROUP,
|
||||
STATE_CLASS_NONE,
|
||||
)
|
||||
|
||||
DEPENDENCIES = ["binary_sensor"]
|
||||
@ -34,7 +35,11 @@ entry = {
|
||||
CONFIG_SCHEMA = cv.typed_schema(
|
||||
{
|
||||
CONF_GROUP: sensor.sensor_schema(
|
||||
UNIT_EMPTY, ICON_CHECK_CIRCLE_OUTLINE, 0, DEVICE_CLASS_EMPTY
|
||||
UNIT_EMPTY,
|
||||
ICON_CHECK_CIRCLE_OUTLINE,
|
||||
0,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
STATE_CLASS_NONE,
|
||||
).extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(BinarySensorMap),
|
||||
@ -48,14 +53,14 @@ CONFIG_SCHEMA = cv.typed_schema(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield sensor.register_sensor(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await sensor.register_sensor(var, config)
|
||||
|
||||
constant = SENSOR_MAP_TYPES[config[CONF_TYPE]]
|
||||
cg.add(var.set_sensor_type(constant))
|
||||
|
||||
for ch in config[CONF_CHANNELS]:
|
||||
input_var = yield cg.get_variable(ch[CONF_BINARY_SENSOR])
|
||||
input_var = await cg.get_variable(ch[CONF_BINARY_SENSOR])
|
||||
cg.add(var.add_channel(input_var, ch[CONF_VALUE]))
|
||||
|
@ -9,7 +9,6 @@ from esphome.const import (
|
||||
CONF_ON_DISCONNECT,
|
||||
CONF_TRIGGER_ID,
|
||||
)
|
||||
from esphome.core import coroutine
|
||||
from esphome import automation
|
||||
|
||||
CODEOWNERS = ["@buxtronix"]
|
||||
@ -68,20 +67,19 @@ BLE_CLIENT_SCHEMA = cv.Schema(
|
||||
)
|
||||
|
||||
|
||||
@coroutine
|
||||
def register_ble_node(var, config):
|
||||
parent = yield cg.get_variable(config[CONF_BLE_CLIENT_ID])
|
||||
async def register_ble_node(var, config):
|
||||
parent = await cg.get_variable(config[CONF_BLE_CLIENT_ID])
|
||||
cg.add(parent.register_ble_node(var))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield esp32_ble_tracker.register_client(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await esp32_ble_tracker.register_client(var, config)
|
||||
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
|
||||
for conf in config.get(CONF_ON_CONNECT, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(trigger, [], conf)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
for conf in config.get(CONF_ON_DISCONNECT, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(trigger, [], conf)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
@ -94,7 +94,7 @@ void BLEClient::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t es
|
||||
esp_ble_gattc_cb_param_t *param) {
|
||||
if (event == ESP_GATTC_REG_EVT && this->app_id != param->reg.app_id)
|
||||
return;
|
||||
if (event != ESP_GATTC_REG_EVT && esp_gattc_if != ESP_GATT_IF_NONE && gattc_if != this->gattc_if)
|
||||
if (event != ESP_GATTC_REG_EVT && esp_gattc_if != ESP_GATT_IF_NONE && esp_gattc_if != this->gattc_if)
|
||||
return;
|
||||
|
||||
bool all_established = this->all_nodes_established();
|
||||
|
@ -4,6 +4,8 @@ from esphome.components import sensor, ble_client, esp32_ble_tracker
|
||||
from esphome.const import (
|
||||
DEVICE_CLASS_EMPTY,
|
||||
CONF_ID,
|
||||
CONF_LAMBDA,
|
||||
STATE_CLASS_NONE,
|
||||
UNIT_EMPTY,
|
||||
ICON_EMPTY,
|
||||
CONF_TRIGGER_ID,
|
||||
@ -20,6 +22,9 @@ CONF_DESCRIPTOR_UUID = "descriptor_uuid"
|
||||
CONF_NOTIFY = "notify"
|
||||
CONF_ON_NOTIFY = "on_notify"
|
||||
|
||||
adv_data_t = cg.std_vector.template(cg.uint8)
|
||||
adv_data_t_const_ref = adv_data_t.operator("ref").operator("const")
|
||||
|
||||
BLESensor = ble_client_ns.class_(
|
||||
"BLESensor", sensor.Sensor, cg.PollingComponent, ble_client.BLEClientNode
|
||||
)
|
||||
@ -28,13 +33,16 @@ BLESensorNotifyTrigger = ble_client_ns.class_(
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY)
|
||||
sensor.sensor_schema(
|
||||
UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
|
||||
)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(BLESensor),
|
||||
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
||||
cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
|
||||
cv.Optional(CONF_DESCRIPTOR_UUID): esp32_ble_tracker.bt_uuid,
|
||||
cv.Optional(CONF_LAMBDA): cv.returning_lambda,
|
||||
cv.Optional(CONF_NOTIFY, default=False): cv.boolean,
|
||||
cv.Optional(CONF_ON_NOTIFY): automation.validate_automation(
|
||||
{
|
||||
@ -50,7 +58,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async 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(
|
||||
@ -105,11 +113,17 @@ def to_code(config):
|
||||
uuid128 = esp32_ble_tracker.as_hex_array(config[CONF_DESCRIPTOR_UUID])
|
||||
cg.add(var.set_descr_uuid128(uuid128))
|
||||
|
||||
yield cg.register_component(var, config)
|
||||
yield ble_client.register_ble_node(var, config)
|
||||
if CONF_LAMBDA in config:
|
||||
lambda_ = await cg.process_lambda(
|
||||
config[CONF_LAMBDA], [(adv_data_t_const_ref, "x")], return_type=cg.float_
|
||||
)
|
||||
cg.add(var.set_data_to_value(lambda_))
|
||||
|
||||
await cg.register_component(var, config)
|
||||
await ble_client.register_ble_node(var, config)
|
||||
cg.add(var.set_enable_notify(config[CONF_NOTIFY]))
|
||||
yield sensor.register_sensor(var, config)
|
||||
await sensor.register_sensor(var, config)
|
||||
for conf in config.get(CONF_ON_NOTIFY, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield ble_client.register_ble_node(trigger, config)
|
||||
yield automation.build_automation(trigger, [(float, "x")], conf)
|
||||
await ble_client.register_ble_node(trigger, config)
|
||||
await automation.build_automation(trigger, [(float, "x")], conf)
|
||||
|
@ -84,7 +84,7 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
}
|
||||
if (param->read.handle == this->handle) {
|
||||
this->status_clear_warning();
|
||||
this->publish_state((float) param->read.value[0]);
|
||||
this->publish_state(this->parse_data(param->read.value, param->read.value_len));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -93,7 +93,7 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
break;
|
||||
ESP_LOGV(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: handle=0x%x, value=0x%x", this->get_name().c_str(),
|
||||
param->notify.handle, param->notify.value[0]);
|
||||
this->publish_state((float) param->notify.value[0]);
|
||||
this->publish_state(this->parse_data(param->notify.value, param->notify.value_len));
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
|
||||
@ -105,6 +105,15 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
}
|
||||
}
|
||||
|
||||
float BLESensor::parse_data(uint8_t *value, uint16_t value_len) {
|
||||
if (this->data_to_value_func_.has_value()) {
|
||||
std::vector<uint8_t> data(value, value + value_len);
|
||||
return (*this->data_to_value_func_)(data);
|
||||
} else {
|
||||
return value[0];
|
||||
}
|
||||
}
|
||||
|
||||
void BLESensor::update() {
|
||||
if (this->node_state != espbt::ClientState::Established) {
|
||||
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->get_name().c_str());
|
||||
|
@ -13,6 +13,8 @@ namespace ble_client {
|
||||
|
||||
namespace espbt = esphome::esp32_ble_tracker;
|
||||
|
||||
using data_to_value_t = std::function<float(std::vector<uint8_t>)>;
|
||||
|
||||
class BLESensor : public sensor::Sensor, public PollingComponent, public BLEClientNode {
|
||||
public:
|
||||
void loop() override;
|
||||
@ -30,11 +32,14 @@ class BLESensor : public sensor::Sensor, public PollingComponent, public BLEClie
|
||||
void set_descr_uuid16(uint16_t uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
|
||||
void set_descr_uuid32(uint32_t uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
|
||||
void set_descr_uuid128(uint8_t *uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||
void set_data_to_value(data_to_value_t &&lambda_) { this->data_to_value_func_ = lambda_; }
|
||||
void set_enable_notify(bool notify) { this->notify_ = notify; }
|
||||
uint16_t handle;
|
||||
|
||||
protected:
|
||||
uint32_t hash_base() override;
|
||||
float parse_data(uint8_t *value, uint16_t value_len);
|
||||
optional<data_to_value_t> data_to_value_func_{};
|
||||
bool notify_;
|
||||
espbt::ESPBTUUID service_uuid_;
|
||||
espbt::ESPBTUUID char_uuid_;
|
||||
|
@ -23,8 +23,8 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield switch.register_switch(var, config)
|
||||
yield ble_client.register_ble_node(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await switch.register_switch(var, config)
|
||||
await ble_client.register_ble_node(var, config)
|
||||
|
@ -27,11 +27,11 @@ CONFIG_SCHEMA = cv.All(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield esp32_ble_tracker.register_ble_device(var, config)
|
||||
yield binary_sensor.register_binary_sensor(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await esp32_ble_tracker.register_ble_device(var, config)
|
||||
await binary_sensor.register_binary_sensor(var, config)
|
||||
|
||||
if CONF_MAC_ADDRESS in config:
|
||||
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
|
||||
|
@ -6,6 +6,7 @@ from esphome.const import (
|
||||
CONF_MAC_ADDRESS,
|
||||
CONF_ID,
|
||||
DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_DECIBEL,
|
||||
ICON_EMPTY,
|
||||
)
|
||||
@ -18,7 +19,13 @@ BLERSSISensor = ble_rssi_ns.class_(
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
sensor.sensor_schema(UNIT_DECIBEL, ICON_EMPTY, 0, DEVICE_CLASS_SIGNAL_STRENGTH)
|
||||
sensor.sensor_schema(
|
||||
UNIT_DECIBEL,
|
||||
ICON_EMPTY,
|
||||
0,
|
||||
DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(BLERSSISensor),
|
||||
@ -32,11 +39,11 @@ CONFIG_SCHEMA = cv.All(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield esp32_ble_tracker.register_ble_device(var, config)
|
||||
yield sensor.register_sensor(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await esp32_ble_tracker.register_ble_device(var, config)
|
||||
await sensor.register_sensor(var, config)
|
||||
|
||||
if CONF_MAC_ADDRESS in config:
|
||||
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
|
||||
|
@ -24,8 +24,8 @@ CONFIG_SCHEMA = cv.All(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield esp32_ble_tracker.register_ble_device(var, config)
|
||||
yield text_sensor.register_text_sensor(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await esp32_ble_tracker.register_ble_device(var, config)
|
||||
await text_sensor.register_text_sensor(var, config)
|
||||
|
@ -12,6 +12,7 @@ from esphome.const import (
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
ICON_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_HECTOPASCAL,
|
||||
UNIT_PERCENT,
|
||||
@ -48,7 +49,11 @@ CONFIG_SCHEMA = (
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(BME280Component),
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
|
||||
UNIT_CELSIUS,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
|
||||
@ -57,7 +62,11 @@ CONFIG_SCHEMA = (
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
|
||||
UNIT_HECTOPASCAL, ICON_EMPTY, 1, DEVICE_CLASS_PRESSURE
|
||||
UNIT_HECTOPASCAL,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
|
||||
@ -66,7 +75,11 @@ CONFIG_SCHEMA = (
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
|
||||
UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY
|
||||
UNIT_PERCENT,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
|
||||
@ -84,26 +97,26 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
if CONF_TEMPERATURE in config:
|
||||
conf = config[CONF_TEMPERATURE]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_temperature_sensor(sens))
|
||||
cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING]))
|
||||
|
||||
if CONF_PRESSURE in config:
|
||||
conf = config[CONF_PRESSURE]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_pressure_sensor(sens))
|
||||
cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING]))
|
||||
|
||||
if CONF_HUMIDITY in config:
|
||||
conf = config[CONF_HUMIDITY]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_humidity_sensor(sens))
|
||||
cg.add(var.set_humidity_oversampling(conf[CONF_OVERSAMPLING]))
|
||||
|
||||
|
@ -16,6 +16,7 @@ from esphome.const import (
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_OHM,
|
||||
ICON_GAS_CYLINDER,
|
||||
UNIT_CELSIUS,
|
||||
@ -58,7 +59,11 @@ CONFIG_SCHEMA = (
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(BME680Component),
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
|
||||
UNIT_CELSIUS,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
|
||||
@ -67,7 +72,11 @@ CONFIG_SCHEMA = (
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
|
||||
UNIT_HECTOPASCAL, ICON_EMPTY, 1, DEVICE_CLASS_PRESSURE
|
||||
UNIT_HECTOPASCAL,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
|
||||
@ -76,7 +85,11 @@ CONFIG_SCHEMA = (
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
|
||||
UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY
|
||||
UNIT_PERCENT,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
|
||||
@ -85,7 +98,11 @@ CONFIG_SCHEMA = (
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_GAS_RESISTANCE): sensor.sensor_schema(
|
||||
UNIT_OHM, ICON_GAS_CYLINDER, 1, DEVICE_CLASS_EMPTY
|
||||
UNIT_OHM,
|
||||
ICON_GAS_CYLINDER,
|
||||
1,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum(
|
||||
IIR_FILTER_OPTIONS, upper=True
|
||||
@ -114,32 +131,32 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
if CONF_TEMPERATURE in config:
|
||||
conf = config[CONF_TEMPERATURE]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_temperature_sensor(sens))
|
||||
cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING]))
|
||||
|
||||
if CONF_PRESSURE in config:
|
||||
conf = config[CONF_PRESSURE]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_pressure_sensor(sens))
|
||||
cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING]))
|
||||
|
||||
if CONF_HUMIDITY in config:
|
||||
conf = config[CONF_HUMIDITY]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_humidity_sensor(sens))
|
||||
cg.add(var.set_humidity_oversampling(conf[CONF_OVERSAMPLING]))
|
||||
|
||||
if CONF_GAS_RESISTANCE in config:
|
||||
conf = config[CONF_GAS_RESISTANCE]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_gas_resistance_sensor(sens))
|
||||
|
||||
cg.add(var.set_iir_filter(IIR_FILTER_OPTIONS[config[CONF_IIR_FILTER]]))
|
||||
|
@ -48,10 +48,10 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
).extend(i2c.i2c_device_schema(0x76))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
cg.add(var.set_temperature_offset(config[CONF_TEMPERATURE_OFFSET]))
|
||||
cg.add(var.set_iaq_mode(config[CONF_IAQ_MODE]))
|
||||
@ -60,5 +60,5 @@ def to_code(config):
|
||||
var.set_state_save_interval(config[CONF_STATE_SAVE_INTERVAL].total_milliseconds)
|
||||
)
|
||||
|
||||
cg.add_define("USING_BSEC")
|
||||
cg.add_define("USE_BSEC")
|
||||
cg.add_library("BSEC Software Library", "1.6.1480")
|
||||
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
#include "bme680_bsec.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
@ -7,7 +5,7 @@
|
||||
|
||||
namespace esphome {
|
||||
namespace bme680_bsec {
|
||||
#ifdef USING_BSEC
|
||||
#ifdef USE_BSEC
|
||||
static const char *TAG = "bme680_bsec.sensor";
|
||||
|
||||
static const std::string IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"};
|
||||
@ -30,7 +28,6 @@ void BME680BSECComponent::setup() {
|
||||
this->bme680_.write = BME680BSECComponent::write_bytes_wrapper;
|
||||
this->bme680_.delay_ms = BME680BSECComponent::delay_ms;
|
||||
this->bme680_.amb_temp = 25;
|
||||
this->bme680_.power_mode = BME680_FORCED_MODE;
|
||||
|
||||
this->bme680_status_ = bme680_init(&this->bme680_);
|
||||
if (this->bme680_status_ != BME680_OK) {
|
||||
@ -43,14 +40,13 @@ void BME680BSECComponent::setup() {
|
||||
#include "config/generic_33v_300s_28d/bsec_iaq.txt"
|
||||
};
|
||||
this->set_config_(bsec_config);
|
||||
this->update_subscription_(BSEC_SAMPLE_RATE_ULP);
|
||||
} else {
|
||||
const uint8_t bsec_config[] = {
|
||||
#include "config/generic_33v_3s_28d/bsec_iaq.txt"
|
||||
};
|
||||
this->set_config_(bsec_config);
|
||||
this->update_subscription_(BSEC_SAMPLE_RATE_LP);
|
||||
}
|
||||
this->update_subscription_();
|
||||
if (this->bsec_status_ != BSEC_OK) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
@ -64,50 +60,57 @@ void BME680BSECComponent::set_config_(const uint8_t *config) {
|
||||
this->bsec_status_ = bsec_set_configuration(config, BSEC_MAX_PROPERTY_BLOB_SIZE, work_buffer, sizeof(work_buffer));
|
||||
}
|
||||
|
||||
void BME680BSECComponent::update_subscription_(float sample_rate) {
|
||||
float BME680BSECComponent::calc_sensor_sample_rate_(SampleRate sample_rate) {
|
||||
if (sample_rate == SAMPLE_RATE_DEFAULT) {
|
||||
sample_rate = this->sample_rate_;
|
||||
}
|
||||
return sample_rate == SAMPLE_RATE_ULP ? BSEC_SAMPLE_RATE_ULP : BSEC_SAMPLE_RATE_LP;
|
||||
}
|
||||
|
||||
void BME680BSECComponent::update_subscription_() {
|
||||
bsec_sensor_configuration_t virtual_sensors[BSEC_NUMBER_OUTPUTS];
|
||||
int num_virtual_sensors = 0;
|
||||
|
||||
if (this->iaq_sensor_) {
|
||||
virtual_sensors[num_virtual_sensors].sensor_id =
|
||||
this->iaq_mode_ == IAQ_MODE_STATIC ? BSEC_OUTPUT_STATIC_IAQ : BSEC_OUTPUT_IAQ;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = sample_rate;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
|
||||
num_virtual_sensors++;
|
||||
}
|
||||
|
||||
if (this->co2_equivalent_sensor_) {
|
||||
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_CO2_EQUIVALENT;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = sample_rate;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
|
||||
num_virtual_sensors++;
|
||||
}
|
||||
|
||||
if (this->breath_voc_equivalent_sensor_) {
|
||||
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_BREATH_VOC_EQUIVALENT;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = sample_rate;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
|
||||
num_virtual_sensors++;
|
||||
}
|
||||
|
||||
if (this->pressure_sensor_) {
|
||||
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = sample_rate;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->pressure_sample_rate_);
|
||||
num_virtual_sensors++;
|
||||
}
|
||||
|
||||
if (this->gas_resistance_sensor_) {
|
||||
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_RAW_GAS;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = sample_rate;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
|
||||
num_virtual_sensors++;
|
||||
}
|
||||
|
||||
if (this->temperature_sensor_) {
|
||||
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = sample_rate;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->temperature_sample_rate_);
|
||||
num_virtual_sensors++;
|
||||
}
|
||||
|
||||
if (this->humidity_sensor_) {
|
||||
virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = sample_rate;
|
||||
virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->humidity_sample_rate_);
|
||||
num_virtual_sensors++;
|
||||
}
|
||||
|
||||
@ -134,12 +137,15 @@ void BME680BSECComponent::dump_config() {
|
||||
|
||||
ESP_LOGCONFIG(TAG, " Temperature Offset: %.2f", this->temperature_offset_);
|
||||
ESP_LOGCONFIG(TAG, " IAQ Mode: %s", this->iaq_mode_ == IAQ_MODE_STATIC ? "Static" : "Mobile");
|
||||
ESP_LOGCONFIG(TAG, " Sample Rate: %s", this->sample_rate_ == SAMPLE_RATE_ULP ? "ULP" : "LP");
|
||||
ESP_LOGCONFIG(TAG, " Sample Rate: %s", BME680_BSEC_SAMPLE_RATE_LOG(this->sample_rate_));
|
||||
ESP_LOGCONFIG(TAG, " State Save Interval: %ims", this->state_save_interval_ms_);
|
||||
|
||||
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Sample Rate: %s", BME680_BSEC_SAMPLE_RATE_LOG(this->temperature_sample_rate_));
|
||||
LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Sample Rate: %s", BME680_BSEC_SAMPLE_RATE_LOG(this->pressure_sample_rate_));
|
||||
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Sample Rate: %s", BME680_BSEC_SAMPLE_RATE_LOG(this->humidity_sample_rate_));
|
||||
LOG_SENSOR(" ", "Gas Resistance", this->gas_resistance_sensor_);
|
||||
LOG_SENSOR(" ", "IAQ", this->iaq_sensor_);
|
||||
LOG_SENSOR(" ", "Numeric IAQ Accuracy", this->iaq_accuracy_sensor_);
|
||||
@ -181,14 +187,15 @@ void BME680BSECComponent::run_() {
|
||||
}
|
||||
this->next_call_ns_ = bme680_settings.next_call;
|
||||
|
||||
this->bme680_.gas_sett.run_gas = bme680_settings.run_gas;
|
||||
this->bme680_.tph_sett.os_hum = bme680_settings.humidity_oversampling;
|
||||
if (bme680_settings.trigger_measurement) {
|
||||
this->bme680_.tph_sett.os_temp = bme680_settings.temperature_oversampling;
|
||||
this->bme680_.tph_sett.os_pres = bme680_settings.pressure_oversampling;
|
||||
this->bme680_.tph_sett.os_hum = bme680_settings.humidity_oversampling;
|
||||
this->bme680_.gas_sett.run_gas = bme680_settings.run_gas;
|
||||
this->bme680_.gas_sett.heatr_temp = bme680_settings.heater_temperature;
|
||||
this->bme680_.gas_sett.heatr_dur = bme680_settings.heating_duration;
|
||||
uint16_t desired_settings =
|
||||
BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL;
|
||||
this->bme680_.power_mode = BME680_FORCED_MODE;
|
||||
uint16_t desired_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL;
|
||||
this->bme680_status_ = bme680_set_sensor_settings(desired_settings, &this->bme680_);
|
||||
if (this->bme680_status_ != BME680_OK) {
|
||||
ESP_LOGW(TAG, "Failed to set sensor settings (BME680 Error Code %d)", this->bme680_status_);
|
||||
@ -204,11 +211,31 @@ void BME680BSECComponent::run_() {
|
||||
uint16_t meas_dur = 0;
|
||||
bme680_get_profile_dur(&meas_dur, &this->bme680_);
|
||||
ESP_LOGV(TAG, "Queueing read in %ums", meas_dur);
|
||||
this->set_timeout("read", meas_dur, [this, bme680_settings]() { this->read_(bme680_settings); });
|
||||
this->set_timeout("read", meas_dur,
|
||||
[this, curr_time_ns, bme680_settings]() { this->read_(curr_time_ns, bme680_settings); });
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Measurement not required");
|
||||
this->read_(curr_time_ns, bme680_settings);
|
||||
}
|
||||
}
|
||||
|
||||
void BME680BSECComponent::read_(bsec_bme_settings_t bme680_settings) {
|
||||
void BME680BSECComponent::read_(int64_t trigger_time_ns, bsec_bme_settings_t bme680_settings) {
|
||||
ESP_LOGV(TAG, "Reading data");
|
||||
|
||||
if (bme680_settings.trigger_measurement) {
|
||||
while (this->bme680_.power_mode != BME680_SLEEP_MODE) {
|
||||
this->bme680_status_ = bme680_get_sensor_mode(&this->bme680_);
|
||||
if (this->bme680_status_ != BME680_OK) {
|
||||
ESP_LOGW(TAG, "Failed to get sensor mode (BME680 Error Code %d)", this->bme680_status_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bme680_settings.process_data) {
|
||||
ESP_LOGV(TAG, "Data processing not required");
|
||||
return;
|
||||
}
|
||||
|
||||
struct bme680_field_data data;
|
||||
this->bme680_status_ = bme680_get_sensor_data(&data, &this->bme680_);
|
||||
|
||||
@ -223,37 +250,40 @@ void BME680BSECComponent::read_(bsec_bme_settings_t bme680_settings) {
|
||||
|
||||
bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temperature, Pressure, Humidity & Gas Resistance
|
||||
uint8_t num_inputs = 0;
|
||||
int64_t curr_time_ns = this->get_time_ns_();
|
||||
|
||||
if (bme680_settings.process_data & BSEC_PROCESS_TEMPERATURE) {
|
||||
inputs[num_inputs].sensor_id = BSEC_INPUT_TEMPERATURE;
|
||||
inputs[num_inputs].signal = data.temperature / 100.0f;
|
||||
inputs[num_inputs].time_stamp = curr_time_ns;
|
||||
inputs[num_inputs].time_stamp = trigger_time_ns;
|
||||
num_inputs++;
|
||||
|
||||
// Temperature offset from the real temperature due to external heat sources
|
||||
inputs[num_inputs].sensor_id = BSEC_INPUT_HEATSOURCE;
|
||||
inputs[num_inputs].signal = this->temperature_offset_;
|
||||
inputs[num_inputs].time_stamp = curr_time_ns;
|
||||
inputs[num_inputs].time_stamp = trigger_time_ns;
|
||||
num_inputs++;
|
||||
}
|
||||
if (bme680_settings.process_data & BSEC_PROCESS_HUMIDITY) {
|
||||
inputs[num_inputs].sensor_id = BSEC_INPUT_HUMIDITY;
|
||||
inputs[num_inputs].signal = data.humidity / 1000.0f;
|
||||
inputs[num_inputs].time_stamp = curr_time_ns;
|
||||
inputs[num_inputs].time_stamp = trigger_time_ns;
|
||||
num_inputs++;
|
||||
}
|
||||
if (bme680_settings.process_data & BSEC_PROCESS_PRESSURE) {
|
||||
inputs[num_inputs].sensor_id = BSEC_INPUT_PRESSURE;
|
||||
inputs[num_inputs].signal = data.pressure;
|
||||
inputs[num_inputs].time_stamp = curr_time_ns;
|
||||
inputs[num_inputs].time_stamp = trigger_time_ns;
|
||||
num_inputs++;
|
||||
}
|
||||
if (bme680_settings.process_data & BSEC_PROCESS_GAS) {
|
||||
if (data.status & BME680_GASM_VALID_MSK) {
|
||||
inputs[num_inputs].sensor_id = BSEC_INPUT_GASRESISTOR;
|
||||
inputs[num_inputs].signal = data.gas_resistance;
|
||||
inputs[num_inputs].time_stamp = curr_time_ns;
|
||||
inputs[num_inputs].time_stamp = trigger_time_ns;
|
||||
num_inputs++;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "BME680 did not report gas data");
|
||||
}
|
||||
}
|
||||
if (num_inputs < 1) {
|
||||
ESP_LOGD(TAG, "No signal inputs available for BSEC");
|
||||
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
@ -9,13 +7,13 @@
|
||||
#include "esphome/core/preferences.h"
|
||||
#include <map>
|
||||
|
||||
#ifdef USING_BSEC
|
||||
#ifdef USE_BSEC
|
||||
#include <bsec.h>
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace bme680_bsec {
|
||||
#ifdef USING_BSEC
|
||||
#ifdef USE_BSEC
|
||||
|
||||
enum IAQMode {
|
||||
IAQ_MODE_STATIC = 0,
|
||||
@ -25,32 +23,31 @@ enum IAQMode {
|
||||
enum SampleRate {
|
||||
SAMPLE_RATE_LP = 0,
|
||||
SAMPLE_RATE_ULP = 1,
|
||||
SAMPLE_RATE_DEFAULT = 2,
|
||||
};
|
||||
|
||||
#define BME680_BSEC_SAMPLE_RATE_LOG(r) (r == SAMPLE_RATE_DEFAULT ? "Default" : (r == SAMPLE_RATE_ULP ? "ULP" : "LP"))
|
||||
|
||||
class BME680BSECComponent : public Component, public i2c::I2CDevice {
|
||||
public:
|
||||
void set_temperature_offset(float offset) { this->temperature_offset_ = offset; }
|
||||
void set_iaq_mode(IAQMode iaq_mode) { this->iaq_mode_ = iaq_mode; }
|
||||
void set_sample_rate(SampleRate sample_rate) { this->sample_rate_ = sample_rate; }
|
||||
void set_state_save_interval(uint32_t interval) { this->state_save_interval_ms_ = interval; }
|
||||
|
||||
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
|
||||
void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; }
|
||||
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; }
|
||||
void set_gas_resistance_sensor(sensor::Sensor *gas_resistance_sensor) {
|
||||
gas_resistance_sensor_ = gas_resistance_sensor;
|
||||
}
|
||||
void set_iaq_sensor(sensor::Sensor *iaq_sensor) { iaq_sensor_ = iaq_sensor; }
|
||||
void set_iaq_accuracy_text_sensor(text_sensor::TextSensor *iaq_accuracy_text_sensor) {
|
||||
iaq_accuracy_text_sensor_ = iaq_accuracy_text_sensor;
|
||||
}
|
||||
void set_iaq_accuracy_sensor(sensor::Sensor *iaq_accuracy_sensor) { iaq_accuracy_sensor_ = iaq_accuracy_sensor; }
|
||||
void set_co2_equivalent_sensor(sensor::Sensor *co2_equivalent_sensor) {
|
||||
co2_equivalent_sensor_ = co2_equivalent_sensor;
|
||||
}
|
||||
void set_breath_voc_equivalent_sensor(sensor::Sensor *breath_voc_equivalent_sensor) {
|
||||
breath_voc_equivalent_sensor_ = breath_voc_equivalent_sensor;
|
||||
}
|
||||
void set_sample_rate(SampleRate sample_rate) { this->sample_rate_ = sample_rate; }
|
||||
void set_temperature_sample_rate(SampleRate sample_rate) { this->temperature_sample_rate_ = sample_rate; }
|
||||
void set_pressure_sample_rate(SampleRate sample_rate) { this->pressure_sample_rate_ = sample_rate; }
|
||||
void set_humidity_sample_rate(SampleRate sample_rate) { this->humidity_sample_rate_ = sample_rate; }
|
||||
|
||||
void set_temperature_sensor(sensor::Sensor *sensor) { this->temperature_sensor_ = sensor; }
|
||||
void set_pressure_sensor(sensor::Sensor *sensor) { this->pressure_sensor_ = sensor; }
|
||||
void set_humidity_sensor(sensor::Sensor *sensor) { this->humidity_sensor_ = sensor; }
|
||||
void set_gas_resistance_sensor(sensor::Sensor *sensor) { this->gas_resistance_sensor_ = sensor; }
|
||||
void set_iaq_sensor(sensor::Sensor *sensor) { this->iaq_sensor_ = sensor; }
|
||||
void set_iaq_accuracy_text_sensor(text_sensor::TextSensor *sensor) { this->iaq_accuracy_text_sensor_ = sensor; }
|
||||
void set_iaq_accuracy_sensor(sensor::Sensor *sensor) { this->iaq_accuracy_sensor_ = sensor; }
|
||||
void set_co2_equivalent_sensor(sensor::Sensor *sensor) { this->co2_equivalent_sensor_ = sensor; }
|
||||
void set_breath_voc_equivalent_sensor(sensor::Sensor *sensor) { this->breath_voc_equivalent_sensor_ = sensor; }
|
||||
|
||||
static BME680BSECComponent *instance;
|
||||
static int8_t read_bytes_wrapper(uint8_t address, uint8_t a_register, uint8_t *data, uint16_t len);
|
||||
@ -64,10 +61,11 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice {
|
||||
|
||||
protected:
|
||||
void set_config_(const uint8_t *config);
|
||||
void update_subscription_(float sample_rate);
|
||||
float calc_sensor_sample_rate_(SampleRate sample_rate);
|
||||
void update_subscription_();
|
||||
|
||||
void run_();
|
||||
void read_(bsec_bme_settings_t bme680_settings);
|
||||
void read_(int64_t trigger_time_ns, bsec_bme_settings_t bme680_settings);
|
||||
void publish_(const bsec_output_t *outputs, uint8_t num_outputs);
|
||||
int64_t get_time_ns_();
|
||||
|
||||
@ -91,7 +89,11 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice {
|
||||
|
||||
float temperature_offset_{0};
|
||||
IAQMode iaq_mode_{IAQ_MODE_STATIC};
|
||||
SampleRate sample_rate_{SAMPLE_RATE_LP};
|
||||
|
||||
SampleRate sample_rate_{SAMPLE_RATE_LP}; // Core/gas sample rate
|
||||
SampleRate temperature_sample_rate_{SAMPLE_RATE_DEFAULT};
|
||||
SampleRate pressure_sample_rate_{SAMPLE_RATE_DEFAULT};
|
||||
SampleRate humidity_sample_rate_{SAMPLE_RATE_DEFAULT};
|
||||
|
||||
sensor::Sensor *temperature_sensor_;
|
||||
sensor::Sensor *pressure_sensor_;
|
||||
|
@ -10,6 +10,7 @@ from esphome.const import (
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_EMPTY,
|
||||
UNIT_HECTOPASCAL,
|
||||
@ -21,8 +22,12 @@ from esphome.const import (
|
||||
ICON_THERMOMETER,
|
||||
ICON_WATER_PERCENT,
|
||||
)
|
||||
from esphome.core import coroutine
|
||||
from . import BME680BSECComponent, CONF_BME680_BSEC_ID
|
||||
from . import (
|
||||
BME680BSECComponent,
|
||||
CONF_BME680_BSEC_ID,
|
||||
CONF_SAMPLE_RATE,
|
||||
SAMPLE_RATE_OPTIONS,
|
||||
)
|
||||
|
||||
DEPENDENCIES = ["bme680_bsec"]
|
||||
|
||||
@ -34,58 +39,84 @@ UNIT_IAQ = "IAQ"
|
||||
ICON_ACCURACY = "mdi:checkbox-marked-circle-outline"
|
||||
ICON_TEST_TUBE = "mdi:test-tube"
|
||||
|
||||
TYPES = {
|
||||
CONF_TEMPERATURE: "set_temperature_sensor",
|
||||
CONF_PRESSURE: "set_pressure_sensor",
|
||||
CONF_HUMIDITY: "set_humidity_sensor",
|
||||
CONF_GAS_RESISTANCE: "set_gas_resistance_sensor",
|
||||
CONF_IAQ: "set_iaq_sensor",
|
||||
CONF_IAQ_ACCURACY: "set_iaq_accuracy_sensor",
|
||||
CONF_CO2_EQUIVALENT: "set_co2_equivalent_sensor",
|
||||
CONF_BREATH_VOC_EQUIVALENT: "set_breath_voc_equivalent_sensor",
|
||||
}
|
||||
TYPES = [
|
||||
CONF_TEMPERATURE,
|
||||
CONF_PRESSURE,
|
||||
CONF_HUMIDITY,
|
||||
CONF_GAS_RESISTANCE,
|
||||
CONF_IAQ,
|
||||
CONF_IAQ_ACCURACY,
|
||||
CONF_CO2_EQUIVALENT,
|
||||
CONF_BREATH_VOC_EQUIVALENT,
|
||||
]
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_BME680_BSEC_ID): cv.use_id(BME680BSECComponent),
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
UNIT_CELSIUS, ICON_THERMOMETER, 1, DEVICE_CLASS_TEMPERATURE
|
||||
UNIT_CELSIUS,
|
||||
ICON_THERMOMETER,
|
||||
1,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)}
|
||||
),
|
||||
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
|
||||
UNIT_HECTOPASCAL, ICON_GAUGE, 1, DEVICE_CLASS_PRESSURE
|
||||
UNIT_HECTOPASCAL,
|
||||
ICON_GAUGE,
|
||||
1,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)}
|
||||
),
|
||||
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
|
||||
UNIT_PERCENT, ICON_WATER_PERCENT, 1, DEVICE_CLASS_HUMIDITY
|
||||
UNIT_PERCENT,
|
||||
ICON_WATER_PERCENT,
|
||||
1,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)}
|
||||
),
|
||||
cv.Optional(CONF_GAS_RESISTANCE): sensor.sensor_schema(
|
||||
UNIT_OHM, ICON_GAS_CYLINDER, 0, DEVICE_CLASS_EMPTY
|
||||
UNIT_OHM, ICON_GAS_CYLINDER, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT
|
||||
),
|
||||
cv.Optional(CONF_IAQ): sensor.sensor_schema(
|
||||
UNIT_IAQ, ICON_GAUGE, 0, DEVICE_CLASS_EMPTY
|
||||
UNIT_IAQ, ICON_GAUGE, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT
|
||||
),
|
||||
cv.Optional(CONF_IAQ_ACCURACY): sensor.sensor_schema(
|
||||
UNIT_EMPTY, ICON_ACCURACY, 0, DEVICE_CLASS_EMPTY
|
||||
UNIT_EMPTY, ICON_ACCURACY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT
|
||||
),
|
||||
cv.Optional(CONF_CO2_EQUIVALENT): sensor.sensor_schema(
|
||||
UNIT_PARTS_PER_MILLION, ICON_TEST_TUBE, 1, DEVICE_CLASS_EMPTY
|
||||
UNIT_PARTS_PER_MILLION,
|
||||
ICON_TEST_TUBE,
|
||||
1,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_BREATH_VOC_EQUIVALENT): sensor.sensor_schema(
|
||||
UNIT_PARTS_PER_MILLION, ICON_TEST_TUBE, 1, DEVICE_CLASS_EMPTY
|
||||
UNIT_PARTS_PER_MILLION,
|
||||
ICON_TEST_TUBE,
|
||||
1,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@coroutine
|
||||
def setup_conf(config, key, hub, funcName):
|
||||
async def setup_conf(config, key, hub):
|
||||
if key in config:
|
||||
conf = config[key]
|
||||
var = yield sensor.new_sensor(conf)
|
||||
func = getattr(hub, funcName)
|
||||
cg.add(func(var))
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(getattr(hub, f"set_{key}_sensor")(sens))
|
||||
if CONF_SAMPLE_RATE in conf:
|
||||
cg.add(getattr(hub, f"set_{key}_sample_rate")(conf[CONF_SAMPLE_RATE]))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = yield cg.get_variable(config[CONF_BME680_BSEC_ID])
|
||||
for key, funcName in TYPES.items():
|
||||
yield setup_conf(config, key, hub, funcName)
|
||||
async def to_code(config):
|
||||
hub = await cg.get_variable(config[CONF_BME680_BSEC_ID])
|
||||
for key in TYPES:
|
||||
await setup_conf(config, key, hub)
|
||||
|
@ -2,7 +2,6 @@ import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import text_sensor
|
||||
from esphome.const import CONF_ID, CONF_ICON
|
||||
from esphome.core import coroutine
|
||||
from . import BME680BSECComponent, CONF_BME680_BSEC_ID
|
||||
|
||||
DEPENDENCIES = ["bme680_bsec"]
|
||||
@ -10,7 +9,7 @@ DEPENDENCIES = ["bme680_bsec"]
|
||||
CONF_IAQ_ACCURACY = "iaq_accuracy"
|
||||
ICON_ACCURACY = "mdi:checkbox-marked-circle-outline"
|
||||
|
||||
TYPES = {CONF_IAQ_ACCURACY: "set_iaq_accuracy_text_sensor"}
|
||||
TYPES = [CONF_IAQ_ACCURACY]
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
@ -25,17 +24,15 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
)
|
||||
|
||||
|
||||
@coroutine
|
||||
def setup_conf(config, key, hub, funcName):
|
||||
async def setup_conf(config, key, hub):
|
||||
if key in config:
|
||||
conf = config[key]
|
||||
var = cg.new_Pvariable(conf[CONF_ID])
|
||||
yield text_sensor.register_text_sensor(var, conf)
|
||||
func = getattr(hub, funcName)
|
||||
cg.add(func(var))
|
||||
sens = cg.new_Pvariable(conf[CONF_ID])
|
||||
await text_sensor.register_text_sensor(sens, conf)
|
||||
cg.add(getattr(hub, f"set_{key}_text_sensor")(sens))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = yield cg.get_variable(config[CONF_BME680_BSEC_ID])
|
||||
for key, funcName in TYPES.items():
|
||||
yield setup_conf(config, key, hub, funcName)
|
||||
async def to_code(config):
|
||||
hub = await cg.get_variable(config[CONF_BME680_BSEC_ID])
|
||||
for key in TYPES:
|
||||
await setup_conf(config, key, hub)
|
||||
|
@ -7,6 +7,7 @@ from esphome.const import (
|
||||
CONF_TEMPERATURE,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
ICON_EMPTY,
|
||||
UNIT_HECTOPASCAL,
|
||||
@ -24,10 +25,18 @@ CONFIG_SCHEMA = (
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(BMP085Component),
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
|
||||
UNIT_CELSIUS,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
|
||||
UNIT_HECTOPASCAL, ICON_EMPTY, 1, DEVICE_CLASS_PRESSURE
|
||||
UNIT_HECTOPASCAL,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
}
|
||||
)
|
||||
@ -36,17 +45,17 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
if CONF_TEMPERATURE in config:
|
||||
conf = config[CONF_TEMPERATURE]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_temperature(sens))
|
||||
|
||||
if CONF_PRESSURE in config:
|
||||
conf = config[CONF_PRESSURE]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_pressure(sens))
|
||||
|
@ -7,6 +7,7 @@ from esphome.const import (
|
||||
CONF_TEMPERATURE,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
ICON_EMPTY,
|
||||
UNIT_HECTOPASCAL,
|
||||
@ -45,7 +46,11 @@ CONFIG_SCHEMA = (
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(BMP280Component),
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
|
||||
UNIT_CELSIUS,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
|
||||
@ -54,7 +59,11 @@ CONFIG_SCHEMA = (
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
|
||||
UNIT_HECTOPASCAL, ICON_EMPTY, 1, DEVICE_CLASS_PRESSURE
|
||||
UNIT_HECTOPASCAL,
|
||||
ICON_EMPTY,
|
||||
1,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
|
||||
@ -72,19 +81,19 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
if CONF_TEMPERATURE in config:
|
||||
conf = config[CONF_TEMPERATURE]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_temperature_sensor(sens))
|
||||
cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING]))
|
||||
|
||||
if CONF_PRESSURE in config:
|
||||
conf = config[CONF_PRESSURE]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_pressure_sensor(sens))
|
||||
cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING]))
|
||||
|
@ -1,7 +1,7 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import automation
|
||||
from esphome.core import CORE, coroutine
|
||||
from esphome.core import CORE
|
||||
from esphome.const import CONF_ID, CONF_TRIGGER_ID, CONF_DATA
|
||||
|
||||
CODEOWNERS = ["@mvturnho", "@danielschramm"]
|
||||
@ -82,10 +82,9 @@ CANBUS_SCHEMA = cv.Schema(
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
@coroutine
|
||||
def setup_canbus_core_(var, config):
|
||||
async def setup_canbus_core_(var, config):
|
||||
validate_id(config[CONF_CAN_ID], config[CONF_USE_EXTENDED_ID])
|
||||
yield cg.register_component(var, config)
|
||||
await cg.register_component(var, config)
|
||||
cg.add(var.set_can_id([config[CONF_CAN_ID]]))
|
||||
cg.add(var.set_use_extended_id([config[CONF_USE_EXTENDED_ID]]))
|
||||
cg.add(var.set_bitrate(CAN_SPEEDS[config[CONF_BIT_RATE]]))
|
||||
@ -95,17 +94,16 @@ def setup_canbus_core_(var, config):
|
||||
ext_id = conf[CONF_USE_EXTENDED_ID]
|
||||
validate_id(can_id, ext_id)
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, can_id, ext_id)
|
||||
yield cg.register_component(trigger, conf)
|
||||
yield automation.build_automation(
|
||||
await cg.register_component(trigger, conf)
|
||||
await automation.build_automation(
|
||||
trigger, [(cg.std_vector.template(cg.uint8), "x")], conf
|
||||
)
|
||||
|
||||
|
||||
@coroutine
|
||||
def register_canbus(var, config):
|
||||
async def register_canbus(var, config):
|
||||
if not CORE.has_id(config[CONF_ID]):
|
||||
var = cg.new_Pvariable(config[CONF_ID], var)
|
||||
yield setup_canbus_core_(var, config)
|
||||
await setup_canbus_core_(var, config)
|
||||
|
||||
|
||||
# Actions
|
||||
@ -122,16 +120,16 @@ def register_canbus(var, config):
|
||||
key=CONF_DATA,
|
||||
),
|
||||
)
|
||||
def canbus_action_to_code(config, action_id, template_arg, args):
|
||||
async def canbus_action_to_code(config, action_id, template_arg, args):
|
||||
validate_id(config[CONF_CAN_ID], config[CONF_USE_EXTENDED_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_CANBUS_ID])
|
||||
await cg.register_parented(var, config[CONF_CANBUS_ID])
|
||||
|
||||
if CONF_CAN_ID in config:
|
||||
can_id = yield cg.templatable(config[CONF_CAN_ID], args, cg.uint32)
|
||||
can_id = await cg.templatable(config[CONF_CAN_ID], args, cg.uint32)
|
||||
cg.add(var.set_can_id(can_id))
|
||||
|
||||
use_extended_id = yield cg.templatable(
|
||||
use_extended_id = await cg.templatable(
|
||||
config[CONF_USE_EXTENDED_ID], args, cg.uint32
|
||||
)
|
||||
cg.add(var.set_use_extended_id(use_extended_id))
|
||||
@ -140,8 +138,8 @@ def canbus_action_to_code(config, action_id, template_arg, args):
|
||||
if isinstance(data, bytes):
|
||||
data = [int(x) for x in data]
|
||||
if cg.is_template(data):
|
||||
templ = yield cg.templatable(data, args, cg.std_vector.template(cg.uint8))
|
||||
templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8))
|
||||
cg.add(var.set_data_template(templ))
|
||||
else:
|
||||
cg.add(var.set_data_static(data))
|
||||
yield var
|
||||
return var
|
||||
|
@ -23,9 +23,9 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
|
||||
|
||||
@coroutine_with_priority(64.0)
|
||||
def to_code(config):
|
||||
paren = yield cg.get_variable(config[CONF_WEB_SERVER_BASE_ID])
|
||||
async def to_code(config):
|
||||
paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID])
|
||||
|
||||
var = cg.new_Pvariable(config[CONF_ID], paren)
|
||||
yield cg.register_component(var, config)
|
||||
await cg.register_component(var, config)
|
||||
cg.add_define("USE_CAPTIVE_PORTAL")
|
||||
|
@ -64,32 +64,11 @@ void CaptivePortal::handle_wifisave(AsyncWebServerRequest *request) {
|
||||
ESP_LOGI(TAG, "Captive Portal Requested WiFi Settings Change:");
|
||||
ESP_LOGI(TAG, " SSID='%s'", ssid.c_str());
|
||||
ESP_LOGI(TAG, " Password=" LOG_SECRET("'%s'"), psk.c_str());
|
||||
this->override_sta_(ssid, psk);
|
||||
wifi::global_wifi_component->save_wifi_sta(ssid, psk);
|
||||
request->redirect("/?save=true");
|
||||
}
|
||||
void CaptivePortal::override_sta_(const std::string &ssid, const std::string &password) {
|
||||
CaptivePortalSettings save{};
|
||||
strcpy(save.ssid, ssid.c_str());
|
||||
strcpy(save.password, password.c_str());
|
||||
this->pref_.save(&save);
|
||||
|
||||
wifi::WiFiAP sta{};
|
||||
sta.set_ssid(ssid);
|
||||
sta.set_password(password);
|
||||
wifi::global_wifi_component->set_sta(sta);
|
||||
}
|
||||
|
||||
void CaptivePortal::setup() {
|
||||
// Hash with compilation time
|
||||
// This ensures the AP override is not applied for OTA
|
||||
uint32_t hash = fnv1_hash(App.get_compilation_time());
|
||||
this->pref_ = global_preferences.make_preference<CaptivePortalSettings>(hash, true);
|
||||
|
||||
CaptivePortalSettings save{};
|
||||
if (this->pref_.load(&save)) {
|
||||
this->override_sta_(save.ssid, save.password);
|
||||
}
|
||||
}
|
||||
void CaptivePortal::setup() {}
|
||||
void CaptivePortal::start() {
|
||||
this->base_->init();
|
||||
if (!this->initialized_) {
|
||||
|
@ -10,11 +10,6 @@ namespace esphome {
|
||||
|
||||
namespace captive_portal {
|
||||
|
||||
struct CaptivePortalSettings {
|
||||
char ssid[33];
|
||||
char password[65];
|
||||
} PACKED; // NOLINT
|
||||
|
||||
class CaptivePortal : public AsyncWebHandler, public Component {
|
||||
public:
|
||||
CaptivePortal(web_server_base::WebServerBase *base);
|
||||
@ -67,12 +62,9 @@ class CaptivePortal : public AsyncWebHandler, public Component {
|
||||
void handleRequest(AsyncWebServerRequest *req) override;
|
||||
|
||||
protected:
|
||||
void override_sta_(const std::string &ssid, const std::string &password);
|
||||
|
||||
web_server_base::WebServerBase *base_;
|
||||
bool initialized_{false};
|
||||
bool active_{false};
|
||||
ESPPreferenceObject pref_;
|
||||
DNSServer *dns_server_{nullptr};
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,7 @@ from esphome.const import (
|
||||
CONF_ID,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
ICON_RADIATOR,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_PARTS_PER_MILLION,
|
||||
UNIT_PARTS_PER_BILLION,
|
||||
CONF_TEMPERATURE,
|
||||
@ -28,10 +29,18 @@ CONFIG_SCHEMA = (
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(CCS811Component),
|
||||
cv.Required(CONF_ECO2): sensor.sensor_schema(
|
||||
UNIT_PARTS_PER_MILLION, ICON_MOLECULE_CO2, 0, DEVICE_CLASS_EMPTY
|
||||
UNIT_PARTS_PER_MILLION,
|
||||
ICON_MOLECULE_CO2,
|
||||
0,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Required(CONF_TVOC): sensor.sensor_schema(
|
||||
UNIT_PARTS_PER_BILLION, ICON_RADIATOR, 0, DEVICE_CLASS_EMPTY
|
||||
UNIT_PARTS_PER_BILLION,
|
||||
ICON_RADIATOR,
|
||||
0,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_BASELINE): cv.hex_uint16_t,
|
||||
cv.Optional(CONF_TEMPERATURE): cv.use_id(sensor.Sensor),
|
||||
@ -43,22 +52,22 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
sens = yield sensor.new_sensor(config[CONF_ECO2])
|
||||
sens = await sensor.new_sensor(config[CONF_ECO2])
|
||||
cg.add(var.set_co2(sens))
|
||||
sens = yield sensor.new_sensor(config[CONF_TVOC])
|
||||
sens = await sensor.new_sensor(config[CONF_TVOC])
|
||||
cg.add(var.set_tvoc(sens))
|
||||
|
||||
if CONF_BASELINE in config:
|
||||
cg.add(var.set_baseline(config[CONF_BASELINE]))
|
||||
|
||||
if CONF_TEMPERATURE in config:
|
||||
sens = yield cg.get_variable(config[CONF_TEMPERATURE])
|
||||
sens = await cg.get_variable(config[CONF_TEMPERATURE])
|
||||
cg.add(var.set_temperature(sens))
|
||||
if CONF_HUMIDITY in config:
|
||||
sens = yield cg.get_variable(config[CONF_HUMIDITY])
|
||||
sens = await cg.get_variable(config[CONF_HUMIDITY])
|
||||
cg.add(var.set_humidity(sens))
|
||||
|
@ -4,11 +4,14 @@ from esphome import automation
|
||||
from esphome.components import mqtt
|
||||
from esphome.const import (
|
||||
CONF_AWAY,
|
||||
CONF_CUSTOM_FAN_MODE,
|
||||
CONF_CUSTOM_PRESET,
|
||||
CONF_ID,
|
||||
CONF_INTERNAL,
|
||||
CONF_MAX_TEMPERATURE,
|
||||
CONF_MIN_TEMPERATURE,
|
||||
CONF_MODE,
|
||||
CONF_PRESET,
|
||||
CONF_TARGET_TEMPERATURE,
|
||||
CONF_TARGET_TEMPERATURE_HIGH,
|
||||
CONF_TARGET_TEMPERATURE_LOW,
|
||||
@ -19,7 +22,7 @@ from esphome.const import (
|
||||
CONF_FAN_MODE,
|
||||
CONF_SWING_MODE,
|
||||
)
|
||||
from esphome.core import CORE, coroutine, coroutine_with_priority
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
|
||||
@ -33,11 +36,12 @@ ClimateTraits = climate_ns.class_("ClimateTraits")
|
||||
ClimateMode = climate_ns.enum("ClimateMode")
|
||||
CLIMATE_MODES = {
|
||||
"OFF": ClimateMode.CLIMATE_MODE_OFF,
|
||||
"AUTO": ClimateMode.CLIMATE_MODE_AUTO,
|
||||
"HEAT_COOL": ClimateMode.CLIMATE_HEAT_COOL,
|
||||
"COOL": ClimateMode.CLIMATE_MODE_COOL,
|
||||
"HEAT": ClimateMode.CLIMATE_MODE_HEAT,
|
||||
"DRY": ClimateMode.CLIMATE_MODE_DRY,
|
||||
"FAN_ONLY": ClimateMode.CLIMATE_MODE_FAN_ONLY,
|
||||
"AUTO": ClimateMode.CLIMATE_MODE_AUTO,
|
||||
}
|
||||
validate_climate_mode = cv.enum(CLIMATE_MODES, upper=True)
|
||||
|
||||
@ -56,6 +60,19 @@ CLIMATE_FAN_MODES = {
|
||||
|
||||
validate_climate_fan_mode = cv.enum(CLIMATE_FAN_MODES, upper=True)
|
||||
|
||||
ClimatePreset = climate_ns.enum("ClimatePreset")
|
||||
CLIMATE_PRESETS = {
|
||||
"ECO": ClimatePreset.CLIMATE_PRESET_ECO,
|
||||
"AWAY": ClimatePreset.CLIMATE_PRESET_AWAY,
|
||||
"BOOST": ClimatePreset.CLIMATE_PRESET_BOOST,
|
||||
"COMFORT": ClimatePreset.CLIMATE_PRESET_COMFORT,
|
||||
"HOME": ClimatePreset.CLIMATE_PRESET_HOME,
|
||||
"SLEEP": ClimatePreset.CLIMATE_PRESET_SLEEP,
|
||||
"ACTIVITY": ClimatePreset.CLIMATE_PRESET_ACTIVITY,
|
||||
}
|
||||
|
||||
validate_climate_preset = cv.enum(CLIMATE_PRESETS, upper=True)
|
||||
|
||||
ClimateSwingMode = climate_ns.enum("ClimateSwingMode")
|
||||
CLIMATE_SWING_MODES = {
|
||||
"OFF": ClimateSwingMode.CLIMATE_SWING_OFF,
|
||||
@ -85,8 +102,7 @@ CLIMATE_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
@coroutine
|
||||
def setup_climate_core_(var, config):
|
||||
async def setup_climate_core_(var, config):
|
||||
cg.add(var.set_name(config[CONF_NAME]))
|
||||
if CONF_INTERNAL in config:
|
||||
cg.add(var.set_internal(config[CONF_INTERNAL]))
|
||||
@ -100,15 +116,14 @@ def setup_climate_core_(var, config):
|
||||
|
||||
if CONF_MQTT_ID in config:
|
||||
mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var)
|
||||
yield mqtt.register_mqtt_component(mqtt_, config)
|
||||
await mqtt.register_mqtt_component(mqtt_, config)
|
||||
|
||||
|
||||
@coroutine
|
||||
def register_climate(var, config):
|
||||
async def register_climate(var, config):
|
||||
if not CORE.has_id(config[CONF_ID]):
|
||||
var = cg.Pvariable(config[CONF_ID], var)
|
||||
cg.add(cg.App.register_climate(var))
|
||||
yield setup_climate_core_(var, config)
|
||||
await setup_climate_core_(var, config)
|
||||
|
||||
|
||||
CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema(
|
||||
@ -119,7 +134,12 @@ CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_TARGET_TEMPERATURE_LOW): cv.templatable(cv.temperature),
|
||||
cv.Optional(CONF_TARGET_TEMPERATURE_HIGH): cv.templatable(cv.temperature),
|
||||
cv.Optional(CONF_AWAY): cv.templatable(cv.boolean),
|
||||
cv.Optional(CONF_FAN_MODE): cv.templatable(validate_climate_fan_mode),
|
||||
cv.Exclusive(CONF_FAN_MODE, "fan_mode"): cv.templatable(
|
||||
validate_climate_fan_mode
|
||||
),
|
||||
cv.Exclusive(CONF_CUSTOM_FAN_MODE, "fan_mode"): cv.string_strict,
|
||||
cv.Exclusive(CONF_PRESET, "preset"): cv.templatable(validate_climate_preset),
|
||||
cv.Exclusive(CONF_CUSTOM_PRESET, "preset"): cv.string_strict,
|
||||
cv.Optional(CONF_SWING_MODE): cv.templatable(validate_climate_swing_mode),
|
||||
}
|
||||
)
|
||||
@ -128,40 +148,49 @@ CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema(
|
||||
@automation.register_action(
|
||||
"climate.control", ControlAction, CLIMATE_CONTROL_ACTION_SCHEMA
|
||||
)
|
||||
def climate_control_to_code(config, action_id, template_arg, args):
|
||||
paren = yield cg.get_variable(config[CONF_ID])
|
||||
async def climate_control_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
if CONF_MODE in config:
|
||||
template_ = yield cg.templatable(config[CONF_MODE], args, ClimateMode)
|
||||
template_ = await cg.templatable(config[CONF_MODE], args, ClimateMode)
|
||||
cg.add(var.set_mode(template_))
|
||||
if CONF_TARGET_TEMPERATURE in config:
|
||||
template_ = yield cg.templatable(config[CONF_TARGET_TEMPERATURE], args, float)
|
||||
template_ = await cg.templatable(config[CONF_TARGET_TEMPERATURE], args, float)
|
||||
cg.add(var.set_target_temperature(template_))
|
||||
if CONF_TARGET_TEMPERATURE_LOW in config:
|
||||
template_ = yield cg.templatable(
|
||||
template_ = await cg.templatable(
|
||||
config[CONF_TARGET_TEMPERATURE_LOW], args, float
|
||||
)
|
||||
cg.add(var.set_target_temperature_low(template_))
|
||||
if CONF_TARGET_TEMPERATURE_HIGH in config:
|
||||
template_ = yield cg.templatable(
|
||||
template_ = await cg.templatable(
|
||||
config[CONF_TARGET_TEMPERATURE_HIGH], args, float
|
||||
)
|
||||
cg.add(var.set_target_temperature_high(template_))
|
||||
if CONF_AWAY in config:
|
||||
template_ = yield cg.templatable(config[CONF_AWAY], args, bool)
|
||||
template_ = await cg.templatable(config[CONF_AWAY], args, bool)
|
||||
cg.add(var.set_away(template_))
|
||||
if CONF_FAN_MODE in config:
|
||||
template_ = yield cg.templatable(config[CONF_FAN_MODE], args, ClimateFanMode)
|
||||
template_ = await cg.templatable(config[CONF_FAN_MODE], args, ClimateFanMode)
|
||||
cg.add(var.set_fan_mode(template_))
|
||||
if CONF_CUSTOM_FAN_MODE in config:
|
||||
template_ = await cg.templatable(config[CONF_CUSTOM_FAN_MODE], args, str)
|
||||
cg.add(var.set_custom_fan_mode(template_))
|
||||
if CONF_PRESET in config:
|
||||
template_ = await cg.templatable(config[CONF_PRESET], args, ClimatePreset)
|
||||
cg.add(var.set_preset(template_))
|
||||
if CONF_CUSTOM_PRESET in config:
|
||||
template_ = await cg.templatable(config[CONF_CUSTOM_PRESET], args, str)
|
||||
cg.add(var.set_custom_preset(template_))
|
||||
if CONF_SWING_MODE in config:
|
||||
template_ = yield cg.templatable(
|
||||
template_ = await cg.templatable(
|
||||
config[CONF_SWING_MODE], args, ClimateSwingMode
|
||||
)
|
||||
cg.add(var.set_swing_mode(template_))
|
||||
yield var
|
||||
return var
|
||||
|
||||
|
||||
@coroutine_with_priority(100.0)
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
cg.add_define("USE_CLIMATE")
|
||||
cg.add_global(climate_ns.using)
|
||||
|
@ -16,6 +16,9 @@ template<typename... Ts> class ControlAction : public Action<Ts...> {
|
||||
TEMPLATABLE_VALUE(float, target_temperature_high)
|
||||
TEMPLATABLE_VALUE(bool, away)
|
||||
TEMPLATABLE_VALUE(ClimateFanMode, fan_mode)
|
||||
TEMPLATABLE_VALUE(std::string, custom_fan_mode)
|
||||
TEMPLATABLE_VALUE(ClimatePreset, preset)
|
||||
TEMPLATABLE_VALUE(std::string, custom_preset)
|
||||
TEMPLATABLE_VALUE(ClimateSwingMode, swing_mode)
|
||||
|
||||
void play(Ts... x) override {
|
||||
@ -26,6 +29,9 @@ template<typename... Ts> class ControlAction : public Action<Ts...> {
|
||||
call.set_target_temperature_high(this->target_temperature_high_.optional_value(x...));
|
||||
call.set_away(this->away_.optional_value(x...));
|
||||
call.set_fan_mode(this->fan_mode_.optional_value(x...));
|
||||
call.set_fan_mode(this->custom_fan_mode_.optional_value(x...));
|
||||
call.set_preset(this->preset_.optional_value(x...));
|
||||
call.set_preset(this->custom_preset_.optional_value(x...));
|
||||
call.set_swing_mode(this->swing_mode_.optional_value(x...));
|
||||
call.perform();
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "climate.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace climate {
|
||||
@ -13,10 +12,24 @@ void ClimateCall::perform() {
|
||||
const char *mode_s = climate_mode_to_string(*this->mode_);
|
||||
ESP_LOGD(TAG, " Mode: %s", mode_s);
|
||||
}
|
||||
if (this->custom_fan_mode_.has_value()) {
|
||||
this->fan_mode_.reset();
|
||||
ESP_LOGD(TAG, " Custom Fan: %s", this->custom_fan_mode_.value().c_str());
|
||||
}
|
||||
if (this->fan_mode_.has_value()) {
|
||||
this->custom_fan_mode_.reset();
|
||||
const char *fan_mode_s = climate_fan_mode_to_string(*this->fan_mode_);
|
||||
ESP_LOGD(TAG, " Fan: %s", fan_mode_s);
|
||||
}
|
||||
if (this->custom_preset_.has_value()) {
|
||||
this->preset_.reset();
|
||||
ESP_LOGD(TAG, " Custom Preset: %s", this->custom_preset_.value().c_str());
|
||||
}
|
||||
if (this->preset_.has_value()) {
|
||||
this->custom_preset_.reset();
|
||||
const char *preset_s = climate_preset_to_string(*this->preset_);
|
||||
ESP_LOGD(TAG, " Preset: %s", preset_s);
|
||||
}
|
||||
if (this->swing_mode_.has_value()) {
|
||||
const char *swing_mode_s = climate_swing_mode_to_string(*this->swing_mode_);
|
||||
ESP_LOGD(TAG, " Swing: %s", swing_mode_s);
|
||||
@ -44,13 +57,32 @@ void ClimateCall::validate_() {
|
||||
this->mode_.reset();
|
||||
}
|
||||
}
|
||||
if (this->fan_mode_.has_value()) {
|
||||
if (this->custom_fan_mode_.has_value()) {
|
||||
auto custom_fan_mode = *this->custom_fan_mode_;
|
||||
if (!traits.supports_custom_fan_mode(custom_fan_mode)) {
|
||||
ESP_LOGW(TAG, " Fan Mode %s is not supported by this device!", custom_fan_mode.c_str());
|
||||
this->custom_fan_mode_.reset();
|
||||
}
|
||||
} else if (this->fan_mode_.has_value()) {
|
||||
auto fan_mode = *this->fan_mode_;
|
||||
if (!traits.supports_fan_mode(fan_mode)) {
|
||||
ESP_LOGW(TAG, " Fan Mode %s is not supported by this device!", climate_fan_mode_to_string(fan_mode));
|
||||
this->fan_mode_.reset();
|
||||
}
|
||||
}
|
||||
if (this->custom_preset_.has_value()) {
|
||||
auto custom_preset = *this->custom_preset_;
|
||||
if (!traits.supports_custom_preset(custom_preset)) {
|
||||
ESP_LOGW(TAG, " Preset %s is not supported by this device!", custom_preset.c_str());
|
||||
this->custom_preset_.reset();
|
||||
}
|
||||
} else if (this->preset_.has_value()) {
|
||||
auto preset = *this->preset_;
|
||||
if (!traits.supports_preset(preset)) {
|
||||
ESP_LOGW(TAG, " Preset %s is not supported by this device!", climate_preset_to_string(preset));
|
||||
this->preset_.reset();
|
||||
}
|
||||
}
|
||||
if (this->swing_mode_.has_value()) {
|
||||
auto swing_mode = *this->swing_mode_;
|
||||
if (!traits.supports_swing_mode(swing_mode)) {
|
||||
@ -117,6 +149,8 @@ ClimateCall &ClimateCall::set_mode(const std::string &mode) {
|
||||
this->set_mode(CLIMATE_MODE_FAN_ONLY);
|
||||
} else if (str_equals_case_insensitive(mode, "DRY")) {
|
||||
this->set_mode(CLIMATE_MODE_DRY);
|
||||
} else if (str_equals_case_insensitive(mode, "HEAT_COOL")) {
|
||||
this->set_mode(CLIMATE_MODE_HEAT_COOL);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized mode %s", this->parent_->get_name().c_str(), mode.c_str());
|
||||
}
|
||||
@ -124,6 +158,7 @@ ClimateCall &ClimateCall::set_mode(const std::string &mode) {
|
||||
}
|
||||
ClimateCall &ClimateCall::set_fan_mode(ClimateFanMode fan_mode) {
|
||||
this->fan_mode_ = fan_mode;
|
||||
this->custom_fan_mode_.reset();
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_fan_mode(const std::string &fan_mode) {
|
||||
@ -145,12 +180,60 @@ ClimateCall &ClimateCall::set_fan_mode(const std::string &fan_mode) {
|
||||
this->set_fan_mode(CLIMATE_FAN_FOCUS);
|
||||
} else if (str_equals_case_insensitive(fan_mode, "DIFFUSE")) {
|
||||
this->set_fan_mode(CLIMATE_FAN_DIFFUSE);
|
||||
} else {
|
||||
auto custom_fan_modes = this->parent_->get_traits().get_supported_custom_fan_modes();
|
||||
if (std::find(custom_fan_modes.begin(), custom_fan_modes.end(), fan_mode) != custom_fan_modes.end()) {
|
||||
this->custom_fan_mode_ = fan_mode;
|
||||
this->fan_mode_.reset();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized fan mode %s", this->parent_->get_name().c_str(), fan_mode.c_str());
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_fan_mode(optional<std::string> fan_mode) {
|
||||
if (fan_mode.has_value()) {
|
||||
this->set_fan_mode(fan_mode.value());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_preset(ClimatePreset preset) {
|
||||
this->preset_ = preset;
|
||||
this->custom_preset_.reset();
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_preset(const std::string &preset) {
|
||||
if (str_equals_case_insensitive(preset, "ECO")) {
|
||||
this->set_preset(CLIMATE_PRESET_ECO);
|
||||
} else if (str_equals_case_insensitive(preset, "AWAY")) {
|
||||
this->set_preset(CLIMATE_PRESET_AWAY);
|
||||
} else if (str_equals_case_insensitive(preset, "BOOST")) {
|
||||
this->set_preset(CLIMATE_PRESET_BOOST);
|
||||
} else if (str_equals_case_insensitive(preset, "COMFORT")) {
|
||||
this->set_preset(CLIMATE_PRESET_COMFORT);
|
||||
} else if (str_equals_case_insensitive(preset, "HOME")) {
|
||||
this->set_preset(CLIMATE_PRESET_HOME);
|
||||
} else if (str_equals_case_insensitive(preset, "SLEEP")) {
|
||||
this->set_preset(CLIMATE_PRESET_SLEEP);
|
||||
} else if (str_equals_case_insensitive(preset, "ACTIVITY")) {
|
||||
this->set_preset(CLIMATE_PRESET_ACTIVITY);
|
||||
} else {
|
||||
auto custom_presets = this->parent_->get_traits().get_supported_custom_presets();
|
||||
if (std::find(custom_presets.begin(), custom_presets.end(), preset) != custom_presets.end()) {
|
||||
this->custom_preset_ = preset;
|
||||
this->preset_.reset();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized preset %s", this->parent_->get_name().c_str(), preset.c_str());
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_preset(optional<std::string> preset) {
|
||||
if (preset.has_value()) {
|
||||
this->set_preset(preset.value());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ClimateCall &ClimateCall::set_swing_mode(ClimateSwingMode swing_mode) {
|
||||
this->swing_mode_ = swing_mode;
|
||||
return *this;
|
||||
@ -188,6 +271,9 @@ const optional<float> &ClimateCall::get_target_temperature_low() const { return
|
||||
const optional<float> &ClimateCall::get_target_temperature_high() const { return this->target_temperature_high_; }
|
||||
const optional<bool> &ClimateCall::get_away() const { return this->away_; }
|
||||
const optional<ClimateFanMode> &ClimateCall::get_fan_mode() const { return this->fan_mode_; }
|
||||
const optional<std::string> &ClimateCall::get_custom_fan_mode() const { return this->custom_fan_mode_; }
|
||||
const optional<ClimatePreset> &ClimateCall::get_preset() const { return this->preset_; }
|
||||
const optional<std::string> &ClimateCall::get_custom_preset() const { return this->custom_preset_; }
|
||||
const optional<ClimateSwingMode> &ClimateCall::get_swing_mode() const { return this->swing_mode_; }
|
||||
ClimateCall &ClimateCall::set_away(bool away) {
|
||||
this->away_ = away;
|
||||
@ -215,6 +301,12 @@ ClimateCall &ClimateCall::set_mode(optional<ClimateMode> mode) {
|
||||
}
|
||||
ClimateCall &ClimateCall::set_fan_mode(optional<ClimateFanMode> fan_mode) {
|
||||
this->fan_mode_ = fan_mode;
|
||||
this->custom_fan_mode_.reset();
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_preset(optional<ClimatePreset> preset) {
|
||||
this->preset_ = preset;
|
||||
this->custom_preset_.reset();
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_swing_mode(optional<ClimateSwingMode> swing_mode) {
|
||||
@ -249,8 +341,31 @@ void Climate::save_state_() {
|
||||
if (traits.get_supports_away()) {
|
||||
state.away = this->away;
|
||||
}
|
||||
if (traits.get_supports_fan_modes()) {
|
||||
state.fan_mode = this->fan_mode;
|
||||
if (traits.get_supports_fan_modes() && fan_mode.has_value()) {
|
||||
state.uses_custom_fan_mode = false;
|
||||
state.fan_mode = this->fan_mode.value();
|
||||
}
|
||||
if (!traits.get_supported_custom_fan_modes().empty() && custom_fan_mode.has_value()) {
|
||||
state.uses_custom_fan_mode = true;
|
||||
auto &custom_fan_modes = traits.get_supported_custom_fan_modes();
|
||||
auto it = std::find(custom_fan_modes.begin(), custom_fan_modes.end(), this->custom_fan_mode.value());
|
||||
// only set custom fan mode if value exists, otherwise leave it as is
|
||||
if (it != custom_fan_modes.cend()) {
|
||||
state.custom_fan_mode = std::distance(custom_fan_modes.begin(), it);
|
||||
}
|
||||
}
|
||||
if (traits.get_supports_presets() && preset.has_value()) {
|
||||
state.uses_custom_preset = false;
|
||||
state.preset = this->preset.value();
|
||||
}
|
||||
if (!traits.get_supported_custom_presets().empty() && custom_preset.has_value()) {
|
||||
state.uses_custom_preset = true;
|
||||
auto custom_presets = traits.get_supported_custom_presets();
|
||||
auto it = std::find(custom_presets.begin(), custom_presets.end(), this->custom_preset.value());
|
||||
// only set custom preset if value exists, otherwise leave it as is
|
||||
if (it != custom_presets.cend()) {
|
||||
state.custom_preset = std::distance(custom_presets.begin(), it);
|
||||
}
|
||||
}
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
state.swing_mode = this->swing_mode;
|
||||
@ -266,8 +381,17 @@ void Climate::publish_state() {
|
||||
if (traits.get_supports_action()) {
|
||||
ESP_LOGD(TAG, " Action: %s", climate_action_to_string(this->action));
|
||||
}
|
||||
if (traits.get_supports_fan_modes()) {
|
||||
ESP_LOGD(TAG, " Fan Mode: %s", climate_fan_mode_to_string(this->fan_mode));
|
||||
if (traits.get_supports_fan_modes() && this->fan_mode.has_value()) {
|
||||
ESP_LOGD(TAG, " Fan Mode: %s", climate_fan_mode_to_string(this->fan_mode.value()));
|
||||
}
|
||||
if (!traits.get_supported_custom_fan_modes().empty() && this->custom_fan_mode.has_value()) {
|
||||
ESP_LOGD(TAG, " Custom Fan Mode: %s", this->custom_fan_mode.value().c_str());
|
||||
}
|
||||
if (traits.get_supports_presets() && this->preset.has_value()) {
|
||||
ESP_LOGD(TAG, " Preset: %s", climate_preset_to_string(this->preset.value()));
|
||||
}
|
||||
if (!traits.get_supported_custom_presets().empty() && this->custom_preset.has_value()) {
|
||||
ESP_LOGD(TAG, " Custom Preset: %s", this->custom_preset.value().c_str());
|
||||
}
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
ESP_LOGD(TAG, " Swing Mode: %s", climate_swing_mode_to_string(this->swing_mode));
|
||||
@ -332,9 +456,12 @@ ClimateCall ClimateDeviceRestoreState::to_call(Climate *climate) {
|
||||
if (traits.get_supports_away()) {
|
||||
call.set_away(this->away);
|
||||
}
|
||||
if (traits.get_supports_fan_modes()) {
|
||||
if (traits.get_supports_fan_modes() || !traits.get_supported_custom_fan_modes().empty()) {
|
||||
call.set_fan_mode(this->fan_mode);
|
||||
}
|
||||
if (traits.get_supports_presets() || !traits.get_supported_custom_presets().empty()) {
|
||||
call.set_preset(this->preset);
|
||||
}
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
call.set_swing_mode(this->swing_mode);
|
||||
}
|
||||
@ -352,9 +479,21 @@ void ClimateDeviceRestoreState::apply(Climate *climate) {
|
||||
if (traits.get_supports_away()) {
|
||||
climate->away = this->away;
|
||||
}
|
||||
if (traits.get_supports_fan_modes()) {
|
||||
if (traits.get_supports_fan_modes() && !this->uses_custom_fan_mode) {
|
||||
climate->fan_mode = this->fan_mode;
|
||||
}
|
||||
if (!traits.get_supported_custom_fan_modes().empty() && this->uses_custom_fan_mode) {
|
||||
climate->custom_fan_mode = traits.get_supported_custom_fan_modes()[this->custom_fan_mode];
|
||||
}
|
||||
if (traits.get_supports_presets() && !this->uses_custom_preset) {
|
||||
climate->preset = this->preset;
|
||||
}
|
||||
if (!traits.get_supported_custom_presets().empty() && this->uses_custom_preset) {
|
||||
climate->custom_preset = traits.get_supported_custom_presets()[this->custom_preset];
|
||||
}
|
||||
if (!traits.get_supported_custom_presets().empty() && uses_custom_preset) {
|
||||
climate->custom_preset = traits.get_supported_custom_presets()[this->preset];
|
||||
}
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
climate->swing_mode = this->swing_mode;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "climate_mode.h"
|
||||
#include "climate_traits.h"
|
||||
|
||||
@ -70,12 +71,22 @@ class ClimateCall {
|
||||
ClimateCall &set_fan_mode(optional<ClimateFanMode> fan_mode);
|
||||
/// Set the fan mode of the climate device based on a string.
|
||||
ClimateCall &set_fan_mode(const std::string &fan_mode);
|
||||
/// Set the fan mode of the climate device based on a string.
|
||||
ClimateCall &set_fan_mode(optional<std::string> fan_mode);
|
||||
/// Set the swing mode of the climate device.
|
||||
ClimateCall &set_swing_mode(ClimateSwingMode swing_mode);
|
||||
/// Set the swing mode of the climate device.
|
||||
ClimateCall &set_swing_mode(optional<ClimateSwingMode> swing_mode);
|
||||
/// Set the swing mode of the climate device based on a string.
|
||||
ClimateCall &set_swing_mode(const std::string &swing_mode);
|
||||
/// Set the preset of the climate device.
|
||||
ClimateCall &set_preset(ClimatePreset preset);
|
||||
/// Set the preset of the climate device.
|
||||
ClimateCall &set_preset(optional<ClimatePreset> preset);
|
||||
/// Set the preset of the climate device based on a string.
|
||||
ClimateCall &set_preset(const std::string &preset);
|
||||
/// Set the preset of the climate device based on a string.
|
||||
ClimateCall &set_preset(optional<std::string> preset);
|
||||
|
||||
void perform();
|
||||
|
||||
@ -86,6 +97,9 @@ class ClimateCall {
|
||||
const optional<bool> &get_away() const;
|
||||
const optional<ClimateFanMode> &get_fan_mode() const;
|
||||
const optional<ClimateSwingMode> &get_swing_mode() const;
|
||||
const optional<std::string> &get_custom_fan_mode() const;
|
||||
const optional<ClimatePreset> &get_preset() const;
|
||||
const optional<std::string> &get_custom_preset() const;
|
||||
|
||||
protected:
|
||||
void validate_();
|
||||
@ -98,13 +112,25 @@ class ClimateCall {
|
||||
optional<bool> away_;
|
||||
optional<ClimateFanMode> fan_mode_;
|
||||
optional<ClimateSwingMode> swing_mode_;
|
||||
optional<std::string> custom_fan_mode_;
|
||||
optional<ClimatePreset> preset_;
|
||||
optional<std::string> custom_preset_;
|
||||
};
|
||||
|
||||
/// Struct used to save the state of the climate device in restore memory.
|
||||
struct ClimateDeviceRestoreState {
|
||||
ClimateMode mode;
|
||||
bool away;
|
||||
bool uses_custom_fan_mode{false};
|
||||
union {
|
||||
ClimateFanMode fan_mode;
|
||||
uint8_t custom_fan_mode;
|
||||
};
|
||||
bool uses_custom_preset{false};
|
||||
union {
|
||||
ClimatePreset preset;
|
||||
uint8_t custom_preset;
|
||||
};
|
||||
ClimateSwingMode swing_mode;
|
||||
union {
|
||||
float target_temperature;
|
||||
@ -168,11 +194,20 @@ class Climate : public Nameable {
|
||||
bool away{false};
|
||||
|
||||
/// The active fan mode of the climate device.
|
||||
ClimateFanMode fan_mode;
|
||||
optional<ClimateFanMode> fan_mode;
|
||||
|
||||
/// The active swing mode of the climate device.
|
||||
ClimateSwingMode swing_mode;
|
||||
|
||||
/// The active custom fan mode of the climate device.
|
||||
optional<std::string> custom_fan_mode;
|
||||
|
||||
/// The active preset of the climate device.
|
||||
optional<ClimatePreset> preset;
|
||||
|
||||
/// The active custom preset mode of the climate device.
|
||||
optional<std::string> custom_preset;
|
||||
|
||||
/** Add a callback for the climate device state, each time the state of the climate device is updated
|
||||
* (using publish_state), this callback will be called.
|
||||
*
|
||||
|
@ -17,6 +17,8 @@ const char *climate_mode_to_string(ClimateMode mode) {
|
||||
return "FAN_ONLY";
|
||||
case CLIMATE_MODE_DRY:
|
||||
return "DRY";
|
||||
case CLIMATE_MODE_HEAT_COOL:
|
||||
return "HEAT_COOL";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@ -80,5 +82,26 @@ const char *climate_swing_mode_to_string(ClimateSwingMode swing_mode) {
|
||||
}
|
||||
}
|
||||
|
||||
const char *climate_preset_to_string(ClimatePreset preset) {
|
||||
switch (preset) {
|
||||
case climate::CLIMATE_PRESET_ECO:
|
||||
return "ECO";
|
||||
case climate::CLIMATE_PRESET_AWAY:
|
||||
return "AWAY";
|
||||
case climate::CLIMATE_PRESET_BOOST:
|
||||
return "BOOST";
|
||||
case climate::CLIMATE_PRESET_COMFORT:
|
||||
return "COMFORT";
|
||||
case climate::CLIMATE_PRESET_HOME:
|
||||
return "HOME";
|
||||
case climate::CLIMATE_PRESET_SLEEP:
|
||||
return "SLEEP";
|
||||
case climate::CLIMATE_PRESET_ACTIVITY:
|
||||
return "ACTIVITY";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace climate
|
||||
} // namespace esphome
|
||||
|
@ -10,7 +10,7 @@ enum ClimateMode : uint8_t {
|
||||
/// The climate device is off (not in auto, heat or cool mode)
|
||||
CLIMATE_MODE_OFF = 0,
|
||||
/// The climate device is set to automatically change the heating/cooling cycle
|
||||
CLIMATE_MODE_AUTO = 1,
|
||||
CLIMATE_MODE_HEAT_COOL = 1,
|
||||
/// The climate device is manually set to cool mode (not in auto mode!)
|
||||
CLIMATE_MODE_COOL = 2,
|
||||
/// The climate device is manually set to heat mode (not in auto mode!)
|
||||
@ -19,6 +19,8 @@ enum ClimateMode : uint8_t {
|
||||
CLIMATE_MODE_FAN_ONLY = 4,
|
||||
/// The climate device is manually set to dry mode
|
||||
CLIMATE_MODE_DRY = 5,
|
||||
/// The climate device is manually set to heat-cool mode
|
||||
CLIMATE_MODE_AUTO = 6
|
||||
};
|
||||
|
||||
/// Enum for the current action of the climate device. Values match those of ClimateMode.
|
||||
@ -61,7 +63,7 @@ enum ClimateFanMode : uint8_t {
|
||||
|
||||
/// Enum for all modes a climate swing can be in
|
||||
enum ClimateSwingMode : uint8_t {
|
||||
/// The sing mode is set to Off
|
||||
/// The swing mode is set to Off
|
||||
CLIMATE_SWING_OFF = 0,
|
||||
/// The fan mode is set to Both
|
||||
CLIMATE_SWING_BOTH = 1,
|
||||
@ -71,6 +73,24 @@ enum ClimateSwingMode : uint8_t {
|
||||
CLIMATE_SWING_HORIZONTAL = 3,
|
||||
};
|
||||
|
||||
/// Enum for all modes a climate swing can be in
|
||||
enum ClimatePreset : uint8_t {
|
||||
/// Preset is set to ECO
|
||||
CLIMATE_PRESET_ECO = 0,
|
||||
/// Preset is set to AWAY
|
||||
CLIMATE_PRESET_AWAY = 1,
|
||||
/// Preset is set to BOOST
|
||||
CLIMATE_PRESET_BOOST = 2,
|
||||
/// Preset is set to COMFORT
|
||||
CLIMATE_PRESET_COMFORT = 3,
|
||||
/// Preset is set to HOME
|
||||
CLIMATE_PRESET_HOME = 4,
|
||||
/// Preset is set to SLEEP
|
||||
CLIMATE_PRESET_SLEEP = 5,
|
||||
/// Preset is set to ACTIVITY
|
||||
CLIMATE_PRESET_ACTIVITY = 6,
|
||||
};
|
||||
|
||||
/// Convert the given ClimateMode to a human-readable string.
|
||||
const char *climate_mode_to_string(ClimateMode mode);
|
||||
|
||||
@ -83,5 +103,8 @@ const char *climate_fan_mode_to_string(ClimateFanMode mode);
|
||||
/// Convert the given ClimateSwingMode to a human-readable string.
|
||||
const char *climate_swing_mode_to_string(ClimateSwingMode mode);
|
||||
|
||||
/// Convert the given ClimateSwingMode to a human-readable string.
|
||||
const char *climate_preset_to_string(ClimatePreset preset);
|
||||
|
||||
} // namespace climate
|
||||
} // namespace esphome
|
||||
|
@ -119,6 +119,71 @@ bool ClimateTraits::get_supports_fan_modes() const {
|
||||
this->supports_fan_mode_low_ || this->supports_fan_mode_medium_ || this->supports_fan_mode_high_ ||
|
||||
this->supports_fan_mode_middle_ || this->supports_fan_mode_focus_ || this->supports_fan_mode_diffuse_;
|
||||
}
|
||||
void ClimateTraits::set_supported_custom_fan_modes(std::vector<std::string> &supported_custom_fan_modes) {
|
||||
this->supported_custom_fan_modes_ = supported_custom_fan_modes;
|
||||
}
|
||||
const std::vector<std::string> ClimateTraits::get_supported_custom_fan_modes() const {
|
||||
return this->supported_custom_fan_modes_;
|
||||
}
|
||||
bool ClimateTraits::supports_custom_fan_mode(std::string &custom_fan_mode) const {
|
||||
return std::count(this->supported_custom_fan_modes_.begin(), this->supported_custom_fan_modes_.end(),
|
||||
custom_fan_mode);
|
||||
}
|
||||
bool ClimateTraits::supports_preset(ClimatePreset preset) const {
|
||||
switch (preset) {
|
||||
case climate::CLIMATE_PRESET_ECO:
|
||||
return this->supports_preset_eco_;
|
||||
case climate::CLIMATE_PRESET_AWAY:
|
||||
return this->supports_preset_away_;
|
||||
case climate::CLIMATE_PRESET_BOOST:
|
||||
return this->supports_preset_boost_;
|
||||
case climate::CLIMATE_PRESET_COMFORT:
|
||||
return this->supports_preset_comfort_;
|
||||
case climate::CLIMATE_PRESET_HOME:
|
||||
return this->supports_preset_home_;
|
||||
case climate::CLIMATE_PRESET_SLEEP:
|
||||
return this->supports_preset_sleep_;
|
||||
case climate::CLIMATE_PRESET_ACTIVITY:
|
||||
return this->supports_preset_activity_;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_eco(bool supports_preset_eco) {
|
||||
this->supports_preset_eco_ = supports_preset_eco;
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_away(bool supports_preset_away) {
|
||||
this->supports_preset_away_ = supports_preset_away;
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_boost(bool supports_preset_boost) {
|
||||
this->supports_preset_boost_ = supports_preset_boost;
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_comfort(bool supports_preset_comfort) {
|
||||
this->supports_preset_comfort_ = supports_preset_comfort;
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_home(bool supports_preset_home) {
|
||||
this->supports_preset_home_ = supports_preset_home;
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_sleep(bool supports_preset_sleep) {
|
||||
this->supports_preset_sleep_ = supports_preset_sleep;
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_activity(bool supports_preset_activity) {
|
||||
this->supports_preset_activity_ = supports_preset_activity;
|
||||
}
|
||||
bool ClimateTraits::get_supports_presets() const {
|
||||
return this->supports_preset_eco_ || this->supports_preset_away_ || this->supports_preset_boost_ ||
|
||||
this->supports_preset_comfort_ || this->supports_preset_home_ || this->supports_preset_sleep_ ||
|
||||
this->supports_preset_activity_;
|
||||
}
|
||||
void ClimateTraits::set_supported_custom_presets(std::vector<std::string> &supported_custom_presets) {
|
||||
this->supported_custom_presets_ = supported_custom_presets;
|
||||
}
|
||||
const std::vector<std::string> ClimateTraits::get_supported_custom_presets() const {
|
||||
return this->supported_custom_presets_;
|
||||
}
|
||||
bool ClimateTraits::supports_custom_preset(std::string &custom_preset) const {
|
||||
return std::count(this->supported_custom_presets_.begin(), this->supported_custom_presets_.end(), custom_preset);
|
||||
}
|
||||
void ClimateTraits::set_supports_swing_mode_off(bool supports_swing_mode_off) {
|
||||
this->supports_swing_mode_off_ = supports_swing_mode_off;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "climate_mode.h"
|
||||
|
||||
namespace esphome {
|
||||
@ -65,6 +66,21 @@ class ClimateTraits {
|
||||
void set_supports_fan_mode_diffuse(bool supports_fan_mode_diffuse);
|
||||
bool supports_fan_mode(ClimateFanMode fan_mode) const;
|
||||
bool get_supports_fan_modes() const;
|
||||
void set_supported_custom_fan_modes(std::vector<std::string> &supported_custom_fan_modes);
|
||||
const std::vector<std::string> get_supported_custom_fan_modes() const;
|
||||
bool supports_custom_fan_mode(std::string &custom_fan_mode) const;
|
||||
bool supports_preset(ClimatePreset preset) const;
|
||||
void set_supports_preset_eco(bool supports_preset_eco);
|
||||
void set_supports_preset_away(bool supports_preset_away);
|
||||
void set_supports_preset_boost(bool supports_preset_boost);
|
||||
void set_supports_preset_comfort(bool supports_preset_comfort);
|
||||
void set_supports_preset_home(bool supports_preset_home);
|
||||
void set_supports_preset_sleep(bool supports_preset_sleep);
|
||||
void set_supports_preset_activity(bool supports_preset_activity);
|
||||
bool get_supports_presets() const;
|
||||
void set_supported_custom_presets(std::vector<std::string> &supported_custom_presets);
|
||||
const std::vector<std::string> get_supported_custom_presets() const;
|
||||
bool supports_custom_preset(std::string &custom_preset) const;
|
||||
void set_supports_swing_mode_off(bool supports_swing_mode_off);
|
||||
void set_supports_swing_mode_both(bool supports_swing_mode_both);
|
||||
void set_supports_swing_mode_vertical(bool supports_swing_mode_vertical);
|
||||
@ -103,6 +119,15 @@ class ClimateTraits {
|
||||
bool supports_swing_mode_both_{false};
|
||||
bool supports_swing_mode_vertical_{false};
|
||||
bool supports_swing_mode_horizontal_{false};
|
||||
bool supports_preset_eco_{false};
|
||||
bool supports_preset_away_{false};
|
||||
bool supports_preset_boost_{false};
|
||||
bool supports_preset_comfort_{false};
|
||||
bool supports_preset_home_{false};
|
||||
bool supports_preset_sleep_{false};
|
||||
bool supports_preset_activity_{false};
|
||||
std::vector<std::string> supported_custom_fan_modes_;
|
||||
std::vector<std::string> supported_custom_presets_;
|
||||
|
||||
float visual_min_temperature_{10};
|
||||
float visual_max_temperature_{30};
|
||||
|
@ -9,7 +9,6 @@ from esphome.components import (
|
||||
)
|
||||
from esphome.components.remote_base import CONF_RECEIVER_ID, CONF_TRANSMITTER_ID
|
||||
from esphome.const import CONF_SUPPORTS_COOL, CONF_SUPPORTS_HEAT, CONF_SENSOR
|
||||
from esphome.core import coroutine
|
||||
|
||||
AUTO_LOAD = ["sensor", "remote_base"]
|
||||
CODEOWNERS = ["@glmnet"]
|
||||
@ -39,19 +38,18 @@ CLIMATE_IR_WITH_RECEIVER_SCHEMA = CLIMATE_IR_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
@coroutine
|
||||
def register_climate_ir(var, config):
|
||||
yield cg.register_component(var, config)
|
||||
yield climate.register_climate(var, config)
|
||||
async def register_climate_ir(var, config):
|
||||
await cg.register_component(var, config)
|
||||
await climate.register_climate(var, config)
|
||||
|
||||
cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL]))
|
||||
cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT]))
|
||||
if CONF_SENSOR in config:
|
||||
sens = yield cg.get_variable(config[CONF_SENSOR])
|
||||
sens = await cg.get_variable(config[CONF_SENSOR])
|
||||
cg.add(var.set_sensor(sens))
|
||||
if CONF_RECEIVER_ID in config:
|
||||
receiver = yield cg.get_variable(config[CONF_RECEIVER_ID])
|
||||
receiver = await cg.get_variable(config[CONF_RECEIVER_ID])
|
||||
cg.add(receiver.register_listener(var))
|
||||
|
||||
transmitter = yield cg.get_variable(config[CONF_TRANSMITTER_ID])
|
||||
transmitter = await cg.get_variable(config[CONF_TRANSMITTER_ID])
|
||||
cg.add(var.set_transmitter(transmitter))
|
||||
|
@ -36,9 +36,9 @@ CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield climate_ir.register_climate_ir(var, config)
|
||||
await climate_ir.register_climate_ir(var, config)
|
||||
|
||||
cg.add(var.set_header_high(config[CONF_HEADER_HIGH]))
|
||||
cg.add(var.set_header_low(config[CONF_HEADER_LOW]))
|
||||
|
@ -72,7 +72,7 @@ void LgIrClimate::transmit_state() {
|
||||
remote_state |= FAN_AUTO;
|
||||
} else if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_DRY ||
|
||||
this->mode == climate::CLIMATE_MODE_HEAT) {
|
||||
switch (this->fan_mode) {
|
||||
switch (this->fan_mode.value()) {
|
||||
case climate::CLIMATE_FAN_HIGH:
|
||||
remote_state |= FAN_MAX;
|
||||
break;
|
||||
|
@ -26,7 +26,7 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
r = 0
|
||||
if CONF_RED in config:
|
||||
r = int(config[CONF_RED] * 255)
|
||||
|
@ -16,6 +16,6 @@ CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield climate_ir.register_climate_ir(var, config)
|
||||
await climate_ir.register_climate_ir(var, config)
|
||||
|
@ -93,7 +93,7 @@ void CoolixClimate::transmit_state() {
|
||||
this->fan_mode = climate::CLIMATE_FAN_AUTO;
|
||||
remote_state |= COOLIX_FAN_MODE_AUTO_DRY;
|
||||
} else {
|
||||
switch (this->fan_mode) {
|
||||
switch (this->fan_mode.value()) {
|
||||
case climate::CLIMATE_FAN_HIGH:
|
||||
remote_state |= COOLIX_FAN_MAX;
|
||||
break;
|
||||
|
@ -14,7 +14,7 @@ from esphome.const import (
|
||||
CONF_MQTT_ID,
|
||||
CONF_NAME,
|
||||
)
|
||||
from esphome.core import CORE, coroutine, coroutine_with_priority
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
|
||||
@ -73,8 +73,7 @@ COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
@coroutine
|
||||
def setup_cover_core_(var, config):
|
||||
async def setup_cover_core_(var, config):
|
||||
cg.add(var.set_name(config[CONF_NAME]))
|
||||
if CONF_INTERNAL in config:
|
||||
cg.add(var.set_internal(config[CONF_INTERNAL]))
|
||||
@ -83,15 +82,14 @@ def setup_cover_core_(var, config):
|
||||
|
||||
if CONF_MQTT_ID in config:
|
||||
mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var)
|
||||
yield mqtt.register_mqtt_component(mqtt_, config)
|
||||
await mqtt.register_mqtt_component(mqtt_, config)
|
||||
|
||||
|
||||
@coroutine
|
||||
def register_cover(var, config):
|
||||
async def register_cover(var, config):
|
||||
if not CORE.has_id(config[CONF_ID]):
|
||||
var = cg.Pvariable(config[CONF_ID], var)
|
||||
cg.add(cg.App.register_cover(var))
|
||||
yield setup_cover_core_(var, config)
|
||||
await setup_cover_core_(var, config)
|
||||
|
||||
|
||||
COVER_ACTION_SCHEMA = maybe_simple_id(
|
||||
@ -102,21 +100,21 @@ COVER_ACTION_SCHEMA = maybe_simple_id(
|
||||
|
||||
|
||||
@automation.register_action("cover.open", OpenAction, COVER_ACTION_SCHEMA)
|
||||
def cover_open_to_code(config, action_id, template_arg, args):
|
||||
paren = yield cg.get_variable(config[CONF_ID])
|
||||
yield cg.new_Pvariable(action_id, template_arg, paren)
|
||||
async def cover_open_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)
|
||||
|
||||
|
||||
@automation.register_action("cover.close", CloseAction, COVER_ACTION_SCHEMA)
|
||||
def cover_close_to_code(config, action_id, template_arg, args):
|
||||
paren = yield cg.get_variable(config[CONF_ID])
|
||||
yield cg.new_Pvariable(action_id, template_arg, paren)
|
||||
async def cover_close_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)
|
||||
|
||||
|
||||
@automation.register_action("cover.stop", StopAction, COVER_ACTION_SCHEMA)
|
||||
def cover_stop_to_code(config, action_id, template_arg, args):
|
||||
paren = yield cg.get_variable(config[CONF_ID])
|
||||
yield cg.new_Pvariable(action_id, template_arg, paren)
|
||||
async def cover_stop_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)
|
||||
|
||||
|
||||
COVER_CONTROL_ACTION_SCHEMA = cv.Schema(
|
||||
@ -131,25 +129,25 @@ COVER_CONTROL_ACTION_SCHEMA = cv.Schema(
|
||||
|
||||
|
||||
@automation.register_action("cover.control", ControlAction, COVER_CONTROL_ACTION_SCHEMA)
|
||||
def cover_control_to_code(config, action_id, template_arg, args):
|
||||
paren = yield cg.get_variable(config[CONF_ID])
|
||||
async def cover_control_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
if CONF_STOP in config:
|
||||
template_ = yield cg.templatable(config[CONF_STOP], args, bool)
|
||||
template_ = await cg.templatable(config[CONF_STOP], args, bool)
|
||||
cg.add(var.set_stop(template_))
|
||||
if CONF_STATE in config:
|
||||
template_ = yield cg.templatable(config[CONF_STATE], args, float)
|
||||
template_ = await cg.templatable(config[CONF_STATE], args, float)
|
||||
cg.add(var.set_position(template_))
|
||||
if CONF_POSITION in config:
|
||||
template_ = yield cg.templatable(config[CONF_POSITION], args, float)
|
||||
template_ = await cg.templatable(config[CONF_POSITION], args, float)
|
||||
cg.add(var.set_position(template_))
|
||||
if CONF_TILT in config:
|
||||
template_ = yield cg.templatable(config[CONF_TILT], args, float)
|
||||
template_ = await cg.templatable(config[CONF_TILT], args, float)
|
||||
cg.add(var.set_tilt(template_))
|
||||
yield var
|
||||
return var
|
||||
|
||||
|
||||
@coroutine_with_priority(100.0)
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
cg.add_define("USE_COVER")
|
||||
cg.add_global(cover_ns.using)
|
||||
|
0
esphome/components/cs5460a/__init__.py
Normal file
0
esphome/components/cs5460a/__init__.py
Normal file
342
esphome/components/cs5460a/cs5460a.cpp
Normal file
342
esphome/components/cs5460a/cs5460a.cpp
Normal file
@ -0,0 +1,342 @@
|
||||
#include "cs5460a.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace cs5460a {
|
||||
|
||||
static const char *TAG = "cs5460a";
|
||||
|
||||
void CS5460AComponent::write_register_(enum CS5460ARegister addr, uint32_t value) {
|
||||
this->write_byte(CMD_WRITE | (addr << 1));
|
||||
this->write_byte(value >> 16);
|
||||
this->write_byte(value >> 8);
|
||||
this->write_byte(value >> 0);
|
||||
}
|
||||
|
||||
uint32_t CS5460AComponent::read_register_(uint8_t addr) {
|
||||
uint32_t value;
|
||||
|
||||
this->write_byte(CMD_READ | (addr << 1));
|
||||
value = (uint32_t) this->transfer_byte(CMD_SYNC0) << 16;
|
||||
value |= (uint32_t) this->transfer_byte(CMD_SYNC0) << 8;
|
||||
value |= this->transfer_byte(CMD_SYNC0) << 0;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool CS5460AComponent::softreset_() {
|
||||
uint32_t pc = ((uint8_t) phase_offset_ & 0x3f) | (phase_offset_ < 0 ? 0x40 : 0);
|
||||
uint32_t config = (1 << 0) | /* K = 0b0001 */
|
||||
(current_hpf_ ? 1 << 5 : 0) | /* IHPF */
|
||||
(voltage_hpf_ ? 1 << 6 : 0) | /* VHPF */
|
||||
(pga_gain_ << 16) | /* Gi */
|
||||
(pc << 17); /* PC */
|
||||
int cnt = 0;
|
||||
|
||||
/* Serial resynchronization */
|
||||
this->write_byte(CMD_SYNC1);
|
||||
this->write_byte(CMD_SYNC1);
|
||||
this->write_byte(CMD_SYNC1);
|
||||
this->write_byte(CMD_SYNC0);
|
||||
|
||||
/* Reset */
|
||||
this->write_register_(REG_CONFIG, 1 << 7);
|
||||
delay(10);
|
||||
while (cnt++ < 50 && (this->read_register_(REG_CONFIG) & 0x81) != 0x000001)
|
||||
;
|
||||
if (cnt > 50)
|
||||
return false;
|
||||
|
||||
this->write_register_(REG_CONFIG, config);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CS5460AComponent::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up CS5460A...");
|
||||
|
||||
float current_full_scale = (pga_gain_ == CS5460A_PGA_GAIN_10X) ? 0.25 : 0.10;
|
||||
float voltage_full_scale = 0.25;
|
||||
current_multiplier_ = current_full_scale / (fabsf(current_gain_) * 0x1000000);
|
||||
voltage_multiplier_ = voltage_full_scale / (voltage_gain_ * 0x1000000);
|
||||
|
||||
/*
|
||||
* Calculate power from the Energy register because the Power register
|
||||
* stores instantaneous power which varies a lot in each AC cycle,
|
||||
* while the Energy value is accumulated over the "computation cycle"
|
||||
* which should be an integer number of AC cycles.
|
||||
*/
|
||||
power_multiplier_ =
|
||||
(current_full_scale * voltage_full_scale * 4096) / (current_gain_ * voltage_gain_ * samples_ * 0x800000);
|
||||
|
||||
pulse_freq_ =
|
||||
(current_full_scale * voltage_full_scale) / (fabsf(current_gain_) * voltage_gain_ * pulse_energy_wh_ * 3600);
|
||||
|
||||
hw_init_();
|
||||
}
|
||||
|
||||
void CS5460AComponent::hw_init_() {
|
||||
this->spi_setup();
|
||||
this->enable();
|
||||
|
||||
if (!this->softreset_()) {
|
||||
this->disable();
|
||||
ESP_LOGE(TAG, "CS5460A reset failed!");
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t status = this->read_register_(REG_STATUS);
|
||||
ESP_LOGCONFIG(TAG, " Version: %x", (status >> 6) & 7);
|
||||
|
||||
this->write_register_(REG_CYCLE_COUNT, samples_);
|
||||
this->write_register_(REG_PULSE_RATE, lroundf(pulse_freq_ * 32.0f));
|
||||
|
||||
/* Use one of the power saving features (assuming external oscillator), reset other CONTROL bits,
|
||||
* sometimes softreset_() is not enough */
|
||||
this->write_register_(REG_CONTROL, 0x000004);
|
||||
|
||||
this->restart_();
|
||||
this->disable();
|
||||
ESP_LOGCONFIG(TAG, " Init ok");
|
||||
}
|
||||
|
||||
/* 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);
|
||||
/* Start continuous conversion */
|
||||
this->write_byte(CMD_START_CONT);
|
||||
this->disable();
|
||||
|
||||
this->started_();
|
||||
}
|
||||
|
||||
void CS5460AComponent::started_() {
|
||||
/*
|
||||
* Try to guess when the next batch of results is going to be ready and
|
||||
* schedule next STATUS check some time before that moment. This assumes
|
||||
* two things:
|
||||
* * a new "computation cycle" started just now. If it started some
|
||||
* time ago we may be a late next time, but hopefully less late in each
|
||||
* iteration -- that's why we schedule the next check in some 0.8 of
|
||||
* the time we actually expect the next reading ready.
|
||||
* * MCLK rate is 4.096MHz and K == 1. If there's a CS5460A module in
|
||||
* use with a different clock this will need to be parametrised.
|
||||
*/
|
||||
expect_data_ts_ = millis() + samples_ * 1024 / 4096;
|
||||
|
||||
schedule_next_check_();
|
||||
}
|
||||
|
||||
void CS5460AComponent::schedule_next_check_() {
|
||||
int32_t time_left = expect_data_ts_ - millis();
|
||||
|
||||
/* First try at 0.8 of the actual expected time (if it's in the future) */
|
||||
if (time_left > 0)
|
||||
time_left -= time_left / 5;
|
||||
|
||||
if (time_left > -500) {
|
||||
/* But not sooner than in 30ms from now */
|
||||
if (time_left < 30)
|
||||
time_left = 30;
|
||||
} else {
|
||||
/*
|
||||
* If the measurement is more than 0.5s overdue start worrying. The
|
||||
* device may be stuck because of an overcurrent error or similar,
|
||||
* from now on just retry every 1s. After 15s try a reset, if it
|
||||
* fails we give up and mark the component "failed".
|
||||
*/
|
||||
if (time_left > -15000) {
|
||||
time_left = 1000;
|
||||
this->status_momentary_warning("warning", 1000);
|
||||
} else {
|
||||
ESP_LOGCONFIG(TAG, "Device officially stuck, resetting");
|
||||
this->cancel_timeout("status-check");
|
||||
this->hw_init_();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this->set_timeout("status-check", time_left, [this]() {
|
||||
if (!this->check_status_())
|
||||
this->schedule_next_check_();
|
||||
});
|
||||
}
|
||||
|
||||
bool CS5460AComponent::check_status_() {
|
||||
this->enable();
|
||||
uint32_t status = this->read_register_(REG_STATUS);
|
||||
|
||||
if (!(status & 0xcbf83c)) {
|
||||
this->disable();
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t clear = 1 << 20;
|
||||
|
||||
/* TODO: Report if IC=0 but only once as it can't be cleared */
|
||||
|
||||
if (status & (1 << 2)) {
|
||||
clear |= 1 << 2;
|
||||
ESP_LOGE(TAG, "Low supply detected");
|
||||
this->status_momentary_warning("warning", 500);
|
||||
}
|
||||
|
||||
if (status & (1 << 3)) {
|
||||
clear |= 1 << 3;
|
||||
ESP_LOGE(TAG, "Modulator oscillation on current channel");
|
||||
this->status_momentary_warning("warning", 500);
|
||||
}
|
||||
|
||||
if (status & (1 << 4)) {
|
||||
clear |= 1 << 4;
|
||||
ESP_LOGE(TAG, "Modulator oscillation on voltage channel");
|
||||
this->status_momentary_warning("warning", 500);
|
||||
}
|
||||
|
||||
if (status & (1 << 5)) {
|
||||
clear |= 1 << 5;
|
||||
ESP_LOGE(TAG, "Watch-dog timeout");
|
||||
this->status_momentary_warning("warning", 500);
|
||||
}
|
||||
|
||||
if (status & (1 << 11)) {
|
||||
clear |= 1 << 11;
|
||||
ESP_LOGE(TAG, "EOUT Energy Accumulation Register out of range");
|
||||
this->status_momentary_warning("warning", 500);
|
||||
}
|
||||
|
||||
if (status & (1 << 12)) {
|
||||
clear |= 1 << 12;
|
||||
ESP_LOGE(TAG, "Energy out of range");
|
||||
this->status_momentary_warning("warning", 500);
|
||||
}
|
||||
|
||||
if (status & (1 << 13)) {
|
||||
clear |= 1 << 13;
|
||||
ESP_LOGE(TAG, "RMS voltage out of range");
|
||||
this->status_momentary_warning("warning", 500);
|
||||
}
|
||||
|
||||
if (status & (1 << 14)) {
|
||||
clear |= 1 << 14;
|
||||
ESP_LOGE(TAG, "RMS current out of range");
|
||||
this->status_momentary_warning("warning", 500);
|
||||
}
|
||||
|
||||
if (status & (1 << 15)) {
|
||||
clear |= 1 << 15;
|
||||
ESP_LOGE(TAG, "Power calculation out of range");
|
||||
this->status_momentary_warning("warning", 500);
|
||||
}
|
||||
|
||||
if (status & (1 << 16)) {
|
||||
clear |= 1 << 16;
|
||||
ESP_LOGE(TAG, "Voltage out of range");
|
||||
this->status_momentary_warning("warning", 500);
|
||||
}
|
||||
|
||||
if (status & (1 << 17)) {
|
||||
clear |= 1 << 17;
|
||||
ESP_LOGE(TAG, "Current out of range");
|
||||
this->status_momentary_warning("warning", 500);
|
||||
}
|
||||
|
||||
if (status & (1 << 19)) {
|
||||
clear |= 1 << 19;
|
||||
ESP_LOGE(TAG, "Divide overflowed");
|
||||
}
|
||||
|
||||
if (status & (1 << 22)) {
|
||||
bool dir = status & (1 << 21);
|
||||
if (current_gain_ < 0)
|
||||
dir = !dir;
|
||||
ESP_LOGI(TAG, "Energy counter %s pulse", dir ? "negative" : "positive");
|
||||
clear |= 1 << 22;
|
||||
}
|
||||
|
||||
uint32_t raw_current = 0; /* Calm the validators */
|
||||
uint32_t raw_voltage = 0;
|
||||
uint32_t raw_energy = 0;
|
||||
|
||||
if (status & (1 << 23)) {
|
||||
clear |= 1 << 23;
|
||||
|
||||
if (current_sensor_ != nullptr)
|
||||
raw_current = this->read_register_(REG_IRMS);
|
||||
|
||||
if (voltage_sensor_ != nullptr)
|
||||
raw_voltage = this->read_register_(REG_VRMS);
|
||||
}
|
||||
|
||||
if (status & ((1 << 23) | (1 << 5))) {
|
||||
/* Read to clear the WDT bit */
|
||||
raw_energy = this->read_register_(REG_E);
|
||||
}
|
||||
|
||||
this->write_register_(REG_STATUS, clear);
|
||||
this->disable();
|
||||
|
||||
/*
|
||||
* Schedule the next STATUS check assuming that DRDY was asserted very
|
||||
* recently, then publish the new values. Do this last for reentrancy in
|
||||
* case the publish triggers a restart() or for whatever reason needs to
|
||||
* cancel the timeout set in schedule_next_check_(), or needs to use SPI.
|
||||
* If the current or power values haven't changed one bit it may be that
|
||||
* the chip somehow forgot to update the registers -- seen happening very
|
||||
* rarely. In that case don't publish them because the user may have
|
||||
* the input connected to a multiplexer and may have switched channels
|
||||
* since the previous reading and we'd be publishing the stale value for
|
||||
* the new channel. If the value *was* updated it's very unlikely that
|
||||
* it wouldn't have changed, especially power/energy which are affected
|
||||
* by the noise on both the current and value channels (in case of energy,
|
||||
* accumulated over many conversion cycles.)
|
||||
*/
|
||||
if (status & (1 << 23)) {
|
||||
this->started_();
|
||||
|
||||
if (current_sensor_ != nullptr && raw_current != prev_raw_current_) {
|
||||
current_sensor_->publish_state(raw_current * current_multiplier_);
|
||||
prev_raw_current_ = raw_current;
|
||||
}
|
||||
|
||||
if (voltage_sensor_ != nullptr)
|
||||
voltage_sensor_->publish_state(raw_voltage * voltage_multiplier_);
|
||||
|
||||
if (power_sensor_ != nullptr && raw_energy != prev_raw_energy_) {
|
||||
int32_t raw = (int32_t)(raw_energy << 8) >> 8; /* Sign-extend */
|
||||
power_sensor_->publish_state(raw * power_multiplier_);
|
||||
prev_raw_energy_ = raw_energy;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CS5460AComponent::dump_config() {
|
||||
uint32_t state = this->get_component_state();
|
||||
|
||||
ESP_LOGCONFIG(TAG, "CS5460A:");
|
||||
ESP_LOGCONFIG(TAG, " Init status: %s",
|
||||
state == COMPONENT_STATE_LOOP ? "OK" : (state == COMPONENT_STATE_FAILED ? "failed" : "other"));
|
||||
LOG_PIN(" CS Pin: ", cs_);
|
||||
ESP_LOGCONFIG(TAG, " Samples / cycle: %u", samples_);
|
||||
ESP_LOGCONFIG(TAG, " Phase offset: %i", phase_offset_);
|
||||
ESP_LOGCONFIG(TAG, " PGA Gain: %s", pga_gain_ == CS5460A_PGA_GAIN_50X ? "50x" : "10x");
|
||||
ESP_LOGCONFIG(TAG, " Current gain: %.5f", current_gain_);
|
||||
ESP_LOGCONFIG(TAG, " Voltage gain: %.5f", voltage_gain_);
|
||||
ESP_LOGCONFIG(TAG, " Current HPF: %s", current_hpf_ ? "enabled" : "disabled");
|
||||
ESP_LOGCONFIG(TAG, " Voltage HPF: %s", voltage_hpf_ ? "enabled" : "disabled");
|
||||
ESP_LOGCONFIG(TAG, " Pulse energy: %.2f Wh", pulse_energy_wh_);
|
||||
LOG_SENSOR(" ", "Voltage", voltage_sensor_);
|
||||
LOG_SENSOR(" ", "Current", current_sensor_);
|
||||
LOG_SENSOR(" ", "Power", power_sensor_);
|
||||
}
|
||||
|
||||
} // namespace cs5460a
|
||||
} // namespace esphome
|
123
esphome/components/cs5460a/cs5460a.h
Normal file
123
esphome/components/cs5460a/cs5460a.h
Normal file
@ -0,0 +1,123 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/spi/spi.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace cs5460a {
|
||||
|
||||
enum CS5460ACommand {
|
||||
CMD_SYNC0 = 0xfe,
|
||||
CMD_SYNC1 = 0xff,
|
||||
CMD_START_SINGLE = 0xe0,
|
||||
CMD_START_CONT = 0xe8,
|
||||
CMD_POWER_UP = 0xa0,
|
||||
CMD_POWER_STANDBY = 0x88,
|
||||
CMD_POWER_SLEEP = 0x90,
|
||||
CMD_CALIBRATION = 0xc0,
|
||||
CMD_READ = 0x00,
|
||||
CMD_WRITE = 0x40,
|
||||
};
|
||||
|
||||
enum CS5460ARegister {
|
||||
REG_CONFIG = 0x00,
|
||||
REG_IDCOFF = 0x01,
|
||||
REG_IGN = 0x02,
|
||||
REG_VDCOFF = 0x03,
|
||||
REG_VGN = 0x04,
|
||||
REG_CYCLE_COUNT = 0x05,
|
||||
REG_PULSE_RATE = 0x06,
|
||||
REG_I = 0x07,
|
||||
REG_V = 0x08,
|
||||
REG_P = 0x09,
|
||||
REG_E = 0x0a,
|
||||
REG_IRMS = 0x0b,
|
||||
REG_VRMS = 0x0c,
|
||||
REG_TBC = 0x0d,
|
||||
REG_POFF = 0x0e,
|
||||
REG_STATUS = 0x0f,
|
||||
REG_IACOFF = 0x10,
|
||||
REG_VACOFF = 0x11,
|
||||
REG_MASK = 0x1a,
|
||||
REG_CONTROL = 0x1c,
|
||||
};
|
||||
|
||||
/** Enum listing the current channel aplifiergain settings for the CS5460A.
|
||||
*/
|
||||
enum CS5460APGAGain {
|
||||
CS5460A_PGA_GAIN_10X = 0b0,
|
||||
CS5460A_PGA_GAIN_50X = 0b1,
|
||||
};
|
||||
|
||||
class CS5460AComponent : public Component,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
|
||||
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_1MHZ> {
|
||||
public:
|
||||
void set_samples(uint32_t samples) { samples_ = samples; }
|
||||
void set_phase_offset(int8_t phase_offset) { phase_offset_ = phase_offset; }
|
||||
void set_pga_gain(CS5460APGAGain pga_gain) { pga_gain_ = pga_gain; }
|
||||
void set_gains(float current_gain, float voltage_gain) {
|
||||
current_gain_ = current_gain;
|
||||
voltage_gain_ = voltage_gain;
|
||||
}
|
||||
void set_hpf_enable(bool current_hpf, bool voltage_hpf) {
|
||||
current_hpf_ = current_hpf;
|
||||
voltage_hpf_ = voltage_hpf;
|
||||
}
|
||||
void set_pulse_energy_wh(float pulse_energy_wh) { pulse_energy_wh_ = pulse_energy_wh; }
|
||||
void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; }
|
||||
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
|
||||
void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; }
|
||||
|
||||
void restart() { restart_(); }
|
||||
|
||||
void setup() override;
|
||||
void loop() override {}
|
||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
uint32_t samples_;
|
||||
int8_t phase_offset_;
|
||||
CS5460APGAGain pga_gain_;
|
||||
float current_gain_;
|
||||
float voltage_gain_;
|
||||
bool current_hpf_;
|
||||
bool voltage_hpf_;
|
||||
float pulse_energy_wh_;
|
||||
sensor::Sensor *current_sensor_{nullptr};
|
||||
sensor::Sensor *voltage_sensor_{nullptr};
|
||||
sensor::Sensor *power_sensor_{nullptr};
|
||||
|
||||
void write_register_(enum CS5460ARegister addr, uint32_t value);
|
||||
uint32_t read_register_(uint8_t addr);
|
||||
bool softreset_();
|
||||
void hw_init_();
|
||||
void restart_();
|
||||
void started_();
|
||||
void schedule_next_check_();
|
||||
bool check_status_();
|
||||
|
||||
float current_multiplier_;
|
||||
float voltage_multiplier_;
|
||||
float power_multiplier_;
|
||||
float pulse_freq_;
|
||||
uint32_t expect_data_ts_;
|
||||
uint32_t prev_raw_current_{0};
|
||||
uint32_t prev_raw_energy_{0};
|
||||
};
|
||||
|
||||
template<typename... Ts> class CS5460ARestartAction : public Action<Ts...> {
|
||||
public:
|
||||
CS5460ARestartAction(CS5460AComponent *cs5460a) : cs5460a_(cs5460a) {}
|
||||
|
||||
void play(Ts... x) override { cs5460a_->restart(); }
|
||||
|
||||
protected:
|
||||
CS5460AComponent *cs5460a_;
|
||||
};
|
||||
|
||||
} // namespace cs5460a
|
||||
} // namespace esphome
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user