Merge branch 'dev' into optolink

This commit is contained in:
j0ta29 2023-10-23 19:24:26 +02:00 committed by GitHub
commit 18737f9a0b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
194 changed files with 2511 additions and 756 deletions

View file

@ -40,7 +40,7 @@ jobs:
arch: [amd64, armv7, aarch64] arch: [amd64, armv7, aarch64]
build_type: ["ha-addon", "docker", "lint"] build_type: ["ha-addon", "docker", "lint"]
steps: steps:
- uses: actions/checkout@v4.1.0 - uses: actions/checkout@v4.1.1
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4.7.1 uses: actions/setup-python@v4.7.1
with: with:

View file

@ -34,7 +34,7 @@ jobs:
cache-key: ${{ steps.cache-key.outputs.key }} cache-key: ${{ steps.cache-key.outputs.key }}
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Generate cache-key - name: Generate cache-key
id: cache-key id: cache-key
run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT
@ -66,7 +66,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@ -87,7 +87,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@ -108,7 +108,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@ -129,7 +129,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@ -150,7 +150,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@ -171,7 +171,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@ -191,7 +191,7 @@ jobs:
- common - common
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@ -216,7 +216,7 @@ jobs:
matrix: ${{ steps.set-matrix.outputs.matrix }} matrix: ${{ steps.set-matrix.outputs.matrix }}
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Find all YAML test files - name: Find all YAML test files
id: set-matrix id: set-matrix
run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT
@ -241,7 +241,7 @@ jobs:
file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }} file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }}
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:
@ -296,7 +296,7 @@ jobs:
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Restore Python - name: Restore Python
uses: ./.github/actions/restore-python uses: ./.github/actions/restore-python
with: with:

View file

@ -19,7 +19,7 @@ jobs:
outputs: outputs:
tag: ${{ steps.tag.outputs.tag }} tag: ${{ steps.tag.outputs.tag }}
steps: steps:
- uses: actions/checkout@v4.1.0 - uses: actions/checkout@v4.1.1
- name: Get tag - name: Get tag
id: tag id: tag
# yamllint disable rule:line-length # yamllint disable rule:line-length
@ -43,7 +43,7 @@ jobs:
if: github.repository == 'esphome/esphome' && github.event_name == 'release' if: github.repository == 'esphome/esphome' && github.event_name == 'release'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4.1.0 - uses: actions/checkout@v4.1.1
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4.7.1 uses: actions/setup-python@v4.7.1
with: with:
@ -88,7 +88,7 @@ jobs:
target: "lint" target: "lint"
baseimg: "docker" baseimg: "docker"
steps: steps:
- uses: actions/checkout@v4.1.0 - uses: actions/checkout@v4.1.1
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4.7.1 uses: actions/setup-python@v4.7.1
with: with:

View file

@ -13,10 +13,10 @@ jobs:
if: github.repository == 'esphome/esphome' if: github.repository == 'esphome/esphome'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Checkout Home Assistant - name: Checkout Home Assistant
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
with: with:
repository: home-assistant/core repository: home-assistant/core
path: lib/home-assistant path: lib/home-assistant

View file

@ -17,6 +17,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
uses: actions/checkout@v4.1.0 uses: actions/checkout@v4.1.1
- name: Run yamllint - name: Run yamllint
uses: frenck/action-yamllint@v1.4.1 uses: frenck/action-yamllint@v1.4.1

View file

@ -3,7 +3,7 @@
# See https://pre-commit.com/hooks.html for more hooks # See https://pre-commit.com/hooks.html for more hooks
repos: repos:
- repo: https://github.com/psf/black-pre-commit-mirror - repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.9.1 rev: 23.10.0
hooks: hooks:
- id: black - id: black
args: args:
@ -27,7 +27,7 @@ repos:
- --branch=release - --branch=release
- --branch=beta - --branch=beta
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: v3.10.1 rev: v3.13.0
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: [--py39-plus] args: [--py39-plus]

View file

