1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-02 16:11:53 +00:00

Compare commits

..

7 Commits

Author SHA1 Message Date
Jesse Hills
d2f7a621eb Move package installs up, add xz-utils 2024-09-10 18:43:29 +12:00
Jesse Hills
a687682978 Merge branch 'dev' into jesserockz-2024-416 2024-09-10 17:35:00 +12:00
Jesse Hills
b012d56cc2 Install s6, tempio and bashio for ha-addon image
Install cryptography manually in armv7 image
2024-09-10 17:33:22 +12:00
Jesse Hills
3e1d031d77 Move arg down 2024-09-10 08:49:41 +12:00
Jesse Hills
b4b44048b4 Use released base image 2024-09-05 16:09:06 +12:00
Jesse Hills
81720db1c9 Merge remote-tracking branch 'origin/dev' into jesserockz-2024-416 2024-09-03 16:15:08 +12:00
Jesse Hills
89edd86de9 [docker] Use new base image for better caching 2024-09-02 18:38:51 +12:00
78 changed files with 379 additions and 1023 deletions

View File

@@ -111,4 +111,5 @@ config/
examples/
Dockerfile
.git/
tests/build/
tests/
.*

View File

@@ -7,11 +7,11 @@ inputs:
target:
description: "Target to build"
required: true
example: "docker"
baseimg:
description: "Base image type"
example: "final / lint"
build_type:
description: "Image type to build"
required: true
example: "docker"
example: "docker / hassio"
suffix:
description: "Suffix to add to tags"
required: true
@@ -58,7 +58,7 @@ runs:
cache-from: type=gha
cache-to: ${{ steps.cache-to.outputs.value }}
build-args: |
BASEIMGTYPE=${{ inputs.baseimg }}
BUILD_TYPE=${{ inputs.build_type }}
BUILD_VERSION=${{ inputs.version }}
outputs: |
type=image,name=ghcr.io/${{ steps.tags.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
@@ -84,7 +84,7 @@ runs:
cache-from: type=gha
cache-to: ${{ steps.cache-to.outputs.value }}
build-args: |
BASEIMGTYPE=${{ inputs.baseimg }}
BUILD_TYPE=${{ inputs.build_type }}
BUILD_VERSION=${{ inputs.version }}
outputs: |
type=image,name=docker.io/${{ steps.tags.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true

View File

@@ -111,8 +111,8 @@ jobs:
uses: ./.github/actions/build-image
with:
platform: ${{ matrix.platform }}
target: docker
baseimg: docker
target: final
build_type: docker
suffix: ""
version: ${{ needs.init.outputs.tag }}
@@ -120,8 +120,8 @@ jobs:
uses: ./.github/actions/build-image
with:
platform: ${{ matrix.platform }}
target: hassio
baseimg: hassio
target: final
build_type: hassio
suffix: "hassio"
version: ${{ needs.init.outputs.tag }}
@@ -130,7 +130,7 @@ jobs:
with:
platform: ${{ matrix.platform }}
target: lint
baseimg: docker
build_type: docker
suffix: lint
version: ${{ needs.init.outputs.tag }}

View File

@@ -1,219 +1,139 @@
# Build these with the build.py script
# Example:
# python3 docker/build.py --tag dev --arch amd64 --build-type docker build
ARG BUILD_VERSION=dev
ARG BUILD_TYPE=docker
# One of "docker", "hassio"
ARG BASEIMGTYPE=docker
FROM ghcr.io/esphome/docker-base:2024.9.0 AS base
RUN git config --system --add safe.directory "*"
# https://github.com/hassio-addons/addon-debian-base/releases
FROM ghcr.io/hassio-addons/debian-base:7.2.0 AS base-hassio
# https://hub.docker.com/_/debian?tab=tags&page=1&name=bookworm
FROM debian:12.2-slim AS base-docker
COPY requirements.txt /
FROM base-${BASEIMGTYPE} AS base
FROM base AS base-amd64
FROM base AS base-arm64
FROM base AS base-armv7
RUN \
export cryptography_version=$(grep 'cryptography==' /requirements.txt | cut -d'=' -f3) \
&& curl -L https://www.piwheels.org/cp311/cryptography-$cryptography_version-cp37-abi3-linux_armv7l.whl -o /tmp/cryptography-$cryptography_version-cp37-abi3-linux_armv7l.whl \
&& uv pip install --no-cache-dir /tmp/cryptography-$cryptography_version-cp37-abi3-linux_armv7l.whl \
&& rm /tmp/cryptography-$cryptography_version-cp37-abi3-linux_armv7l.whl
ARG TARGETARCH
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.
FROM base-${TARGETARCH}${TARGETVARIANT} AS base-final
RUN \
apt-get update \
# Use pinned versions so that we get updates with build caching
&& apt-get install -y --no-install-recommends \
python3-pip=23.0.1+dfsg-1 \
python3-setuptools=66.1.1-1 \
python3-venv=3.11.2-1+b1 \
python3-wheel=0.38.4-2 \
iputils-ping=3:20221126-1 \
git=1:2.39.5-0+deb12u1 \
curl=7.88.1-10+deb12u7 \
openssh-client=1:9.2p1-2+deb12u3 \
python3-cffi=1.15.1-5 \
libcairo2=1.16.0-7 \
libmagic1=1:5.44-3 \
patch=2.7.6-7 \
&& ( \
( \
[ "$TARGETARCH$TARGETVARIANT" = "armv7" ] && \
apt-get install -y --no-install-recommends \
build-essential=12.9 \
python3-dev=3.11.2-1+b1 \
zlib1g-dev=1:1.2.13.dfsg-1 \
libjpeg-dev=1:2.1.5-2 \
libfreetype-dev=2.12.1+dfsg-5+deb12u3 \
libssl-dev=3.0.14-1~deb12u2 \
libffi-dev=3.4.4-1 \
libopenjp2-7=2.5.0-2 \
libtiff6=4.5.0-6+deb12u1 \
cargo=0.66.0+ds1-1 \
pkg-config=1.8.1-1 \
gcc-arm-linux-gnueabihf=4:12.2.0-3 \
) \
|| [ "$TARGETARCH$TARGETVARIANT" != "armv7" ] \
) \
&& rm -rf \
/tmp/* \
/var/{cache,log}/* \
/var/lib/apt/lists/*
ENV \
# Fix click python3 lang warning https://click.palletsprojects.com/en/7.x/python3/
LANG=C.UTF-8 LC_ALL=C.UTF-8 \
# Store globally installed pio libs in /piolibs
PLATFORMIO_GLOBALLIB_DIR=/piolibs
# Support legacy binaries on Debian multiarch system. There is no "correct" way
# 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
RUN \
if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
ln -s /lib/arm-linux-gnueabihf/ld-linux-armhf.so.3 /lib/ld-linux.so.3; \
fi
uv pip install --no-cache-dir \
-r /requirements.txt
RUN \
# Ubuntu python3-pip is missing wheel
if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
fi; \
pip3 install \
--break-system-packages --no-cache-dir \
# Keep platformio version in sync with requirements.txt
platformio==6.1.15 \
# Change some platformio settings
&& platformio settings set enable_telemetry No \
platformio settings set enable_telemetry No \
&& platformio settings set check_platformio_interval 1000000 \
&& mkdir -p /piolibs
# 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 /
RUN --mount=type=tmpfs,target=/root/.cargo if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
curl -L https://www.piwheels.org/cp311/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl -o /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \
&& pip3 install --break-system-packages --no-cache-dir /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \
&& rm /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \
&& export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
fi; \
CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse CARGO_HOME=/root/.cargo \
pip3 install \
--break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt
COPY script/platformio_install_deps.py platformio.ini /
RUN /platformio_install_deps.py /platformio.ini --libraries
# Avoid unsafe git error when container user and file config volume permissions don't match
RUN git config --system --add safe.directory '*'
FROM base-final AS base-docker
# ======================= docker-type image =======================
FROM base AS docker
# Copy esphome and install
COPY . /esphome
RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
fi; \
pip3 install \
--break-system-packages --no-cache-dir -e /esphome
# Settings for dashboard
ENV USERNAME="" PASSWORD=""
# Expose the dashboard to Docker
EXPOSE 6052
# Run healthcheck (heartbeat)
HEALTHCHECK --interval=30s --timeout=30s \
CMD curl --fail http://localhost:6052/version -A "HealthCheck" || exit 1
CMD curl --fail http://localhost:6052/version -A "HealthCheck" || exit 1
COPY docker/docker_entrypoint.sh /entrypoint.sh
# The directory the user should mount their configuration files to
VOLUME /config
WORKDIR /config
# Set entrypoint to esphome (via a script) so that the user doesn't have to type 'esphome'
# in every docker command twice
ENTRYPOINT ["/entrypoint.sh"]
# When no arguments given, start the dashboard in the workdir
CMD ["dashboard", "/config"]
# ======================= hassio-type image =======================
FROM base AS hassio
FROM base-final AS base-hassio
RUN \
apt-get update \
# Use pinned versions so that we get updates with build caching
set -x \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
nginx-light=1.22.1-9 \
jq \
xz-utils \
&& rm -rf \
/tmp/* \
/var/{cache,log}/* \
/var/lib/apt/lists/*
/var/lib/apt/lists/* \
/usr/src/*
ARG BUILD_VERSION=dev
ARG \
BASHIO_VERSION=0.16.2 \
TEMPIO_VERSION=2021.09.0 \
S6_OVERLAY_VERSION=3.2.0.0
# Copy root filesystem
COPY docker/ha-addon-rootfs/ /
WORKDIR /usr/src
# Copy esphome and install
COPY . /esphome
RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
fi; \
pip3 install \
--break-system-packages --no-cache-dir -e /esphome
# Labels
LABEL \
io.hass.name="ESPHome" \
io.hass.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \
io.hass.type="addon" \
io.hass.version="${BUILD_VERSION}"
# io.hass.arch is inherited from addon-debian-base
# ======================= lint-type image =======================
FROM base AS lint
ENV \
PLATFORMIO_CORE_DIR=/esphome/.temp/platformio
ARG TARGETARCH
ARG TARGETVARIANT
RUN \
apt-get update \
# Use pinned versions so that we get updates with build caching
&& apt-get install -y --no-install-recommends \
clang-format-13=1:13.0.1-11+b2 \
clang-tidy-14=1:14.0.6-12 \
patch=2.7.6-7 \
software-properties-common=0.99.30-4.1~deb12u1 \
nano=7.2-1+deb12u1 \
build-essential=12.9 \
python3-dev=3.11.2-1+b1 \
&& rm -rf \
/tmp/* \
/var/{cache,log}/* \
/var/lib/apt/lists/*
set -x \
&& if [ "${TARGETARCH}${TARGETVARIANT}" = "armv7" ]; then \
export S6_ARCH="arm"; \
export TEMPIO_ARCH="armv7"; \
elif [ "${TARGETARCH}${TARGETVARIANT}" = "amd64" ]; then \
export S6_ARCH="x86_64"; \
export TEMPIO_ARCH="amd64"; \
elif [ "${TARGETARCH}${TARGETVARIANT}" = "arm64" ]; then \
export S6_ARCH="aarch64"; \
export TEMPIO_ARCH="aarch64"; \
fi \
\
&& curl -L -f -s "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz" \
| tar Jxvf - -C / \
&& curl -L -f -s "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz" \
| tar Jxvf - -C / \
&& curl -L -f -s "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-symlinks-arch.tar.xz" \
| tar Jxvf - -C / \
&& curl -L -f -s "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-symlinks-noarch.tar.xz" \
| tar Jxvf - -C / \
&& mkdir -p /etc/fix-attrs.d \
&& mkdir -p /etc/services.d \
\
&& curl -L -f -s -o /usr/bin/tempio \
"https://github.com/home-assistant/tempio/releases/download/${TEMPIO_VERSION}/tempio_${TEMPIO_ARCH}" \
&& chmod a+x /usr/bin/tempio \
\
&& mkdir -p /usr/src/bashio \
&& curl -L -f -s "https://github.com/hassio-addons/bashio/archive/v${BASHIO_VERSION}.tar.gz" \
| tar -xzf - --strip 1 -C /usr/src/bashio \
&& mv /usr/src/bashio/lib /usr/lib/bashio \
&& ln -s /usr/lib/bashio/bashio /usr/bin/bashio \
\
&& rm -rf /usr/src/*
COPY requirements_test.txt /
RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
fi; \
pip3 install \
--break-system-packages --no-cache-dir -r /requirements_test.txt
VOLUME ["/esphome"]
WORKDIR /esphome
COPY docker/ha-addon-rootfs/ /
WORKDIR /root
ENTRYPOINT ["/init"]
ARG BUILD_VERSION
LABEL \
io.hass.name="ESPHome" \
io.hass.description="Manage and program microcontrollers through YAML configuration files" \
io.hass.type="addon" \
io.hass.version="${BUILD_VERSION}"
ARG BUILD_TYPE
FROM base-${BUILD_TYPE} AS final
COPY . /esphome
RUN uv pip install --no-cache-dir -e /esphome
FROM base-final AS lint
# TODO:

View File

@@ -1,13 +1,11 @@
#!/usr/bin/env python3
from dataclasses import dataclass
import subprocess
import argparse
from platform import machine
import shlex
from dataclasses import dataclass
import re
import shlex
import subprocess
import sys
CHANNEL_DEV = "dev"
CHANNEL_BETA = "beta"
CHANNEL_RELEASE = "release"
@@ -57,7 +55,7 @@ manifest_parser = subparsers.add_parser(
class DockerParams:
build_to: str
manifest_to: str
baseimgtype: str
build_type: str
platform: str
target: str
@@ -69,7 +67,7 @@ class DockerParams:
TYPE_LINT: "esphome/esphome-lint",
}[build_type]
build_to = f"{prefix}-{arch}"
baseimgtype = {
_build_type = {
TYPE_DOCKER: "docker",
TYPE_HA_ADDON: "hassio",
TYPE_LINT: "docker",
@@ -80,14 +78,14 @@ class DockerParams:
ARCH_AARCH64: "linux/arm64",
}[arch]
target = {
TYPE_DOCKER: "docker",
TYPE_HA_ADDON: "hassio",
TYPE_DOCKER: "final",
TYPE_HA_ADDON: "final",
TYPE_LINT: "lint",
}[build_type]
return cls(
build_to=build_to,
manifest_to=prefix,
baseimgtype=baseimgtype,
build_type=_build_type,
platform=platform,
target=target,
)
@@ -149,7 +147,7 @@ def main():
"buildx",
"build",
"--build-arg",
f"BASEIMGTYPE={params.baseimgtype}",
f"BUILD_TYPE={params.build_type}",
"--build-arg",
f"BUILD_VERSION={args.tag}",
"--cache-from",

View File

@@ -62,8 +62,6 @@ service APIConnection {
rpc unsubscribe_bluetooth_le_advertisements(UnsubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
rpc subscribe_voice_assistant(SubscribeVoiceAssistantRequest) returns (void) {}
rpc voice_assistant_get_configuration(VoiceAssistantConfigurationRequest) returns (VoiceAssistantConfigurationResponse) {}
rpc voice_assistant_set_configuration(VoiceAssistantSetConfiguration) returns (void) {}
rpc alarm_control_panel_command (AlarmControlPanelCommandRequest) returns (void) {}
}
@@ -1120,7 +1118,6 @@ message MediaPlayerSupportedFormat {
uint32 sample_rate = 2;
uint32 num_channels = 3;
MediaPlayerFormatPurpose purpose = 4;
uint32 sample_bytes = 5;
}
message ListEntitiesMediaPlayerResponse {
option (id) = 63;
@@ -1573,36 +1570,6 @@ message VoiceAssistantAnnounceFinished {
bool success = 1;
}
message VoiceAssistantWakeWord {
string id = 1;
string wake_word = 2;
repeated string trained_languages = 3;
}
message VoiceAssistantConfigurationRequest {
option (id) = 121;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VOICE_ASSISTANT";
}
message VoiceAssistantConfigurationResponse {
option (id) = 122;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_VOICE_ASSISTANT";
repeated VoiceAssistantWakeWord available_wake_words = 1;
repeated string active_wake_words = 2;
uint32 max_active_wake_words = 3;
}
message VoiceAssistantSetConfiguration {
option (id) = 123;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_VOICE_ASSISTANT";
repeated string active_wake_words = 1;
}
// ==================== ALARM CONTROL PANEL ====================
enum AlarmControlPanelState {
ALARM_STATE_DISARMED = 0;

View File

@@ -1032,7 +1032,6 @@ bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_play
media_format.sample_rate = supported_format.sample_rate;
media_format.num_channels = supported_format.num_channels;
media_format.purpose = static_cast<enums::MediaPlayerFormatPurpose>(supported_format.purpose);
media_format.sample_bytes = supported_format.sample_bytes;
msg.supported_formats.push_back(media_format);
}
@@ -1224,42 +1223,6 @@ void APIConnection::on_voice_assistant_announce_request(const VoiceAssistantAnno
}
}
VoiceAssistantConfigurationResponse APIConnection::voice_assistant_get_configuration(
const VoiceAssistantConfigurationRequest &msg) {
VoiceAssistantConfigurationResponse resp;
if (voice_assistant::global_voice_assistant != nullptr) {
if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
return resp;
}
auto &config = voice_assistant::global_voice_assistant->get_configuration();
for (auto &wake_word : config.available_wake_words) {
VoiceAssistantWakeWord resp_wake_word;
resp_wake_word.id = wake_word.id;
resp_wake_word.wake_word = wake_word.wake_word;
for (const auto &lang : wake_word.trained_languages) {
resp_wake_word.trained_languages.push_back(lang);
}
resp.available_wake_words.push_back(std::move(resp_wake_word));
}
for (auto &wake_word_id : config.active_wake_words) {
resp.active_wake_words.push_back(wake_word_id);
}
resp.max_active_wake_words = config.max_active_wake_words;
}
return resp;
}
void APIConnection::voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) {
if (voice_assistant::global_voice_assistant != nullptr) {
if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
return;
}
voice_assistant::global_voice_assistant->on_set_configuration(msg.active_wake_words);
}
}
#endif
#ifdef USE_ALARM_CONTROL_PANEL

View File

@@ -152,9 +152,6 @@ class APIConnection : public APIServerConnection {
void on_voice_assistant_audio(const VoiceAssistantAudio &msg) override;
void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) override;
void on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &msg) override;
VoiceAssistantConfigurationResponse voice_assistant_get_configuration(
const VoiceAssistantConfigurationRequest &msg) override;
void voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) override;
#endif
#ifdef USE_ALARM_CONTROL_PANEL

View File

@@ -5149,10 +5149,6 @@ bool MediaPlayerSupportedFormat::decode_varint(uint32_t field_id, ProtoVarInt va
this->purpose = value.as_enum<enums::MediaPlayerFormatPurpose>();
return true;
}
case 5: {
this->sample_bytes = value.as_uint32();
return true;
}
default:
return false;
}
@@ -5172,7 +5168,6 @@ void MediaPlayerSupportedFormat::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(2, this->sample_rate);
buffer.encode_uint32(3, this->num_channels);
buffer.encode_enum<enums::MediaPlayerFormatPurpose>(4, this->purpose);
buffer.encode_uint32(5, this->sample_bytes);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void MediaPlayerSupportedFormat::dump_to(std::string &out) const {
@@ -5195,11 +5190,6 @@ void MediaPlayerSupportedFormat::dump_to(std::string &out) const {
out.append(" purpose: ");
out.append(proto_enum_to_string<enums::MediaPlayerFormatPurpose>(this->purpose));
out.append("\n");
out.append(" sample_bytes: ");
sprintf(buffer, "%" PRIu32, this->sample_bytes);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
@@ -7124,140 +7114,6 @@ void VoiceAssistantAnnounceFinished::dump_to(std::string &out) const {
out.append("}");
}
#endif
bool VoiceAssistantWakeWord::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
this->id = value.as_string();
return true;
}
case 2: {
this->wake_word = value.as_string();
return true;
}
case 3: {
this->trained_languages.push_back(value.as_string());
return true;
}
default:
return false;
}
}
void VoiceAssistantWakeWord::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->id);
buffer.encode_string(2, this->wake_word);
for (auto &it : this->trained_languages) {
buffer.encode_string(3, it, true);
}
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantWakeWord::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantWakeWord {\n");
out.append(" id: ");
out.append("'").append(this->id).append("'");
out.append("\n");
out.append(" wake_word: ");
out.append("'").append(this->wake_word).append("'");
out.append("\n");
for (const auto &it : this->trained_languages) {
out.append(" trained_languages: ");
out.append("'").append(it).append("'");
out.append("\n");
}
out.append("}");
}
#endif
void VoiceAssistantConfigurationRequest::encode(ProtoWriteBuffer buffer) const {}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantConfigurationRequest::dump_to(std::string &out) const {
out.append("VoiceAssistantConfigurationRequest {}");
}
#endif
bool VoiceAssistantConfigurationResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 3: {
this->max_active_wake_words = value.as_uint32();
return true;
}
default:
return false;
}
}
bool VoiceAssistantConfigurationResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
this->available_wake_words.push_back(value.as_message<VoiceAssistantWakeWord>());
return true;
}
case 2: {
this->active_wake_words.push_back(value.as_string());
return true;
}
default:
return false;
}
}
void VoiceAssistantConfigurationResponse::encode(ProtoWriteBuffer buffer) const {
for (auto &it : this->available_wake_words) {
buffer.encode_message<VoiceAssistantWakeWord>(1, it, true);
}
for (auto &it : this->active_wake_words) {
buffer.encode_string(2, it, true);
}
buffer.encode_uint32(3, this->max_active_wake_words);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantConfigurationResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantConfigurationResponse {\n");
for (const auto &it : this->available_wake_words) {
out.append(" available_wake_words: ");
it.dump_to(out);
out.append("\n");
}
for (const auto &it : this->active_wake_words) {
out.append(" active_wake_words: ");
out.append("'").append(it).append("'");
out.append("\n");
}
out.append(" max_active_wake_words: ");
sprintf(buffer, "%" PRIu32, this->max_active_wake_words);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool VoiceAssistantSetConfiguration::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
this->active_wake_words.push_back(value.as_string());
return true;
}
default:
return false;
}
}
void VoiceAssistantSetConfiguration::encode(ProtoWriteBuffer buffer) const {
for (auto &it : this->active_wake_words) {
buffer.encode_string(1, it, true);
}
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void VoiceAssistantSetConfiguration::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("VoiceAssistantSetConfiguration {\n");
for (const auto &it : this->active_wake_words) {
out.append(" active_wake_words: ");
out.append("'").append(it).append("'");
out.append("\n");
}
out.append("}");
}
#endif
bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 6: {

View File

@@ -1277,7 +1277,6 @@ class MediaPlayerSupportedFormat : public ProtoMessage {
uint32_t sample_rate{0};
uint32_t num_channels{0};
enums::MediaPlayerFormatPurpose purpose{};
uint32_t sample_bytes{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -1849,53 +1848,6 @@ class VoiceAssistantAnnounceFinished : public ProtoMessage {
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class VoiceAssistantWakeWord : public ProtoMessage {
public:
std::string id{};
std::string wake_word{};
std::vector<std::string> trained_languages{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
};
class VoiceAssistantConfigurationRequest : public ProtoMessage {
public:
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
};
class VoiceAssistantConfigurationResponse : public ProtoMessage {
public:
std::vector<VoiceAssistantWakeWord> available_wake_words{};
std::vector<std::string> active_wake_words{};
uint32_t max_active_wake_words{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class VoiceAssistantSetConfiguration : public ProtoMessage {
public:
std::vector<std::string> active_wake_words{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
};
class ListEntitiesAlarmControlPanelResponse : public ProtoMessage {
public:
std::string object_id{};

View File

@@ -496,19 +496,6 @@ bool APIServerConnectionBase::send_voice_assistant_announce_finished(const Voice
return this->send_message_<VoiceAssistantAnnounceFinished>(msg, 120);
}
#endif
#ifdef USE_VOICE_ASSISTANT
#endif
#ifdef USE_VOICE_ASSISTANT
bool APIServerConnectionBase::send_voice_assistant_configuration_response(
const VoiceAssistantConfigurationResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_voice_assistant_configuration_response: %s", msg.dump().c_str());
#endif
return this->send_message_<VoiceAssistantConfigurationResponse>(msg, 122);
}
#endif
#ifdef USE_VOICE_ASSISTANT
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response(
const ListEntitiesAlarmControlPanelResponse &msg) {
@@ -1169,28 +1156,6 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ESP_LOGVV(TAG, "on_voice_assistant_announce_request: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_announce_request(msg);
#endif
break;
}
case 121: {
#ifdef USE_VOICE_ASSISTANT
VoiceAssistantConfigurationRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_configuration_request: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_configuration_request(msg);
#endif
break;
}
case 123: {
#ifdef USE_VOICE_ASSISTANT
VoiceAssistantSetConfiguration msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_set_configuration: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_set_configuration(msg);
#endif
break;
}
@@ -1681,35 +1646,6 @@ void APIServerConnection::on_subscribe_voice_assistant_request(const SubscribeVo
this->subscribe_voice_assistant(msg);
}
#endif
#ifdef USE_VOICE_ASSISTANT
void APIServerConnection::on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
VoiceAssistantConfigurationResponse ret = this->voice_assistant_get_configuration(msg);
if (!this->send_voice_assistant_configuration_response(ret)) {
this->on_fatal_error();
}
}
#endif
#ifdef USE_VOICE_ASSISTANT
void APIServerConnection::on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->voice_assistant_set_configuration(msg);
}
#endif
#ifdef USE_ALARM_CONTROL_PANEL
void APIServerConnection::on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) {
if (!this->is_connection_setup()) {

View File

@@ -253,15 +253,6 @@ class APIServerConnectionBase : public ProtoService {
#ifdef USE_VOICE_ASSISTANT
bool send_voice_assistant_announce_finished(const VoiceAssistantAnnounceFinished &msg);
#endif
#ifdef USE_VOICE_ASSISTANT
virtual void on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &value){};
#endif
#ifdef USE_VOICE_ASSISTANT
bool send_voice_assistant_configuration_response(const VoiceAssistantConfigurationResponse &msg);
#endif
#ifdef USE_VOICE_ASSISTANT
virtual void on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &value){};
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg);
#endif
@@ -434,13 +425,6 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_VOICE_ASSISTANT
virtual void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) = 0;
#endif
#ifdef USE_VOICE_ASSISTANT
virtual VoiceAssistantConfigurationResponse voice_assistant_get_configuration(
const VoiceAssistantConfigurationRequest &msg) = 0;
#endif
#ifdef USE_VOICE_ASSISTANT
virtual void voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) = 0;
#endif
#ifdef USE_ALARM_CONTROL_PANEL
virtual void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) = 0;
#endif
@@ -542,12 +526,6 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_VOICE_ASSISTANT
void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg) override;
#endif
#ifdef USE_VOICE_ASSISTANT
void on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &msg) override;
#endif
#ifdef USE_VOICE_ASSISTANT
void on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) override;
#endif
#ifdef USE_ALARM_CONTROL_PANEL
void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) override;
#endif

View File

@@ -1,13 +1,13 @@
# Dummy integration to allow relying on AsyncTCP
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.core import CORE, coroutine_with_priority
from esphome.const import (
PLATFORM_BK72XX,
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_BK72XX,
PLATFORM_RTL87XX,
)
from esphome.core import CORE, coroutine_with_priority
CODEOWNERS = ["@OttoWinter"]
@@ -22,7 +22,7 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config):
if CORE.is_esp32 or CORE.is_libretiny:
# https://github.com/esphome/AsyncTCP/blob/master/library.json
cg.add_library("esphome/AsyncTCP-esphome", "2.1.4")
cg.add_library("esphome/AsyncTCP-esphome", "2.1.3")
elif CORE.is_esp8266:
# https://github.com/esphome/ESPAsyncTCP
cg.add_library("esphome/ESPAsyncTCP-esphome", "2.0.0")

View File

@@ -145,9 +145,8 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
),
)
async def reset_energy_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
async def to_code(config):

View File

@@ -41,7 +41,7 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t,
cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t,
cv.Optional(CONF_IBEACON_UUID): esp32_ble_tracker.bt_uuid,
cv.Optional(CONF_IBEACON_UUID): cv.uuid,
cv.Optional(CONF_TIMEOUT, default="5min"): cv.positive_time_period,
cv.Optional(CONF_MIN_RSSI): cv.All(
cv.decibel, cv.int_range(min=-100, max=-30)
@@ -83,7 +83,7 @@ async def to_code(config):
cg.add(var.set_service_uuid128(uuid128))
if ibeacon_uuid := config.get(CONF_IBEACON_UUID):
ibeacon_uuid = esp32_ble_tracker.as_reversed_hex_array(ibeacon_uuid)
ibeacon_uuid = esp32_ble_tracker.as_hex_array(str(ibeacon_uuid))
cg.add(var.set_ibeacon_uuid(ibeacon_uuid))
if (ibeacon_major := config.get(CONF_IBEACON_MAJOR)) is not None:

View File

@@ -256,7 +256,6 @@ bool Dsmr::parse_telegram() {
MyData data;
ESP_LOGV(TAG, "Trying to parse telegram");
this->stop_requesting_data_();
::dsmr::ParseResult<void> res =
::dsmr::P1Parser::parse(&data, this->telegram_, this->bytes_read_, false,
this->crc_check_); // Parse telegram according to data definition. Ignore unknown values.
@@ -268,11 +267,6 @@ bool Dsmr::parse_telegram() {
} else {
this->status_clear_warning();
this->publish_sensors(data);
// publish the telegram, after publishing the sensors so it can also trigger action based on latest values
if (this->s_telegram_ != nullptr) {
this->s_telegram_->publish_state(std::string(this->telegram_, this->bytes_read_));
}
return true;
}
}

View File

@@ -85,9 +85,6 @@ class Dsmr : public Component, public uart::UARTDevice {
void set_##s(text_sensor::TextSensor *sensor) { s_##s##_ = sensor; }
DSMR_TEXT_SENSOR_LIST(DSMR_SET_TEXT_SENSOR, )
// handled outside dsmr
void set_telegram(text_sensor::TextSensor *sensor) { s_telegram_ = sensor; }
protected:
void receive_telegram_();
void receive_encrypted_telegram_();
@@ -127,9 +124,6 @@ class Dsmr : public Component, public uart::UARTDevice {
bool header_found_{false};
bool footer_found_{false};
// handled outside dsmr
text_sensor::TextSensor *s_telegram_{nullptr};
// Sensor member pointers
#define DSMR_DECLARE_SENSOR(s) sensor::Sensor *s_##s##_{nullptr};
DSMR_SENSOR_LIST(DSMR_DECLARE_SENSOR, )

View File

@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import text_sensor
from esphome.const import CONF_INTERNAL
from . import Dsmr, CONF_DSMR_ID
AUTO_LOAD = ["dsmr"]
@@ -22,9 +22,6 @@ CONFIG_SCHEMA = cv.Schema(
cv.Optional("water_equipment_id"): text_sensor.text_sensor_schema(),
cv.Optional("sub_equipment_id"): text_sensor.text_sensor_schema(),
cv.Optional("gas_delivered_text"): text_sensor.text_sensor_schema(),
cv.Optional("telegram"): text_sensor.text_sensor_schema().extend(
{cv.Optional(CONF_INTERNAL, default=True): cv.boolean}
),
}
).extend(cv.COMPONENT_SCHEMA)
@@ -40,9 +37,7 @@ async def to_code(config):
if id and id.type == text_sensor.TextSensor:
var = await text_sensor.new_text_sensor(conf)
cg.add(getattr(hub, f"set_{key}")(var))
if key != "telegram":
# telegram is not handled by dsmr
text_sensors.append(f"F({key})")
text_sensors.append(f"F({key})")
if text_sensors:
cg.add_define(

View File

@@ -31,13 +31,6 @@ ESPBTUUID ESPBTUUID::from_raw(const uint8_t *data) {
memcpy(ret.uuid_.uuid.uuid128, data, ESP_UUID_LEN_128);
return ret;
}
ESPBTUUID ESPBTUUID::from_raw_reversed(const uint8_t *data) {
ESPBTUUID ret;
ret.uuid_.len = ESP_UUID_LEN_128;
for (int i = 0; i < ESP_UUID_LEN_128; i++)
ret.uuid_.uuid.uuid128[ESP_UUID_LEN_128 - 1 - i] = data[i];
return ret;
}
ESPBTUUID ESPBTUUID::from_raw(const std::string &data) {
ESPBTUUID ret;
if (data.length() == 4) {

View File

@@ -20,7 +20,6 @@ class ESPBTUUID {
static ESPBTUUID from_uint32(uint32_t uuid);
static ESPBTUUID from_raw(const uint8_t *data);
static ESPBTUUID from_raw_reversed(const uint8_t *data);
static ESPBTUUID from_raw(const std::string &data);

View File

@@ -462,16 +462,14 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e
ESP_LOGVV(TAG, " Service UUID: %s", uuid.to_string().c_str());
}
for (auto &data : this->manufacturer_datas_) {
auto ibeacon = ESPBLEiBeacon::from_manufacturer_data(data);
if (ibeacon.has_value()) {
ESP_LOGVV(TAG, " Manufacturer iBeacon:");
ESP_LOGVV(TAG, " UUID: %s", ibeacon.value().get_uuid().to_string().c_str());
ESP_LOGVV(TAG, " Major: %u", ibeacon.value().get_major());
ESP_LOGVV(TAG, " Minor: %u", ibeacon.value().get_minor());
ESP_LOGVV(TAG, " TXPower: %d", ibeacon.value().get_signal_power());
} else {
ESP_LOGVV(TAG, " Manufacturer ID: %s, data: %s", data.uuid.to_string().c_str(),
format_hex_pretty(data.data).c_str());
ESP_LOGVV(TAG, " Manufacturer data: %s", format_hex_pretty(data.data).c_str());
if (this->get_ibeacon().has_value()) {
auto ibeacon = this->get_ibeacon().value();
ESP_LOGVV(TAG, " iBeacon data:");
ESP_LOGVV(TAG, " UUID: %s", ibeacon.get_uuid().to_string().c_str());
ESP_LOGVV(TAG, " Major: %u", ibeacon.get_major());
ESP_LOGVV(TAG, " Minor: %u", ibeacon.get_minor());
ESP_LOGVV(TAG, " TXPower: %d", ibeacon.get_signal_power());
}
}
for (auto &data : this->service_datas_) {
@@ -480,7 +478,7 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e
ESP_LOGVV(TAG, " Data: %s", format_hex_pretty(data.data).c_str());
}
ESP_LOGVV(TAG, " Adv data: %s", format_hex_pretty(param.ble_adv, param.adv_data_len + param.scan_rsp_len).c_str());
ESP_LOGVV(TAG, "Adv data: %s", format_hex_pretty(param.ble_adv, param.adv_data_len + param.scan_rsp_len).c_str());
#endif
}
void ESPBTDevice::parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &param) {

View File

@@ -44,10 +44,10 @@ class ESPBLEiBeacon {
ESPBLEiBeacon(const uint8_t *data);
static optional<ESPBLEiBeacon> from_manufacturer_data(const ServiceData &data);
uint16_t get_major() { return byteswap(this->beacon_data_.major); }
uint16_t get_minor() { return byteswap(this->beacon_data_.minor); }
uint16_t get_major() { return ((this->beacon_data_.major & 0xFF) << 8) | (this->beacon_data_.major >> 8); }
uint16_t get_minor() { return ((this->beacon_data_.minor & 0xFF) << 8) | (this->beacon_data_.minor >> 8); }
int8_t get_signal_power() { return this->beacon_data_.signal_power; }
ESPBTUUID get_uuid() { return ESPBTUUID::from_raw_reversed(this->beacon_data_.proximity_uuid); }
ESPBTUUID get_uuid() { return ESPBTUUID::from_raw(this->beacon_data_.proximity_uuid); }
protected:
struct {

View File

@@ -140,8 +140,6 @@ CONF_TEST_PATTERN = "test_pattern"
# framerates
CONF_MAX_FRAMERATE = "max_framerate"
CONF_IDLE_FRAMERATE = "idle_framerate"
# frame buffer
CONF_FRAME_BUFFER_COUNT = "frame_buffer_count"
# stream trigger
CONF_ON_STREAM_START = "on_stream_start"
@@ -215,7 +213,6 @@ CONFIG_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
cv.Optional(CONF_IDLE_FRAMERATE, default="0.1 fps"): cv.All(
cv.framerate, cv.Range(min=0, max=1)
),
cv.Optional(CONF_FRAME_BUFFER_COUNT, default=1): cv.int_range(min=1, max=2),
cv.Optional(CONF_ON_STREAM_START): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
@@ -288,7 +285,6 @@ async def to_code(config):
cg.add(var.set_idle_update_interval(0))
else:
cg.add(var.set_idle_update_interval(1000 / config[CONF_IDLE_FRAMERATE]))
cg.add(var.set_frame_buffer_count(config[CONF_FRAME_BUFFER_COUNT]))
cg.add(var.set_frame_size(config[CONF_RESOLUTION]))
cg.add_define("USE_ESP32_CAMERA")

View File

@@ -127,7 +127,7 @@ void ESP32Camera::dump_config() {
sensor_t *s = esp_camera_sensor_get();
auto st = s->status;
ESP_LOGCONFIG(TAG, " JPEG Quality: %u", st.quality);
ESP_LOGCONFIG(TAG, " Framebuffer Count: %u", conf.fb_count);
// ESP_LOGCONFIG(TAG, " Framebuffer Count: %u", conf.fb_count);
ESP_LOGCONFIG(TAG, " Contrast: %d", st.contrast);
ESP_LOGCONFIG(TAG, " Brightness: %d", st.brightness);
ESP_LOGCONFIG(TAG, " Saturation: %d", st.saturation);
@@ -212,8 +212,6 @@ ESP32Camera::ESP32Camera() {
this->config_.frame_size = FRAMESIZE_VGA; // 640x480
this->config_.jpeg_quality = 10;
this->config_.fb_count = 1;
this->config_.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
this->config_.fb_location = CAMERA_FB_IN_PSRAM;
global_esp32_camera = this;
}
@@ -335,12 +333,6 @@ void ESP32Camera::set_max_update_interval(uint32_t max_update_interval) {
void ESP32Camera::set_idle_update_interval(uint32_t idle_update_interval) {
this->idle_update_interval_ = idle_update_interval;
}
/* set frame buffer parameters */
void ESP32Camera::set_frame_buffer_mode(camera_grab_mode_t mode) { this->config_.grab_mode = mode; }
void ESP32Camera::set_frame_buffer_count(uint8_t fb_count) {
this->config_.fb_count = fb_count;
this->set_frame_buffer_mode(fb_count > 1 ? CAMERA_GRAB_LATEST : CAMERA_GRAB_WHEN_EMPTY);
}
/* ---------------- public API (specific) ---------------- */
void ESP32Camera::add_image_callback(std::function<void(std::shared_ptr<CameraImage>)> &&callback) {

View File

@@ -145,9 +145,6 @@ class ESP32Camera : public Component, public EntityBase {
/* -- framerates */
void set_max_update_interval(uint32_t max_update_interval);
void set_idle_update_interval(uint32_t idle_update_interval);
/* -- frame buffer */
void set_frame_buffer_mode(camera_grab_mode_t mode);
void set_frame_buffer_count(uint8_t fb_count);
/* public API (derivated) */
void setup() override;

View File

@@ -1,16 +1,16 @@
from esphome import pins
import esphome.config_validation as cv
import esphome.final_validate as fv
import esphome.codegen as cg
from esphome import pins
from esphome.const import CONF_ID
from esphome.components.esp32 import get_esp32_variant
from esphome.components.esp32.const import (
VARIANT_ESP32,
VARIANT_ESP32C3,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
VARIANT_ESP32C3,
)
import esphome.config_validation as cv
from esphome.const import CONF_CHANNEL, CONF_ID, CONF_SAMPLE_RATE
from esphome.cpp_generator import MockObjClass
import esphome.final_validate as fv
CODEOWNERS = ["@jesserockz"]
DEPENDENCIES = ["esp32"]
@@ -25,26 +25,16 @@ CONF_I2S_LRCLK_PIN = "i2s_lrclk_pin"
CONF_I2S_AUDIO = "i2s_audio"
CONF_I2S_AUDIO_ID = "i2s_audio_id"
CONF_BITS_PER_SAMPLE = "bits_per_sample"
CONF_I2S_MODE = "i2s_mode"
CONF_PRIMARY = "primary"
CONF_SECONDARY = "secondary"
CONF_USE_APLL = "use_apll"
CONF_BITS_PER_SAMPLE = "bits_per_sample"
CONF_BITS_PER_CHANNEL = "bits_per_channel"
CONF_MONO = "mono"
CONF_LEFT = "left"
CONF_RIGHT = "right"
CONF_STEREO = "stereo"
i2s_audio_ns = cg.esphome_ns.namespace("i2s_audio")
I2SAudioComponent = i2s_audio_ns.class_("I2SAudioComponent", cg.Component)
I2SAudioBase = i2s_audio_ns.class_(
"I2SAudioBase", cg.Parented.template(I2SAudioComponent)
I2SAudioIn = i2s_audio_ns.class_("I2SAudioIn", cg.Parented.template(I2SAudioComponent))
I2SAudioOut = i2s_audio_ns.class_(
"I2SAudioOut", cg.Parented.template(I2SAudioComponent)
)
I2SAudioIn = i2s_audio_ns.class_("I2SAudioIn", I2SAudioBase)
I2SAudioOut = i2s_audio_ns.class_("I2SAudioOut", I2SAudioBase)
i2s_mode_t = cg.global_ns.enum("i2s_mode_t")
I2S_MODE_OPTIONS = {
@@ -60,75 +50,6 @@ I2S_PORTS = {
VARIANT_ESP32C3: 1,
}
i2s_channel_fmt_t = cg.global_ns.enum("i2s_channel_fmt_t")
I2S_CHANNELS = {
CONF_MONO: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ALL_LEFT,
CONF_LEFT: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_LEFT,
CONF_RIGHT: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_RIGHT,
CONF_STEREO: i2s_channel_fmt_t.I2S_CHANNEL_FMT_RIGHT_LEFT,
}
i2s_bits_per_sample_t = cg.global_ns.enum("i2s_bits_per_sample_t")
I2S_BITS_PER_SAMPLE = {
8: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_8BIT,
16: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_16BIT,
24: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_24BIT,
32: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_32BIT,
}
i2s_bits_per_chan_t = cg.global_ns.enum("i2s_bits_per_chan_t")
I2S_BITS_PER_CHANNEL = {
"default": i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_DEFAULT,
8: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_8BIT,
16: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_16BIT,
24: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_24BIT,
32: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_32BIT,
}
_validate_bits = cv.float_with_unit("bits", "bit")
def i2s_audio_component_schema(
class_: MockObjClass,
*,
default_sample_rate: int,
default_channel: str,
default_bits_per_sample: str,
):
return cv.Schema(
{
cv.GenerateID(): cv.declare_id(class_),
cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent),
cv.Optional(CONF_CHANNEL, default=default_channel): cv.enum(I2S_CHANNELS),
cv.Optional(CONF_SAMPLE_RATE, default=default_sample_rate): cv.int_range(
min=1
),
cv.Optional(CONF_BITS_PER_SAMPLE, default=default_bits_per_sample): cv.All(
_validate_bits, cv.enum(I2S_BITS_PER_SAMPLE)
),
cv.Optional(CONF_I2S_MODE, default=CONF_PRIMARY): cv.enum(
I2S_MODE_OPTIONS, lower=True
),
cv.Optional(CONF_USE_APLL, default=False): cv.boolean,
cv.Optional(CONF_BITS_PER_CHANNEL, default="default"): cv.All(
cv.Any(cv.float_with_unit("bits", "bit"), "default"),
cv.enum(I2S_BITS_PER_CHANNEL),
),
}
)
async def register_i2s_audio_component(var, config):
await cg.register_parented(var, config[CONF_I2S_AUDIO_ID])
cg.add(var.set_i2s_mode(config[CONF_I2S_MODE]))
cg.add(var.set_channel(config[CONF_CHANNEL]))
cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE]))
cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE]))
cg.add(var.set_bits_per_channel(config[CONF_BITS_PER_CHANNEL]))
cg.add(var.set_use_apll(config[CONF_USE_APLL]))
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(I2SAudioComponent),

View File

@@ -11,27 +11,9 @@ namespace i2s_audio {
class I2SAudioComponent;
class I2SAudioBase : public Parented<I2SAudioComponent> {
public:
void set_i2s_mode(i2s_mode_t mode) { this->i2s_mode_ = mode; }
void set_channel(i2s_channel_fmt_t channel) { this->channel_ = channel; }
void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; }
void set_bits_per_sample(i2s_bits_per_sample_t bits_per_sample) { this->bits_per_sample_ = bits_per_sample; }
void set_bits_per_channel(i2s_bits_per_chan_t bits_per_channel) { this->bits_per_channel_ = bits_per_channel; }
void set_use_apll(uint32_t use_apll) { this->use_apll_ = use_apll; }
class I2SAudioIn : public Parented<I2SAudioComponent> {};
protected:
i2s_mode_t i2s_mode_{};
i2s_channel_fmt_t channel_;
uint32_t sample_rate_;
i2s_bits_per_sample_t bits_per_sample_;
i2s_bits_per_chan_t bits_per_channel_;
bool use_apll_;
};
class I2SAudioIn : public I2SAudioBase {};
class I2SAudioOut : public I2SAudioBase {};
class I2SAudioOut : public Parented<I2SAudioComponent> {};
class I2SAudioComponent : public Component {
public:

View File

@@ -12,10 +12,6 @@ from .. import (
I2SAudioOut,
CONF_I2S_AUDIO_ID,
CONF_I2S_DOUT_PIN,
CONF_LEFT,
CONF_RIGHT,
CONF_MONO,
CONF_STEREO,
)
CODEOWNERS = ["@jesserockz"]
@@ -34,12 +30,12 @@ CONF_DAC_TYPE = "dac_type"
CONF_I2S_COMM_FMT = "i2s_comm_fmt"
INTERNAL_DAC_OPTIONS = {
CONF_LEFT: i2s_dac_mode_t.I2S_DAC_CHANNEL_LEFT_EN,
CONF_RIGHT: i2s_dac_mode_t.I2S_DAC_CHANNEL_RIGHT_EN,
CONF_STEREO: i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN,
"left": i2s_dac_mode_t.I2S_DAC_CHANNEL_LEFT_EN,
"right": i2s_dac_mode_t.I2S_DAC_CHANNEL_RIGHT_EN,
"stereo": i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN,
}
EXTERNAL_DAC_OPTIONS = [CONF_MONO, CONF_STEREO]
EXTERNAL_DAC_OPTIONS = ["mono", "stereo"]
NO_INTERNAL_DAC_VARIANTS = [esp32.const.VARIANT_ESP32S2]

View File

@@ -23,7 +23,7 @@ enum I2SState : uint8_t {
I2S_STATE_STOPPING,
};
class I2SAudioMediaPlayer : public Component, public Parented<I2SAudioComponent>, public media_player::MediaPlayer {
class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer, public I2SAudioOut {
public:
void setup() override;
float get_setup_priority() const override { return esphome::setup_priority::LATE; }

View File

@@ -1,17 +1,20 @@
from esphome import pins
import esphome.codegen as cg
from esphome.components import esp32, microphone
from esphome.components.adc import ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, validate_adc_pin
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_NUMBER
import esphome.codegen as cg
from esphome import pins
from esphome.const import CONF_CHANNEL, CONF_ID, CONF_NUMBER, CONF_SAMPLE_RATE
from esphome.components import microphone, esp32
from esphome.components.adc import ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, validate_adc_pin
from .. import (
CONF_I2S_DIN_PIN,
CONF_RIGHT,
I2SAudioIn,
i2s_audio_component_schema,
CONF_I2S_MODE,
CONF_PRIMARY,
I2S_MODE_OPTIONS,
i2s_audio_ns,
register_i2s_audio_component,
I2SAudioComponent,
I2SAudioIn,
CONF_I2S_AUDIO_ID,
CONF_I2S_DIN_PIN,
)
CODEOWNERS = ["@jesserockz"]
@@ -20,14 +23,29 @@ DEPENDENCIES = ["i2s_audio"]
CONF_ADC_PIN = "adc_pin"
CONF_ADC_TYPE = "adc_type"
CONF_PDM = "pdm"
CONF_BITS_PER_SAMPLE = "bits_per_sample"
CONF_USE_APLL = "use_apll"
I2SAudioMicrophone = i2s_audio_ns.class_(
"I2SAudioMicrophone", I2SAudioIn, microphone.Microphone, cg.Component
)
i2s_channel_fmt_t = cg.global_ns.enum("i2s_channel_fmt_t")
CHANNELS = {
"left": i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_LEFT,
"right": i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_RIGHT,
}
i2s_bits_per_sample_t = cg.global_ns.enum("i2s_bits_per_sample_t")
BITS_PER_SAMPLE = {
16: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_16BIT,
32: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_32BIT,
}
INTERNAL_ADC_VARIANTS = [esp32.const.VARIANT_ESP32]
PDM_VARIANTS = [esp32.const.VARIANT_ESP32, esp32.const.VARIANT_ESP32S3]
_validate_bits = cv.float_with_unit("bits", "bit")
def validate_esp32_variant(config):
variant = esp32.get_esp32_variant()
@@ -44,15 +62,21 @@ def validate_esp32_variant(config):
BASE_SCHEMA = microphone.MICROPHONE_SCHEMA.extend(
i2s_audio_component_schema(
I2SAudioMicrophone,
default_sample_rate=16000,
default_channel=CONF_RIGHT,
default_bits_per_sample="32bit",
)
{
cv.GenerateID(): cv.declare_id(I2SAudioMicrophone),
cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent),
cv.Optional(CONF_CHANNEL, default="right"): cv.enum(CHANNELS),
cv.Optional(CONF_SAMPLE_RATE, default=16000): cv.int_range(min=1),
cv.Optional(CONF_BITS_PER_SAMPLE, default="32bit"): cv.All(
_validate_bits, cv.enum(BITS_PER_SAMPLE)
),
cv.Optional(CONF_USE_APLL, default=False): cv.boolean,
cv.Optional(CONF_I2S_MODE, default=CONF_PRIMARY): cv.enum(
I2S_MODE_OPTIONS, lower=True
),
}
).extend(cv.COMPONENT_SCHEMA)
CONFIG_SCHEMA = cv.All(
cv.typed_schema(
{
@@ -64,7 +88,7 @@ CONFIG_SCHEMA = cv.All(
"external": BASE_SCHEMA.extend(
{
cv.Required(CONF_I2S_DIN_PIN): pins.internal_gpio_input_pin_number,
cv.Optional(CONF_PDM, default=False): cv.boolean,
cv.Required(CONF_PDM): cv.boolean,
}
),
},
@@ -77,8 +101,8 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await register_i2s_audio_component(var, config)
await microphone.register_microphone(var, config)
await cg.register_parented(var, config[CONF_I2S_AUDIO_ID])
if config[CONF_ADC_TYPE] == "internal":
variant = esp32.get_esp32_variant()
@@ -88,3 +112,11 @@ async def to_code(config):
else:
cg.add(var.set_din_pin(config[CONF_I2S_DIN_PIN]))
cg.add(var.set_pdm(config[CONF_PDM]))
cg.add(var.set_i2s_mode(config[CONF_I2S_MODE]))
cg.add(var.set_channel(config[CONF_CHANNEL]))
cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE]))
cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE]))
cg.add(var.set_use_apll(config[CONF_USE_APLL]))
await microphone.register_microphone(var, config)