@ -226,7 +226,7 @@ esphome/components/pn532_spi/* @OttoWinter @jesserockz
esphome/components/power_supply/* @esphome/core esphome/components/power_supply/* @esphome/core
esphome/components/preferences/* @esphome/core esphome/components/preferences/* @esphome/core
esphome/components/psram/* @esphome/core esphome/components/psram/* @esphome/core
esphome/components/pulse_meter/* @cstaahl @stevebaxter esphome/components/pulse_meter/* @TrentHouliston @cstaahl @stevebaxter
esphome/components/pvvx_mithermometer/* @pasiz esphome/components/pvvx_mithermometer/* @pasiz
esphome/components/qmp6988/* @andrewpc esphome/components/qmp6988/* @andrewpc
esphome/components/qr_code/* @wjtje esphome/components/qr_code/* @wjtje
@ -255,6 +255,7 @@ esphome/components/sen21231/* @shreyaskarnik
esphome/components/sen5x/* @martgras esphome/components/sen5x/* @martgras
esphome/components/sensirion_common/* @martgras esphome/components/sensirion_common/* @martgras
esphome/components/sensor/* @esphome/core esphome/components/sensor/* @esphome/core
esphome/components/sfa30/* @ghsensdev
esphome/components/sgp40/* @SenexCrenshaw esphome/components/sgp40/* @SenexCrenshaw
esphome/components/sgp4x/* @SenexCrenshaw @martgras esphome/components/sgp4x/* @SenexCrenshaw @martgras
esphome/components/shelly_dimmer/* @edge90 @rnauber esphome/components/shelly_dimmer/* @edge90 @rnauber
@ -323,6 +324,7 @@ esphome/components/tuya/sensor/* @jesserockz
esphome/components/tuya/switch/* @jesserockz esphome/components/tuya/switch/* @jesserockz
esphome/components/tuya/text_sensor/* @dentra esphome/components/tuya/text_sensor/* @dentra
esphome/components/uart/* @esphome/core esphome/components/uart/* @esphome/core
esphome/components/uart/button/* @ssieb
esphome/components/ufire_ec/* @pvizeli esphome/components/ufire_ec/* @pvizeli
esphome/components/ufire_ise/* @pvizeli esphome/components/ufire_ise/* @pvizeli
esphome/components/ultrasonic/* @OttoWinter esphome/components/ultrasonic/* @OttoWinter

View file

@ -6,38 +6,47 @@
ARG BASEIMGTYPE=docker ARG BASEIMGTYPE=docker
# https://github.com/hassio-addons/addon-debian-base/releases # https://github.com/hassio-addons/addon-debian-base/releases
FROM ghcr.io/hassio-addons/debian-base:6.2.3 AS base-hassio FROM ghcr.io/hassio-addons/debian-base:7.2.0 AS base-hassio
# https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye # https://hub.docker.com/_/debian?tab=tags&page=1&name=bookworm
FROM debian:bullseye-20230208-slim AS base-docker FROM debian:12.2-slim AS base-docker
FROM base-${BASEIMGTYPE} AS base FROM base-${BASEIMGTYPE} AS base
ARG TARGETARCH ARG TARGETARCH
ARG TARGETVARIANT ARG TARGETVARIANT
# Note that --break-system-packages is used below because
# https://peps.python.org/pep-0668/ added a safety check that prevents
# installing packages with the same name as a system package. This is
# not a problem for us because we are not concerned about overwriting
# system packages because we are running in an isolated container.
RUN \ RUN \
apt-get update \ apt-get update \
# Use pinned versions so that we get updates with build caching # Use pinned versions so that we get updates with build caching
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
python3=3.9.2-3 \ python3-pip=23.0.1+dfsg-1 \
python3-pip=20.3.4-4+deb11u1 \ python3-setuptools=66.1.1-1 \
python3-setuptools=52.0.0-4 \ python3-venv=3.11.2-1+b1 \
python3-cryptography=3.3.2-1 \ python3-wheel=0.38.4-2 \
python3-venv=3.9.2-3 \ iputils-ping=3:20221126-1 \
iputils-ping=3:20210202-1 \ git=1:2.39.2-1.1 \
git=1:2.30.2-1+deb11u2 \ curl=7.88.1-10+deb12u4 \
curl=7.74.0-1.3+deb11u9 \ openssh-client=1:9.2p1-2+deb12u1 \
openssh-client=1:8.4p1-5+deb11u2 \ python3-cffi=1.15.1-5 \
python3-cffi=1.14.5-1 \ libcairo2=1.16.0-7 \
libcairo2=1.16.0-5 \
patch=2.7.6-7; \ patch=2.7.6-7; \
if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \ if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
build-essential=12.9 \ build-essential=12.9 \
python3-dev=3.9.2-3 \ python3-dev=3.11.2-1+b1 \
zlib1g-dev=1:1.2.11.dfsg-2+deb11u2 \ zlib1g-dev=1:1.2.13.dfsg-1 \
libjpeg-dev=1:2.0.6-4 \ libjpeg-dev=1:2.1.5-2 \
libfreetype-dev=2.10.4+dfsg-1+deb11u1; \ libfreetype-dev=2.12.1+dfsg-5 \
libssl-dev=3.0.11-1~deb12u1 \
libffi-dev=3.4.4-1 \
cargo=0.66.0+ds1-1 \
pkg-config=1.8.1-1; \
fi; \ fi; \
rm -rf \ rm -rf \
/tmp/* \ /tmp/* \
@ -50,6 +59,7 @@ ENV \
# Store globally installed pio libs in /piolibs # Store globally installed pio libs in /piolibs
PLATFORMIO_GLOBALLIB_DIR=/piolibs PLATFORMIO_GLOBALLIB_DIR=/piolibs
# Support legacy binaries on Debian multiarch system. There is no "correct" way # Support legacy binaries on Debian multiarch system. There is no "correct" way
# to do this, other than using properly built toolchains... # to do this, other than using properly built toolchains...
# See: https://unix.stackexchange.com/questions/553743/correct-way-to-add-lib-ld-linux-so-3-in-debian # See: https://unix.stackexchange.com/questions/553743/correct-way-to-add-lib-ld-linux-so-3-in-debian
@ -60,8 +70,7 @@ RUN \
RUN \ RUN \
# Ubuntu python3-pip is missing wheel # Ubuntu python3-pip is missing wheel
pip3 install --no-cache-dir \ pip3 install --break-system-packages --no-cache-dir \
wheel==0.37.1 \
platformio==6.1.11 \ platformio==6.1.11 \
# Change some platformio settings # Change some platformio settings
&& platformio settings set enable_telemetry No \ && platformio settings set enable_telemetry No \
@ -70,9 +79,11 @@ RUN \
# First install requirements to leverage caching when requirements don't change # First install requirements to leverage caching when requirements don't change
# tmpfs is for https://github.com/rust-lang/cargo/issues/8719
COPY requirements.txt requirements_optional.txt script/platformio_install_deps.py platformio.ini / COPY requirements.txt requirements_optional.txt script/platformio_install_deps.py platformio.ini /
RUN \ RUN --mount=type=tmpfs,target=/root/.cargo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse CARGO_HOME=/root/.cargo \
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \ pip3 install --break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
&& /platformio_install_deps.py /platformio.ini --libraries && /platformio_install_deps.py /platformio.ini --libraries
@ -81,7 +92,7 @@ FROM base AS docker
# Copy esphome and install # Copy esphome and install
COPY . /esphome COPY . /esphome
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome RUN pip3 install --break-system-packages --no-cache-dir --no-use-pep517 -e /esphome
# Settings for dashboard # Settings for dashboard
ENV USERNAME="" PASSWORD="" ENV USERNAME="" PASSWORD=""
@ -110,7 +121,7 @@ RUN \
apt-get update \ apt-get update \
# Use pinned versions so that we get updates with build caching # Use pinned versions so that we get updates with build caching
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
nginx-light=1.18.0-6.1+deb11u3 \ nginx-light=1.22.1-9 \
&& rm -rf \ && rm -rf \
/tmp/* \ /tmp/* \
/var/{cache,log}/* \ /var/{cache,log}/* \
@ -123,7 +134,7 @@ COPY docker/ha-addon-rootfs/ /
# Copy esphome and install # Copy esphome and install
COPY . /esphome COPY . /esphome
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome RUN pip3 install --break-system-packages --no-cache-dir --no-use-pep517 -e /esphome
# Labels # Labels
LABEL \ LABEL \
@ -146,20 +157,20 @@ RUN \
apt-get update \ apt-get update \
# Use pinned versions so that we get updates with build caching # Use pinned versions so that we get updates with build caching
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
clang-format-13=1:13.0.1-6~deb11u1 \ clang-format-13=1:13.0.1-11+b2 \
clang-tidy-11=1:11.0.1-2 \ clang-tidy-14=1:14.0.6-12 \
patch=2.7.6-7 \ patch=2.7.6-7 \
software-properties-common=0.96.20.2-2.1 \ software-properties-common=0.99.30-4 \
nano=5.4-2+deb11u2 \ nano=7.2-1 \
build-essential=12.9 \ build-essential=12.9 \
python3-dev=3.9.2-3 \ python3-dev=3.11.2-1+b1 \
&& rm -rf \ && rm -rf \
/tmp/* \ /tmp/* \
/var/{cache,log}/* \ /var/{cache,log}/* \
/var/lib/apt/lists/* /var/lib/apt/lists/*
COPY requirements_test.txt / COPY requirements_test.txt /
RUN pip3 install --no-cache-dir -r /requirements_test.txt RUN pip3 install --break-system-packages --no-cache-dir -r /requirements_test.txt
VOLUME ["/esphome"] VOLUME ["/esphome"]
WORKDIR /esphome WORKDIR /esphome

View file

@ -1413,6 +1413,18 @@ message SubscribeVoiceAssistantRequest {
bool subscribe = 1; bool subscribe = 1;
} }
enum VoiceAssistantRequestFlag {
VOICE_ASSISTANT_REQUEST_NONE = 0;
VOICE_ASSISTANT_REQUEST_USE_VAD = 1;
VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD = 2;
}
message VoiceAssistantAudioSettings {
uint32 noise_suppression_level = 1;
uint32 auto_gain = 2;
float volume_multiplier = 3;
}
message VoiceAssistantRequest { message VoiceAssistantRequest {
option (id) = 90; option (id) = 90;
option (source) = SOURCE_SERVER; option (source) = SOURCE_SERVER;
@ -1420,7 +1432,8 @@ message VoiceAssistantRequest {
bool start = 1; bool start = 1;
string conversation_id = 2; string conversation_id = 2;
bool use_vad = 3; uint32 flags = 3;
VoiceAssistantAudioSettings audio_settings = 4;
} }
message VoiceAssistantResponse { message VoiceAssistantResponse {
@ -1442,6 +1455,12 @@ enum VoiceAssistantEvent {
VOICE_ASSISTANT_INTENT_END = 6; VOICE_ASSISTANT_INTENT_END = 6;
VOICE_ASSISTANT_TTS_START = 7; VOICE_ASSISTANT_TTS_START = 7;
VOICE_ASSISTANT_TTS_END = 8; VOICE_ASSISTANT_TTS_END = 8;
VOICE_ASSISTANT_WAKE_WORD_START = 9;
VOICE_ASSISTANT_WAKE_WORD_END = 10;
VOICE_ASSISTANT_STT_VAD_START = 11;
VOICE_ASSISTANT_STT_VAD_END = 12;
VOICE_ASSISTANT_TTS_STREAM_START = 98;
VOICE_ASSISTANT_TTS_STREAM_END = 99;
} }
message VoiceAssistantEventData { message VoiceAssistantEventData {

View file

@ -907,21 +907,22 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_
#endif #endif
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
bool APIConnection::request_voice_assistant(bool start, const std::string &conversation_id, bool use_vad) { bool APIConnection::request_voice_assistant(const VoiceAssistantRequest &msg) {
if (!this->voice_assistant_subscription_) if (!this->voice_assistant_subscription_)
return false; return false;
VoiceAssistantRequest msg;
msg.start = start;
msg.conversation_id = conversation_id;
msg.use_vad = use_vad;
return this->send_voice_assistant_request(msg); return this->send_voice_assistant_request(msg);
} }
void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) { void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) {
if (voice_assistant::global_voice_assistant != nullptr) { if (voice_assistant::global_voice_assistant != nullptr) {
if (msg.error) {
voice_assistant::global_voice_assistant->failed_to_start();
return;
}
struct sockaddr_storage storage; struct sockaddr_storage storage;
socklen_t len = sizeof(storage); socklen_t len = sizeof(storage);
this->helper_->getpeername((struct sockaddr *) &storage, &len); this->helper_->getpeername((struct sockaddr *) &storage, &len);
voice_assistant::global_voice_assistant->start(&storage, msg.port); voice_assistant::global_voice_assistant->start_streaming(&storage, msg.port);
} }
}; };
void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) { void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) {

View file

@ -124,7 +124,7 @@ class APIConnection : public APIServerConnection {
void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override { void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override {
this->voice_assistant_subscription_ = msg.subscribe; this->voice_assistant_subscription_ = msg.subscribe;
} }
bool request_voice_assistant(bool start, const std::string &conversation_id, bool use_vad); bool request_voice_assistant(const VoiceAssistantRequest &msg);
void on_voice_assistant_response(const VoiceAssistantResponse &msg) override; void on_voice_assistant_response(const VoiceAssistantResponse &msg) override;
void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override; void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override;
#endif #endif

View file

@ -410,6 +410,20 @@ const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::Bluet
} }
#endif #endif
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::VoiceAssistantRequestFlag>(enums::VoiceAssistantRequestFlag value) {
switch (value) {
case enums::VOICE_ASSISTANT_REQUEST_NONE:
return "VOICE_ASSISTANT_REQUEST_NONE";
case enums::VOICE_ASSISTANT_REQUEST_USE_VAD:
return "VOICE_ASSISTANT_REQUEST_USE_VAD";
case enums::VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD:
return "VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD";
default:
return "UNKNOWN";
}
}
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::VoiceAssistantEvent>(enums::VoiceAssistantEvent value) { template<> const char *proto_enum_to_string<enums::VoiceAssistantEvent>(enums::VoiceAssistantEvent value) {
switch (value) { switch (value) {
case enums::VOICE_ASSISTANT_ERROR: case enums::VOICE_ASSISTANT_ERROR:
@ -430,6 +444,18 @@ template<> const char *proto_enum_to_string<enums::VoiceAssistantEvent>(enums::V
return "VOICE_ASSISTANT_TTS_START"; return "VOICE_ASSISTANT_TTS_START";
case enums::VOICE_ASSISTANT_TTS_END: case enums::VOICE_ASSISTANT_TTS_END:
return "VOICE_ASSISTANT_TTS_END"; return "VOICE_ASSISTANT_TTS_END";
case enums::VOICE_ASSISTANT_WAKE_WORD_START:
return "VOICE_ASSISTANT_WAKE_WORD_START";
case enums::VOICE_ASSISTANT_WAKE_WORD_END:
return "VOICE_ASSISTANT_WAKE_WORD_END";
case enums::VOICE_ASSISTANT_STT_VAD_START:
return "VOICE_ASSISTANT_STT_VAD_START";
case enums::VOICE_ASSISTANT_STT_VAD_END:
return "VOICE_ASSISTANT_STT_VAD_END";
case enums::VOICE_ASSISTANT_TTS_STREAM_START:
return "VOICE_ASSISTANT_TTS_STREAM_START";
case enums::VOICE_ASSISTANT_TTS_STREAM_END:
return "VOICE_ASSISTANT_TTS_STREAM_END";
default: default:
return "UNKNOWN"; return "UNKNOWN";
} }
@ -6344,6 +6370,56 @@ void SubscribeVoiceAssistantRequest::dump_to(std::string &out) const {
out.append("}"); out.append("}");
} }
#endif #endif
bool VoiceAssistantAudioSettings::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->noise_suppression_level = value.as_uint32();
return true;
}
case 2: {
this->auto_gain = value.as_uint32();
return true;
}
default:
return false;
}
}
bool VoiceAssistantAudioSettings::decode_32bit(uint32_t field_id, Proto32Bit value) {
switch (field_id) {
case 3: {
this->volume_multiplier = value.as_float();
return true;
}
default:
return false;
}
}
void VoiceAssistantAudioSettings::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(1, this->noise_suppression_level);
buffer.encode_uint32(2, this->auto_gain);
buffer.encode_float(3, this->volume_multiplier);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantAudioSettings::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantAudioSettings {\n");
out.append(" noise_suppression_level: ");
sprintf(buffer, "%" PRIu32, this->noise_suppression_level);
out.append(buffer);
out.append("\n");
out.append(" auto_gain: ");
sprintf(buffer, "%" PRIu32, this->auto_gain);
out.append(buffer);
out.append("\n");
out.append(" volume_multiplier: ");
sprintf(buffer, "%g", this->volume_multiplier);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) { switch (field_id) {
case 1: { case 1: {
@ -6351,7 +6427,7 @@ bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
return true; return true;
} }
case 3: { case 3: {
this->use_vad = value.as_bool(); this->flags = value.as_uint32();
return true; return true;
} }
default: default:
@ -6364,6 +6440,10 @@ bool VoiceAssistantRequest::decode_length(uint32_t field_id, ProtoLengthDelimite
this->conversation_id = value.as_string(); this->conversation_id = value.as_string();
return true; return true;
} }
case 4: {
this->audio_settings = value.as_message<VoiceAssistantAudioSettings>();
return true;
}
default: default:
return false; return false;
} }
@ -6371,7 +6451,8 @@ bool VoiceAssistantRequest::decode_length(uint32_t field_id, ProtoLengthDelimite
void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_bool(1, this->start); buffer.encode_bool(1, this->start);
buffer.encode_string(2, this->conversation_id); buffer.encode_string(2, this->conversation_id);
buffer.encode_bool(3, this->use_vad); buffer.encode_uint32(3, this->flags);
buffer.encode_message<VoiceAssistantAudioSettings>(4, this->audio_settings);
} }
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantRequest::dump_to(std::string &out) const { void VoiceAssistantRequest::dump_to(std::string &out) const {
@ -6385,8 +6466,13 @@ void VoiceAssistantRequest::dump_to(std::string &out) const {
out.append("'").append(this->conversation_id).append("'"); out.append("'").append(this->conversation_id).append("'");
out.append("\n"); out.append("\n");
out.append(" use_vad: "); out.append(" flags: ");
out.append(YESNO(this->use_vad)); sprintf(buffer, "%" PRIu32, this->flags);
out.append(buffer);
out.append("\n");
out.append(" audio_settings: ");
this->audio_settings.dump_to(out);
out.append("\n"); out.append("\n");
out.append("}"); out.append("}");
} }

View file

@ -165,6 +165,11 @@ enum BluetoothDeviceRequestType : uint32_t {
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5, BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5,
BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6, BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6,
}; };
enum VoiceAssistantRequestFlag : uint32_t {
VOICE_ASSISTANT_REQUEST_NONE = 0,
VOICE_ASSISTANT_REQUEST_USE_VAD = 1,
VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD = 2,
};
enum VoiceAssistantEvent : uint32_t { enum VoiceAssistantEvent : uint32_t {
VOICE_ASSISTANT_ERROR = 0, VOICE_ASSISTANT_ERROR = 0,
VOICE_ASSISTANT_RUN_START = 1, VOICE_ASSISTANT_RUN_START = 1,
@ -175,6 +180,12 @@ enum VoiceAssistantEvent : uint32_t {
VOICE_ASSISTANT_INTENT_END = 6, VOICE_ASSISTANT_INTENT_END = 6,
VOICE_ASSISTANT_TTS_START = 7, VOICE_ASSISTANT_TTS_START = 7,
VOICE_ASSISTANT_TTS_END = 8, VOICE_ASSISTANT_TTS_END = 8,
VOICE_ASSISTANT_WAKE_WORD_START = 9,
VOICE_ASSISTANT_WAKE_WORD_END = 10,
VOICE_ASSISTANT_STT_VAD_START = 11,
VOICE_ASSISTANT_STT_VAD_END = 12,
VOICE_ASSISTANT_TTS_STREAM_START = 98,
VOICE_ASSISTANT_TTS_STREAM_END = 99,
}; };
enum AlarmControlPanelState : uint32_t { enum AlarmControlPanelState : uint32_t {
ALARM_STATE_DISARMED = 0, ALARM_STATE_DISARMED = 0,
@ -1651,11 +1662,26 @@ class SubscribeVoiceAssistantRequest : public ProtoMessage {
protected: protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
class VoiceAssistantAudioSettings : public ProtoMessage {
public:
uint32_t noise_suppression_level{0};
uint32_t auto_gain{0};
float volume_multiplier{0.0f};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class VoiceAssistantRequest : public ProtoMessage { class VoiceAssistantRequest : public ProtoMessage {
public: public:
bool start{false}; bool start{false};
std::string conversation_id{}; std::string conversation_id{};
bool use_vad{false}; uint32_t flags{0};
VoiceAssistantAudioSettings audio_settings{};
void encode(ProtoWriteBuffer buffer) const override; void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override; void dump_to(std::string &out) const override;

View file

@ -1,13 +1,13 @@
#include "api_server.h" #include "api_server.h"
#include <cerrno>
#include "api_connection.h" #include "api_connection.h"
#include "esphome/components/network/util.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/util.h" #include "esphome/core/util.h"
#include "esphome/core/version.h" #include "esphome/core/version.h"
#include "esphome/core/hal.h"
#include "esphome/components/network/util.h"
#include <cerrno>
#ifdef USE_LOGGER #ifdef USE_LOGGER
#include "esphome/components/logger/logger.h" #include "esphome/components/logger/logger.h"
@ -323,16 +323,24 @@ void APIServer::on_shutdown() {
} }
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
bool APIServer::start_voice_assistant(const std::string &conversation_id, bool use_vad) { bool APIServer::start_voice_assistant(const std::string &conversation_id, uint32_t flags,
const api::VoiceAssistantAudioSettings &audio_settings) {
VoiceAssistantRequest msg;
msg.start = true;
msg.conversation_id = conversation_id;
msg.flags = flags;
msg.audio_settings = audio_settings;
for (auto &c : this->clients_) { for (auto &c : this->clients_) {
if (c->request_voice_assistant(true, conversation_id, use_vad)) if (c->request_voice_assistant(msg))
return true; return true;
} }
return false; return false;
} }
void APIServer::stop_voice_assistant() { void APIServer::stop_voice_assistant() {
VoiceAssistantRequest msg;
msg.start = false;
for (auto &c : this->clients_) { for (auto &c : this->clients_) {
if (c->request_voice_assistant(false, "", false)) if (c->request_voice_assistant(msg))
return; return;
} }
} }

View file

@ -1,16 +1,16 @@
#pragma once #pragma once
#include "api_noise_context.h"
#include "api_pb2.h"
#include "api_pb2_service.h"
#include "esphome/components/socket/socket.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/controller.h" #include "esphome/core/controller.h"
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/components/socket/socket.h"
#include "api_pb2.h"
#include "api_pb2_service.h"
#include "list_entities.h" #include "list_entities.h"
#include "subscribe_state.h" #include "subscribe_state.h"
#include "user_services.h" #include "user_services.h"
#include "api_noise_context.h"
#include <vector> #include <vector>
@ -81,7 +81,8 @@ class APIServer : public Component, public Controller {
#endif #endif
#ifdef USE_VOICE_ASSISTANT #ifdef USE_VOICE_ASSISTANT
bool start_voice_assistant(const std::string &conversation_id, bool use_vad); bool start_voice_assistant(const std::string &conversation_id, uint32_t flags,
const api::VoiceAssistantAudioSettings &audio_settings);
void stop_voice_assistant(); void stop_voice_assistant();
#endif #endif

View file

@ -8,6 +8,8 @@ from esphome.const import (
CONF_IRQ_PIN, CONF_IRQ_PIN,
CONF_LIGHTNING_THRESHOLD, CONF_LIGHTNING_THRESHOLD,
CONF_MASK_DISTURBER, CONF_MASK_DISTURBER,
CONF_CALIBRATION,
CONF_TUNE_ANTENNA,
CONF_NOISE_LEVEL, CONF_NOISE_LEVEL,
CONF_SPIKE_REJECTION, CONF_SPIKE_REJECTION,
CONF_WATCHDOG_THRESHOLD, CONF_WATCHDOG_THRESHOLD,
@ -34,6 +36,8 @@ AS3935_SCHEMA = cv.Schema(
cv.Optional(CONF_MASK_DISTURBER, default=False): cv.boolean, cv.Optional(CONF_MASK_DISTURBER, default=False): cv.boolean,
cv.Optional(CONF_DIV_RATIO, default=0): cv.one_of(0, 16, 32, 64, 128, int=True), cv.Optional(CONF_DIV_RATIO, default=0): cv.one_of(0, 16, 32, 64, 128, int=True),
cv.Optional(CONF_CAPACITANCE, default=0): cv.int_range(min=0, max=15), cv.Optional(CONF_CAPACITANCE, default=0): cv.int_range(min=0, max=15),
cv.Optional(CONF_TUNE_ANTENNA, default=False): cv.boolean,
cv.Optional(CONF_CALIBRATION, default=True): cv.boolean,
} }
) )
@ -51,3 +55,5 @@ async def setup_as3935(var, config):
cg.add(var.set_mask_disturber(config[CONF_MASK_DISTURBER])) cg.add(var.set_mask_disturber(config[CONF_MASK_DISTURBER]))
cg.add(var.set_div_ratio(config[CONF_DIV_RATIO])) cg.add(var.set_div_ratio(config[CONF_DIV_RATIO]))
cg.add(var.set_capacitance(config[CONF_CAPACITANCE])) cg.add(var.set_capacitance(config[CONF_CAPACITANCE]))
cg.add(var.set_tune_antenna(config[CONF_TUNE_ANTENNA]))
cg.add(var.set_calibration(config[CONF_CALIBRATION]))

View file

@ -21,6 +21,14 @@ void AS3935Component::setup() {
this->write_mask_disturber(this->mask_disturber_); this->write_mask_disturber(this->mask_disturber_);
this->write_div_ratio(this->div_ratio_); this->write_div_ratio(this->div_ratio_);
this->write_capacitance(this->capacitance_); this->write_capacitance(this->capacitance_);
// Handle setting up tuning or auto-calibration
if (this->tune_antenna_) {
ESP_LOGCONFIG(TAG, " Antenna tuning: ENABLED - lightning detection will not function in this mode");
this->tune_antenna();
} else if (this->calibration_) {
this->calibrate_oscillator();
}
} }
void AS3935Component::dump_config() { void AS3935Component::dump_config() {
@ -227,6 +235,87 @@ uint32_t AS3935Component::get_lightning_energy_() {
return pure_light; return pure_light;
} }
// REG0x03, bit [7:6], manufacturer default: 0 (16 division ratio).
// This function returns the current division ratio of the resonance frequency.
// The antenna resonance frequency should be within 3.5 percent of 500kHz, and
// so when modifying the resonance frequency with the internal capacitors
// (tuneCap()) it's important to keep in mind that the displayed frequency on
// the IRQ pin is divided by this number.
uint8_t AS3935Component::read_div_ratio() {
ESP_LOGV(TAG, "Calling read_div_ratio");
uint8_t reg_val = this->read_register_(INT_MASK_ANT, DIV_MASK);
reg_val >>= 6; // Front of the line.
if (reg_val == 0) {
return 16;
} else if (reg_val == 1) {
return 32;
} else if (reg_val == 2) {
return 64;
} else if (reg_val == 3) {
return 128;
}
ESP_LOGW(TAG, "Unknown response received for div_ratio");
return 0;
}
uint8_t AS3935Component::read_capacitance() {
ESP_LOGV(TAG, "Calling read_capacitance");
uint8_t reg_val = this->read_register_(FREQ_DISP_IRQ, CAP_MASK) * 8;
return (reg_val);
}
// REG0x08, bits [5,6,7], manufacturer default: 0.
// This will send the frequency of the oscillators to the IRQ pin.
// _osc 1, bit[5] = TRCO - System RCO at 32.768kHz
// _osc 2, bit[6] = SRCO - Timer RCO Oscillators 1.1MHz
// _osc 3, bit[7] = LCO - Frequency of the Antenna
void AS3935Component::display_oscillator(bool state, uint8_t osc) {
if ((osc < 1) || (osc > 3))
return;
this->write_register(FREQ_DISP_IRQ, OSC_MASK, state, 4 + osc);
}
// REG0x3D, bits[7:0]
// This function calibrates both internal oscillators The oscillators are tuned
// based on the resonance frequency of the antenna and so it should be trimmed
// before the calibration is done.
bool AS3935Component::calibrate_oscillator() {
ESP_LOGI(TAG, "Starting oscillators calibration...");
this->write_register(CALIB_RCO, WIPE_ALL, DIRECT_COMMAND, 0); // Send command to calibrate the oscillators
this->display_oscillator(true, 2);
delay(2); // Give time for the internal oscillators to start up.
this->display_oscillator(false, 2);
// Check it they were calibrated successfully.
uint8_t reg_val_srco = this->read_register_(CALIB_SRCO, CALIB_MASK_NOK);
uint8_t reg_val_trco = this->read_register_(CALIB_TRCO, CALIB_MASK_NOK);
// reg_val_srco &= CALIB_MASK;
// reg_val_srco >>= 6;
// reg_val_trco &= CALIB_MASK;
// reg_val_trco >>= 6;
if (!reg_val_srco && !reg_val_trco) { // Zero upon success
ESP_LOGI(TAG, "Calibration was succesful");
return true;
} else {
ESP_LOGW(TAG, "Calibration was NOT succesful");
return false;
}
}
void AS3935Component::tune_antenna() {
ESP_LOGI(TAG, "Starting antenna tuning...");
uint8_t div_ratio = this->read_div_ratio();
uint8_t tune_val = this->read_capacitance();
ESP_LOGI(TAG, "Division Ratio is set to: %d", div_ratio);
ESP_LOGI(TAG, "Internal Capacitor is set to: %d", tune_val);
ESP_LOGI(TAG, "Displaying oscillator on INT pin. Measure its frequency - multiply value by Division Ratio");
this->display_oscillator(true, ANTFREQ);
}
uint8_t AS3935Component::read_register_(uint8_t reg, uint8_t mask) { uint8_t AS3935Component::read_register_(uint8_t reg, uint8_t mask) {
uint8_t value = this->read_register(reg); uint8_t value = this->read_register(reg);
value &= (~mask); value &= (~mask);

View file

@ -13,6 +13,9 @@
namespace esphome { namespace esphome {
namespace as3935 { namespace as3935 {
static const uint8_t DIRECT_COMMAND = 0x96;
static const uint8_t ANTFREQ = 3;
enum AS3935RegisterNames { enum AS3935RegisterNames {
AFE_GAIN = 0x00, AFE_GAIN = 0x00,
THRESHOLD, THRESHOLD,
@ -30,6 +33,7 @@ enum AS3935RegisterNames {
}; };
enum AS3935RegisterMasks { enum AS3935RegisterMasks {
WIPE_ALL = 0x0,
GAIN_MASK = 0x3E, GAIN_MASK = 0x3E,
SPIKE_MASK = 0xF, SPIKE_MASK = 0xF,
IO_MASK = 0xC1, IO_MASK = 0xC1,
@ -44,6 +48,7 @@ enum AS3935RegisterMasks {
NOISE_FLOOR_MASK = 0x70, NOISE_FLOOR_MASK = 0x70,
OSC_MASK = 0xE0, OSC_MASK = 0xE0,
CALIB_MASK = 0x7F, CALIB_MASK = 0x7F,
CALIB_MASK_NOK = 0xBF,
DIV_MASK = 0x3F DIV_MASK = 0x3F
}; };
@ -90,6 +95,13 @@ class AS3935Component : public Component {
void write_div_ratio(uint8_t div_ratio); void write_div_ratio(uint8_t div_ratio);
void set_capacitance(uint8_t capacitance) { capacitance_ = capacitance; } void set_capacitance(uint8_t capacitance) { capacitance_ = capacitance; }
void write_capacitance(uint8_t capacitance); void write_capacitance(uint8_t capacitance);
uint8_t read_div_ratio();
uint8_t read_capacitance();
bool calibrate_oscillator();
void display_oscillator(bool state, uint8_t osc);
void tune_antenna();
void set_tune_antenna(bool tune_antenna) { tune_antenna_ = tune_antenna; }
void set_calibration(bool calibration) { calibration_ = calibration; }
protected: protected:
uint8_t read_interrupt_register_(); uint8_t read_interrupt_register_();
@ -112,6 +124,8 @@ class AS3935Component : public Component {
bool mask_disturber_; bool mask_disturber_;
uint8_t div_ratio_; uint8_t div_ratio_;
uint8_t capacitance_; uint8_t capacitance_;
bool tune_antenna_;
bool calibration_;
}; };
} // namespace as3935 } // namespace as3935

View file

@ -2,13 +2,19 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
from esphome.const import (
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_BK72XX,
PLATFORM_RTL87XX,
)
CODEOWNERS = ["@OttoWinter"] CODEOWNERS = ["@OttoWinter"]
CONFIG_SCHEMA = cv.All( CONFIG_SCHEMA = cv.All(
cv.Schema({}), cv.Schema({}),
cv.only_with_arduino, cv.only_with_arduino,
cv.only_on(["esp32", "esp8266", "bk72xx", "rtl87xx"]), cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX, PLATFORM_RTL87XX]),
) )

View file

@ -22,7 +22,7 @@ void binary_sensor::MultiClickTrigger::on_state_(bool state) {
// Start matching // Start matching
MultiClickTriggerEvent evt = this->timing_[0]; MultiClickTriggerEvent evt = this->timing_[0];
if (evt.state == state) { if (evt.state == state) {
ESP_LOGV(TAG, "START min=%u max=%u", evt.min_length, evt.max_length); ESP_LOGV(TAG, "START min=%" PRIu32 " max=%" PRIu32, evt.min_length, evt.max_length);
ESP_LOGV(TAG, "Multi Click: Starting multi click action!"); ESP_LOGV(TAG, "Multi Click: Starting multi click action!");
this->at_index_ = 1; this->at_index_ = 1;
if (this->timing_.size() == 1 && evt.max_length == 4294967294UL) { if (this->timing_.size() == 1 && evt.max_length == 4294967294UL) {
@ -51,15 +51,15 @@ void binary_sensor::MultiClickTrigger::on_state_(bool state) {
MultiClickTriggerEvent evt = this->timing_[*this->at_index_]; MultiClickTriggerEvent evt = this->timing_[*this->at_index_];
if (evt.max_length != 4294967294UL) { if (evt.max_length != 4294967294UL) {
ESP_LOGV(TAG, "A i=%u min=%u max=%u", *this->at_index_, evt.min_length, evt.max_length); // NOLINT ESP_LOGV(TAG, "A i=%u min=%" PRIu32 " max=%" PRIu32, *this->at_index_, evt.min_length, evt.max_length); // NOLINT
this->schedule_is_valid_(evt.min_length); this->schedule_is_valid_(evt.min_length);
this->schedule_is_not_valid_(evt.max_length); this->schedule_is_not_valid_(evt.max_length);
} else if (*this->at_index_ + 1 != this->timing_.size()) { } else if (*this->at_index_ + 1 != this->timing_.size()) {
ESP_LOGV(TAG, "B i=%u min=%u", *this->at_index_, evt.min_length); // NOLINT ESP_LOGV(TAG, "B i=%u min=%" PRIu32, *this->at_index_, evt.min_length); // NOLINT
this->cancel_timeout("is_not_valid"); this->cancel_timeout("is_not_valid");
this->schedule_is_valid_(evt.min_length); this->schedule_is_valid_(evt.min_length);
} else { } else {
ESP_LOGV(TAG, "C i=%u min=%u", *this->at_index_, evt.min_length); // NOLINT ESP_LOGV(TAG, "C i=%u min=%" PRIu32, *this->at_index_, evt.min_length); // NOLINT
this->is_valid_ = false; this->is_valid_ = false;
this->cancel_timeout("is_not_valid"); this->cancel_timeout("is_not_valid");
this->set_timeout("trigger", evt.min_length, [this]() { this->trigger_(); }); this->set_timeout("trigger", evt.min_length, [this]() { this->trigger_(); });
@ -68,7 +68,8 @@ void binary_sensor::MultiClickTrigger::on_state_(bool state) {
*this->at_index_ = *this->at_index_ + 1; *this->at_index_ = *this->at_index_ + 1;
} }
void binary_sensor::MultiClickTrigger::schedule_cooldown_() { void binary_sensor::MultiClickTrigger::schedule_cooldown_() {
ESP_LOGV(TAG, "Multi Click: Invalid length of press, starting cooldown of %u ms...", this->invalid_cooldown_); ESP_LOGV(TAG, "Multi Click: Invalid length of press, starting cooldown of %" PRIu32 " ms...",
this->invalid_cooldown_);
this->is_in_cooldown_ = true; this->is_in_cooldown_ = true;
this->set_timeout("cooldown", this->invalid_cooldown_, [this]() { this->set_timeout("cooldown", this->invalid_cooldown_, [this]() {
ESP_LOGV(TAG, "Multi Click: Cooldown ended, matching is now enabled again."); ESP_LOGV(TAG, "Multi Click: Cooldown ended, matching is now enabled again.");

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <cinttypes>
#include <utility> #include <utility>
#include <vector> #include <vector>

View file

@ -37,10 +37,14 @@ void BP1658CJ::loop() {
uint8_t data[12]; uint8_t data[12];
if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) { this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
// Off / Sleep
data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_STANDBY;
for (int i = 1; i < 12; i++) for (int i = 1; i < 12; i++)
data[i] = 0; data[i] = 0;
// First turn all channels off
data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_START_5CH;
this->write_buffer_(data, 12);
// Then sleep
data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_STANDBY;
this->write_buffer_(data, 12); this->write_buffer_(data, 12);
} else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && } else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
(this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) { (this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) {

View file

@ -17,12 +17,16 @@ static const uint8_t BP5758D_ADDR_START_2CH = 0b00100000;
static const uint8_t BP5758D_ADDR_START_5CH = 0b00110000; static const uint8_t BP5758D_ADDR_START_5CH = 0b00110000;
static const uint8_t BP5758D_ALL_DATA_CHANNEL_ENABLEMENT = 0b00011111; static const uint8_t BP5758D_ALL_DATA_CHANNEL_ENABLEMENT = 0b00011111;
static const uint8_t BP5758D_DELAY = 2;
void BP5758D::setup() { void BP5758D::setup() {
ESP_LOGCONFIG(TAG, "Setting up BP5758D Output Component..."); ESP_LOGCONFIG(TAG, "Setting up BP5758D Output Component...");
this->data_pin_->setup(); this->data_pin_->setup();
this->data_pin_->digital_write(false); this->data_pin_->digital_write(false);
delayMicroseconds(BP5758D_DELAY);
this->clock_pin_->setup(); this->clock_pin_->setup();
this->clock_pin_->digital_write(false); this->clock_pin_->digital_write(false);
delayMicroseconds(BP5758D_DELAY);
this->channel_current_.resize(5, 0); this->channel_current_.resize(5, 0);
this->pwm_amounts_.resize(5, 0); this->pwm_amounts_.resize(5, 0);
} }
@ -39,11 +43,11 @@ void BP5758D::loop() {
uint8_t data[17]; uint8_t data[17];
if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 && if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) { this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
for (int i = 1; i < 16; i++) for (int i = 1; i < 17; i++)
data[i] = 0; data[i] = 0;
// First turn all channels off // First turn all channels off
data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_3CH; data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_5CH;
this->write_buffer_(data, 17); this->write_buffer_(data, 17);
// Then sleep // Then sleep
data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY; data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY;
@ -123,28 +127,42 @@ void BP5758D::set_channel_value_(uint8_t channel, uint16_t value) {
void BP5758D::set_channel_current_(uint8_t channel, uint8_t current) { this->channel_current_[channel] = current; } void BP5758D::set_channel_current_(uint8_t channel, uint8_t current) { this->channel_current_[channel] = current; }
void BP5758D::write_bit_(bool value) { void BP5758D::write_bit_(bool value) {
this->clock_pin_->digital_write(false);
this->data_pin_->digital_write(value); this->data_pin_->digital_write(value);
delayMicroseconds(BP5758D_DELAY);
this->clock_pin_->digital_write(true); this->clock_pin_->digital_write(true);
delayMicroseconds(BP5758D_DELAY);
this->clock_pin_->digital_write(false);
delayMicroseconds(BP5758D_DELAY);
} }
void BP5758D::write_byte_(uint8_t data) { void BP5758D::write_byte_(uint8_t data) {
for (uint8_t mask = 0x80; mask; mask >>= 1) { for (uint8_t mask = 0x80; mask; mask >>= 1) {
this->write_bit_(data & mask); this->write_bit_(data & mask);
} }
this->clock_pin_->digital_write(false);
this->data_pin_->digital_write(true); // ack bit
this->data_pin_->pin_mode(gpio::FLAG_INPUT);
this->clock_pin_->digital_write(true); this->clock_pin_->digital_write(true);
delayMicroseconds(BP5758D_DELAY);
this->clock_pin_->digital_write(false);
delayMicroseconds(BP5758D_DELAY);
this->data_pin_->pin_mode(gpio::FLAG_OUTPUT);
} }
void BP5758D::write_buffer_(uint8_t *buffer, uint8_t size) { void BP5758D::write_buffer_(uint8_t *buffer, uint8_t size) {
this->data_pin_->digital_write(false); this->data_pin_->digital_write(false);
delayMicroseconds(BP5758D_DELAY);
this->clock_pin_->digital_write(false);
delayMicroseconds(BP5758D_DELAY);
for (uint32_t i = 0; i < size; i++) { for (uint32_t i = 0; i < size; i++) {
this->write_byte_(buffer[i]); this->write_byte_(buffer[i]);
} }
this->clock_pin_->digital_write(false);
this->clock_pin_->digital_write(true); this->clock_pin_->digital_write(true);
delayMicroseconds(BP5758D_DELAY);
this->data_pin_->digital_write(true); this->data_pin_->digital_write(true);
delayMicroseconds(BP5758D_DELAY);
} }
} // namespace bp5758d } // namespace bp5758d

View file

@ -16,9 +16,9 @@ void Canbus::setup() {
void Canbus::dump_config() { void Canbus::dump_config() {
if (this->use_extended_id_) { if (this->use_extended_id_) {
ESP_LOGCONFIG(TAG, "config extended id=0x%08x", this->can_id_); ESP_LOGCONFIG(TAG, "config extended id=0x%08" PRIx32, this->can_id_);
} else { } else {
ESP_LOGCONFIG(TAG, "config standard id=0x%03x", this->can_id_); ESP_LOGCONFIG(TAG, "config standard id=0x%03" PRIx32, this->can_id_);
} }
} }
@ -28,9 +28,11 @@ void Canbus::send_data(uint32_t can_id, bool use_extended_id, bool remote_transm
uint8_t size = static_cast<uint8_t>(data.size()); uint8_t size = static_cast<uint8_t>(data.size());
if (use_extended_id) { if (use_extended_id) {
ESP_LOGD(TAG, "send extended id=0x%08x rtr=%s size=%d", can_id, TRUEFALSE(remote_transmission_request), size); ESP_LOGD(TAG, "send extended id=0x%08" PRIx32 " rtr=%s size=%d", can_id, TRUEFALSE(remote_transmission_request),
size);
} else { } else {
ESP_LOGD(TAG, "send standard id=0x%03x rtr=%s size=%d", can_id, TRUEFALSE(remote_transmission_request), size); ESP_LOGD(TAG, "send standard id=0x%03" PRIx32 " rtr=%s size=%d", can_id, TRUEFALSE(remote_transmission_request),
size);
} }
if (size > CAN_MAX_DATA_LENGTH) if (size > CAN_MAX_DATA_LENGTH)
size = CAN_MAX_DATA_LENGTH; size = CAN_MAX_DATA_LENGTH;
@ -63,10 +65,10 @@ void Canbus::loop() {
while (this->read_message(&can_message) == canbus::ERROR_OK) { while (this->read_message(&can_message) == canbus::ERROR_OK) {
message_counter++; message_counter++;
if (can_message.use_extended_id) { if (can_message.use_extended_id) {
ESP_LOGD(TAG, "received can message (#%d) extended can_id=0x%x size=%d", message_counter, can_message.can_id, ESP_LOGD(TAG, "received can message (#%d) extended can_id=0x%" PRIx32 " size=%d", message_counter,
can_message.can_data_length_code); can_message.can_id, can_message.can_data_length_code);
} else { } else {
ESP_LOGD(TAG, "received can message (#%d) std can_id=0x%x size=%d", message_counter, can_message.can_id, ESP_LOGD(TAG, "received can message (#%d) std can_id=0x%" PRIx32 " size=%d", message_counter, can_message.can_id,
can_message.can_data_length_code); can_message.can_data_length_code);
} }

View file

@ -4,6 +4,7 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/optional.h" #include "esphome/core/optional.h"
#include <cinttypes>
#include <vector> #include <vector>
namespace esphome { namespace esphome {

View file

@ -2,7 +2,13 @@ import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import web_server_base from esphome.components import web_server_base
from esphome.components.web_server_base import CONF_WEB_SERVER_BASE_ID from esphome.components.web_server_base import CONF_WEB_SERVER_BASE_ID
from esphome.const import CONF_ID from esphome.const import (
CONF_ID,
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_BK72XX,
PLATFORM_RTL87XX,
)
from esphome.core import coroutine_with_priority, CORE from esphome.core import coroutine_with_priority, CORE
AUTO_LOAD = ["web_server_base"] AUTO_LOAD = ["web_server_base"]
@ -21,7 +27,7 @@ CONFIG_SCHEMA = cv.All(
), ),
} }
).extend(cv.COMPONENT_SCHEMA), ).extend(cv.COMPONENT_SCHEMA),
cv.only_on(["esp32", "esp8266", "bk72xx", "rtl87xx"]), cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX, PLATFORM_RTL87XX]),
) )

View file

@ -121,7 +121,7 @@ bool LgIrClimate::on_receive(remote_base::RemoteReceiveData data) {
} }
} }
ESP_LOGD(TAG, "Decoded 0x%02X", remote_state); ESP_LOGD(TAG, "Decoded 0x%02" PRIX32, remote_state);
if ((remote_state & 0xFF00000) != 0x8800000) if ((remote_state & 0xFF00000) != 0x8800000)
return false; return false;
@ -173,7 +173,7 @@ bool LgIrClimate::on_receive(remote_base::RemoteReceiveData data) {
} }
void LgIrClimate::transmit_(uint32_t value) { void LgIrClimate::transmit_(uint32_t value) {
calc_checksum_(value); calc_checksum_(value);
ESP_LOGD(TAG, "Sending climate_lg_ir code: 0x%02X", value); ESP_LOGD(TAG, "Sending climate_lg_ir code: 0x%02" PRIX32, value);
auto transmit = this->transmitter_->transmit(); auto transmit = this->transmitter_->transmit();
auto *data = transmit.get_data(); auto *data = transmit.get_data();

View file

@ -2,6 +2,8 @@
#include "esphome/components/climate_ir/climate_ir.h" #include "esphome/components/climate_ir/climate_ir.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace climate_ir_lg { namespace climate_ir_lg {

View file

@ -101,7 +101,7 @@ void CoolixClimate::transmit_state() {
} }
} }
} }
ESP_LOGV(TAG, "Sending coolix code: 0x%06X", remote_state); ESP_LOGV(TAG, "Sending coolix code: 0x%06" PRIX32, remote_state);
auto transmit = this->transmitter_->transmit(); auto transmit = this->transmitter_->transmit();
auto *data = transmit.get_data(); auto *data = transmit.get_data();
@ -115,7 +115,7 @@ bool CoolixClimate::on_coolix(climate::Climate *parent, remote_base::RemoteRecei
return false; return false;
// Decoded remote state y 3 bytes long code. // Decoded remote state y 3 bytes long code.
uint32_t remote_state = (*decoded).second; uint32_t remote_state = (*decoded).second;
ESP_LOGV(TAG, "Decoded 0x%06X", remote_state); ESP_LOGV(TAG, "Decoded 0x%06" PRIX32, remote_state);
if ((remote_state & 0xFF0000) != 0xB20000) if ((remote_state & 0xFF0000) != 0xB20000)
return false; return false;

View file

@ -2,6 +2,8 @@
#include "esphome/components/climate_ir/climate_ir.h" #include "esphome/components/climate_ir/climate_ir.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace coolix { namespace coolix {

View file

@ -86,7 +86,7 @@ void CS5460AComponent::hw_init_() {
} }
uint32_t status = this->read_register_(REG_STATUS); uint32_t status = this->read_register_(REG_STATUS);
ESP_LOGCONFIG(TAG, " Version: %x", (status >> 6) & 7); ESP_LOGCONFIG(TAG, " Version: %" PRIx32, (status >> 6) & 7);
this->write_register_(REG_CYCLE_COUNT, samples_); this->write_register_(REG_CYCLE_COUNT, samples_);
this->write_register_(REG_PULSE_RATE, lroundf(pulse_freq_ * 32.0f)); this->write_register_(REG_PULSE_RATE, lroundf(pulse_freq_ * 32.0f));
@ -323,7 +323,7 @@ void CS5460AComponent::dump_config() {
ESP_LOGCONFIG(TAG, " Init status: %s", ESP_LOGCONFIG(TAG, " Init status: %s",
state == COMPONENT_STATE_LOOP ? "OK" : (state == COMPONENT_STATE_FAILED ? "failed" : "other")); state == COMPONENT_STATE_LOOP ? "OK" : (state == COMPONENT_STATE_FAILED ? "failed" : "other"));
LOG_PIN(" CS Pin: ", cs_); LOG_PIN(" CS Pin: ", cs_);
ESP_LOGCONFIG(TAG, " Samples / cycle: %u", samples_); ESP_LOGCONFIG(TAG, " Samples / cycle: %" PRIu32, samples_);
ESP_LOGCONFIG(TAG, " Phase offset: %i", phase_offset_); 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, " PGA Gain: %s", pga_gain_ == CS5460A_PGA_GAIN_50X ? "50x" : "10x");
ESP_LOGCONFIG(TAG, " Current gain: %.5f", current_gain_); ESP_LOGCONFIG(TAG, " Current gain: %.5f", current_gain_);

View file

@ -5,6 +5,8 @@
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include "esphome/components/spi/spi.h" #include "esphome/components/spi/spi.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace cs5460a { namespace cs5460a {

View file

@ -14,6 +14,8 @@ from esphome.const import (
CONF_SLEEP_DURATION, CONF_SLEEP_DURATION,
CONF_TIME_ID, CONF_TIME_ID,
CONF_WAKEUP_PIN, CONF_WAKEUP_PIN,
PLATFORM_ESP32,
PLATFORM_ESP8266,
) )
from esphome.components.esp32 import get_esp32_variant from esphome.components.esp32 import get_esp32_variant
@ -165,34 +167,39 @@ WAKEUP_CAUSES_SCHEMA = cv.Schema(
} }
) )
CONFIG_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.All(
{ cv.Schema(
cv.GenerateID(): cv.declare_id(DeepSleepComponent), {
cv.Optional(CONF_RUN_DURATION): cv.Any( cv.GenerateID(): cv.declare_id(DeepSleepComponent),
cv.All(cv.only_on_esp32, WAKEUP_CAUSES_SCHEMA), cv.Optional(CONF_RUN_DURATION): cv.Any(
cv.positive_time_period_milliseconds, cv.All(cv.only_on_esp32, WAKEUP_CAUSES_SCHEMA),
), cv.positive_time_period_milliseconds,
cv.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds,
cv.Optional(CONF_WAKEUP_PIN): cv.All(
cv.only_on_esp32, pins.internal_gpio_input_pin_schema, validate_pin_number
),
cv.Optional(CONF_WAKEUP_PIN_MODE): cv.All(
cv.only_on_esp32, cv.enum(WAKEUP_PIN_MODES), upper=True
),
cv.Optional(CONF_ESP32_EXT1_WAKEUP): cv.All(
cv.only_on_esp32,
cv.Schema(
{
cv.Required(CONF_PINS): cv.ensure_list(
pins.internal_gpio_input_pin_schema, validate_pin_number
),
cv.Required(CONF_MODE): cv.enum(EXT1_WAKEUP_MODES, upper=True),
}
), ),
), cv.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds,
cv.Optional(CONF_TOUCH_WAKEUP): cv.All(cv.only_on_esp32, cv.boolean), cv.Optional(CONF_WAKEUP_PIN): cv.All(
} cv.only_on_esp32,
).extend(cv.COMPONENT_SCHEMA) pins.internal_gpio_input_pin_schema,
validate_pin_number,
),
cv.Optional(CONF_WAKEUP_PIN_MODE): cv.All(
cv.only_on_esp32, cv.enum(WAKEUP_PIN_MODES), upper=True
),
cv.Optional(CONF_ESP32_EXT1_WAKEUP): cv.All(
cv.only_on_esp32,
cv.Schema(
{
cv.Required(CONF_PINS): cv.ensure_list(
pins.internal_gpio_input_pin_schema, validate_pin_number
),
cv.Required(CONF_MODE): cv.enum(EXT1_WAKEUP_MODES, upper=True),
}
),
),
cv.Optional(CONF_TOUCH_WAKEUP): cv.All(cv.only_on_esp32, cv.boolean),
}
).extend(cv.COMPONENT_SCHEMA),
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266]),
)
async def to_code(config): async def to_code(config):

View file

@ -39,7 +39,7 @@ void DeepSleepComponent::setup() {
const optional<uint32_t> run_duration = get_run_duration_(); const optional<uint32_t> run_duration = get_run_duration_();
if (run_duration.has_value()) { if (run_duration.has_value()) {
ESP_LOGI(TAG, "Scheduling Deep Sleep to start in %u ms", *run_duration); ESP_LOGI(TAG, "Scheduling Deep Sleep to start in %" PRIu32 " ms", *run_duration);
this->set_timeout(*run_duration, [this]() { this->begin_sleep(); }); this->set_timeout(*run_duration, [this]() { this->begin_sleep(); });
} else { } else {
ESP_LOGD(TAG, "Not scheduling Deep Sleep, as no run duration is configured."); ESP_LOGD(TAG, "Not scheduling Deep Sleep, as no run duration is configured.");
@ -49,19 +49,20 @@ void DeepSleepComponent::dump_config() {
ESP_LOGCONFIG(TAG, "Setting up Deep Sleep..."); ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
if (this->sleep_duration_.has_value()) { if (this->sleep_duration_.has_value()) {
uint32_t duration = *this->sleep_duration_ / 1000; uint32_t duration = *this->sleep_duration_ / 1000;
ESP_LOGCONFIG(TAG, " Sleep Duration: %u ms", duration); ESP_LOGCONFIG(TAG, " Sleep Duration: %" PRIu32 " ms", duration);
} }
if (this->run_duration_.has_value()) { if (this->run_duration_.has_value()) {
ESP_LOGCONFIG(TAG, " Run Duration: %u ms", *this->run_duration_); ESP_LOGCONFIG(TAG, " Run Duration: %" PRIu32 " ms", *this->run_duration_);
} }
#ifdef USE_ESP32 #ifdef USE_ESP32
if (wakeup_pin_ != nullptr) { if (wakeup_pin_ != nullptr) {
LOG_PIN(" Wakeup Pin: ", this->wakeup_pin_); LOG_PIN(" Wakeup Pin: ", this->wakeup_pin_);
} }
if (this->wakeup_cause_to_run_duration_.has_value()) { if (this->wakeup_cause_to_run_duration_.has_value()) {
ESP_LOGCONFIG(TAG, " Default Wakeup Run Duration: %u ms", this->wakeup_cause_to_run_duration_->default_cause); ESP_LOGCONFIG(TAG, " Default Wakeup Run Duration: %" PRIu32 " ms",
ESP_LOGCONFIG(TAG, " Touch Wakeup Run Duration: %u ms", this->wakeup_cause_to_run_duration_->touch_cause); this->wakeup_cause_to_run_duration_->default_cause);
ESP_LOGCONFIG(TAG, " GPIO Wakeup Run Duration: %u ms", this->wakeup_cause_to_run_duration_->gpio_cause); ESP_LOGCONFIG(TAG, " Touch Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->touch_cause);
ESP_LOGCONFIG(TAG, " GPIO Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->gpio_cause);
} }
#endif #endif
} }

View file

@ -14,6 +14,8 @@
#include "esphome/core/time.h" #include "esphome/core/time.h"
#endif #endif
#include <cinttypes>
namespace esphome { namespace esphome {
namespace deep_sleep { namespace deep_sleep {

View file

@ -40,7 +40,6 @@ void E131Component::setup() {
this->mark_failed(); this->mark_failed();
return; return;
} }
server.ss_family = AF_INET;
err = this->socket_->bind((struct sockaddr *) &server, sizeof(server)); err = this->socket_->bind((struct sockaddr *) &server, sizeof(server));
if (err != 0) { if (err != 0) {

View file

@ -3,6 +3,7 @@
#include "esphome/components/socket/socket.h" #include "esphome/components/socket/socket.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include <cinttypes>
#include <map> #include <map>
#include <memory> #include <memory>
#include <set> #include <set>

View file

@ -57,8 +57,8 @@ bool E131AddressableLightEffect::process_(int universe, const E131Packet &packet
std::min(it->size(), std::min(output_offset + get_lights_per_universe(), output_offset + packet.count - 1)); std::min(it->size(), std::min(output_offset + get_lights_per_universe(), output_offset + packet.count - 1));
auto *input_data = packet.values + 1; auto *input_data = packet.values + 1;
ESP_LOGV(TAG, "Applying data for '%s' on %d universe, for %d-%d.", get_name().c_str(), universe, output_offset, ESP_LOGV(TAG, "Applying data for '%s' on %d universe, for %" PRId32 "-%d.", get_name().c_str(), universe,
output_end); output_offset, output_end);
switch (channels_) { switch (channels_) {
case E131_MONO: case E131_MONO:

View file

@ -25,6 +25,7 @@ from esphome.const import (
KEY_NAME, KEY_NAME,
KEY_TARGET_FRAMEWORK, KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM, KEY_TARGET_PLATFORM,
PLATFORM_ESP32,
TYPE_GIT, TYPE_GIT,
TYPE_LOCAL, TYPE_LOCAL,
__version__, __version__,
@ -62,7 +63,7 @@ AUTO_LOAD = ["preferences"]
def set_core_data(config): def set_core_data(config):
CORE.data[KEY_ESP32] = {} CORE.data[KEY_ESP32] = {}
CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = "esp32" CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_ESP32
conf = config[CONF_FRAMEWORK] conf = config[CONF_FRAMEWORK]
if conf[CONF_TYPE] == FRAMEWORK_ESP_IDF: if conf[CONF_TYPE] == FRAMEWORK_ESP_IDF:
CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "esp-idf" CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "esp-idf"

View file

@ -11,6 +11,7 @@ from esphome.const import (
CONF_OUTPUT, CONF_OUTPUT,
CONF_PULLDOWN, CONF_PULLDOWN,
CONF_PULLUP, CONF_PULLUP,
CONF_IGNORE_STRAPPING_WARNING,
) )
from esphome import pins from esphome import pins
from esphome.core import CORE from esphome.core import CORE
@ -176,6 +177,7 @@ ESP32_PIN_SCHEMA = cv.All(
} }
), ),
cv.Optional(CONF_INVERTED, default=False): cv.boolean, cv.Optional(CONF_INVERTED, default=False): cv.boolean,
cv.Optional(CONF_IGNORE_STRAPPING_WARNING, default=False): cv.boolean,
cv.Optional(CONF_DRIVE_STRENGTH, default="20mA"): cv.All( cv.Optional(CONF_DRIVE_STRENGTH, default="20mA"): cv.All(
cv.float_with_unit("current", "mA", optional_unit=True), cv.float_with_unit("current", "mA", optional_unit=True),
cv.enum(DRIVE_STRENGTHS), cv.enum(DRIVE_STRENGTHS),

View file

@ -9,6 +9,7 @@ from esphome.const import (
CONF_PULLUP, CONF_PULLUP,
) )
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.pins import check_strapping_pin
_ESP_SDIO_PINS = { _ESP_SDIO_PINS = {
@ -18,7 +19,7 @@ _ESP_SDIO_PINS = {
11: "Flash Command", 11: "Flash Command",
} }
_ESP32_STRAPPING_PINS = {0, 2, 4, 12, 15} _ESP32_STRAPPING_PINS = {0, 2, 5, 12, 15}
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -35,13 +36,6 @@ def esp32_validate_gpio_pin(value):
"flash interface in QUAD IO flash mode.", "flash interface in QUAD IO flash mode.",
value, value,
) )
if value in _ESP32_STRAPPING_PINS:
_LOGGER.warning(
"GPIO%d is a Strapping PIN and should be avoided.\n"
"Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n"
"See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins",
value,
)
if value in (24, 28, 29, 30, 31): if value in (24, 28, 29, 30, 31):
# These pins are not exposed in GPIO mux (reason unknown) # These pins are not exposed in GPIO mux (reason unknown)
# but they're missing from IO_MUX list in datasheet # but they're missing from IO_MUX list in datasheet
@ -74,4 +68,5 @@ def esp32_validate_supports(value):
f"GPIO{num} (34-39) does not support pulldowns.", [CONF_MODE, CONF_PULLDOWN] f"GPIO{num} (34-39) does not support pulldowns.", [CONF_MODE, CONF_PULLDOWN]
) )
check_strapping_pin(value, _ESP32_STRAPPING_PINS, _LOGGER)
return value return value

View file

@ -1,6 +1,7 @@
import logging import logging
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
from esphome.pins import check_strapping_pin
import esphome.config_validation as cv import esphome.config_validation as cv
@ -12,13 +13,6 @@ _LOGGER = logging.getLogger(__name__)
def esp32_c2_validate_gpio_pin(value): def esp32_c2_validate_gpio_pin(value):
if value < 0 or value > 20: if value < 0 or value > 20:
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-20)") raise cv.Invalid(f"Invalid pin number: {value} (must be 0-20)")
if value in _ESP32C2_STRAPPING_PINS:
_LOGGER.warning(
"GPIO%d is a Strapping PIN and should be avoided.\n"
"Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n"
"See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins",
value,
)
return value return value
@ -34,4 +28,6 @@ def esp32_c2_validate_supports(value):
if is_input: if is_input:
# All ESP32 pins support input mode # All ESP32 pins support input mode
pass pass
check_strapping_pin(value, _ESP32C2_STRAPPING_PINS, _LOGGER)
return value return value

View file

@ -6,6 +6,7 @@ from esphome.const import (
CONF_NUMBER, CONF_NUMBER,
) )
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.pins import check_strapping_pin
_ESP32C3_SPI_PSRAM_PINS = { _ESP32C3_SPI_PSRAM_PINS = {
12: "SPIHD", 12: "SPIHD",
@ -28,13 +29,6 @@ def esp32_c3_validate_gpio_pin(value):
raise cv.Invalid( raise cv.Invalid(
f"This pin cannot be used on ESP32-C3s and is already used by the SPI/PSRAM interface (function: {_ESP32C3_SPI_PSRAM_PINS[value]})" f"This pin cannot be used on ESP32-C3s and is already used by the SPI/PSRAM interface (function: {_ESP32C3_SPI_PSRAM_PINS[value]})"
) )
if value in _ESP32C3_STRAPPING_PINS:
_LOGGER.warning(
"GPIO%d is a Strapping PIN and should be avoided.\n"
"Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n"
"See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins",
value,
)
return value return value
@ -50,4 +44,6 @@ def esp32_c3_validate_supports(value):
if is_input: if is_input:
# All ESP32 pins support input mode # All ESP32 pins support input mode
pass pass
check_strapping_pin(value, _ESP32C3_STRAPPING_PINS, _LOGGER)
return value return value

View file

@ -3,6 +3,7 @@ import logging
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.pins import check_strapping_pin
_ESP32C6_SPI_PSRAM_PINS = { _ESP32C6_SPI_PSRAM_PINS = {
24: "SPICS0", 24: "SPICS0",
@ -26,13 +27,6 @@ def esp32_c6_validate_gpio_pin(value):
raise cv.Invalid( raise cv.Invalid(
f"This pin cannot be used on ESP32-C6s and is already used by the SPI/PSRAM interface (function: {_ESP32C6_SPI_PSRAM_PINS[value]})" f"This pin cannot be used on ESP32-C6s and is already used by the SPI/PSRAM interface (function: {_ESP32C6_SPI_PSRAM_PINS[value]})"
) )
if value in _ESP32C6_STRAPPING_PINS:
_LOGGER.warning(
"GPIO%d is a Strapping PIN and should be avoided.\n"
"Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n"
"See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins",
value,
)
return value return value
@ -47,4 +41,6 @@ def esp32_c6_validate_supports(value):
if is_input: if is_input:
# All ESP32 pins support input mode # All ESP32 pins support input mode
pass pass
check_strapping_pin(value, _ESP32C6_STRAPPING_PINS, _LOGGER)
return value return value

View file

@ -10,6 +10,7 @@ from esphome.const import (
) )
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.pins import check_strapping_pin
_ESP32S2_SPI_PSRAM_PINS = { _ESP32S2_SPI_PSRAM_PINS = {
26: "SPICS1", 26: "SPICS1",
@ -34,13 +35,6 @@ def esp32_s2_validate_gpio_pin(value):
raise cv.Invalid( raise cv.Invalid(
f"This pin cannot be used on ESP32-S2s and is already used by the SPI/PSRAM interface (function: {_ESP32S2_SPI_PSRAM_PINS[value]})" f"This pin cannot be used on ESP32-S2s and is already used by the SPI/PSRAM interface (function: {_ESP32S2_SPI_PSRAM_PINS[value]})"
) )
if value in _ESP32S2_STRAPPING_PINS:
_LOGGER.warning(
"GPIO%d is a Strapping PIN and should be avoided.\n"
"Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n"
"See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins",
value,
)
if value in (22, 23, 24, 25): if value in (22, 23, 24, 25):
# These pins are not exposed in GPIO mux (reason unknown) # These pins are not exposed in GPIO mux (reason unknown)
@ -77,4 +71,5 @@ def esp32_s2_validate_supports(value):
f"GPIO{num} does not support pulldowns.", [CONF_MODE, CONF_PULLDOWN] f"GPIO{num} does not support pulldowns.", [CONF_MODE, CONF_PULLDOWN]
) )
check_strapping_pin(value, _ESP32S2_STRAPPING_PINS, _LOGGER)
return value return value

View file

@ -7,6 +7,7 @@ from esphome.const import (
) )
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.pins import check_strapping_pin
_ESP_32S3_SPI_PSRAM_PINS = { _ESP_32S3_SPI_PSRAM_PINS = {
26: "SPICS1", 26: "SPICS1",
@ -45,14 +46,6 @@ def esp32_s3_validate_gpio_pin(value):
value, value,
) )
if value in _ESP_32S3_STRAPPING_PINS:
_LOGGER.warning(
"GPIO%d is a Strapping PIN and should be avoided.\n"
"Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n"
"See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins",
value,
)
if value in (22, 23, 24, 25): if value in (22, 23, 24, 25):
# These pins are not exposed in GPIO mux (reason unknown) # These pins are not exposed in GPIO mux (reason unknown)
# but they're missing from IO_MUX list in datasheet # but they're missing from IO_MUX list in datasheet
@ -71,4 +64,6 @@ def esp32_s3_validate_supports(value):
if is_input: if is_input:
# All ESP32 pins support input mode # All ESP32 pins support input mode
pass pass
check_strapping_pin(value, _ESP_32S3_STRAPPING_PINS, _LOGGER)
return value return value

View file

@ -2,9 +2,9 @@
#ifdef USE_ESP32 #ifdef USE_ESP32
#include "ble_uuid.h"
#include <cstring>
#include <cstdio> #include <cstdio>
#include <cstring>
#include "ble_uuid.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome {
@ -16,8 +16,8 @@ BLEAdvertising::BLEAdvertising() {
this->advertising_data_.set_scan_rsp = false; this->advertising_data_.set_scan_rsp = false;
this->advertising_data_.include_name = true; this->advertising_data_.include_name = true;
this->advertising_data_.include_txpower = true; this->advertising_data_.include_txpower = true;
this->advertising_data_.min_interval = 0x20; this->advertising_data_.min_interval = 0;
this->advertising_data_.max_interval = 0x40; this->advertising_data_.max_interval = 0;
this->advertising_data_.appearance = 0x00; this->advertising_data_.appearance = 0x00;
this->advertising_data_.manufacturer_len = 0; this->advertising_data_.manufacturer_len = 0;
this->advertising_data_.p_manufacturer_data = nullptr; this->advertising_data_.p_manufacturer_data = nullptr;
@ -42,6 +42,17 @@ void BLEAdvertising::remove_service_uuid(ESPBTUUID uuid) {
this->advertising_uuids_.end()); this->advertising_uuids_.end());
} }
void BLEAdvertising::set_service_data(const std::vector<uint8_t> &data) {
delete[] this->advertising_data_.p_service_data;
this->advertising_data_.p_service_data = nullptr;
this->advertising_data_.service_data_len = data.size();
if (!data.empty()) {
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
this->advertising_data_.p_service_data = new uint8_t[data.size()];
memcpy(this->advertising_data_.p_service_data, data.data(), data.size());
}
}
void BLEAdvertising::set_manufacturer_data(const std::vector<uint8_t> &data) { void BLEAdvertising::set_manufacturer_data(const std::vector<uint8_t> &data) {
delete[] this->advertising_data_.p_manufacturer_data; delete[] this->advertising_data_.p_manufacturer_data;
this->advertising_data_.p_manufacturer_data = nullptr; this->advertising_data_.p_manufacturer_data = nullptr;
@ -85,8 +96,6 @@ void BLEAdvertising::start() {
this->scan_response_data_.set_scan_rsp = true; this->scan_response_data_.set_scan_rsp = true;
this->scan_response_data_.include_name = true; this->scan_response_data_.include_name = true;
this->scan_response_data_.include_txpower = true; this->scan_response_data_.include_txpower = true;
this->scan_response_data_.min_interval = 0;
this->scan_response_data_.max_interval = 0;
this->scan_response_data_.manufacturer_len = 0; this->scan_response_data_.manufacturer_len = 0;
this->scan_response_data_.appearance = 0; this->scan_response_data_.appearance = 0;
this->scan_response_data_.flag = 0; this->scan_response_data_.flag = 0;

View file

@ -21,6 +21,7 @@ class BLEAdvertising {
void set_scan_response(bool scan_response) { this->scan_response_ = scan_response; } void set_scan_response(bool scan_response) { this->scan_response_ = scan_response; }
void set_min_preferred_interval(uint16_t interval) { this->advertising_data_.min_interval = interval; } void set_min_preferred_interval(uint16_t interval) { this->advertising_data_.min_interval = interval; }
void set_manufacturer_data(const std::vector<uint8_t> &data); void set_manufacturer_data(const std::vector<uint8_t> &data);
void set_service_data(const std::vector<uint8_t> &data);
void start(); void start();
void stop(); void stop();

View file

@ -90,6 +90,8 @@ void BLEService::stop() {
ESP_LOGE(TAG, "esp_ble_gatts_stop_service failed: %d", err); ESP_LOGE(TAG, "esp_ble_gatts_stop_service failed: %d", err);
return; return;
} }
esp32_ble::global_ble->get_advertising()->remove_service_uuid(this->uuid_);
esp32_ble::global_ble->get_advertising()->start();
this->running_state_ = STOPPING; this->running_state_ = STOPPING;
} }

View file

@ -7,11 +7,11 @@
#ifdef USE_ESP32 #ifdef USE_ESP32
#include <esp_bt_defs.h>
#include <esp_gap_ble_api.h> #include <esp_gap_ble_api.h>
#include <esp_gatt_defs.h> #include <esp_gatt_defs.h>
#include <esp_gattc_api.h> #include <esp_gattc_api.h>
#include <esp_gatts_api.h> #include <esp_gatts_api.h>
#include <esp_bt_defs.h>
namespace esphome { namespace esphome {
namespace esp32_ble_server { namespace esp32_ble_server {

View file

@ -4,7 +4,7 @@ from esphome.components import binary_sensor, output, esp32_ble_server
from esphome.const import CONF_ID from esphome.const import CONF_ID
AUTO_LOAD = ["binary_sensor", "output", "esp32_ble_server"] AUTO_LOAD = ["esp32_ble_server"]
CODEOWNERS = ["@jesserockz"] CODEOWNERS = ["@jesserockz"]
CONFLICTS_WITH = ["esp32_ble_beacon"] CONFLICTS_WITH = ["esp32_ble_beacon"]
DEPENDENCIES = ["wifi", "esp32"] DEPENDENCIES = ["wifi", "esp32"]
@ -36,6 +36,9 @@ CONFIG_SCHEMA = cv.Schema(
cv.Optional( cv.Optional(
CONF_AUTHORIZED_DURATION, default="1min" CONF_AUTHORIZED_DURATION, default="1min"
): cv.positive_time_period_milliseconds, ): cv.positive_time_period_milliseconds,
cv.Optional(
CONF_WIFI_TIMEOUT, default="1min"
): cv.positive_time_period_milliseconds,
} }
).extend(cv.COMPONENT_SCHEMA) ).extend(cv.COMPONENT_SCHEMA)
@ -53,6 +56,8 @@ async def to_code(config):
cg.add(var.set_identify_duration(config[CONF_IDENTIFY_DURATION])) cg.add(var.set_identify_duration(config[CONF_IDENTIFY_DURATION]))
cg.add(var.set_authorized_duration(config[CONF_AUTHORIZED_DURATION])) cg.add(var.set_authorized_duration(config[CONF_AUTHORIZED_DURATION]))
cg.add(var.set_wifi_timeout(config[CONF_WIFI_TIMEOUT]))
if CONF_AUTHORIZER in config and config[CONF_AUTHORIZER] is not None: if CONF_AUTHORIZER in config and config[CONF_AUTHORIZER] is not None:
activator = await cg.get_variable(config[CONF_AUTHORIZER]) activator = await cg.get_variable(config[CONF_AUTHORIZER])
cg.add(var.set_authorizer(activator)) cg.add(var.set_authorizer(activator))

View file

@ -18,6 +18,17 @@ ESP32ImprovComponent::ESP32ImprovComponent() { global_improv_component = this; }
void ESP32ImprovComponent::setup() { void ESP32ImprovComponent::setup() {
this->service_ = global_ble_server->create_service(improv::SERVICE_UUID, true); this->service_ = global_ble_server->create_service(improv::SERVICE_UUID, true);
this->setup_characteristics(); this->setup_characteristics();
#ifdef USE_BINARY_SENSOR
if (this->authorizer_ != nullptr) {
this->authorizer_->add_on_state_callback([this](bool state) {
if (state) {
this->authorized_start_ = millis();
this->identify_start_ = 0;
}
});
}
#endif
} }
void ESP32ImprovComponent::setup_characteristics() { void ESP32ImprovComponent::setup_characteristics() {
@ -50,8 +61,10 @@ void ESP32ImprovComponent::setup_characteristics() {
BLEDescriptor *capabilities_descriptor = new BLE2902(); BLEDescriptor *capabilities_descriptor = new BLE2902();
this->capabilities_->add_descriptor(capabilities_descriptor); this->capabilities_->add_descriptor(capabilities_descriptor);
uint8_t capabilities = 0x00; uint8_t capabilities = 0x00;
#ifdef USE_OUTPUT
if (this->status_indicator_ != nullptr) if (this->status_indicator_ != nullptr)
capabilities |= improv::CAPABILITY_IDENTIFY; capabilities |= improv::CAPABILITY_IDENTIFY;
#endif
this->capabilities_->set_value(capabilities); this->capabilities_->set_value(capabilities);
this->setup_complete_ = true; this->setup_complete_ = true;
} }
@ -63,8 +76,7 @@ void ESP32ImprovComponent::loop() {
switch (this->state_) { switch (this->state_) {
case improv::STATE_STOPPED: case improv::STATE_STOPPED:
if (this->status_indicator_ != nullptr) this->set_status_indicator_state_(false);
this->status_indicator_->turn_off();
if (this->service_->is_created() && this->should_start_ && this->setup_complete_) { if (this->service_->is_created() && this->should_start_ && this->setup_complete_) {
if (this->service_->is_running()) { if (this->service_->is_running()) {
@ -80,18 +92,22 @@ void ESP32ImprovComponent::loop() {
} }
break; break;
case improv::STATE_AWAITING_AUTHORIZATION: { case improv::STATE_AWAITING_AUTHORIZATION: {
if (this->authorizer_ == nullptr || this->authorizer_->state) { #ifdef USE_BINARY_SENSOR
if (this->authorizer_ == nullptr ||
(this->authorized_start_ != 0 && ((now - this->authorized_start_) < this->authorized_duration_))) {
this->set_state_(improv::STATE_AUTHORIZED); this->set_state_(improv::STATE_AUTHORIZED);
this->authorized_start_ = now; } else
} else { #else
if (this->status_indicator_ != nullptr) { this->set_state_(improv::STATE_AUTHORIZED);
if (!this->check_identify_()) #endif
this->status_indicator_->turn_on(); {
} if (!this->check_identify_())
this->set_status_indicator_state_(true);
} }
break; break;
} }
case improv::STATE_AUTHORIZED: { case improv::STATE_AUTHORIZED: {
#ifdef USE_BINARY_SENSOR
if (this->authorizer_ != nullptr) { if (this->authorizer_ != nullptr) {
if (now - this->authorized_start_ > this->authorized_duration_) { if (now - this->authorized_start_ > this->authorized_duration_) {
ESP_LOGD(TAG, "Authorization timeout"); ESP_LOGD(TAG, "Authorization timeout");
@ -99,25 +115,14 @@ void ESP32ImprovComponent::loop() {
return; return;
} }
} }
if (this->status_indicator_ != nullptr) { #endif
if (!this->check_identify_()) { if (!this->check_identify_()) {
if ((now % 1000) < 500) { this->set_status_indicator_state_((now % 1000) < 500);
this->status_indicator_->turn_on();
} else {
this->status_indicator_->turn_off();
}
}
} }
break; break;
} }
case improv::STATE_PROVISIONING: { case improv::STATE_PROVISIONING: {
if (this->status_indicator_ != nullptr) { this->set_status_indicator_state_((now % 200) < 100);
if ((now % 200) < 100) {
this->status_indicator_->turn_on();
} else {
this->status_indicator_->turn_off();
}
}
if (wifi::global_wifi_component->is_connected()) { if (wifi::global_wifi_component->is_connected()) {
wifi::global_wifi_component->save_wifi_sta(this->connecting_sta_.get_ssid(), wifi::global_wifi_component->save_wifi_sta(this->connecting_sta_.get_ssid(),
this->connecting_sta_.get_password()); this->connecting_sta_.get_password());
@ -142,13 +147,27 @@ void ESP32ImprovComponent::loop() {
} }
case improv::STATE_PROVISIONED: { case improv::STATE_PROVISIONED: {
this->incoming_data_.clear(); this->incoming_data_.clear();
if (this->status_indicator_ != nullptr) this->set_status_indicator_state_(false);
this->status_indicator_->turn_off();
break; break;
} }
} }
} }
void ESP32ImprovComponent::set_status_indicator_state_(bool state) {
#ifdef USE_OUTPUT
if (this->status_indicator_ == nullptr)
return;
if (this->status_indicator_state_ == state)
return;
this->status_indicator_state_ = state;
if (state) {
this->status_indicator_->turn_on();
} else {
this->status_indicator_->turn_off();
}
#endif
}
bool ESP32ImprovComponent::check_identify_() { bool ESP32ImprovComponent::check_identify_() {
uint32_t now = millis(); uint32_t now = millis();
@ -156,11 +175,7 @@ bool ESP32ImprovComponent::check_identify_() {
if (identify) { if (identify) {
uint32_t time = now % 1000; uint32_t time = now % 1000;
if (time < 600 && time % 200 < 100) { this->set_status_indicator_state_(time < 600 && time % 200 < 100);
this->status_indicator_->turn_on();
} else {
this->status_indicator_->turn_off();
}
} }
return identify; return identify;
} }
@ -174,6 +189,25 @@ void ESP32ImprovComponent::set_state_(improv::State state) {
if (state != improv::STATE_STOPPED) if (state != improv::STATE_STOPPED)
this->status_->notify(); this->status_->notify();
} }
std::vector<uint8_t> service_data(8, 0);
service_data[0] = 0x77; // PR
service_data[1] = 0x46; // IM
service_data[2] = static_cast<uint8_t>(state);
uint8_t capabilities = 0x00;
#ifdef USE_OUTPUT
if (this->status_indicator_ != nullptr)
capabilities |= improv::CAPABILITY_IDENTIFY;
#endif
service_data[3] = capabilities;
service_data[4] = 0x00; // Reserved
service_data[5] = 0x00; // Reserved
service_data[6] = 0x00; // Reserved
service_data[7] = 0x00; // Reserved
esp32_ble::global_ble->get_advertising()->set_service_data(service_data);
esp32_ble::global_ble->get_advertising()->start();
} }
void ESP32ImprovComponent::set_error_(improv::Error error) { void ESP32ImprovComponent::set_error_(improv::Error error) {
@ -213,8 +247,12 @@ float ESP32ImprovComponent::get_setup_priority() const { return setup_priority::
void ESP32ImprovComponent::dump_config() { void ESP32ImprovComponent::dump_config() {
ESP_LOGCONFIG(TAG, "ESP32 Improv:"); ESP_LOGCONFIG(TAG, "ESP32 Improv:");
#ifdef USE_BINARY_SENSOR
LOG_BINARY_SENSOR(" ", "Authorizer", this->authorizer_); LOG_BINARY_SENSOR(" ", "Authorizer", this->authorizer_);
#endif
#ifdef USE_OUTPUT
ESP_LOGCONFIG(TAG, " Status Indicator: '%s'", YESNO(this->status_indicator_ != nullptr)); ESP_LOGCONFIG(TAG, " Status Indicator: '%s'", YESNO(this->status_indicator_ != nullptr));
#endif
} }
void ESP32ImprovComponent::process_incoming_data_() { void ESP32ImprovComponent::process_incoming_data_() {
@ -273,8 +311,10 @@ void ESP32ImprovComponent::process_incoming_data_() {
void ESP32ImprovComponent::on_wifi_connect_timeout_() { void ESP32ImprovComponent::on_wifi_connect_timeout_() {
this->set_error_(improv::ERROR_UNABLE_TO_CONNECT); this->set_error_(improv::ERROR_UNABLE_TO_CONNECT);
this->set_state_(improv::STATE_AUTHORIZED); this->set_state_(improv::STATE_AUTHORIZED);
#ifdef USE_BINARY_SENSOR
if (this->authorizer_ != nullptr) if (this->authorizer_ != nullptr)
this->authorized_start_ = millis(); this->authorized_start_ = millis();
#endif
ESP_LOGW(TAG, "Timed out trying to connect to given WiFi network"); ESP_LOGW(TAG, "Timed out trying to connect to given WiFi network");
wifi::global_wifi_component->clear_sta(); wifi::global_wifi_component->clear_sta();
} }

View file

@ -1,14 +1,22 @@
#pragma once #pragma once
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/esp32_ble_server/ble_characteristic.h"
#include "esphome/components/esp32_ble_server/ble_server.h"
#include "esphome/components/output/binary_output.h"
#include "esphome/components/wifi/wifi_component.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/preferences.h" #include "esphome/core/preferences.h"
#include "esphome/components/esp32_ble_server/ble_characteristic.h"
#include "esphome/components/esp32_ble_server/ble_server.h"
#include "esphome/components/wifi/wifi_component.h"
#ifdef USE_BINARY_SENSOR
#include "esphome/components/binary_sensor/binary_sensor.h"
#endif
#ifdef USE_OUTPUT
#include "esphome/components/output/binary_output.h"
#endif
#include <vector> #include <vector>
#ifdef USE_ESP32 #ifdef USE_ESP32
@ -34,11 +42,18 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent {
void stop() override; void stop() override;
bool is_active() const { return this->state_ != improv::STATE_STOPPED; } bool is_active() const { return this->state_ != improv::STATE_STOPPED; }
#ifdef USE_BINARY_SENSOR
void set_authorizer(binary_sensor::BinarySensor *authorizer) { this->authorizer_ = authorizer; } void set_authorizer(binary_sensor::BinarySensor *authorizer) { this->authorizer_ = authorizer; }
#endif
#ifdef USE_OUTPUT
void set_status_indicator(output::BinaryOutput *status_indicator) { this->status_indicator_ = status_indicator; } void set_status_indicator(output::BinaryOutput *status_indicator) { this->status_indicator_ = status_indicator; }
#endif
void set_identify_duration(uint32_t identify_duration) { this->identify_duration_ = identify_duration; } void set_identify_duration(uint32_t identify_duration) { this->identify_duration_ = identify_duration; }
void set_authorized_duration(uint32_t authorized_duration) { this->authorized_duration_ = authorized_duration; } void set_authorized_duration(uint32_t authorized_duration) { this->authorized_duration_ = authorized_duration; }
void set_wifi_timeout(uint32_t wifi_timeout) { this->wifi_timeout_ = wifi_timeout; }
uint32_t get_wifi_timeout() const { return this->wifi_timeout_; }
protected: protected:
bool should_start_{false}; bool should_start_{false};
bool setup_complete_{false}; bool setup_complete_{false};
@ -48,6 +63,8 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent {
uint32_t authorized_start_{0}; uint32_t authorized_start_{0};
uint32_t authorized_duration_; uint32_t authorized_duration_;
uint32_t wifi_timeout_{};
std::vector<uint8_t> incoming_data_; std::vector<uint8_t> incoming_data_;
wifi::WiFiAP connecting_sta_; wifi::WiFiAP connecting_sta_;
@ -58,12 +75,19 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent {
BLECharacteristic *rpc_response_; BLECharacteristic *rpc_response_;
BLECharacteristic *capabilities_; BLECharacteristic *capabilities_;
#ifdef USE_BINARY_SENSOR
binary_sensor::BinarySensor *authorizer_{nullptr}; binary_sensor::BinarySensor *authorizer_{nullptr};
#endif
#ifdef USE_OUTPUT
output::BinaryOutput *status_indicator_{nullptr}; output::BinaryOutput *status_indicator_{nullptr};
#endif
improv::State state_{improv::STATE_STOPPED}; improv::State state_{improv::STATE_STOPPED};
improv::Error error_state_{improv::ERROR_NONE}; improv::Error error_state_{improv::ERROR_NONE};
bool status_indicator_state_{false};
void set_status_indicator_state_(bool state);
void set_state_(improv::State state); void set_state_(improv::State state);
void set_error_(improv::Error error); void set_error_(improv::Error error);
void send_response_(std::vector<uint8_t> &response); void send_response_(std::vector<uint8_t> &response);

View file

@ -11,6 +11,7 @@ from esphome.const import (
KEY_FRAMEWORK_VERSION, KEY_FRAMEWORK_VERSION,
KEY_TARGET_FRAMEWORK, KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM, KEY_TARGET_PLATFORM,
PLATFORM_ESP8266,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
import esphome.config_validation as cv import esphome.config_validation as cv
@ -38,7 +39,7 @@ AUTO_LOAD = ["preferences"]
def set_core_data(config): def set_core_data(config):
CORE.data[KEY_ESP8266] = {} CORE.data[KEY_ESP8266] = {}
CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = "esp8266" CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_ESP8266
CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "arduino" CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "arduino"
CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version.parse( CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version.parse(
config[CONF_FRAMEWORK][CONF_VERSION] config[CONF_FRAMEWORK][CONF_VERSION]

View file

@ -14,6 +14,7 @@ from esphome.const import (
CONF_SPEED_LEVEL_STATE_TOPIC, CONF_SPEED_LEVEL_STATE_TOPIC,
CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_COMMAND_TOPIC,
CONF_SPEED_STATE_TOPIC, CONF_SPEED_STATE_TOPIC,
CONF_OFF_SPEED_CYCLE,
CONF_ON_SPEED_SET, CONF_ON_SPEED_SET,
CONF_ON_TURN_OFF, CONF_ON_TURN_OFF,
CONF_ON_TURN_ON, CONF_ON_TURN_ON,
@ -217,10 +218,22 @@ async def fan_turn_on_to_code(config, action_id, template_arg, args):
return var return var
@automation.register_action("fan.cycle_speed", CycleSpeedAction, FAN_ACTION_SCHEMA) @automation.register_action(
"fan.cycle_speed",
CycleSpeedAction,
maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(Fan),
cv.Optional(CONF_OFF_SPEED_CYCLE, default=True): cv.boolean,
}
),
)
async def fan_cycle_speed_to_code(config, action_id, template_arg, args): async def fan_cycle_speed_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID]) paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren) var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_OFF_SPEED_CYCLE], args, bool)
cg.add(var.set_no_off_cycle(template_))
return var
@automation.register_condition( @automation.register_condition(

View file

@ -54,18 +54,26 @@ template<typename... Ts> class CycleSpeedAction : public Action<Ts...> {
public: public:
explicit CycleSpeedAction(Fan *state) : state_(state) {} explicit CycleSpeedAction(Fan *state) : state_(state) {}
TEMPLATABLE_VALUE(bool, no_off_cycle)
void play(Ts... x) override { void play(Ts... x) override {
// check to see if fan supports speeds and is on // check to see if fan supports speeds and is on
if (this->state_->get_traits().supported_speed_count()) { if (this->state_->get_traits().supported_speed_count()) {
if (this->state_->state) { if (this->state_->state) {
int speed = this->state_->speed + 1; int speed = this->state_->speed + 1;
int supported_speed_count = this->state_->get_traits().supported_speed_count(); int supported_speed_count = this->state_->get_traits().supported_speed_count();
if (speed > supported_speed_count) { bool off_speed_cycle = no_off_cycle_.value(x...);
// was running at max speed, so turn off if (speed > supported_speed_count && off_speed_cycle) {
// was running at max speed, off speed cycle enabled, so turn off
speed = 1; speed = 1;
auto call = this->state_->turn_off(); auto call = this->state_->turn_off();
call.set_speed(speed); call.set_speed(speed);
call.perform(); call.perform();
} else if (speed > supported_speed_count && !off_speed_cycle) {
// was running at max speed, off speed cycle disabled, so set to lowest speed
auto call = this->state_->turn_on();
call.set_speed(1);
call.perform();
} else { } else {
auto call = this->state_->turn_on(); auto call = this->state_->turn_on();
call.set_speed(speed); call.set_speed(speed);

View file

@ -8,12 +8,15 @@ from esphome.const import (
CONF_CHANNEL, CONF_CHANNEL,
CONF_SPEED, CONF_SPEED,
CONF_DIRECTION, CONF_DIRECTION,
CONF_ADDRESS,
) )
DEPENDENCIES = ["i2c"] DEPENDENCIES = ["i2c"]
CODEOWNERS = ["@max246"] CODEOWNERS = ["@max246"]
MULTI_CONF = True
grove_tb6612fng_ns = cg.esphome_ns.namespace("grove_tb6612fng") grove_tb6612fng_ns = cg.esphome_ns.namespace("grove_tb6612fng")
GROVE_TB6612FNG = grove_tb6612fng_ns.class_( GROVE_TB6612FNG = grove_tb6612fng_ns.class_(
"GroveMotorDriveTB6612FNG", cg.Component, i2c.I2CDevice "GroveMotorDriveTB6612FNG", cg.Component, i2c.I2CDevice
@ -33,6 +36,9 @@ GROVETB6612FNGMotorStandbyAction = grove_tb6612fng_ns.class_(
GROVETB6612FNGMotorNoStandbyAction = grove_tb6612fng_ns.class_( GROVETB6612FNGMotorNoStandbyAction = grove_tb6612fng_ns.class_(
"GROVETB6612FNGMotorNoStandbyAction", automation.Action "GROVETB6612FNGMotorNoStandbyAction", automation.Action
) )
GROVETB6612FNGMotorChangeAddressAction = grove_tb6612fng_ns.class_(
"GROVETB6612FNGMotorChangeAddressAction", automation.Action
)
DIRECTION_TYPE = { DIRECTION_TYPE = {
"FORWARD": 1, "FORWARD": 1,
@ -150,3 +156,22 @@ async def grove_tb6612fng_no_standby_to_code(config, action_id, template_arg, ar
await cg.register_parented(var, config[CONF_ID]) await cg.register_parented(var, config[CONF_ID])
return var return var
@automation.register_action(
"grove_tb6612fng.change_address",
GROVETB6612FNGMotorChangeAddressAction,
cv.Schema(
{
cv.Required(CONF_ID): cv.use_id(GROVE_TB6612FNG),
cv.Required(CONF_ADDRESS): cv.i2c_address,
}
),
)
async def grove_tb6612fng_change_address_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
template_channel = await cg.templatable(config[CONF_ADDRESS], args, int)
cg.add(var.set_address(template_channel))
return var

View file

@ -84,8 +84,7 @@ class GroveMotorDriveTB6612FNG : public Component, public i2c::I2CDevice {
*************************************************************/ *************************************************************/
void set_i2c_addr(uint8_t addr); void set_i2c_addr(uint8_t addr);
/************************************************************* /***********************************change_address
Description
Drive a motor. Drive a motor.
Parameter Parameter
chl: MOTOR_CHA or MOTOR_CHB chl: MOTOR_CHA or MOTOR_CHB
@ -204,5 +203,13 @@ class GROVETB6612FNGMotorNoStandbyAction : public Action<Ts...>, public Parented
void play(Ts... x) override { this->parent_->not_standby(); } void play(Ts... x) override { this->parent_->not_standby(); }
}; };
template<typename... Ts>
class GROVETB6612FNGMotorChangeAddressAction : public Action<Ts...>, public Parented<GroveMotorDriveTB6612FNG> {
public:
TEMPLATABLE_VALUE(uint8_t, address)
void play(Ts... x) override { this->parent_->set_i2c_addr(this->address_.value(x...)); }
};
} // namespace grove_tb6612fng } // namespace grove_tb6612fng
} // namespace esphome } // namespace esphome

View file

@ -38,7 +38,7 @@ void HLW8012Component::dump_config() {
LOG_PIN(" SEL Pin: ", this->sel_pin_) LOG_PIN(" SEL Pin: ", this->sel_pin_)
LOG_PIN(" CF Pin: ", this->cf_pin_) LOG_PIN(" CF Pin: ", this->cf_pin_)
LOG_PIN(" CF1 Pin: ", this->cf1_pin_) LOG_PIN(" CF1 Pin: ", this->cf1_pin_)
ESP_LOGCONFIG(TAG, " Change measurement mode every %u", this->change_mode_every_); ESP_LOGCONFIG(TAG, " Change measurement mode every %" PRIu32, this->change_mode_every_);
ESP_LOGCONFIG(TAG, " Current resistor: %.1f mΩ", this->current_resistor_ * 1000.0f); ESP_LOGCONFIG(TAG, " Current resistor: %.1f mΩ", this->current_resistor_ * 1000.0f);
ESP_LOGCONFIG(TAG, " Voltage Divider: %.1f", this->voltage_divider_); ESP_LOGCONFIG(TAG, " Voltage Divider: %.1f", this->voltage_divider_);
LOG_UPDATE_INTERVAL(this) LOG_UPDATE_INTERVAL(this)

View file

@ -5,6 +5,8 @@
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include "esphome/components/pulse_counter/pulse_counter_sensor.h" #include "esphome/components/pulse_counter/pulse_counter_sensor.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace hlw8012 { namespace hlw8012 {

View file

@ -3,6 +3,7 @@ from esphome.const import (
KEY_FRAMEWORK_VERSION, KEY_FRAMEWORK_VERSION,
KEY_TARGET_FRAMEWORK, KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM, KEY_TARGET_PLATFORM,
PLATFORM_HOST,
) )
from esphome.core import CORE from esphome.core import CORE
import esphome.config_validation as cv import esphome.config_validation as cv
@ -20,7 +21,7 @@ AUTO_LOAD = ["network"]
def set_core_data(config): def set_core_data(config):
CORE.data[KEY_HOST] = {} CORE.data[KEY_HOST] = {}
CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = "host" CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_HOST
CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "host" CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "host"
CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version(1, 0, 0) CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version(1, 0, 0)
return config return config

View file

@ -76,7 +76,7 @@ void HTU21DComponent::update() {
if (this->humidity_ != nullptr) if (this->humidity_ != nullptr)
this->humidity_->publish_state(humidity); this->humidity_->publish_state(humidity);
if (this->heater_ != nullptr) if (this->heater_ != nullptr)
this->heater_->publish_state(humidity); this->heater_->publish_state(heater_level);
this->status_clear_warning(); this->status_clear_warning();
} }

View file

@ -28,7 +28,7 @@ void HX711Sensor::update() {
uint32_t result; uint32_t result;
if (this->read_sensor_(&result)) { if (this->read_sensor_(&result)) {
int32_t value = static_cast<int32_t>(result); int32_t value = static_cast<int32_t>(result);
ESP_LOGD(TAG, "'%s': Got value %d", this->name_.c_str(), value); ESP_LOGD(TAG, "'%s': Got value %" PRId32, this->name_.c_str(), value);
this->publish_state(value); this->publish_state(value);
} }
} }

View file

@ -4,6 +4,8 @@
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace hx711 { namespace hx711 {

View file

@ -25,6 +25,10 @@ void HydreonRGxxComponent::dump_config() {
LOG_SENSOR(" ", #s, this->sensors_[i - 1]); \ LOG_SENSOR(" ", #s, this->sensors_[i - 1]); \
} }
HYDREON_RGXX_PROTOCOL_LIST(HYDREON_RGXX_LOG_SENSOR, ); HYDREON_RGXX_PROTOCOL_LIST(HYDREON_RGXX_LOG_SENSOR, );
if (this->model_ == RG9) {
ESP_LOGCONFIG(TAG, "disable_led: %s", TRUEFALSE(this->disable_led_));
}
} }
void HydreonRGxxComponent::setup() { void HydreonRGxxComponent::setup() {
@ -187,7 +191,20 @@ void HydreonRGxxComponent::process_line_() {
this->cancel_interval("reboot"); this->cancel_interval("reboot");
this->no_response_count_ = 0; this->no_response_count_ = 0;
ESP_LOGI(TAG, "Boot detected: %s", this->buffer_.substr(0, this->buffer_.size() - 2).c_str()); ESP_LOGI(TAG, "Boot detected: %s", this->buffer_.substr(0, this->buffer_.size() - 2).c_str());
this->write_str("P\nH\nM\n"); // set sensor to polling mode, high res mode, metric mode
if (this->model_ == RG15) {
this->write_str("P\nH\nM\n"); // set sensor to (P)polling mode, (H)high res mode, (M)metric mode
}
if (this->model_ == RG9) {
this->write_str("P\n"); // set sensor to (P)polling mode
if (this->disable_led_) {
this->write_str("D 1\n"); // set sensor (D 1)rain detection LED disabled
} else {
this->write_str("D 0\n"); // set sensor (D 0)rain detection LED enabled
}
}
return; return;
} }
if (this->buffer_starts_with_("SW")) { if (this->buffer_starts_with_("SW")) {
@ -227,7 +244,22 @@ void HydreonRGxxComponent::process_line_() {
if (n == std::string::npos) { if (n == std::string::npos) {
continue; continue;
} }
float data = strtof(this->buffer_.substr(n + strlen(PROTOCOL_NAMES[i])).c_str(), nullptr);
if (n == this->buffer_.find('t', n)) {
// The device temperature ('t') response contains both °C and °F values:
// "t 72F 22C".
// ESPHome uses only °C, only parse °C value (move past 'F').
n = this->buffer_.find('F', n);
if (n == std::string::npos) {
continue;
}
n += 1; // move past 'F'
} else {
n += strlen(PROTOCOL_NAMES[i]); // move past protocol name
}
// parse value, starting at str position n
float data = strtof(this->buffer_.substr(n).c_str(), nullptr);
this->sensors_[i]->publish_state(data); this->sensors_[i]->publish_state(data);
ESP_LOGD(TAG, "Received %s: %f", PROTOCOL_NAMES[i], this->sensors_[i]->get_raw_state()); ESP_LOGD(TAG, "Received %s: %f", PROTOCOL_NAMES[i], this->sensors_[i]->get_raw_state());
this->sensors_received_ |= (1 << i); this->sensors_received_ |= (1 << i);

View file

@ -49,6 +49,8 @@ class HydreonRGxxComponent : public PollingComponent, public uart::UARTDevice {
float get_setup_priority() const override; float get_setup_priority() const override;
void set_disable_led(bool disable_led) { this->disable_led_ = disable_led; }
protected: protected:
void process_line_(); void process_line_();
void schedule_reboot_(); void schedule_reboot_();
@ -72,6 +74,7 @@ class HydreonRGxxComponent : public PollingComponent, public uart::UARTDevice {
bool lens_bad_ = false; bool lens_bad_ = false;
bool em_sat_ = false; bool em_sat_ = false;
bool request_temperature_ = false; bool request_temperature_ = false;
bool disable_led_ = false;
// bit field showing which sensors we have received data for // bit field showing which sensors we have received data for
int sensors_received_ = -1; int sensors_received_ = -1;

View file

@ -25,12 +25,17 @@ CONF_EVENT_ACC = "event_acc"
CONF_TOTAL_ACC = "total_acc" CONF_TOTAL_ACC = "total_acc"
CONF_R_INT = "r_int" CONF_R_INT = "r_int"
CONF_DISABLE_LED = "disable_led"
RG_MODELS = { RG_MODELS = {
"RG_9": RGModel.RG9, "RG_9": RGModel.RG9,
"RG_15": RGModel.RG15, "RG_15": RGModel.RG15,
# https://rainsensors.com/wp-content/uploads/sites/3/2020/07/rg-15_instructions_sw_1.000.pdf # RG-15
# https://rainsensors.com/wp-content/uploads/sites/3/2021/03/2020.08.25-rg-9_instructions.pdf # 1.000 - https://rainsensors.com/wp-content/uploads/sites/3/2020/07/rg-15_instructions_sw_1.000.pdf
# https://rainsensors.com/wp-content/uploads/sites/3/2021/03/2021.03.11-rg-9_instructions.pdf # RG-9
# 1.000 - https://rainsensors.com/wp-content/uploads/sites/3/2021/03/2020.08.25-rg-9_instructions.pdf
# 1.100 - https://rainsensors.com/wp-content/uploads/sites/3/2021/03/2021.03.11-rg-9_instructions.pdf
# 1.200 - https://rainsensors.com/wp-content/uploads/sites/3/2022/03/2022.02.17-rev-1.200-rg-9_instructions.pdf
} }
SUPPORTED_SENSORS = { SUPPORTED_SENSORS = {
CONF_ACC: ["RG_15"], CONF_ACC: ["RG_15"],
@ -39,6 +44,7 @@ SUPPORTED_SENSORS = {
CONF_R_INT: ["RG_15"], CONF_R_INT: ["RG_15"],
CONF_MOISTURE: ["RG_9"], CONF_MOISTURE: ["RG_9"],
CONF_TEMPERATURE: ["RG_9"], CONF_TEMPERATURE: ["RG_9"],
CONF_DISABLE_LED: ["RG_9"],
} }
PROTOCOL_NAMES = { PROTOCOL_NAMES = {
CONF_MOISTURE: "R", CONF_MOISTURE: "R",
@ -105,6 +111,7 @@ CONFIG_SCHEMA = cv.All(
icon=ICON_THERMOMETER, icon=ICON_THERMOMETER,
state_class=STATE_CLASS_MEASUREMENT, state_class=STATE_CLASS_MEASUREMENT,
), ),
cv.Optional(CONF_DISABLE_LED): cv.boolean,
} }
) )
.extend(cv.polling_component_schema("60s")) .extend(cv.polling_component_schema("60s"))
@ -132,3 +139,6 @@ async def to_code(config):
cg.add(var.set_sensor(sens, i)) cg.add(var.set_sensor(sens, i))
cg.add(var.set_request_temperature(CONF_TEMPERATURE in config)) cg.add(var.set_request_temperature(CONF_TEMPERATURE in config))
if CONF_DISABLE_LED in config:
cg.add(var.set_disable_led(config[CONF_DISABLE_LED]))

View file

@ -17,7 +17,7 @@ void HYT271Component::dump_config() {
LOG_SENSOR(" ", "Humidity", this->humidity_); LOG_SENSOR(" ", "Humidity", this->humidity_);
} }
void HYT271Component::update() { void HYT271Component::update() {
uint8_t raw_data[4]; uint8_t raw_data[4] = {0, 0, 0, 0};
if (this->write(&raw_data[0], 0) != i2c::ERROR_OK) { if (this->write(&raw_data[0], 0) != i2c::ERROR_OK) {
this->status_set_warning(); this->status_set_warning();

View file

@ -12,6 +12,9 @@ from esphome.const import (
CONF_SDA, CONF_SDA,
CONF_ADDRESS, CONF_ADDRESS,
CONF_I2C_ID, CONF_I2C_ID,
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_RP2040,
) )
from esphome.core import coroutine_with_priority, CORE from esphome.core import coroutine_with_priority, CORE
@ -60,7 +63,7 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_SCAN, default=True): cv.boolean, cv.Optional(CONF_SCAN, default=True): cv.boolean,
} }
).extend(cv.COMPONENT_SCHEMA), ).extend(cv.COMPONENT_SCHEMA),
cv.only_on(["esp32", "esp8266", "rp2040"]), cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]),
) )

View file

@ -37,6 +37,8 @@ void I2SAudioMicrophone::setup() {
void I2SAudioMicrophone::start() { void I2SAudioMicrophone::start() {
if (this->is_failed()) if (this->is_failed())
return; return;
if (this->state_ == microphone::STATE_RUNNING)
return; // Already running
this->state_ = microphone::STATE_STARTING; this->state_ = microphone::STATE_STARTING;
} }
void I2SAudioMicrophone::start_() { void I2SAudioMicrophone::start_() {
@ -66,8 +68,9 @@ void I2SAudioMicrophone::start_() {
i2s_set_adc_mode(ADC_UNIT_1, this->adc_channel_); i2s_set_adc_mode(ADC_UNIT_1, this->adc_channel_);
i2s_adc_enable(this->parent_->get_port()); i2s_adc_enable(this->parent_->get_port());
} else { } else
#endif #endif
{
if (this->pdm_) if (this->pdm_)
config.mode = (i2s_mode_t) (config.mode | I2S_MODE_PDM); config.mode = (i2s_mode_t) (config.mode | I2S_MODE_PDM);
@ -77,9 +80,7 @@ void I2SAudioMicrophone::start_() {
pin_config.data_in_num = this->din_pin_; pin_config.data_in_num = this->din_pin_;
i2s_set_pin(this->parent_->get_port(), &pin_config); i2s_set_pin(this->parent_->get_port(), &pin_config);
#if SOC_I2S_SUPPORTS_ADC
} }
#endif
this->state_ = microphone::STATE_RUNNING; this->state_ = microphone::STATE_RUNNING;
this->high_freq_.start(); this->high_freq_.start();
} }
@ -110,6 +111,10 @@ size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) {
this->status_set_warning(); this->status_set_warning();
return 0; return 0;
} }
if (bytes_read == 0) {
this->status_set_warning();
return 0;
}
this->status_clear_warning(); this->status_clear_warning();
if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_16BIT) { if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_16BIT) {
return bytes_read; return bytes_read;

View file

@ -11,7 +11,7 @@
namespace esphome { namespace esphome {
namespace i2s_audio { namespace i2s_audio {
static const size_t BUFFER_COUNT = 10; static const size_t BUFFER_COUNT = 20;
static const char *const TAG = "i2s_audio.speaker"; static const char *const TAG = "i2s_audio.speaker";
@ -19,7 +19,7 @@ void I2SAudioSpeaker::setup() {
ESP_LOGCONFIG(TAG, "Setting up I2S Audio Speaker..."); ESP_LOGCONFIG(TAG, "Setting up I2S Audio Speaker...");
this->buffer_queue_ = xQueueCreate(BUFFER_COUNT, sizeof(DataEvent)); this->buffer_queue_ = xQueueCreate(BUFFER_COUNT, sizeof(DataEvent));
this->event_queue_ = xQueueCreate(20, sizeof(TaskEvent)); this->event_queue_ = xQueueCreate(BUFFER_COUNT, sizeof(TaskEvent));
} }
void I2SAudioSpeaker::start() { this->state_ = speaker::STATE_STARTING; } void I2SAudioSpeaker::start() { this->state_ = speaker::STATE_STARTING; }
@ -47,7 +47,7 @@ void I2SAudioSpeaker::player_task(void *params) {
.communication_format = I2S_COMM_FORMAT_STAND_I2S, .communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8, .dma_buf_count = 8,
.dma_buf_len = 1024, .dma_buf_len = 128,
.use_apll = false, .use_apll = false,
.tx_desc_auto_clear = true, .tx_desc_auto_clear = true,
.fixed_mclk = I2S_PIN_NO_CHANGE, .fixed_mclk = I2S_PIN_NO_CHANGE,
@ -60,7 +60,17 @@ void I2SAudioSpeaker::player_task(void *params) {
} }
#endif #endif
i2s_driver_install(this_speaker->parent_->get_port(), &config, 0, nullptr); esp_err_t err = i2s_driver_install(this_speaker->parent_->get_port(), &config, 0, nullptr);
if (err != ESP_OK) {
event.type = TaskEventType::WARNING;
event.err = err;
xQueueSend(this_speaker->event_queue_, &event, 0);
event.type = TaskEventType::STOPPED;
xQueueSend(this_speaker->event_queue_, &event, 0);
while (true) {
delay(10);
}
}
#if SOC_I2S_SUPPORTS_DAC #if SOC_I2S_SUPPORTS_DAC
if (this_speaker->internal_dac_mode_ == I2S_DAC_CHANNEL_DISABLE) { if (this_speaker->internal_dac_mode_ == I2S_DAC_CHANNEL_DISABLE) {
@ -88,9 +98,7 @@ void I2SAudioSpeaker::player_task(void *params) {
} }
if (data_event.stop) { if (data_event.stop) {
// Stop signal from main thread // Stop signal from main thread
while (xQueueReceive(this_speaker->buffer_queue_, &data_event, 0) == pdTRUE) { xQueueReset(this_speaker->buffer_queue_); // Flush queue
// Flush queue
}
break; break;
} }
size_t bytes_written; size_t bytes_written;
@ -103,7 +111,7 @@ void I2SAudioSpeaker::player_task(void *params) {
uint32_t sample = (buffer[current] << 16) | (buffer[current] & 0xFFFF); uint32_t sample = (buffer[current] << 16) | (buffer[current] & 0xFFFF);
esp_err_t err = i2s_write(this_speaker->parent_->get_port(), &sample, sizeof(sample), &bytes_written, esp_err_t err = i2s_write(this_speaker->parent_->get_port(), &sample, sizeof(sample), &bytes_written,
(100 / portTICK_PERIOD_MS)); (10 / portTICK_PERIOD_MS));
if (err != ESP_OK) { if (err != ESP_OK) {
event = {.type = TaskEventType::WARNING, .err = err}; event = {.type = TaskEventType::WARNING, .err = err};
xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY);
@ -122,7 +130,6 @@ void I2SAudioSpeaker::player_task(void *params) {
event.type = TaskEventType::STOPPING; event.type = TaskEventType::STOPPING;
xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY);
i2s_stop(this_speaker->parent_->get_port());
i2s_driver_uninstall(this_speaker->parent_->get_port()); i2s_driver_uninstall(this_speaker->parent_->get_port());
event.type = TaskEventType::STOPPED; event.type = TaskEventType::STOPPED;
@ -151,17 +158,24 @@ void I2SAudioSpeaker::watch_() {
if (xQueueReceive(this->event_queue_, &event, 0) == pdTRUE) { if (xQueueReceive(this->event_queue_, &event, 0) == pdTRUE) {
switch (event.type) { switch (event.type) {
case TaskEventType::STARTING: case TaskEventType::STARTING:
ESP_LOGD(TAG, "Starting I2S Audio Speaker");
break;
case TaskEventType::STARTED: case TaskEventType::STARTED:
ESP_LOGD(TAG, "Started I2S Audio Speaker");
break;
case TaskEventType::STOPPING: case TaskEventType::STOPPING:
ESP_LOGD(TAG, "Stopping I2S Audio Speaker");
break; break;
case TaskEventType::PLAYING: case TaskEventType::PLAYING:
this->status_clear_warning(); this->status_clear_warning();
break; break;
case TaskEventType::STOPPED: case TaskEventType::STOPPED:
this->parent_->unlock();
this->state_ = speaker::STATE_STOPPED; this->state_ = speaker::STATE_STOPPED;
vTaskDelete(this->player_task_handle_); vTaskDelete(this->player_task_handle_);
this->player_task_handle_ = nullptr; this->player_task_handle_ = nullptr;
this->parent_->unlock();
xQueueReset(this->buffer_queue_);
ESP_LOGD(TAG, "Stopped I2S Audio Speaker");
break; break;
case TaskEventType::WARNING: case TaskEventType::WARNING:
ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(event.err)); ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(event.err));
@ -177,9 +191,9 @@ void I2SAudioSpeaker::loop() {
this->start_(); this->start_();
break; break;
case speaker::STATE_RUNNING: case speaker::STATE_RUNNING:
case speaker::STATE_STOPPING:
this->watch_(); this->watch_();
break; break;
case speaker::STATE_STOPPING:
case speaker::STATE_STOPPED: case speaker::STATE_STOPPED:
break; break;
} }

View file

@ -54,6 +54,7 @@ COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE")
CONF_LED_PIN = "led_pin" CONF_LED_PIN = "led_pin"
CONF_COLOR_PALETTE_IMAGES = "color_palette_images" CONF_COLOR_PALETTE_IMAGES = "color_palette_images"
CONF_INVERT_DISPLAY = "invert_display"
def _validate(config): def _validate(config):
@ -100,6 +101,7 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_COLOR_PALETTE_IMAGES, default=[]): cv.ensure_list( cv.Optional(CONF_COLOR_PALETTE_IMAGES, default=[]): cv.ensure_list(
cv.file_ cv.file_
), ),
cv.Optional(CONF_INVERT_DISPLAY): cv.boolean,
} }
) )
.extend(cv.polling_component_schema("1s")) .extend(cv.polling_component_schema("1s"))
@ -176,3 +178,6 @@ async def to_code(config):
if rhs is not None: if rhs is not None:
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
cg.add(var.set_palette(prog_arr)) cg.add(var.set_palette(prog_arr))
if CONF_INVERT_DISPLAY in config:
cg.add(var.invert_display(config[CONF_INVERT_DISPLAY]))

View file

@ -12,11 +12,13 @@ static const char *const TAG = "ili9xxx";
void ILI9XXXDisplay::setup() { void ILI9XXXDisplay::setup() {
this->setup_pins_(); this->setup_pins_();
this->initialize(); this->initialize();
this->command(this->pre_invertdisplay_ ? ILI9XXX_INVON : ILI9XXX_INVOFF);
this->x_low_ = this->width_; this->x_low_ = this->width_;
this->y_low_ = this->height_; this->y_low_ = this->height_;
this->x_high_ = 0; this->x_high_ = 0;
this->y_high_ = 0; this->y_high_ = 0;
if (this->buffer_color_mode_ == BITS_16) { if (this->buffer_color_mode_ == BITS_16) {
this->init_internal_(this->get_buffer_length_() * 2); this->init_internal_(this->get_buffer_length_() * 2);
if (this->buffer_ != nullptr) { if (this->buffer_ != nullptr) {
@ -178,7 +180,7 @@ void ILI9XXXDisplay::display_() {
ESP_LOGV(TAG, ESP_LOGV(TAG,
"Start display(xlow:%d, ylow:%d, xhigh:%d, yhigh:%d, width:%d, " "Start display(xlow:%d, ylow:%d, xhigh:%d, yhigh:%d, width:%d, "
"heigth:%d, start_pos:%d)", "heigth:%d, start_pos:%" PRId32 ")",
this->x_low_, this->y_low_, this->x_high_, this->y_high_, w, h, start_pos); this->x_low_, this->y_low_, this->x_high_, this->y_high_, w, h, start_pos);
this->start_data_(); this->start_data_();
@ -333,7 +335,12 @@ void ILI9XXXDisplay::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t w, uint
this->command(ILI9XXX_RAMWR); // Write to RAM this->command(ILI9XXX_RAMWR); // Write to RAM
} }
void ILI9XXXDisplay::invert_display_(bool invert) { this->command(invert ? ILI9XXX_INVON : ILI9XXX_INVOFF); } void ILI9XXXDisplay::invert_display(bool invert) {
this->pre_invertdisplay_ = invert;
if (is_ready()) {
this->command(invert ? ILI9XXX_INVON : ILI9XXX_INVOFF);
}
}
int ILI9XXXDisplay::get_width_internal() { return this->width_; } int ILI9XXXDisplay::get_width_internal() { return this->width_; }
int ILI9XXXDisplay::get_height_internal() { return this->height_; } int ILI9XXXDisplay::get_height_internal() { return this->height_; }
@ -345,7 +352,7 @@ void ILI9XXXM5Stack::initialize() {
this->width_ = 320; this->width_ = 320;
if (this->height_ == 0) if (this->height_ == 0)
this->height_ = 240; this->height_ = 240;
this->invert_display_(true); this->pre_invertdisplay_ = true;
} }
// M5CORE display // Based on the configuration settings of M5stact's M5GFX code. // M5CORE display // Based on the configuration settings of M5stact's M5GFX code.
@ -355,7 +362,7 @@ void ILI9XXXM5CORE::initialize() {
this->width_ = 320; this->width_ = 320;
if (this->height_ == 0) if (this->height_ == 0)
this->height_ = 240; this->height_ = 240;
this->invert_display_(true); this->pre_invertdisplay_ = true;
} }
// 24_TFT display // 24_TFT display
@ -462,7 +469,7 @@ void ILI9XXXS3BoxLite::initialize() {
if (this->height_ == 0) { if (this->height_ == 0) {
this->height_ = 240; this->height_ = 240;
} }
this->invert_display_(true); this->pre_invertdisplay_ = true;
} }
} // namespace ili9xxx } // namespace ili9xxx

View file

@ -33,6 +33,7 @@ class ILI9XXXDisplay : public PollingComponent,
this->height_ = height; this->height_ = height;
this->width_ = width; this->width_ = width;
} }
void invert_display(bool invert);
void command(uint8_t value); void command(uint8_t value);
void data(uint8_t value); void data(uint8_t value);
void send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes); void send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes);
@ -55,7 +56,7 @@ class ILI9XXXDisplay : public PollingComponent,
void display_(); void display_();
void init_lcd_(const uint8_t *init_cmd); void init_lcd_(const uint8_t *init_cmd);
void set_addr_window_(uint16_t x, uint16_t y, uint16_t w, uint16_t h); void set_addr_window_(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
void invert_display_(bool invert);
void reset_(); void reset_();
int16_t width_{0}; ///< Display width as modified by current rotation int16_t width_{0}; ///< Display width as modified by current rotation
@ -88,6 +89,7 @@ class ILI9XXXDisplay : public PollingComponent,
bool prossing_update_ = false; bool prossing_update_ = false;
bool need_update_ = false; bool need_update_ = false;
bool is_18bitdisplay_ = false; bool is_18bitdisplay_ = false;
bool pre_invertdisplay_ = false;
}; };
//----------- M5Stack display -------------- //----------- M5Stack display --------------

View file

@ -1,6 +1,8 @@
#pragma once #pragma once
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace ili9xxx { namespace ili9xxx {

View file

@ -1,10 +1,14 @@
from esphome.components.logger import USB_CDC, USB_SERIAL_JTAG from esphome.components import improv_base
from esphome.components.esp32 import get_esp32_variant
from esphome.components.esp32.const import (
VARIANT_ESP32S3,
)
from esphome.components.logger import USB_CDC
from esphome.const import CONF_BAUD_RATE, CONF_HARDWARE_UART, CONF_ID, CONF_LOGGER from esphome.const import CONF_BAUD_RATE, CONF_HARDWARE_UART, CONF_ID, CONF_LOGGER
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.core import CORE from esphome.core import CORE
import esphome.final_validate as fv import esphome.final_validate as fv
from esphome.components import improv_base
AUTO_LOAD = ["improv_base"] AUTO_LOAD = ["improv_base"]
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
@ -30,7 +34,10 @@ def validate_logger(config):
if logger_conf[CONF_BAUD_RATE] == 0: if logger_conf[CONF_BAUD_RATE] == 0:
raise cv.Invalid("improv_serial requires the logger baud_rate to be not 0") raise cv.Invalid("improv_serial requires the logger baud_rate to be not 0")
if CORE.using_esp_idf: if CORE.using_esp_idf:
if logger_conf[CONF_HARDWARE_UART] in [USB_SERIAL_JTAG, USB_CDC]: if (
logger_conf[CONF_HARDWARE_UART] == USB_CDC
and get_esp32_variant() == VARIANT_ESP32S3
):
raise cv.Invalid( raise cv.Invalid(
"improv_serial does not support the selected logger hardware_uart" "improv_serial does not support the selected logger hardware_uart"
) )

View file

@ -31,26 +31,57 @@ void ImprovSerialComponent::setup() {
void ImprovSerialComponent::dump_config() { ESP_LOGCONFIG(TAG, "Improv Serial:"); } void ImprovSerialComponent::dump_config() { ESP_LOGCONFIG(TAG, "Improv Serial:"); }
int ImprovSerialComponent::available_() { optional<uint8_t> ImprovSerialComponent::read_byte_() {
optional<uint8_t> byte;
uint8_t data = 0;
#ifdef USE_ARDUINO #ifdef USE_ARDUINO
return this->hw_serial_->available(); if (this->hw_serial_->available()) {
this->hw_serial_->readBytes(&data, 1);
byte = data;
}
#endif #endif
#ifdef USE_ESP_IDF #ifdef USE_ESP_IDF
size_t available; switch (logger::global_logger->get_uart()) {
uart_get_buffered_data_len(this->uart_num_, &available); case logger::UART_SELECTION_UART0:
return available; case logger::UART_SELECTION_UART1:
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
!defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3)
case logger::UART_SELECTION_UART2:
#endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3
if (this->uart_num_ >= 0) {
size_t available;
uart_get_buffered_data_len(this->uart_num_, &available);
if (available) {
uart_read_bytes(this->uart_num_, &data, 1, 20 / portTICK_PERIOD_MS);
byte = data;
}
}
break;
#if defined(CONFIG_ESP_CONSOLE_USB_CDC) && (defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3))
case logger::UART_SELECTION_USB_CDC:
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
if (esp_usb_console_available_for_read()) {
#else
if (esp_usb_console_read_available()) {
#endif #endif
} esp_usb_console_read_buf((char *) &data, 1);
byte = data;
uint8_t ImprovSerialComponent::read_byte_() { }
uint8_t data; break;
#ifdef USE_ARDUINO #endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
this->hw_serial_->readBytes(&data, 1); #if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3)
case logger::UART_SELECTION_USB_SERIAL_JTAG: {
if (usb_serial_jtag_read_bytes((char *) &data, 1, 20 / portTICK_PERIOD_MS)) {
byte = data;
}
break;
}
#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32S3
default:
break;
}
#endif #endif
#ifdef USE_ESP_IDF return byte;
uart_read_bytes(this->uart_num_, &data, 1, 20 / portTICK_PERIOD_MS);
#endif
return data;
} }
void ImprovSerialComponent::write_data_(std::vector<uint8_t> &data) { void ImprovSerialComponent::write_data_(std::vector<uint8_t> &data) {
@ -59,24 +90,49 @@ void ImprovSerialComponent::write_data_(std::vector<uint8_t> &data) {
this->hw_serial_->write(data.data(), data.size()); this->hw_serial_->write(data.data(), data.size());
#endif #endif
#ifdef USE_ESP_IDF #ifdef USE_ESP_IDF
uart_write_bytes(this->uart_num_, data.data(), data.size()); switch (logger::global_logger->get_uart()) {
case logger::UART_SELECTION_UART0:
case logger::UART_SELECTION_UART1:
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
!defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3)
case logger::UART_SELECTION_UART2:
#endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3
uart_write_bytes(this->uart_num_, data.data(), data.size());
break;
#if defined(CONFIG_ESP_CONSOLE_USB_CDC) && (defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3))
case logger::UART_SELECTION_USB_CDC: {
const char *msg = (char *) data.data();
esp_usb_console_write_buf(msg, data.size());
break;
}
#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3)
case logger::UART_SELECTION_USB_SERIAL_JTAG:
usb_serial_jtag_write_bytes((char *) data.data(), data.size(), 20 / portTICK_PERIOD_MS);
break;
#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32S3
default:
break;
}
#endif #endif
} }
void ImprovSerialComponent::loop() { void ImprovSerialComponent::loop() {
const uint32_t now = millis(); if (this->last_read_byte_ && (millis() - this->last_read_byte_ > IMPROV_SERIAL_TIMEOUT)) {
if (now - this->last_read_byte_ > 50) { this->last_read_byte_ = 0;
this->rx_buffer_.clear(); this->rx_buffer_.clear();
this->last_read_byte_ = now; ESP_LOGV(TAG, "Improv Serial timeout");
} }
while (this->available_()) { auto byte = this->read_byte_();
uint8_t byte = this->read_byte_(); while (byte.has_value()) {
if (this->parse_improv_serial_byte_(byte)) { if (this->parse_improv_serial_byte_(byte.value())) {
this->last_read_byte_ = now; this->last_read_byte_ = millis();
} else { } else {
this->last_read_byte_ = 0;
this->rx_buffer_.clear(); this->rx_buffer_.clear();
} }
byte = this->read_byte_();
} }
if (this->state_ == improv::STATE_PROVISIONING) { if (this->state_ == improv::STATE_PROVISIONING) {

View file

@ -14,6 +14,13 @@
#endif #endif
#ifdef USE_ESP_IDF #ifdef USE_ESP_IDF
#include <driver/uart.h> #include <driver/uart.h>
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \
defined(USE_ESP32_VARIANT_ESP32H2)
#include <driver/usb_serial_jtag.h>
#endif
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
#include <esp_private/usb_console.h>
#endif
#endif #endif
namespace esphome { namespace esphome {
@ -26,6 +33,7 @@ enum ImprovSerialType : uint8_t {
TYPE_RPC_RESPONSE = 0x04 TYPE_RPC_RESPONSE = 0x04
}; };
static const uint16_t IMPROV_SERIAL_TIMEOUT = 100;
static const uint8_t IMPROV_SERIAL_VERSION = 1; static const uint8_t IMPROV_SERIAL_VERSION = 1;
class ImprovSerialComponent : public Component, public improv_base::ImprovBase { class ImprovSerialComponent : public Component, public improv_base::ImprovBase {
@ -48,8 +56,7 @@ class ImprovSerialComponent : public Component, public improv_base::ImprovBase {
std::vector<uint8_t> build_rpc_settings_response_(improv::Command command); std::vector<uint8_t> build_rpc_settings_response_(improv::Command command);
std::vector<uint8_t> build_version_info_(); std::vector<uint8_t> build_version_info_();
int available_(); optional<uint8_t> read_byte_();
uint8_t read_byte_();
void write_data_(std::vector<uint8_t> &data); void write_data_(std::vector<uint8_t> &data);
#ifdef USE_ARDUINO #ifdef USE_ARDUINO

View file

@ -122,7 +122,7 @@ void INA219Component::setup() {
this->calibration_lsb_ = lsb; this->calibration_lsb_ = lsb;
auto calibration = uint32_t(0.04096f / (0.000001 * lsb * this->shunt_resistance_ohm_)); auto calibration = uint32_t(0.04096f / (0.000001 * lsb * this->shunt_resistance_ohm_));
ESP_LOGV(TAG, " Using LSB=%u calibration=%u", lsb, calibration); ESP_LOGV(TAG, " Using LSB=%" PRIu32 " calibration=%" PRIu32, lsb, calibration);
if (!this->write_byte_16(INA219_REGISTER_CALIBRATION, calibration)) { if (!this->write_byte_16(INA219_REGISTER_CALIBRATION, calibration)) {
this->mark_failed(); this->mark_failed();
return; return;

View file

@ -4,6 +4,8 @@
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h" #include "esphome/components/i2c/i2c.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace ina219 { namespace ina219 {

View file

@ -12,6 +12,8 @@ from esphome.const import (
ENTITY_CATEGORY_DIAGNOSTIC, ENTITY_CATEGORY_DIAGNOSTIC,
KEY_CORE, KEY_CORE,
KEY_FRAMEWORK_VERSION, KEY_FRAMEWORK_VERSION,
PLATFORM_ESP32,
PLATFORM_RP2040,
) )
from esphome.core import CORE from esphome.core import CORE
@ -49,7 +51,7 @@ CONFIG_SCHEMA = cv.All(
state_class=STATE_CLASS_MEASUREMENT, state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC, entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
).extend(cv.polling_component_schema("60s")), ).extend(cv.polling_component_schema("60s")),
cv.only_on(["esp32", "rp2040"]), cv.only_on([PLATFORM_ESP32, PLATFORM_RP2040]),
validate_config, validate_config,
) )

View file

@ -251,7 +251,7 @@ async def component_to_code(config):
# setup board config # setup board config
cg.add_platformio_option("board", config[CONF_BOARD]) cg.add_platformio_option("board", config[CONF_BOARD])
cg.add_build_flag("-DUSE_LIBRETINY") cg.add_build_flag("-DUSE_LIBRETINY")
cg.add_build_flag(f"-DUSE_{config[CONF_COMPONENT_ID]}") cg.add_build_flag(f"-DUSE_{config[CONF_COMPONENT_ID].upper()}")
cg.add_build_flag(f"-DUSE_LIBRETINY_VARIANT_{config[CONF_FAMILY]}") cg.add_build_flag(f"-DUSE_LIBRETINY_VARIANT_{config[CONF_FAMILY]}")
cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_define("ESPHOME_BOARD", config[CONF_BOARD])
cg.add_define("ESPHOME_VARIANT", FAMILY_FRIENDLY[config[CONF_FAMILY]]) cg.add_define("ESPHOME_VARIANT", FAMILY_FRIENDLY[config[CONF_FAMILY]])

View file

@ -3,8 +3,21 @@
#ifdef USE_ESP_IDF #ifdef USE_ESP_IDF
#include <driver/uart.h> #include <driver/uart.h>
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \
defined(USE_ESP32_VARIANT_ESP32H2)
#include <driver/usb_serial_jtag.h>
#include <esp_vfs_dev.h>
#include <esp_vfs_usb_serial_jtag.h>
#endif
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "esp_idf_version.h" #include "esp_idf_version.h"
#include <cstdint>
#include <cstdio>
#include <fcntl.h>
#endif // USE_ESP_IDF #endif // USE_ESP_IDF
#if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_ESP_IDF) #if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_ESP_IDF)
@ -93,6 +106,58 @@ void Logger::log_vprintf_(int level, const char *tag, int line, const __FlashStr
} }
#endif #endif
#ifdef USE_ESP_IDF
void Logger::init_uart_() {
uart_config_t uart_config{};
uart_config.baud_rate = (int) baud_rate_;
uart_config.data_bits = UART_DATA_8_BITS;
uart_config.parity = UART_PARITY_DISABLE;
uart_config.stop_bits = UART_STOP_BITS_1;
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
uart_config.source_clk = UART_SCLK_DEFAULT;
#endif
uart_param_config(this->uart_num_, &uart_config);
const int uart_buffer_size = tx_buffer_size_;
// Install UART driver using an event queue here
uart_driver_install(this->uart_num_, uart_buffer_size, uart_buffer_size, 10, nullptr, 0);
}
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
void Logger::init_usb_cdc_() {}
#endif
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \
defined(USE_ESP32_VARIANT_ESP32H2)
void Logger::init_usb_serial_jtag_() {
setvbuf(stdin, NULL, _IONBF, 0); // Disable buffering on stdin
// Minicom, screen, idf_monitor send CR when ENTER key is pressed
esp_vfs_dev_usb_serial_jtag_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
// Move the caret to the beginning of the next line on '\n'
esp_vfs_dev_usb_serial_jtag_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
// Enable non-blocking mode on stdin and stdout
fcntl(fileno(stdout), F_SETFL, 0);
fcntl(fileno(stdin), F_SETFL, 0);
usb_serial_jtag_driver_config_t usb_serial_jtag_config{};
usb_serial_jtag_config.rx_buffer_size = 512;
usb_serial_jtag_config.tx_buffer_size = 512;
esp_err_t ret = ESP_OK;
// Install USB-SERIAL-JTAG driver for interrupt-driven reads and writes
ret = usb_serial_jtag_driver_install(&usb_serial_jtag_config);
if (ret != ESP_OK) {
return;
}
// Tell vfs to use usb-serial-jtag driver
esp_vfs_usb_serial_jtag_use_driver();
}
#endif
#endif
int HOT Logger::level_for(const char *tag) { int HOT Logger::level_for(const char *tag) {
// Uses std::vector<> for low memory footprint, though the vector // Uses std::vector<> for low memory footprint, though the vector
// could be sorted to minimize lookup times. This feature isn't used that // could be sorted to minimize lookup times. This feature isn't used that
@ -120,19 +185,19 @@ void HOT Logger::log_message_(int level, const char *tag, int offset) {
#ifdef USE_ESP_IDF #ifdef USE_ESP_IDF
if ( if (
#if defined(USE_ESP32_VARIANT_ESP32S2) #if defined(USE_ESP32_VARIANT_ESP32S2)
uart_ == UART_SELECTION_USB_CDC this->uart_ == UART_SELECTION_USB_CDC
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) #elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2)
uart_ == UART_SELECTION_USB_SERIAL_JTAG this->uart_ == UART_SELECTION_USB_SERIAL_JTAG
#elif defined(USE_ESP32_VARIANT_ESP32S3) #elif defined(USE_ESP32_VARIANT_ESP32S3)
uart_ == UART_SELECTION_USB_CDC || uart_ == UART_SELECTION_USB_SERIAL_JTAG this->uart_ == UART_SELECTION_USB_CDC || this->uart_ == UART_SELECTION_USB_SERIAL_JTAG
#else #else
/* DISABLES CODE */ (false) // NOLINT /* DISABLES CODE */ (false) // NOLINT
#endif #endif
) { ) {
puts(msg); puts(msg);
} else { } else {
uart_write_bytes(uart_num_, msg, strlen(msg)); uart_write_bytes(this->uart_num_, msg, strlen(msg));
uart_write_bytes(uart_num_, "\n", 1); uart_write_bytes(this->uart_num_, "\n", 1);
} }
#endif #endif
} }
@ -209,48 +274,38 @@ void Logger::pre_setup() {
} }
#endif // USE_ARDUINO #endif // USE_ARDUINO
#ifdef USE_ESP_IDF #ifdef USE_ESP_IDF
uart_num_ = UART_NUM_0; this->uart_num_ = UART_NUM_0;
switch (uart_) { switch (this->uart_) {
case UART_SELECTION_UART0: case UART_SELECTION_UART0:
uart_num_ = UART_NUM_0; this->uart_num_ = UART_NUM_0;
break; break;
case UART_SELECTION_UART1: case UART_SELECTION_UART1:
uart_num_ = UART_NUM_1; this->uart_num_ = UART_NUM_1;
break; break;
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ #if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
!defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) && !defined(USE_ESP32_VARIANT_ESP32H2) !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) && !defined(USE_ESP32_VARIANT_ESP32H2)
case UART_SELECTION_UART2: case UART_SELECTION_UART2:
uart_num_ = UART_NUM_2; this->uart_num_ = UART_NUM_2;
break; break;
#endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 && #endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 &&
// !USE_ESP32_VARIANT_ESP32H2 // !USE_ESP32_VARIANT_ESP32H2
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
case UART_SELECTION_USB_CDC: case UART_SELECTION_USB_CDC:
uart_num_ = -1; this->uart_num_ = -1;
this->init_usb_cdc_();
break; break;
#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 #endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \ #if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \
defined(USE_ESP32_VARIANT_ESP32H2) defined(USE_ESP32_VARIANT_ESP32H2)
case UART_SELECTION_USB_SERIAL_JTAG: case UART_SELECTION_USB_SERIAL_JTAG:
uart_num_ = -1; this->uart_num_ = -1;
this->init_usb_serial_jtag_();
break; break;
#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32S3 || #endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32S3 ||
// USE_ESP32_VARIANT_ESP32H2 // USE_ESP32_VARIANT_ESP32H2
} }
if (uart_num_ >= 0) { if (this->uart_num_ >= 0) {
uart_config_t uart_config{}; this->init_uart_();
uart_config.baud_rate = (int) baud_rate_;
uart_config.data_bits = UART_DATA_8_BITS;
uart_config.parity = UART_PARITY_DISABLE;
uart_config.stop_bits = UART_STOP_BITS_1;
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
uart_config.source_clk = UART_SCLK_DEFAULT;
#endif
uart_param_config(uart_num_, &uart_config);
const int uart_buffer_size = tx_buffer_size_;
// Install UART driver using an event queue here
uart_driver_install(uart_num_, uart_buffer_size, uart_buffer_size, 10, nullptr, 0);
} }
#endif // USE_ESP_IDF #endif // USE_ESP_IDF
} }