View File

@@ -58,7 +58,7 @@ void I2SAudioMicrophone::start_() {
.tx_desc_auto_clear = false,
.fixed_mclk = 0,
.mclk_multiple = I2S_MCLK_MULTIPLE_256,
.bits_per_chan = this->bits_per_channel_,
.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
};
esp_err_t err;
@@ -167,24 +167,21 @@ size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) {
return 0;
}
this->status_clear_warning();
// ESP-IDF I2S implementation right-extends 8-bit data to 16 bits,
// and 24-bit data to 32 bits.
switch (this->bits_per_sample_) {
case I2S_BITS_PER_SAMPLE_8BIT:
case I2S_BITS_PER_SAMPLE_16BIT:
return bytes_read;
case I2S_BITS_PER_SAMPLE_24BIT:
case I2S_BITS_PER_SAMPLE_32BIT: {
size_t samples_read = bytes_read / sizeof(int32_t);
for (size_t i = 0; i < samples_read; i++) {
int32_t temp = reinterpret_cast<int32_t *>(buf)[i] >> 14;
buf[i] = clamp<int16_t>(temp, INT16_MIN, INT16_MAX);
}
return samples_read * sizeof(int16_t);
if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_16BIT) {
return bytes_read;
} else if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_32BIT) {
std::vector<int16_t> samples;
size_t samples_read = bytes_read / sizeof(int32_t);
samples.resize(samples_read);
for (size_t i = 0; i < samples_read; i++) {
int32_t temp = reinterpret_cast<int32_t *>(buf)[i] >> 14;
samples[i] = clamp<int16_t>(temp, INT16_MIN, INT16_MAX);
}
default:
ESP_LOGE(TAG, "Unsupported bits per sample: %d", this->bits_per_sample_);
return 0;
memcpy(buf, samples.data(), samples_read * sizeof(int16_t));
return samples_read * sizeof(int16_t);
} else {
ESP_LOGE(TAG, "Unsupported bits per sample: %d", this->bits_per_sample_);
return 0;
}
}

View File

@@ -30,6 +30,13 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub
}
#endif
void set_i2s_mode(i2s_mode_t mode) { this->i2s_mode_ = mode; }
void set_channel(i2s_channel_fmt_t channel) { this->channel_ = channel; }
void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; }
void set_bits_per_sample(i2s_bits_per_sample_t bits_per_sample) { this->bits_per_sample_ = bits_per_sample; }
void set_use_apll(uint32_t use_apll) { this->use_apll_ = use_apll; }
protected:
void start_();
void stop_();
@@ -41,6 +48,11 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub
bool adc_{false};
#endif
bool pdm_{false};
i2s_mode_t i2s_mode_{};
i2s_channel_fmt_t channel_;
uint32_t sample_rate_;
i2s_bits_per_sample_t bits_per_sample_;
bool use_apll_;
HighFrequencyLoopRequester high_freq_;
};

View File

@@ -1,19 +1,15 @@
from esphome import pins
import esphome.codegen as cg
from esphome.components import esp32, speaker
import esphome.config_validation as cv
from esphome.const import CONF_CHANNEL, CONF_ID, CONF_MODE, CONF_TIMEOUT
from esphome import pins
from esphome.const import CONF_ID, CONF_MODE
from esphome.components import esp32, speaker
from .. import (
CONF_I2S_AUDIO_ID,
CONF_I2S_DOUT_PIN,
CONF_LEFT,
CONF_MONO,
CONF_RIGHT,
CONF_STEREO,
I2SAudioComponent,
I2SAudioOut,
i2s_audio_component_schema,
i2s_audio_ns,
register_i2s_audio_component,
)
CODEOWNERS = ["@jesserockz"]
@@ -23,16 +19,19 @@ I2SAudioSpeaker = i2s_audio_ns.class_(
"I2SAudioSpeaker", cg.Component, speaker.Speaker, I2SAudioOut
)
i2s_dac_mode_t = cg.global_ns.enum("i2s_dac_mode_t")
CONF_MUTE_PIN = "mute_pin"
CONF_DAC_TYPE = "dac_type"
i2s_dac_mode_t = cg.global_ns.enum("i2s_dac_mode_t")
INTERNAL_DAC_OPTIONS = {
CONF_LEFT: i2s_dac_mode_t.I2S_DAC_CHANNEL_LEFT_EN,
CONF_RIGHT: i2s_dac_mode_t.I2S_DAC_CHANNEL_RIGHT_EN,
CONF_STEREO: i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN,
"left": i2s_dac_mode_t.I2S_DAC_CHANNEL_LEFT_EN,
"right": i2s_dac_mode_t.I2S_DAC_CHANNEL_RIGHT_EN,
"stereo": i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN,
}
EXTERNAL_DAC_OPTIONS = ["mono", "stereo"]
NO_INTERNAL_DAC_VARIANTS = [esp32.const.VARIANT_ESP32S2]
@@ -45,40 +44,28 @@ def validate_esp32_variant(config):
return config
BASE_SCHEMA = (
speaker.SPEAKER_SCHEMA.extend(
i2s_audio_component_schema(
I2SAudioSpeaker,
default_sample_rate=16000,
default_channel=CONF_MONO,
default_bits_per_sample="16bit",
)
)
.extend(
{
cv.Optional(
CONF_TIMEOUT, default="100ms"
): cv.positive_time_period_milliseconds,
}
)
.extend(cv.COMPONENT_SCHEMA)
)
CONFIG_SCHEMA = cv.All(
cv.typed_schema(
{
"internal": BASE_SCHEMA.extend(
"internal": speaker.SPEAKER_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(I2SAudioSpeaker),
cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent),
cv.Required(CONF_MODE): cv.enum(INTERNAL_DAC_OPTIONS, lower=True),
}
),
"external": BASE_SCHEMA.extend(
).extend(cv.COMPONENT_SCHEMA),
"external": speaker.SPEAKER_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(I2SAudioSpeaker),
cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent),
cv.Required(
CONF_I2S_DOUT_PIN
): pins.internal_gpio_output_pin_number,
cv.Optional(CONF_MODE, default="mono"): cv.one_of(
*EXTERNAL_DAC_OPTIONS, lower=True
),
}
),
).extend(cv.COMPONENT_SCHEMA),
},
key=CONF_DAC_TYPE,
),
@@ -89,11 +76,12 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await register_i2s_audio_component(var, config)
await speaker.register_speaker(var, config)
await cg.register_parented(var, config[CONF_I2S_AUDIO_ID])
if config[CONF_DAC_TYPE] == "internal":
cg.add(var.set_internal_dac_mode(config[CONF_CHANNEL]))
cg.add(var.set_internal_dac_mode(config[CONF_MODE]))
else:
cg.add(var.set_dout_pin(config[CONF_I2S_DOUT_PIN]))
cg.add(var.set_timeout(config[CONF_TIMEOUT]))
cg.add(var.set_external_dac_channels(2 if config[CONF_MODE] == "stereo" else 1))