View file

@ -107,6 +107,16 @@ class Logger : public Component {
#endif #endif
protected: protected:
#ifdef USE_ESP_IDF
void init_uart_();
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
void init_usb_cdc_();
#endif
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \
defined(USE_ESP32_VARIANT_ESP32H2)
void init_usb_serial_jtag_();
#endif
#endif
void write_header_(int level, const char *tag, int line); void write_header_(int level, const char *tag, int line);
void write_footer_(); void write_footer_();
void log_message_(int level, const char *tag, int offset = 0); void log_message_(int level, const char *tag, int offset = 0);

View file

@ -47,7 +47,7 @@ void MAX31855Sensor::read_data_() {
if (mem != 0xFFFFFFFF) { if (mem != 0xFFFFFFFF) {
this->status_clear_error(); this->status_clear_error();
} else { } else {
ESP_LOGE(TAG, "No data received from MAX31855 (0x%08X). Check wiring!", mem); ESP_LOGE(TAG, "No data received from MAX31855 (0x%08" PRIX32 "). Check wiring!", mem);
this->publish_state(NAN); this->publish_state(NAN);
if (this->temperature_reference_) { if (this->temperature_reference_) {
this->temperature_reference_->publish_state(NAN); this->temperature_reference_->publish_state(NAN);
@ -69,25 +69,25 @@ void MAX31855Sensor::read_data_() {
// Check thermocouple faults // Check thermocouple faults
if (mem & 0x00000001) { if (mem & 0x00000001) {
ESP_LOGW(TAG, "Thermocouple open circuit (not connected) fault from MAX31855 (0x%08X)", mem); ESP_LOGW(TAG, "Thermocouple open circuit (not connected) fault from MAX31855 (0x%08" PRIX32 ")", mem);
this->publish_state(NAN); this->publish_state(NAN);
this->status_set_warning(); this->status_set_warning();
return; return;
} }
if (mem & 0x00000002) { if (mem & 0x00000002) {
ESP_LOGW(TAG, "Thermocouple short circuit to ground fault from MAX31855 (0x%08X)", mem); ESP_LOGW(TAG, "Thermocouple short circuit to ground fault from MAX31855 (0x%08" PRIX32 ")", mem);
this->publish_state(NAN); this->publish_state(NAN);
this->status_set_warning(); this->status_set_warning();
return; return;
} }
if (mem & 0x00000004) { if (mem & 0x00000004) {
ESP_LOGW(TAG, "Thermocouple short circuit to VCC fault from MAX31855 (0x%08X)", mem); ESP_LOGW(TAG, "Thermocouple short circuit to VCC fault from MAX31855 (0x%08" PRIX32 ")", mem);
this->publish_state(NAN); this->publish_state(NAN);
this->status_set_warning(); this->status_set_warning();
return; return;
} }
if (mem & 0x00010000) { if (mem & 0x00010000) {
ESP_LOGW(TAG, "Got faulty reading from MAX31855 (0x%08X)", mem); ESP_LOGW(TAG, "Got faulty reading from MAX31855 (0x%08" PRIX32 ")", mem);
this->publish_state(NAN); this->publish_state(NAN);
this->status_set_warning(); this->status_set_warning();
return; return;

View file

@ -4,6 +4,8 @@
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include "esphome/components/spi/spi.h" #include "esphome/components/spi/spi.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace max31855 { namespace max31855 {

View file

@ -188,7 +188,7 @@ uint32_t MAX31856Sensor::read_register24_(uint8_t reg) {
ESP_LOGVV(TAG, "read_byte lsb=0x%02X", lsb); ESP_LOGVV(TAG, "read_byte lsb=0x%02X", lsb);
this->disable(); this->disable();
const uint32_t value((msb << 16) | (mid << 8) | lsb); const uint32_t value((msb << 16) | (mid << 8) | lsb);
ESP_LOGV(TAG, "read_register_24_ reg=0x%02X: value=0x%06X", reg, value); ESP_LOGV(TAG, "read_register_24_ reg=0x%02X: value=0x%06" PRIX32, reg, value);
return value; return value;
} }

View file

@ -4,6 +4,8 @@
#include "esphome/components/spi/spi.h" #include "esphome/components/spi/spi.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace max31856 { namespace max31856 {

View file

@ -45,8 +45,8 @@ void MitsubishiClimate::transmit_state() {
remote_state[7] = (uint8_t) roundf(clamp<float>(this->target_temperature, MITSUBISHI_TEMP_MIN, MITSUBISHI_TEMP_MAX) - remote_state[7] = (uint8_t) roundf(clamp<float>(this->target_temperature, MITSUBISHI_TEMP_MIN, MITSUBISHI_TEMP_MAX) -
MITSUBISHI_TEMP_MIN); MITSUBISHI_TEMP_MIN);
ESP_LOGV(TAG, "Sending Mitsubishi target temp: %.1f state: %02X mode: %02X temp: %02X", this->target_temperature, ESP_LOGV(TAG, "Sending Mitsubishi target temp: %.1f state: %02" PRIX32 " mode: %02" PRIX32 " temp: %02" PRIX32,
remote_state[5], remote_state[6], remote_state[7]); this->target_temperature, remote_state[5], remote_state[6], remote_state[7]);
// Checksum // Checksum
for (int i = 0; i < 17; i++) { for (int i = 0; i < 17; i++) {

View file

@ -2,6 +2,8 @@
#include "esphome/components/climate_ir/climate_ir.h" #include "esphome/components/climate_ir/climate_ir.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace mitsubishi { namespace mitsubishi {

View file

@ -43,6 +43,9 @@ from esphome.const import (
CONF_USE_ABBREVIATIONS, CONF_USE_ABBREVIATIONS,
CONF_USERNAME, CONF_USERNAME,
CONF_WILL_MESSAGE, CONF_WILL_MESSAGE,
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_BK72XX,
) )
from esphome.core import coroutine_with_priority, CORE from esphome.core import coroutine_with_priority, CORE
from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.components.esp32 import add_idf_sdkconfig_option
@ -250,7 +253,7 @@ CONFIG_SCHEMA = cv.All(
} }
), ),
validate_config, validate_config,
cv.only_on(["esp32", "esp8266", "bk72xx"]), cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX]),
) )

View file

@ -19,9 +19,7 @@ class MQTTBackendLibreTiny final : public MQTTBackend {
void set_will(const char *topic, uint8_t qos, bool retain, const char *payload) final { void set_will(const char *topic, uint8_t qos, bool retain, const char *payload) final {
mqtt_client_.setWill(topic, qos, retain, payload); mqtt_client_.setWill(topic, qos, retain, payload);
} }
void set_server(network::IPAddress ip, uint16_t port) final { void set_server(network::IPAddress ip, uint16_t port) final { mqtt_client_.setServer(IPAddress(ip), port); }
mqtt_client_.setServer(IPAddress(static_cast<uint32_t>(ip)), port);
}
void set_server(const char *host, uint16_t port) final { mqtt_client_.setServer(host, port); } void set_server(const char *host, uint16_t port) final { mqtt_client_.setServer(host, port); }
#if ASYNC_TCP_SSL_ENABLED #if ASYNC_TCP_SSL_ENABLED
void set_secure(bool secure) { mqtt_client.setSecure(secure); } void set_secure(bool secure) { mqtt_client.setSecure(secure); }

View file

@ -34,7 +34,12 @@ struct IPAddress {
} }
IPAddress(const ip_addr_t *other_ip) { ip_addr_copy(ip_addr_, *other_ip); } IPAddress(const ip_addr_t *other_ip) { ip_addr_copy(ip_addr_, *other_ip); }
IPAddress(const std::string &in_address) { ipaddr_aton(in_address.c_str(), &ip_addr_); } IPAddress(const std::string &in_address) { ipaddr_aton(in_address.c_str(), &ip_addr_); }
IPAddress(ip4_addr_t *other_ip) { memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip4_addr_t)); } IPAddress(ip4_addr_t *other_ip) {
memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip4_addr_t));
#if USE_ESP32
ip_addr_.type = IPADDR_TYPE_V4;
#endif
}
#if USE_ARDUINO #if USE_ARDUINO
IPAddress(const arduino_ns::IPAddress &other_ip) { ip_addr_set_ip4_u32(&ip_addr_, other_ip); } IPAddress(const arduino_ns::IPAddress &other_ip) { ip_addr_set_ip4_u32(&ip_addr_, other_ip); }
#endif #endif
@ -87,7 +92,7 @@ struct IPAddress {
bool is_ip6() { return IP_IS_V6(&ip_addr_); } bool is_ip6() { return IP_IS_V6(&ip_addr_); }
std::string str() const { return ipaddr_ntoa(&ip_addr_); } std::string str() const { return ipaddr_ntoa(&ip_addr_); }
bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); } bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
bool operator!=(const IPAddress &other) const { return !(&ip_addr_ == &other.ip_addr_); } bool operator!=(const IPAddress &other) const { return !ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
IPAddress &operator+=(uint8_t increase) { IPAddress &operator+=(uint8_t increase) {
if (IP_IS_V4(&ip_addr_)) { if (IP_IS_V4(&ip_addr_)) {
#if LWIP_IPV6 #if LWIP_IPV6

View file

@ -61,6 +61,11 @@ bool Nextion::check_connect_() {
std::string response; std::string response;
this->recv_ret_string_(response, 0, false); this->recv_ret_string_(response, 0, false);
if (!response.empty() && response[0] == 0x1A) {
// Swallow invalid variable name responses that may be caused by the above commands
ESP_LOGD(TAG, "0x1A error ignored during setup");
return false;
}
if (response.empty() || response.find("comok") == std::string::npos) { if (response.empty() || response.find("comok") == std::string::npos) {
#ifdef NEXTION_PROTOCOL_LOG #ifdef NEXTION_PROTOCOL_LOG
ESP_LOGN(TAG, "Bad connect request %s", response.c_str()); ESP_LOGN(TAG, "Bad connect request %s", response.c_str());

View file

@ -10,15 +10,11 @@ static const char *const TAG = "nextion";
void Nextion::soft_reset() { this->send_command_("rest"); } void Nextion::soft_reset() { this->send_command_("rest"); }
void Nextion::set_wake_up_page(uint8_t page_id) { void Nextion::set_wake_up_page(uint8_t page_id) {
if (page_id > 255) {
ESP_LOGD(TAG, "Wake up page of bounds, range 0-255");
return;
}
this->add_no_result_to_queue_with_set_internal_("wake_up_page", "wup", page_id, true); this->add_no_result_to_queue_with_set_internal_("wake_up_page", "wup", page_id, true);
} }
void Nextion::set_touch_sleep_timeout(uint16_t timeout) { void Nextion::set_touch_sleep_timeout(uint16_t timeout) {
if (timeout < 3 || timeout > 65535) { if (timeout < 3) {
ESP_LOGD(TAG, "Sleep timeout out of bounds, range 3-65535"); ESP_LOGD(TAG, "Sleep timeout out of bounds, range 3-65535");
return; return;
} }

View file

@ -76,9 +76,15 @@ void NextionSensor::set_state(float state, bool publish, bool send_to_nextion) {
} }
} }
float published_state = state;
if (this->wave_chan_id_ == UINT8_MAX) { if (this->wave_chan_id_ == UINT8_MAX) {
if (publish) { if (publish) {
this->publish_state(state); if (this->precision_ > 0) {
double to_multiply = pow(10, -this->precision_);
published_state = (float) (state * to_multiply);
}
this->publish_state(published_state);
} else { } else {
this->raw_state = state; this->raw_state = state;
this->state = state; this->state = state;
@ -87,7 +93,7 @@ void NextionSensor::set_state(float state, bool publish, bool send_to_nextion) {
} }
this->update_component_settings(); this->update_component_settings();
ESP_LOGN(TAG, "Wrote state for sensor \"%s\" state %lf", this->variable_name_.c_str(), state); ESP_LOGN(TAG, "Wrote state for sensor \"%s\" state %lf", this->variable_name_.c_str(), published_state);
} }
void NextionSensor::wave_update_() { void NextionSensor::wave_update_() {

View file

@ -128,7 +128,7 @@ async def to_code(config):
use_state_callback = True use_state_callback = True
for conf in config.get(CONF_ON_ERROR, []): for conf in config.get(CONF_ON_ERROR, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [(int, "x")], conf) await automation.build_automation(trigger, [(cg.uint8, "x")], conf)
use_state_callback = True use_state_callback = True
if use_state_callback: if use_state_callback:
cg.add_define("USE_OTA_STATE_CALLBACK") cg.add_define("USE_OTA_STATE_CALLBACK")

View file

@ -54,7 +54,7 @@ class OTAEndTrigger : public Trigger<> {
} }
}; };
class OTAErrorTrigger : public Trigger<int> { class OTAErrorTrigger : public Trigger<uint8_t> {
public: public:
explicit OTAErrorTrigger(OTAComponent *parent) { explicit OTAErrorTrigger(OTAComponent *parent) {
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {

View file

@ -106,4 +106,5 @@ async def output_set_level_to_code(config, action_id, template_arg, args):
async def to_code(config): async def to_code(config):
cg.add_define("USE_OUTPUT")
cg.add_global(output_ns.using) cg.add_global(output_ns.using)

View file

@ -16,7 +16,7 @@ void PowerSupply::setup() {
void PowerSupply::dump_config() { void PowerSupply::dump_config() {
ESP_LOGCONFIG(TAG, "Power Supply:"); ESP_LOGCONFIG(TAG, "Power Supply:");
LOG_PIN(" Pin: ", this->pin_); LOG_PIN(" Pin: ", this->pin_);
ESP_LOGCONFIG(TAG, " Time to enable: %u ms", this->enable_time_); ESP_LOGCONFIG(TAG, " Time to enable: %" PRIu32 " ms", this->enable_time_);
ESP_LOGCONFIG(TAG, " Keep on time: %.1f s", this->keep_on_time_ / 1000.0f); ESP_LOGCONFIG(TAG, " Keep on time: %.1f s", this->keep_on_time_ / 1000.0f);
} }

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