View File

@@ -56,21 +56,6 @@ void I2SAudioSpeaker::start_() {
this->task_created_ = true;
}
template<typename a, typename b> const uint8_t *convert_data_format(const a *from, b *to, size_t &bytes, bool repeat) {
if (sizeof(a) == sizeof(b) && !repeat) {
return reinterpret_cast<const uint8_t *>(from);
}
const b *result = to;
for (size_t i = 0; i < bytes; i += sizeof(a)) {
b value = static_cast<b>(*from++) << (sizeof(b) - sizeof(a)) * 8;
*to++ = value;
if (repeat)
*to++ = value;
}
bytes *= (sizeof(b) / sizeof(a)) * (repeat ? 2 : 1); // NOLINT
return reinterpret_cast<const uint8_t *>(result);
}
void I2SAudioSpeaker::player_task(void *params) {
I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) params;
@@ -79,19 +64,19 @@ void I2SAudioSpeaker::player_task(void *params) {
xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY);
i2s_driver_config_t config = {
.mode = (i2s_mode_t) (this_speaker->i2s_mode_ | I2S_MODE_TX),
.sample_rate = this_speaker->sample_rate_,
.bits_per_sample = this_speaker->bits_per_sample_,
.channel_format = this_speaker->channel_,
.mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = 16000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 256,
.use_apll = this_speaker->use_apll_,
.dma_buf_len = 128,
.use_apll = false,
.tx_desc_auto_clear = true,
.fixed_mclk = 0,
.fixed_mclk = I2S_PIN_NO_CHANGE,
.mclk_multiple = I2S_MCLK_MULTIPLE_256,
.bits_per_chan = this_speaker->bits_per_channel_,
.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
};
#if SOC_I2S_SUPPORTS_DAC
if (this_speaker->internal_dac_mode_ != I2S_DAC_CHANNEL_DISABLE) {
@@ -129,11 +114,10 @@ void I2SAudioSpeaker::player_task(void *params) {
event.type = TaskEventType::STARTED;
xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY);
int32_t buffer[BUFFER_SIZE];
int16_t buffer[BUFFER_SIZE / 2];
while (true) {
if (xQueueReceive(this_speaker->buffer_queue_, &data_event, this_speaker->timeout_ / portTICK_PERIOD_MS) !=
pdTRUE) {
if (xQueueReceive(this_speaker->buffer_queue_, &data_event, 100 / portTICK_PERIOD_MS) != pdTRUE) {
break; // End of audio from main thread
}
if (data_event.stop) {
@@ -141,28 +125,17 @@ void I2SAudioSpeaker::player_task(void *params) {
xQueueReset(this_speaker->buffer_queue_); // Flush queue
break;
}
size_t bytes_written;
const uint8_t *data = data_event.data;
size_t remaining = data_event.len;
switch (this_speaker->bits_per_sample_) {
case I2S_BITS_PER_SAMPLE_8BIT:
case I2S_BITS_PER_SAMPLE_16BIT: {
data = convert_data_format(reinterpret_cast<const int16_t *>(data), reinterpret_cast<int16_t *>(buffer),
remaining, this_speaker->channel_ == I2S_CHANNEL_FMT_ALL_LEFT);
break;
}
case I2S_BITS_PER_SAMPLE_24BIT:
case I2S_BITS_PER_SAMPLE_32BIT: {
data = convert_data_format(reinterpret_cast<const int16_t *>(data), reinterpret_cast<int32_t *>(buffer),
remaining, this_speaker->channel_ == I2S_CHANNEL_FMT_ALL_LEFT);
break;
}
}
memmove(buffer, data_event.data, data_event.len);
size_t remaining = data_event.len / 2;
size_t current = 0;
while (remaining != 0) {
size_t bytes_written;
esp_err_t err =
i2s_write(this_speaker->parent_->get_port(), data, remaining, &bytes_written, (32 / portTICK_PERIOD_MS));
while (remaining > 0) {
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,
(10 / portTICK_PERIOD_MS));
if (err != ESP_OK) {
event = {.type = TaskEventType::WARNING, .err = err};
if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) {
@@ -170,8 +143,21 @@ void I2SAudioSpeaker::player_task(void *params) {
}
continue;
}
data += bytes_written;
remaining -= bytes_written;
if (bytes_written != sizeof(sample)) {
event = {.type = TaskEventType::WARNING, .err = ESP_FAIL};
if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) {
ESP_LOGW(TAG, "Failed to send WARNING event");
}
continue;
}
remaining--;
current++;
}
event.type = TaskEventType::PLAYING;
event.err = current;
if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) {
ESP_LOGW(TAG, "Failed to send PLAYING event");
}
}
@@ -227,11 +213,13 @@ void I2SAudioSpeaker::watch_() {
case TaskEventType::STARTED:
ESP_LOGD(TAG, "Started I2S Audio Speaker");
this->state_ = speaker::STATE_RUNNING;
this->status_clear_warning();
break;
case TaskEventType::STOPPING:
ESP_LOGD(TAG, "Stopping I2S Audio Speaker");
break;
case TaskEventType::PLAYING:
this->status_clear_warning();
break;
case TaskEventType::STOPPED:
this->state_ = speaker::STATE_STOPPED;
vTaskDelete(this->player_task_handle_);

View File

@@ -21,6 +21,7 @@ static const size_t BUFFER_SIZE = 1024;
enum class TaskEventType : uint8_t {
STARTING = 0,
STARTED,
PLAYING,
STOPPING,
STOPPED,
WARNING = 255,
@@ -37,18 +38,18 @@ struct DataEvent {
uint8_t data[BUFFER_SIZE];
};
class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Component {
class I2SAudioSpeaker : public Component, public speaker::Speaker, public I2SAudioOut {
public:
float get_setup_priority() const override { return esphome::setup_priority::LATE; }
void setup() override;
void loop() override;
void set_timeout(uint32_t ms) { this->timeout_ = ms; }
void set_dout_pin(uint8_t pin) { this->dout_pin_ = pin; }
#if SOC_I2S_SUPPORTS_DAC
void set_internal_dac_mode(i2s_dac_mode_t mode) { this->internal_dac_mode_ = mode; }
#endif
void set_external_dac_channels(uint8_t channels) { this->external_dac_channels_ = channels; }
void start() override;
void stop() override;
@@ -69,13 +70,13 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp
QueueHandle_t buffer_queue_;
QueueHandle_t event_queue_;
uint32_t timeout_{0};
uint8_t dout_pin_{0};
bool task_created_{false};
#if SOC_I2S_SUPPORTS_DAC
i2s_dac_mode_t internal_dac_mode_{I2S_DAC_CHANNEL_DISABLE};
#endif
uint8_t external_dac_channels_;
};
} // namespace i2s_audio

View File

@@ -170,11 +170,13 @@ def _notify_old_style(config):
return config
# NOTE: Keep this in mind when updating the recommended version:
# * For all constants below, update platformio.ini (in this repo)
# The dev and latest branches will be at *least* this version, which is what matters.
ARDUINO_VERSIONS = {
"dev": (cv.Version(1, 7, 0), "https://github.com/libretiny-eu/libretiny.git"),
"latest": (cv.Version(1, 7, 0), "libretiny"),
"recommended": (cv.Version(1, 7, 0), None),
"recommended": (cv.Version(1, 5, 1), None),
}

View File

@@ -32,12 +32,6 @@ void MAX31856Sensor::dump_config() {
LOG_PIN(" CS Pin: ", this->cs_);
ESP_LOGCONFIG(TAG, " Mains Filter: %s",
(filter_ == FILTER_60HZ ? "60 Hz" : (filter_ == FILTER_50HZ ? "50 Hz" : "Unknown!")));
if (this->thermocouple_type_ < 0 || this->thermocouple_type_ > 7) {
ESP_LOGCONFIG(TAG, " Thermocouple Type: Unknown");
} else {
ESP_LOGCONFIG(TAG, " Thermocouple Type: %c", "BEJKNRST"[this->thermocouple_type_]);
}
LOG_UPDATE_INTERVAL(this);
}
@@ -135,12 +129,7 @@ void MAX31856Sensor::clear_fault_() {
}
void MAX31856Sensor::set_thermocouple_type_() {
MAX31856ThermocoupleType type;
if (this->thermocouple_type_ < 0 || this->thermocouple_type_ > 7) {
type = MAX31856_TCTYPE_K;
} else {
type = this->thermocouple_type_;
}
MAX31856ThermocoupleType type = MAX31856_TCTYPE_K;
ESP_LOGCONFIG(TAG, "set_thermocouple_type_: 0x%02X", type);
uint8_t t = this->read_register_(MAX31856_CR1_REG);
t &= 0xF0; // mask off bottom 4 bits

View File

@@ -50,6 +50,7 @@ enum MAX31856Registers {
/**
* Multiple types of thermocouples supported by the chip.
* Currently only K type implemented here.
*/
enum MAX31856ThermocoupleType {
MAX31856_TCTYPE_B = 0b0000, // 0x00
@@ -77,15 +78,11 @@ class MAX31856Sensor : public sensor::Sensor,
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
void set_filter(MAX31856ConfigFilter filter) { this->filter_ = filter; }
void set_thermocouple_type(MAX31856ThermocoupleType thermocouple_type) {
this->thermocouple_type_ = thermocouple_type;
}
void set_filter(MAX31856ConfigFilter filter) { filter_ = filter; }
void update() override;
protected:
MAX31856ConfigFilter filter_;
MAX31856ThermocoupleType thermocouple_type_;
uint8_t read_register_(uint8_t reg);
uint32_t read_register24_(uint8_t reg);

View File

@@ -3,7 +3,6 @@ from esphome.components import sensor, spi
import esphome.config_validation as cv
from esphome.const import (
CONF_MAINS_FILTER,
CONF_THERMOCOUPLE_TYPE,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
@@ -19,17 +18,6 @@ FILTER = {
50: MAX31865ConfigFilter.FILTER_50HZ,
60: MAX31865ConfigFilter.FILTER_60HZ,
}
MAX31856ThermocoupleType = max31856_ns.enum("MAX31856ThermocoupleType")
THERMOCOUPLE_TYPE = {
"B": MAX31856ThermocoupleType.MAX31856_TCTYPE_B,
"E": MAX31856ThermocoupleType.MAX31856_TCTYPE_E,
"J": MAX31856ThermocoupleType.MAX31856_TCTYPE_J,
"K": MAX31856ThermocoupleType.MAX31856_TCTYPE_K,
"N": MAX31856ThermocoupleType.MAX31856_TCTYPE_N,
"R": MAX31856ThermocoupleType.MAX31856_TCTYPE_R,
"S": MAX31856ThermocoupleType.MAX31856_TCTYPE_S,
"T": MAX31856ThermocoupleType.MAX31856_TCTYPE_T,
}
CONFIG_SCHEMA = (
sensor.sensor_schema(
@@ -46,13 +34,6 @@ CONFIG_SCHEMA = (
),
}
)
.extend(
{
cv.Optional(CONF_THERMOCOUPLE_TYPE, default="K"): cv.enum(
THERMOCOUPLE_TYPE, upper=True, space=""
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(spi.spi_device_schema())
)
@@ -63,4 +44,3 @@ async def to_code(config):
await cg.register_component(var, config)
await spi.register_spi_device(var, config)
cg.add(var.set_filter(config[CONF_MAINS_FILTER]))
cg.add(var.set_thermocouple_type(config[CONF_THERMOCOUPLE_TYPE]))

View File

@@ -1,14 +1,14 @@
import esphome.codegen as cg
from esphome.components import i2c, sensor
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import (
CONF_ID,
CONF_THERMOCOUPLE_TYPE,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
)
CONF_THERMOCOUPLE_TYPE = "thermocouple_type"
CONF_HOT_JUNCTION = "hot_junction"
CONF_COLD_JUNCTION = "cold_junction"

View File

@@ -37,7 +37,6 @@ struct MediaPlayerSupportedFormat {
uint32_t sample_rate;
uint32_t num_channels;
MediaPlayerFormatPurpose purpose;
uint32_t sample_bytes;
};
class MediaPlayer;

View File

@@ -21,7 +21,6 @@ from .const import (
CONF_CUSTOM_COMMAND,
CONF_FORCE_NEW_RANGE,
CONF_MODBUS_CONTROLLER_ID,
CONF_MAX_CMD_RETRIES,
CONF_ON_COMMAND_SENT,
CONF_REGISTER_COUNT,
CONF_REGISTER_TYPE,
@@ -132,7 +131,6 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(
CONF_COMMAND_THROTTLE, default="0ms"
): cv.positive_time_period_milliseconds,
cv.Optional(CONF_MAX_CMD_RETRIES, default=4): cv.positive_int,
cv.Optional(CONF_OFFLINE_SKIP_UPDATES, default=0): cv.positive_int,
cv.Optional(
CONF_SERVER_REGISTERS,
@@ -259,7 +257,6 @@ async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_allow_duplicate_commands(config[CONF_ALLOW_DUPLICATE_COMMANDS]))
cg.add(var.set_command_throttle(config[CONF_COMMAND_THROTTLE]))
cg.add(var.set_max_cmd_retries(config[CONF_MAX_CMD_RETRIES]))
cg.add(var.set_offline_skip_updates(config[CONF_OFFLINE_SKIP_UPDATES]))
if CONF_SERVER_REGISTERS in config:
for server_register in config[CONF_SERVER_REGISTERS]:

View File

@@ -5,7 +5,6 @@ CONF_COMMAND_THROTTLE = "command_throttle"
CONF_OFFLINE_SKIP_UPDATES = "offline_skip_updates"
CONF_CUSTOM_COMMAND = "custom_command"
CONF_FORCE_NEW_RANGE = "force_new_range"
CONF_MAX_CMD_RETRIES = "max_cmd_retries"
CONF_MODBUS_CONTROLLER_ID = "modbus_controller_id"
CONF_MODBUS_FUNCTIONCODE = "modbus_functioncode"
CONF_ON_COMMAND_SENT = "on_command_sent"

View File

@@ -18,11 +18,11 @@ void ModbusController::setup() { this->create_register_ranges_(); }
bool ModbusController::send_next_command_() {
uint32_t last_send = millis() - this->last_command_timestamp_;
if ((last_send > this->command_throttle_) && !waiting_for_response() && !this->command_queue_.empty()) {
auto &command = this->command_queue_.front();
if ((last_send > this->command_throttle_) && !waiting_for_response() && !command_queue_.empty()) {
auto &command = command_queue_.front();
// remove from queue if command was sent too often
if (!command->should_retry(this->max_cmd_retries_)) {
if (command->send_countdown < 1) {
if (!this->module_offline_) {
ESP_LOGW(TAG, "Modbus device=%d set offline", this->address_);
@@ -34,9 +34,11 @@ bool ModbusController::send_next_command_() {
}
}
this->module_offline_ = true;
ESP_LOGD(TAG, "Modbus command to device=%d register=0x%02X no response received - removed from send queue",
this->address_, command->register_address);
this->command_queue_.pop_front();
ESP_LOGD(
TAG,
"Modbus command to device=%d register=0x%02X countdown=%d no response received - removed from send queue",
this->address_, command->register_address, command->send_countdown);
command_queue_.pop_front();
} else {
ESP_LOGV(TAG, "Sending next modbus command to device %d register 0x%02X count %d", this->address_,
command->register_address, command->register_count);
@@ -48,11 +50,11 @@ bool ModbusController::send_next_command_() {
// remove from queue if no handler is defined
if (!command->on_data_func) {
this->command_queue_.pop_front();
command_queue_.pop_front();
}
}
}
return (!this->command_queue_.empty());
return (!command_queue_.empty());
}
// Queue incoming response
@@ -75,7 +77,7 @@ void ModbusController::on_modbus_data(const std::vector<uint8_t> &data) {
current_command->payload = data;
this->incoming_queue_.push(std::move(current_command));
ESP_LOGV(TAG, "Modbus response queued");
this->command_queue_.pop_front();
command_queue_.pop_front();
}
}
@@ -97,7 +99,7 @@ void ModbusController::on_modbus_error(uint8_t function_code, uint8_t exception_
"payload size=%zu",
function_code, current_command->register_address, current_command->register_count,
current_command->payload.size());
this->command_queue_.pop_front();
command_queue_.pop_front();
}
}
@@ -176,7 +178,7 @@ void ModbusController::queue_command(const ModbusCommandItem &command) {
if (!this->allow_duplicate_commands_) {
// check if this command is already qeued.
// not very effective but the queue is never really large
for (auto &item : this->command_queue_) {
for (auto &item : command_queue_) {
if (item->is_equal(command)) {
ESP_LOGW(TAG, "Duplicate modbus command found: type=0x%x address=%u count=%u",
static_cast<uint8_t>(command.register_type), command.register_address, command.register_count);
@@ -187,7 +189,7 @@ void ModbusController::queue_command(const ModbusCommandItem &command) {
}
}
}
this->command_queue_.push_back(make_unique<ModbusCommandItem>(command));
command_queue_.push_back(make_unique<ModbusCommandItem>(command));
}
void ModbusController::update_range_(RegisterRange &r) {
@@ -222,8 +224,8 @@ void ModbusController::update_range_(RegisterRange &r) {
// Once we get a response to the command it is removed from the queue and the next command is send
//
void ModbusController::update() {
if (!this->command_queue_.empty()) {
ESP_LOGV(TAG, "%zu modbus commands already in queue", this->command_queue_.size());
if (!command_queue_.empty()) {
ESP_LOGV(TAG, "%zu modbus commands already in queue", command_queue_.size());
} else {
ESP_LOGV(TAG, "Updating modbus component");
}
@@ -344,8 +346,6 @@ size_t ModbusController::create_register_ranges_() {
void ModbusController::dump_config() {
ESP_LOGCONFIG(TAG, "ModbusController:");
ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_);
ESP_LOGCONFIG(TAG, " Max Command Retries: %d", this->max_cmd_retries_);
ESP_LOGCONFIG(TAG, " Offline Skip Updates: %d", this->offline_skip_updates_);
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
ESP_LOGCONFIG(TAG, "sensormap");
for (auto &it : sensorset_) {
@@ -560,9 +560,8 @@ bool ModbusCommandItem::send() {
} else {
modbusdevice->send_raw(this->payload);
}
this->send_count_++;
ESP_LOGV(TAG, "Command sent %d 0x%X %d send_count: %d", uint8_t(this->function_code), this->register_address,
this->register_count, this->send_count_);
ESP_LOGV(TAG, "Command sent %d 0x%X %d", uint8_t(this->function_code), this->register_address, this->register_count);
send_countdown--;
return true;
}

View File

@@ -312,6 +312,7 @@ struct RegisterRange {
class ModbusCommandItem {
public:
static const size_t MAX_PAYLOAD_BYTES = 240;
static const uint8_t MAX_SEND_REPEATS = 5;
ModbusController *modbusdevice;
uint16_t register_address;
uint16_t register_count;
@@ -321,9 +322,9 @@ class ModbusCommandItem {
on_data_func;
std::vector<uint8_t> payload = {};
bool send();
/// Check if the command should be retried based on the max_retries parameter
bool should_retry(uint8_t max_retries) { return this->send_count_ <= max_retries; };
// wrong commands (esp. custom commands) can block the send queue
// limit the number of repeats
uint8_t send_countdown{MAX_SEND_REPEATS};
/// factory methods
/** Create modbus read command
* Function code 02-04
@@ -412,11 +413,6 @@ class ModbusCommandItem {
&&handler = nullptr);
bool is_equal(const ModbusCommandItem &other);
protected:
// wrong commands (esp. custom commands) can block the send queue, limit the number of repeats.
/// How many times this command has been sent
uint8_t send_count_{0};
};
/** Modbus controller class.
@@ -468,10 +464,6 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
bool get_module_offline() { return module_offline_; }
/// Set callback for commands
void add_on_command_sent_callback(std::function<void(int, int)> &&callback);
/// called by esphome generated code to set the max_cmd_retries.
void set_max_cmd_retries(uint8_t max_cmd_retries) { this->max_cmd_retries_ = max_cmd_retries; }
/// get how many times a command will be (re)sent if no response is received
uint8_t get_max_cmd_retries() { return this->max_cmd_retries_; }
protected:
/// parse sensormap_ and create range of sequential addresses
@@ -506,8 +498,6 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
bool module_offline_;
/// how many updates to skip if module is offline
uint16_t offline_skip_updates_;
/// How many times we will retry a command if we get no response
uint8_t max_cmd_retries_{4};
CallbackManager<void(int, int)> command_sent_callback_{};
};

View File

@@ -17,7 +17,6 @@ CONFIG_SCHEMA = cv.Schema(
esp8266=False,
esp32=False,
rp2040=False,
bk72xx=False,
): cv.All(
cv.boolean,
cv.Any(
@@ -26,7 +25,6 @@ CONFIG_SCHEMA = cv.Schema(
esp32_arduino=cv.Version(0, 0, 0),
esp8266_arduino=cv.Version(0, 0, 0),
rp2040_arduino=cv.Version(0, 0, 0),
bk72xx_libretiny=cv.Version(1, 7, 0),
),
cv.boolean_false,
),
@@ -54,5 +52,3 @@ async def to_code(config):
cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6")
if CORE.is_esp8266:
cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY")
if CORE.is_bk72xx:
cg.add_build_flag("-DCONFIG_IPV6")

View File

@@ -71,14 +71,6 @@ def _format_framework_arduino_version(ver: cv.Version) -> str:
# return f"~1.{ver.major}{ver.minor:02d}{ver.patch:02d}.0"
def _parse_platform_version(value):
value = cv.string(value)
if value.startswith("http"):
return value
return f"https://github.com/maxgerhardt/platform-raspberrypi.git#{value}"
# NOTE: Keep this in mind when updating the recommended version:
# * The new version needs to be thoroughly validated before changing the
# recommended version as otherwise a bunch of devices could be bricked
@@ -90,9 +82,10 @@ def _parse_platform_version(value):
# - https://api.registry.platformio.org/v3/packages/earlephilhower/tool/framework-arduinopico
RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 9, 4)
# The raspberrypi platform version to use for arduino frameworks
# - https://github.com/maxgerhardt/platform-raspberrypi/tags
RECOMMENDED_ARDUINO_PLATFORM_VERSION = "v1.2.0-gcc12"
# The platformio/raspberrypi version to use for arduino frameworks
# - https://github.com/platformio/platform-raspberrypi/releases
# - https://api.registry.platformio.org/v3/packages/platformio/platform/raspberrypi
ARDUINO_PLATFORM_VERSION = cv.Version(1, 13, 0)
def _arduino_check_versions(value):
@@ -118,8 +111,7 @@ def _arduino_check_versions(value):
value[CONF_SOURCE] = source or _format_framework_arduino_version(version)
value[CONF_PLATFORM_VERSION] = value.get(
CONF_PLATFORM_VERSION,
_parse_platform_version(RECOMMENDED_ARDUINO_PLATFORM_VERSION),
CONF_PLATFORM_VERSION, _parse_platform_version(str(ARDUINO_PLATFORM_VERSION))
)
if version != RECOMMENDED_ARDUINO_FRAMEWORK_VERSION:
@@ -130,6 +122,15 @@ def _arduino_check_versions(value):
return value
def _parse_platform_version(value):
try:
# if platform version is a valid version constraint, prefix the default package
cv.platformio_version_constraint(value)
return f"platformio/raspberrypi@{value}"
except cv.Invalid:
return value
ARDUINO_FRAMEWORK_SCHEMA = cv.All(
cv.Schema(
{

View File

@@ -45,8 +45,11 @@ void UponorSmatrixComponent::loop() {
// Read incoming data
while (this->available()) {
// The controller polls devices every 10 seconds in some units or continuously in others with around 200 ms between
// devices. Remember timestamps so we can send our own packets when the bus is expected to be silent.
// The controller polls devices every 10 seconds, with around 200 ms between devices.
// Remember timestamps so we can send our own packets when the bus is expected to be silent.
if (now - this->last_rx_ > 500) {
this->last_poll_start_ = now;
}
this->last_rx_ = now;
uint8_t byte;
@@ -57,8 +60,7 @@ void UponorSmatrixComponent::loop() {
}
// Send packets during bus silence
if (this->rx_buffer_.empty() && (now - this->last_rx_ > 50) && (now - this->last_rx_ < 100) &&
(now - this->last_tx_ > 200)) {
if ((now - this->last_rx_ > 300) && (now - this->last_poll_start_ < 9500) && (now - this->last_tx_ > 200)) {
#ifdef USE_TIME
// Only build time packet when bus is silent and queue is empty to make sure we can send it right away
if (this->send_time_requested_ && this->tx_queue_.empty() && this->do_send_time_())

View File

@@ -93,6 +93,7 @@ class UponorSmatrixComponent : public uart::UARTDevice, public Component {
std::queue<std::vector<uint8_t>> tx_queue_;
uint32_t last_rx_;
uint32_t last_tx_;
uint32_t last_poll_start_;
#ifdef USE_TIME
time::RealTimeClock *time_id_{nullptr};

View File

@@ -755,7 +755,7 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
message = std::move(arg.value);
}
}
if (code == "wake-word-timeout" || code == "wake_word_detection_aborted" || code == "no_wake_word") {
if (code == "wake-word-timeout" || code == "wake_word_detection_aborted") {
// Don't change state here since either the "tts-end" or "run-end" events will do it.
return;
} else if (code == "wake-provider-missing" || code == "wake-engine-missing") {

View File

@@ -77,18 +77,6 @@ struct Timer {
}
};
struct WakeWord {
std::string id;
std::string wake_word;
std::vector<std::string> trained_languages;
};
struct Configuration {
std::vector<WakeWord> available_wake_words;
std::vector<std::string> active_wake_words;
uint32_t max_active_wake_words;
};
class VoiceAssistant : public Component {
public:
void setup() override;
@@ -145,8 +133,6 @@ class VoiceAssistant : public Component {
void on_audio(const api::VoiceAssistantAudio &msg);
void on_timer_event(const api::VoiceAssistantTimerEventResponse &msg);
void on_announce(const api::VoiceAssistantAnnounceRequest &msg);
void on_set_configuration(const std::vector<std::string> &active_wake_words){};
const Configuration &get_configuration() { return this->config_; };
bool is_running() const { return this->state_ != State::IDLE; }
void set_continuous(bool continuous) { this->continuous_ = continuous; }
@@ -293,8 +279,6 @@ class VoiceAssistant : public Component {
AudioMode audio_mode_{AUDIO_MODE_UDP};
bool udp_socket_running_{false};
bool start_udp_socket_();
Configuration config_{};
};
template<typename... Ts> class StartAction : public Action<Ts...>, public Parented<VoiceAssistant> {

View File

@@ -85,16 +85,7 @@ bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) {
network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() {
if (!this->has_sta())
return {};
network::IPAddresses addresses;
addresses[0] = WiFi.localIP();
#if USE_NETWORK_IPV6
int i = 1;
auto v6_addresses = WiFi.allLocalIPv6();
for (auto address : v6_addresses) {
addresses[i++] = network::IPAddress(address.toString().c_str());
}
#endif /* USE_NETWORK_IPV6 */
return addresses;
return {WiFi.localIP()};
}
bool WiFiComponent::wifi_apply_hostname_() {
@@ -330,11 +321,6 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
s_sta_connecting = false;
break;
}
case ESPHOME_EVENT_ID_WIFI_STA_GOT_IP6: {
// auto it = info.got_ip.ip_info;
ESP_LOGV(TAG, "Event: Got IPv6");
break;
}
case ESPHOME_EVENT_ID_WIFI_STA_LOST_IP: {
ESP_LOGV(TAG, "Event: Lost IP");
break;

View File

@@ -1,6 +1,6 @@
"""Constants used by esphome."""
__version__ = "2024.9.2"
__version__ = "2024.9.0-dev"
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
VALID_SUBSTITUTIONS_CHARACTERS = (
@@ -852,7 +852,6 @@ CONF_TEMPERATURE_STEP = "temperature_step"
CONF_TEXT = "text"
CONF_TEXT_SENSORS = "text_sensors"
CONF_THEN = "then"
CONF_THERMOCOUPLE_TYPE = "thermocouple_type"
CONF_THRESHOLD = "threshold"
CONF_THROTTLE = "throttle"
CONF_TILT = "tilt"

View File

@@ -100,6 +100,9 @@ def valid_include(value):
def valid_project_name(value: str):
if value.count(".") != 1:
raise cv.Invalid("project name needs to have a namespace")
value = value.replace(" ", "_")
return value

View File

@@ -226,6 +226,4 @@ class _Schema(vol.Schema):
if isinstance(schema, vol.Schema):
schema = schema.schema
ret = super().extend(schema, extra=extra)
return _Schema(
ret.schema, extra=ret.extra, extra_schemas=self._extra_schemas.copy()
)
return _Schema(ret.schema, extra=ret.extra, extra_schemas=self._extra_schemas)

View File

@@ -90,6 +90,9 @@ esp32:
RP2040_CONFIG = """
rp2040:
board: {board}
framework:
# Required until https://github.com/platformio/platform-raspberrypi/pull/36 is merged
platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git
"""
BK72XX_CONFIG = """

View File

@@ -119,7 +119,7 @@ lib_deps =
WiFi ; wifi,web_server_base,ethernet (Arduino built-in)
Update ; ota,web_server_base (Arduino built-in)
${common:arduino.lib_deps}
esphome/AsyncTCP-esphome@2.1.4 ; async_tcp
esphome/AsyncTCP-esphome@2.1.3 ; async_tcp
WiFiClientSecure ; http_request,nextion (Arduino built-in)
HTTPClient ; http_request,nextion (Arduino built-in)
ESPmDNS ; mdns (Arduino built-in)
@@ -165,7 +165,7 @@ platform_packages =
extends = common:arduino
board_build.filesystem_size = 0.5m
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#v1.2.0-gcc12
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
platform_packages =
; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted
earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.9.4/rp2040-3.9.4.zip

View File

@@ -9,7 +9,7 @@ tornado==6.4
tzlocal==5.2 # from time
tzdata>=2021.1 # from time
pyserial==3.5
platformio==6.1.15 # When updating platformio, also update Dockerfile
platformio==6.1.15
esptool==4.7.0
click==8.1.7
esphome-dashboard==20240620.0
@@ -17,6 +17,9 @@ aioesphomeapi==24.6.2
zeroconf==0.132.2
python-magic==0.4.27
ruamel.yaml==0.18.6 # dashboard_import
pillow==10.2.0
cairosvg==2.7.1
# esp-idf requires this, but doesn't bundle it by default
# https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24

View File

@@ -1,2 +0,0 @@
pillow==10.2.0
cairosvg==2.7.1

View File

@@ -8,7 +8,6 @@ uart:
sensor:
- platform: bl0906
id: bl
frequency:
name: 'Frequency'
temperature:
@@ -61,9 +60,3 @@ sensor:
name: 'Total_Energy'
total_power:
name: 'Total_Power'
button:
- platform: template
id: reset
on_press:
- bl0906.reset_energy: bl

View File

@@ -10,4 +10,3 @@ sensor:
cs_pin: 12
update_interval: 15s
mains_filter: 50Hz
thermocouple_type: N

View File

@@ -10,5 +10,3 @@ sensor:
cs_pin: 8
update_interval: 15s
mains_filter: 50Hz
thermocouple_type: N

View File

@@ -10,5 +10,3 @@ sensor:
cs_pin: 8
update_interval: 15s
mains_filter: 50Hz
thermocouple_type: N

View File

@@ -10,4 +10,3 @@ sensor:
cs_pin: 12
update_interval: 15s
mains_filter: 50Hz
thermocouple_type: N

View File

@@ -10,5 +10,3 @@ sensor:
cs_pin: 15
update_interval: 15s
mains_filter: 50Hz
thermocouple_type: N

View File

@@ -10,5 +10,3 @@ sensor:
cs_pin: 6
update_interval: 15s
mains_filter: 50Hz
thermocouple_type: N

View File

@@ -29,4 +29,3 @@ modbus_controller:
value_type: S_DWORD_R
read_lambda: |-
return 42.3;
max_cmd_retries: 0

View File

@@ -13,4 +13,3 @@ modbus_controller:
address: 0x2
modbus_id: mod_bus1
allow_duplicate_commands: true
max_cmd_retries: 10

View File

@@ -1,8 +1,4 @@
substitutions:
network_enable_ipv6: "true"
bk72xx:
framework:
version: 1.7.0
network_enable_ipv6: "false"
<<: !include common.yaml

View File

@@ -21,3 +21,4 @@ speaker:
id: speaker_id
dac_type: external
i2s_dout_pin: 13
mode: mono

View File

@@ -21,3 +21,4 @@ speaker:
id: speaker_id
dac_type: external
i2s_dout_pin: 3
mode: mono

View File

@@ -21,3 +21,4 @@ speaker:
id: speaker_id
dac_type: external
i2s_dout_pin: 3
mode: mono

View File

@@ -21,3 +21,4 @@ speaker:
id: speaker_id
dac_type: external
i2s_dout_pin: 13
mode: mono

View File

@@ -28,6 +28,7 @@ speaker:
id: speaker_id
dac_type: external
i2s_dout_pin: 12
mode: mono
voice_assistant:
microphone: mic_id_external

View File

@@ -28,6 +28,7 @@ speaker:
id: speaker_id
dac_type: external
i2s_dout_pin: 2
mode: mono
voice_assistant:
microphone: mic_id_external

View File

@@ -28,6 +28,7 @@ speaker:
id: speaker_id
dac_type: external
i2s_dout_pin: 2
mode: mono
voice_assistant:
microphone: mic_id_external

View File

@@ -28,6 +28,7 @@ speaker:
id: speaker_id
dac_type: external
i2s_dout_pin: 12
mode: mono
voice_assistant:
microphone: mic_id_external

View File

@@ -4,6 +4,9 @@ esphome:
rp2040:
board: rpipicow
framework:
# Waiting for https://github.com/platformio/platform-raspberrypi/pull/36
platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git
logger:
level: VERY_VERBOSE