mirror of
https://github.com/esphome/esphome.git
synced 2026-08-31 10:06:03 +00:00
Merge branch 'dev' into remove-set-retry
This commit is contained in:
@@ -124,6 +124,28 @@ This document provides essential context for AI models interacting with this pro
|
||||
* **Indentation:** Use spaces (two per indentation level), not tabs
|
||||
* **Type aliases:** Prefer `using type_t = int;` over `typedef int type_t;`
|
||||
* **Line length:** Wrap lines at no more than 120 characters
|
||||
* **Constructor parameters vs setters:** Component properties that are both **required** and **invariant**
|
||||
(never change after construction) should be constructor parameters rather than set via setter methods.
|
||||
This makes the dependency explicit and prevents use of the object in an incompletely-initialized state.
|
||||
In code generation, when calling `cg.new_Pvariable()` or the relevant helper function to create the component, pass these as arguments.
|
||||
```cpp
|
||||
// Good - required invariant dependency as constructor parameter
|
||||
class SourceTextSensor : public text_sensor::TextSensor, public Component {
|
||||
public:
|
||||
explicit SourceTextSensor(text::Text *source) : source_(source) {}
|
||||
protected:
|
||||
text::Text *source_;
|
||||
};
|
||||
```
|
||||
```cpp
|
||||
// Bad - required invariant dependency as setter
|
||||
class SourceTextSensor : public text_sensor::TextSensor, public Component {
|
||||
public:
|
||||
void set_source(text::Text *source) { this->source_ = source; }
|
||||
protected:
|
||||
text::Text *source_{nullptr};
|
||||
};
|
||||
```
|
||||
|
||||
* **Component Structure:**
|
||||
* **Standard Files:**
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
44c877ff43765562ac8298902bf2208799643b77facf09c1c0c3c8c4e17187eb
|
||||
f31f13994768b5b07e29624406c9b053bf4bb26e1623ac2bc1e9d4a9477502d6
|
||||
|
||||
@@ -339,7 +339,7 @@ jobs:
|
||||
echo "binary=$BINARY" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run CodSpeed benchmarks
|
||||
uses: CodSpeedHQ/action@281164b0f014a4e7badd2c02cecad9b595b70537 # v4
|
||||
uses: CodSpeedHQ/action@1c8ae4843586d3ba879736b7f6b7b0c990757fab # v4
|
||||
with:
|
||||
run: ${{ steps.build.outputs.binary }}
|
||||
mode: simulation
|
||||
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0
|
||||
uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
@@ -86,6 +86,6 @@ jobs:
|
||||
exit 1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0
|
||||
uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
@@ -458,6 +458,8 @@ esphome/components/socket/* @esphome/core
|
||||
esphome/components/sonoff_d1/* @anatoly-savchenkov
|
||||
esphome/components/sound_level/* @kahrendt
|
||||
esphome/components/spa06_base/* @danielkent-net
|
||||
esphome/components/spa06_i2c/* @danielkent-net
|
||||
esphome/components/spa06_spi/* @danielkent-net
|
||||
esphome/components/speaker/* @jesserockz @kahrendt
|
||||
esphome/components/speaker/media_player/* @kahrendt @synesthesiam
|
||||
esphome/components/speaker_source/* @kahrendt
|
||||
|
||||
+10
-1
@@ -1046,7 +1046,11 @@ def show_logs(config: ConfigType, args: ArgsProtocol, devices: list[str]) -> int
|
||||
):
|
||||
from esphome.components.api.client import run_logs
|
||||
|
||||
return run_logs(config, network_devices)
|
||||
return run_logs(
|
||||
config,
|
||||
network_devices,
|
||||
subscribe_states=not getattr(args, "no_states", False),
|
||||
)
|
||||
|
||||
if port_type in (PortType.NETWORK, PortType.MQTT) and has_mqtt_logging():
|
||||
from esphome import mqtt
|
||||
@@ -1664,6 +1668,11 @@ def parse_args(argv):
|
||||
help="Reset the device before starting serial logs.",
|
||||
default=os.getenv("ESPHOME_SERIAL_LOGGING_RESET"),
|
||||
)
|
||||
parser_logs.add_argument(
|
||||
"--no-states",
|
||||
action="store_true",
|
||||
help="Do not show entity state changes in log output.",
|
||||
)
|
||||
|
||||
parser_discover = subparsers.add_parser(
|
||||
"discover",
|
||||
|
||||
@@ -56,6 +56,10 @@ _COMPONENT_PREFIX_LIB = "[lib]"
|
||||
_COMPONENT_CORE = f"{_COMPONENT_PREFIX_ESPHOME}core"
|
||||
_COMPONENT_API = f"{_COMPONENT_PREFIX_ESPHOME}api"
|
||||
|
||||
# Placement new storage suffix (generated by codegen Pvariable)
|
||||
_PSTORAGE_SUFFIX = "__pstorage"
|
||||
|
||||
|
||||
# C++ namespace prefixes
|
||||
_NAMESPACE_ESPHOME = "esphome::"
|
||||
_NAMESPACE_STD = "std::"
|
||||
@@ -201,6 +205,9 @@ class MemoryAnalyzer:
|
||||
self._cswtch_symbols: list[tuple[str, int, str, str]] = []
|
||||
# Library symbol mapping: symbol_name -> library_name
|
||||
self._lib_symbol_map: dict[str, str] = {}
|
||||
# Source file symbol mapping: symbol_name -> component_name
|
||||
# Used for extern "C" and other symbols without C++ namespace
|
||||
self._source_symbol_map: dict[str, str] = {}
|
||||
# Library dir to name mapping: "lib641" -> "espsoftwareserial",
|
||||
# "espressif__mdns" -> "mdns"
|
||||
self._lib_hash_to_name: dict[str, str] = {}
|
||||
@@ -214,6 +221,7 @@ class MemoryAnalyzer:
|
||||
self._parse_sections()
|
||||
self._parse_symbols()
|
||||
self._scan_libraries()
|
||||
self._scan_source_symbols()
|
||||
self._categorize_symbols()
|
||||
self._analyze_cswtch_symbols()
|
||||
self._analyze_sdk_libraries()
|
||||
@@ -328,6 +336,13 @@ class MemoryAnalyzer:
|
||||
# Demangle C++ names if needed
|
||||
demangled = self._demangle_symbol(symbol_name)
|
||||
|
||||
# Check for placement new storage symbols (generated by codegen)
|
||||
# Format: {component}__{id}__pstorage
|
||||
if demangled.endswith(_PSTORAGE_SUFFIX) and (
|
||||
component := self._match_pstorage_component(demangled)
|
||||
):
|
||||
return component
|
||||
|
||||
# Check for special component classes first (before namespace pattern)
|
||||
# This handles cases like esphome::ESPHomeOTAComponent which should map to ota
|
||||
if _NAMESPACE_ESPHOME in demangled:
|
||||
@@ -363,6 +378,11 @@ class MemoryAnalyzer:
|
||||
if lib_name := self._lib_symbol_map.get(symbol_name):
|
||||
return f"{_COMPONENT_PREFIX_LIB}{lib_name}"
|
||||
|
||||
# Check source file mapping (catches extern "C" functions in ESPHome sources)
|
||||
# Must be before heuristic patterns since source attribution is authoritative
|
||||
if component := self._source_symbol_map.get(symbol_name):
|
||||
return component
|
||||
|
||||
# Check against symbol patterns
|
||||
for component, patterns in SYMBOL_PATTERNS.items():
|
||||
if any(pattern in symbol_name for pattern in patterns):
|
||||
@@ -390,6 +410,24 @@ class MemoryAnalyzer:
|
||||
# Track uncategorized symbols for analysis
|
||||
return "other"
|
||||
|
||||
def _match_pstorage_component(self, symbol_name: str) -> str | None:
|
||||
"""Match a __pstorage symbol to its ESPHome component.
|
||||
|
||||
Symbol format: {component}__{id}__pstorage
|
||||
The component namespace is embedded by codegen before the double underscore.
|
||||
"""
|
||||
prefix = symbol_name[: -len(_PSTORAGE_SUFFIX)]
|
||||
# Extract component namespace before the first double underscore
|
||||
dunder_pos = prefix.find("__")
|
||||
if dunder_pos == -1:
|
||||
return None
|
||||
component_name = prefix[:dunder_pos]
|
||||
if component_name in get_esphome_components():
|
||||
return f"{_COMPONENT_PREFIX_ESPHOME}{component_name}"
|
||||
if component_name in self.external_components:
|
||||
return f"{_COMPONENT_PREFIX_EXTERNAL}{component_name}"
|
||||
return None
|
||||
|
||||
def _batch_demangle_symbols(self, symbols: list[str]) -> None:
|
||||
"""Batch demangle C++ symbol names for efficiency."""
|
||||
if not symbols:
|
||||
@@ -653,6 +691,7 @@ class MemoryAnalyzer:
|
||||
return None
|
||||
|
||||
symbol_map: dict[str, str] = {}
|
||||
source_symbol_map: dict[str, str] = {}
|
||||
current_symbol: str | None = None
|
||||
section_prefixes = (".text.", ".rodata.", ".data.", ".bss.", ".literal.")
|
||||
|
||||
@@ -688,9 +727,18 @@ class MemoryAnalyzer:
|
||||
if dir_key in source_path:
|
||||
symbol_map[current_symbol] = lib_name
|
||||
break
|
||||
else:
|
||||
# Map ESPHome source files to components for extern "C"
|
||||
# and other symbols without C++ namespace
|
||||
component = self._source_file_to_component(source_path)
|
||||
if component.startswith(
|
||||
(_COMPONENT_PREFIX_ESPHOME, _COMPONENT_PREFIX_EXTERNAL)
|
||||
):
|
||||
source_symbol_map[current_symbol] = component
|
||||
|
||||
current_symbol = None
|
||||
|
||||
self._source_symbol_map = source_symbol_map
|
||||
return symbol_map or None
|
||||
|
||||
def _scan_libraries(self) -> None:
|
||||
@@ -741,6 +789,112 @@ class MemoryAnalyzer:
|
||||
len(libraries),
|
||||
)
|
||||
|
||||
def _scan_source_symbols(self) -> None:
|
||||
"""Scan ESPHome source object files to map extern "C" symbols to components.
|
||||
|
||||
When no linker map file is available, this uses ``nm`` to scan ``.o`` files
|
||||
under ``src/esphome/`` and build a symbol-to-component mapping. This catches
|
||||
``extern "C"`` functions and other symbols that lack C++ namespace prefixes.
|
||||
|
||||
Skips scanning if ``_source_symbol_map`` was already populated by
|
||||
``_parse_map_file()``.
|
||||
"""
|
||||
if self._source_symbol_map or not self.nm_path:
|
||||
return
|
||||
|
||||
obj_dir = self._find_object_files_dir()
|
||||
if obj_dir is None:
|
||||
return
|
||||
|
||||
# Find ESPHome source object files
|
||||
esphome_src_dir = obj_dir / "src" / "esphome"
|
||||
if not esphome_src_dir.is_dir():
|
||||
return
|
||||
|
||||
obj_files = sorted(esphome_src_dir.rglob("*.o"))
|
||||
if not obj_files:
|
||||
return
|
||||
|
||||
# Run nm with --print-file-name to get file:symbol mapping
|
||||
result = run_tool(
|
||||
[self.nm_path, "--print-file-name", "-g", "--defined-only"]
|
||||
+ [str(f) for f in obj_files],
|
||||
)
|
||||
if result is None or result.returncode != 0:
|
||||
_LOGGER.debug("nm scan of source objects failed")
|
||||
return
|
||||
|
||||
self._source_symbol_map = self._parse_nm_source_output(result.stdout, obj_dir)
|
||||
if self._source_symbol_map:
|
||||
_LOGGER.info(
|
||||
"Built source symbol map from nm: %d symbols",
|
||||
len(self._source_symbol_map),
|
||||
)
|
||||
|
||||
def _parse_nm_source_output(self, output: str, base_dir: Path) -> dict[str, str]:
|
||||
"""Parse nm output to map non-namespaced symbols to ESPHome components.
|
||||
|
||||
Extracts global defined symbols from ESPHome source object files that
|
||||
don't use C++ namespacing (e.g. ``extern "C"`` functions).
|
||||
|
||||
Args:
|
||||
output: Raw stdout from ``nm --print-file-name -g --defined-only``
|
||||
or ``nm --print-file-name -S``.
|
||||
base_dir: Build directory for computing relative paths.
|
||||
|
||||
Returns:
|
||||
Dict mapping symbol names to component names.
|
||||
"""
|
||||
source_map: dict[str, str] = {}
|
||||
for line in output.splitlines():
|
||||
# Format: /path/to/file.o: addr type name
|
||||
# or: /path/to/file.o: addr size type name (with -S)
|
||||
colon_idx = line.rfind(".o:")
|
||||
if colon_idx == -1:
|
||||
continue
|
||||
|
||||
file_path = line[: colon_idx + 2]
|
||||
fields = line[colon_idx + 3 :].split()
|
||||
if len(fields) < 3:
|
||||
continue
|
||||
|
||||
# With -S flag, format is: addr size type name
|
||||
# Without -S flag: addr type name
|
||||
# type is a single char; size is hex digits
|
||||
# Detect by checking if fields[1] is a single uppercase letter (type)
|
||||
if len(fields[1]) == 1 and fields[1].isalpha():
|
||||
# addr type name
|
||||
sym_type = fields[1]
|
||||
symbol_name = fields[2]
|
||||
elif len(fields) >= 4:
|
||||
# addr size type name
|
||||
sym_type = fields[2]
|
||||
symbol_name = fields[3]
|
||||
else:
|
||||
continue
|
||||
|
||||
# Only global defined symbols (uppercase type)
|
||||
if not sym_type.isupper() or sym_type == "U":
|
||||
continue
|
||||
|
||||
# Skip symbols already in esphome:: namespace
|
||||
if symbol_name.startswith("_ZN7esphome"):
|
||||
continue
|
||||
|
||||
# Make path relative to base_dir for _source_file_to_component
|
||||
try:
|
||||
rel_path = str(Path(file_path).relative_to(base_dir))
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
component = self._source_file_to_component(rel_path)
|
||||
if component.startswith(
|
||||
(_COMPONENT_PREFIX_ESPHOME, _COMPONENT_PREFIX_EXTERNAL)
|
||||
):
|
||||
source_map[symbol_name] = component
|
||||
|
||||
return source_map
|
||||
|
||||
def _find_object_files_dir(self) -> Path | None:
|
||||
"""Find the directory containing object files for this build.
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ from . import (
|
||||
_COMPONENT_PREFIX_ESPHOME,
|
||||
_COMPONENT_PREFIX_EXTERNAL,
|
||||
_COMPONENT_PREFIX_LIB,
|
||||
_PSTORAGE_SUFFIX,
|
||||
RAM_SECTIONS,
|
||||
MemoryAnalyzer,
|
||||
)
|
||||
@@ -23,6 +24,17 @@ if TYPE_CHECKING:
|
||||
from . import ComponentMemory
|
||||
|
||||
|
||||
def _format_pstorage_name(name: str) -> str:
|
||||
"""Format a __pstorage symbol as 'storage for {id}'."""
|
||||
if not name.endswith(_PSTORAGE_SUFFIX):
|
||||
return name
|
||||
prefix = name[: -len(_PSTORAGE_SUFFIX)]
|
||||
# Strip component namespace prefix: {component}__{id} -> {id}
|
||||
dunder_pos = prefix.find("__")
|
||||
var_id = prefix[dunder_pos + 2 :] if dunder_pos != -1 else prefix
|
||||
return f"storage for {var_id}"
|
||||
|
||||
|
||||
class MemoryAnalyzerCLI(MemoryAnalyzer):
|
||||
"""Memory analyzer with CLI-specific report generation."""
|
||||
|
||||
@@ -148,11 +160,14 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
||||
If section is one of the RAM sections (.data or .bss), a label like
|
||||
" [data]" or " [bss]" is appended. For non-RAM sections or when
|
||||
section is None, no section label is added.
|
||||
|
||||
Placement new storage symbols are formatted as "storage for {id}".
|
||||
"""
|
||||
display_name = _format_pstorage_name(demangled)
|
||||
section_label = ""
|
||||
if section in RAM_SECTIONS:
|
||||
section_label = f" [{section[1:]}]" # .data -> [data], .bss -> [bss]
|
||||
return f"{demangled} ({size:,} B){section_label}"
|
||||
return f"{display_name} ({size:,} B){section_label}"
|
||||
|
||||
def _add_top_symbols(self, lines: list[str]) -> None:
|
||||
"""Add a section showing the top largest symbols in the binary."""
|
||||
@@ -175,11 +190,13 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
||||
for i, (_, demangled, size, section, component) in enumerate(top_symbols):
|
||||
# Format section label
|
||||
section_label = f"[{section[1:]}]" if section else ""
|
||||
# Truncate demangled name if too long
|
||||
# Format storage symbols readably
|
||||
display_name = _format_pstorage_name(demangled)
|
||||
# Truncate if too long
|
||||
demangled_display = (
|
||||
f"{demangled[:truncate_limit]}..."
|
||||
if len(demangled) > self.COL_TOP_SYMBOL_NAME
|
||||
else demangled
|
||||
f"{display_name[:truncate_limit]}..."
|
||||
if len(display_name) > self.COL_TOP_SYMBOL_NAME
|
||||
else display_name
|
||||
)
|
||||
lines.append(
|
||||
f"{i + 1:>2}. {size:>7,} B {section_label:<8} {demangled_display:<{self.COL_TOP_SYMBOL_NAME}} {component}"
|
||||
@@ -573,15 +590,16 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
||||
lines.append(f"Total size: {comp_mem.flash_total:,} B")
|
||||
lines.append("")
|
||||
|
||||
# Show all symbols above threshold for better visibility
|
||||
# Show symbols above threshold, always include storage symbols
|
||||
large_symbols = [
|
||||
(sym, dem, size, sec)
|
||||
for sym, dem, size, sec in sorted_symbols
|
||||
if size > self.SYMBOL_SIZE_THRESHOLD
|
||||
or dem.endswith(_PSTORAGE_SUFFIX)
|
||||
]
|
||||
|
||||
lines.append(
|
||||
f"{comp_name} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B ({len(large_symbols)} symbols):"
|
||||
f"{comp_name} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B & storage ({len(large_symbols)} symbols):"
|
||||
)
|
||||
for i, (symbol, demangled, size, section) in enumerate(large_symbols):
|
||||
lines.append(
|
||||
@@ -604,7 +622,10 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
||||
# Sort by size descending
|
||||
sorted_ram_syms = sorted(ram_syms, key=lambda x: x[2], reverse=True)
|
||||
large_ram_syms = [
|
||||
s for s in sorted_ram_syms if s[2] > self.RAM_SYMBOL_SIZE_THRESHOLD
|
||||
s
|
||||
for s in sorted_ram_syms
|
||||
if s[2] > self.RAM_SYMBOL_SIZE_THRESHOLD
|
||||
or s[1].endswith(_PSTORAGE_SUFFIX)
|
||||
]
|
||||
|
||||
lines.append(f"{name} ({mem.ram_total:,} B total RAM):")
|
||||
@@ -622,13 +643,14 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
||||
for symbol, demangled, size, section in large_ram_syms[:10]:
|
||||
# Format section label consistently by stripping leading dot
|
||||
section_label = section.lstrip(".") if section else ""
|
||||
display_name = _format_pstorage_name(demangled)
|
||||
# Add ellipsis if name is truncated
|
||||
demangled_display = (
|
||||
f"{demangled[:70]}..." if len(demangled) > 70 else demangled
|
||||
)
|
||||
lines.append(
|
||||
f" {size:>6,} B [{section_label}] {demangled_display}"
|
||||
display_name = (
|
||||
f"{display_name[:70]}..."
|
||||
if len(display_name) > 70
|
||||
else display_name
|
||||
)
|
||||
lines.append(f" {size:>6,} B [{section_label}] {display_name}")
|
||||
if len(large_ram_syms) > 10:
|
||||
lines.append(f" ... and {len(large_ram_syms) - 10} more")
|
||||
lines.append("")
|
||||
|
||||
@@ -408,7 +408,6 @@ SYMBOL_PATTERNS = {
|
||||
],
|
||||
"arduino_core": [
|
||||
"pinMode",
|
||||
"resetPins",
|
||||
"millis",
|
||||
"micros",
|
||||
"delay(", # More specific - Arduino delay function with parenthesis
|
||||
|
||||
@@ -413,13 +413,16 @@ async def if_action_to_code(
|
||||
template_arg: cg.TemplateArguments,
|
||||
args: TemplateArgsType,
|
||||
) -> MockObj:
|
||||
has_else = CONF_ELSE in config
|
||||
# Prepend HasElse bool to template arguments: IfAction<HasElse, Ts...>
|
||||
if_template_arg = cg.TemplateArguments(has_else, *template_arg)
|
||||
cond_conf = next(el for el in config if el in (CONF_ANY, CONF_ALL, CONF_CONDITION))
|
||||
condition = await build_condition(config[cond_conf], template_arg, args)
|
||||
var = cg.new_Pvariable(action_id, template_arg, condition)
|
||||
var = cg.new_Pvariable(action_id, if_template_arg, condition)
|
||||
if CONF_THEN in config:
|
||||
actions = await build_action_list(config[CONF_THEN], template_arg, args)
|
||||
cg.add(var.add_then(actions))
|
||||
if CONF_ELSE in config:
|
||||
if has_else:
|
||||
actions = await build_action_list(config[CONF_ELSE], template_arg, args)
|
||||
cg.add(var.add_else(actions))
|
||||
return var
|
||||
|
||||
@@ -53,6 +53,13 @@ def get_project_cmakelists() -> str:
|
||||
variant = get_esp32_variant()
|
||||
idf_target = variant.lower().replace("-", "")
|
||||
|
||||
# Extract compile definitions from build flags (-DXXX -> XXX)
|
||||
compile_defs = [flag for flag in CORE.build_flags if flag.startswith("-D")]
|
||||
extra_compile_options = "\n".join(
|
||||
f'idf_build_set_property(COMPILE_OPTIONS "{compile_def}" APPEND)'
|
||||
for compile_def in compile_defs
|
||||
)
|
||||
|
||||
return f"""\
|
||||
# Auto-generated by ESPHome
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
@@ -61,6 +68,9 @@ set(IDF_TARGET {idf_target})
|
||||
set(EXTRA_COMPONENT_DIRS ${{CMAKE_SOURCE_DIR}}/src)
|
||||
|
||||
include($ENV{{IDF_PATH}}/tools/cmake/project.cmake)
|
||||
|
||||
{extra_compile_options}
|
||||
|
||||
project({CORE.name})
|
||||
"""
|
||||
|
||||
@@ -70,10 +80,6 @@ def get_component_cmakelists(minimal: bool = False) -> str:
|
||||
idf_requires = [] if minimal else (get_available_components() or [])
|
||||
requires_str = " ".join(idf_requires)
|
||||
|
||||
# Extract compile definitions from build flags (-DXXX -> XXX)
|
||||
compile_defs = [flag[2:] for flag in CORE.build_flags if flag.startswith("-D")]
|
||||
compile_defs_str = "\n ".join(sorted(compile_defs)) if compile_defs else ""
|
||||
|
||||
# Extract compile options (-W flags, excluding linker flags)
|
||||
compile_opts = [
|
||||
flag
|
||||
@@ -104,11 +110,6 @@ idf_component_register(
|
||||
# Apply C++ standard
|
||||
target_compile_features(${{COMPONENT_LIB}} PUBLIC cxx_std_20)
|
||||
|
||||
# ESPHome compile definitions
|
||||
target_compile_definitions(${{COMPONENT_LIB}} PUBLIC
|
||||
{compile_defs_str}
|
||||
)
|
||||
|
||||
# ESPHome compile options
|
||||
target_compile_options(${{COMPONENT_LIB}} PUBLIC
|
||||
{compile_opts_str}
|
||||
|
||||
@@ -31,7 +31,7 @@ void AlarmControlPanel::publish_state(AlarmControlPanelState state) {
|
||||
this->last_update_ = millis();
|
||||
if (state != this->current_state_) {
|
||||
auto prev_state = this->current_state_;
|
||||
ESP_LOGD(TAG, "'%s' >> %s (was %s)", this->get_name().c_str(),
|
||||
ESP_LOGV(TAG, "'%s' >> %s (was %s)", this->get_name().c_str(),
|
||||
LOG_STR_ARG(alarm_control_panel_state_to_string(state)),
|
||||
LOG_STR_ARG(alarm_control_panel_state_to_string(prev_state)));
|
||||
this->current_state_ = state;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
@@ -455,6 +455,9 @@ async def to_code(config: ConfigType) -> None:
|
||||
cg.add_define("USE_API_PLAINTEXT")
|
||||
cg.add_define("USE_API_NOISE")
|
||||
cg.add_library("esphome/noise-c", "0.1.11")
|
||||
# Enable optimized memzero/memcmp in libsodium instead of volatile byte loops
|
||||
cg.add_build_flag("-DHAVE_WEAK_SYMBOLS=1")
|
||||
cg.add_build_flag("-DHAVE_INLINE_ASM=1")
|
||||
else:
|
||||
cg.add_define("USE_API_PLAINTEXT")
|
||||
|
||||
|
||||
@@ -316,7 +316,7 @@ message ListEntitiesBinarySensorResponse {
|
||||
option (ifdef) = "USE_BINARY_SENSOR";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -334,7 +334,7 @@ message BinarySensorStateResponse {
|
||||
option (ifdef) = "USE_BINARY_SENSOR";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bool state = 2;
|
||||
// If the binary sensor does not have a valid state yet.
|
||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||
@@ -350,7 +350,7 @@ message ListEntitiesCoverResponse {
|
||||
option (ifdef) = "USE_COVER";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -383,7 +383,7 @@ message CoverStateResponse {
|
||||
option (ifdef) = "USE_COVER";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
// legacy: state has been removed in 1.13
|
||||
// clients/servers must still send/accept it until the next protocol change
|
||||
// Deprecated in API version 1.1
|
||||
@@ -409,7 +409,7 @@ message CoverCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
|
||||
// legacy: command has been removed in 1.13
|
||||
// clients/servers must still send/accept it until the next protocol change
|
||||
@@ -434,7 +434,7 @@ message ListEntitiesFanResponse {
|
||||
option (ifdef) = "USE_FAN";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -466,7 +466,7 @@ message FanStateResponse {
|
||||
option (ifdef) = "USE_FAN";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bool state = 2;
|
||||
bool oscillating = 3;
|
||||
// Deprecated in API version 1.6
|
||||
@@ -483,7 +483,7 @@ message FanCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bool has_state = 2;
|
||||
bool state = 3;
|
||||
// Deprecated in API version 1.6
|
||||
@@ -522,7 +522,7 @@ message ListEntitiesLightResponse {
|
||||
option (ifdef) = "USE_LIGHT";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -551,7 +551,7 @@ message LightStateResponse {
|
||||
option (ifdef) = "USE_LIGHT";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bool state = 2;
|
||||
float brightness = 3;
|
||||
ColorMode color_mode = 11;
|
||||
@@ -573,7 +573,7 @@ message LightCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bool has_state = 2;
|
||||
bool state = 3;
|
||||
bool has_brightness = 4;
|
||||
@@ -627,7 +627,7 @@ message ListEntitiesSensorResponse {
|
||||
option (ifdef) = "USE_SENSOR";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -651,7 +651,7 @@ message SensorStateResponse {
|
||||
option (ifdef) = "USE_SENSOR";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
float state = 2;
|
||||
// If the sensor does not have a valid state yet.
|
||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||
@@ -667,7 +667,7 @@ message ListEntitiesSwitchResponse {
|
||||
option (ifdef) = "USE_SWITCH";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -685,7 +685,7 @@ message SwitchStateResponse {
|
||||
option (ifdef) = "USE_SWITCH";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bool state = 2;
|
||||
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
@@ -696,7 +696,7 @@ message SwitchCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bool state = 2;
|
||||
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
@@ -709,7 +709,7 @@ message ListEntitiesTextSensorResponse {
|
||||
option (ifdef) = "USE_TEXT_SENSOR";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -726,7 +726,7 @@ message TextSensorStateResponse {
|
||||
option (ifdef) = "USE_TEXT_SENSOR";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
string state = 2;
|
||||
// If the text sensor does not have a valid state yet.
|
||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||
@@ -922,7 +922,7 @@ message ListEntitiesServicesResponse {
|
||||
option (ifdef) = "USE_API_USER_DEFINED_ACTIONS";
|
||||
|
||||
string name = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
repeated ListEntitiesServicesArgument args = 3 [(fixed_vector) = true];
|
||||
SupportsResponseType supports_response = 4;
|
||||
}
|
||||
@@ -945,7 +945,7 @@ message ExecuteServiceRequest {
|
||||
option (no_delay) = true;
|
||||
option (ifdef) = "USE_API_USER_DEFINED_ACTIONS";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
repeated ExecuteServiceArgument args = 2 [(fixed_vector) = true];
|
||||
uint32 call_id = 3 [(field_ifdef) = "USE_API_USER_DEFINED_ACTION_RESPONSES"];
|
||||
bool return_response = 4 [(field_ifdef) = "USE_API_USER_DEFINED_ACTION_RESPONSES"];
|
||||
@@ -972,7 +972,7 @@ message ListEntitiesCameraResponse {
|
||||
option (ifdef) = "USE_CAMERA";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
bool disabled_by_default = 5;
|
||||
@@ -987,7 +987,7 @@ message CameraImageResponse {
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_CAMERA";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bytes data = 2;
|
||||
bool done = 3;
|
||||
uint32 device_id = 4 [(field_ifdef) = "USE_DEVICES"];
|
||||
@@ -1057,7 +1057,7 @@ message ListEntitiesClimateResponse {
|
||||
option (ifdef) = "USE_CLIMATE";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -1095,7 +1095,7 @@ message ClimateStateResponse {
|
||||
option (ifdef) = "USE_CLIMATE";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
ClimateMode mode = 2;
|
||||
float current_temperature = 3;
|
||||
float target_temperature = 4;
|
||||
@@ -1121,7 +1121,7 @@ message ClimateCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bool has_mode = 2;
|
||||
ClimateMode mode = 3;
|
||||
bool has_target_temperature = 4;
|
||||
@@ -1168,7 +1168,7 @@ message ListEntitiesWaterHeaterResponse {
|
||||
option (ifdef) = "USE_WATER_HEATER";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
string icon = 4 [(field_ifdef) = "USE_ENTITY_ICON"];
|
||||
bool disabled_by_default = 5;
|
||||
@@ -1189,7 +1189,7 @@ message WaterHeaterStateResponse {
|
||||
option (ifdef) = "USE_WATER_HEATER";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
float current_temperature = 2;
|
||||
float target_temperature = 3;
|
||||
WaterHeaterMode mode = 4;
|
||||
@@ -1219,7 +1219,7 @@ message WaterHeaterCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
// Bitmask of which fields are set (see WaterHeaterCommandHasField)
|
||||
uint32 has_fields = 2;
|
||||
WaterHeaterMode mode = 3;
|
||||
@@ -1244,7 +1244,7 @@ message ListEntitiesNumberResponse {
|
||||
option (ifdef) = "USE_NUMBER";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -1266,7 +1266,7 @@ message NumberStateResponse {
|
||||
option (ifdef) = "USE_NUMBER";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
float state = 2;
|
||||
// If the number does not have a valid state yet.
|
||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||
@@ -1280,7 +1280,7 @@ message NumberCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
float state = 2;
|
||||
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
@@ -1293,7 +1293,7 @@ message ListEntitiesSelectResponse {
|
||||
option (ifdef) = "USE_SELECT";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -1310,7 +1310,7 @@ message SelectStateResponse {
|
||||
option (ifdef) = "USE_SELECT";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
string state = 2;
|
||||
// If the select does not have a valid state yet.
|
||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||
@@ -1324,7 +1324,7 @@ message SelectCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
string state = 2;
|
||||
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
@@ -1337,7 +1337,7 @@ message ListEntitiesSirenResponse {
|
||||
option (ifdef) = "USE_SIREN";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -1356,7 +1356,7 @@ message SirenStateResponse {
|
||||
option (ifdef) = "USE_SIREN";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bool state = 2;
|
||||
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
@@ -1367,7 +1367,7 @@ message SirenCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bool has_state = 2;
|
||||
bool state = 3;
|
||||
bool has_tone = 4;
|
||||
@@ -1400,7 +1400,7 @@ message ListEntitiesLockResponse {
|
||||
option (ifdef) = "USE_LOCK";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -1422,7 +1422,7 @@ message LockStateResponse {
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_LOCK";
|
||||
option (no_delay) = true;
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
LockState state = 2;
|
||||
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
@@ -1432,7 +1432,7 @@ message LockCommandRequest {
|
||||
option (ifdef) = "USE_LOCK";
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
LockCommand command = 2;
|
||||
|
||||
// Not yet implemented:
|
||||
@@ -1449,7 +1449,7 @@ message ListEntitiesButtonResponse {
|
||||
option (ifdef) = "USE_BUTTON";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -1466,7 +1466,7 @@ message ButtonCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
uint32 device_id = 2 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
|
||||
@@ -1516,7 +1516,7 @@ message ListEntitiesMediaPlayerResponse {
|
||||
option (ifdef) = "USE_MEDIA_PLAYER";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -1538,7 +1538,7 @@ message MediaPlayerStateResponse {
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_MEDIA_PLAYER";
|
||||
option (no_delay) = true;
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
MediaPlayerState state = 2;
|
||||
float volume = 3;
|
||||
bool muted = 4;
|
||||
@@ -1551,7 +1551,7 @@ message MediaPlayerCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
|
||||
bool has_command = 2;
|
||||
MediaPlayerCommand command = 3;
|
||||
@@ -2104,7 +2104,7 @@ message ListEntitiesAlarmControlPanelResponse {
|
||||
option (ifdef) = "USE_ALARM_CONTROL_PANEL";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON"];
|
||||
@@ -2122,7 +2122,7 @@ message AlarmControlPanelStateResponse {
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_ALARM_CONTROL_PANEL";
|
||||
option (no_delay) = true;
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
AlarmControlPanelState state = 2;
|
||||
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
@@ -2133,7 +2133,7 @@ message AlarmControlPanelCommandRequest {
|
||||
option (ifdef) = "USE_ALARM_CONTROL_PANEL";
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
AlarmControlPanelStateCommand command = 2;
|
||||
string code = 3;
|
||||
uint32 device_id = 4 [(field_ifdef) = "USE_DEVICES"];
|
||||
@@ -2151,7 +2151,7 @@ message ListEntitiesTextResponse {
|
||||
option (ifdef) = "USE_TEXT";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON"];
|
||||
@@ -2171,7 +2171,7 @@ message TextStateResponse {
|
||||
option (ifdef) = "USE_TEXT";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
string state = 2;
|
||||
// If the Text does not have a valid state yet.
|
||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||
@@ -2185,7 +2185,7 @@ message TextCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
string state = 2;
|
||||
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
@@ -2199,7 +2199,7 @@ message ListEntitiesDateResponse {
|
||||
option (ifdef) = "USE_DATETIME_DATE";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -2215,7 +2215,7 @@ message DateStateResponse {
|
||||
option (ifdef) = "USE_DATETIME_DATE";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
// If the date does not have a valid state yet.
|
||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||
bool missing_state = 2;
|
||||
@@ -2231,7 +2231,7 @@ message DateCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
uint32 year = 2;
|
||||
uint32 month = 3;
|
||||
uint32 day = 4;
|
||||
@@ -2246,7 +2246,7 @@ message ListEntitiesTimeResponse {
|
||||
option (ifdef) = "USE_DATETIME_TIME";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -2262,7 +2262,7 @@ message TimeStateResponse {
|
||||
option (ifdef) = "USE_DATETIME_TIME";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
// If the time does not have a valid state yet.
|
||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||
bool missing_state = 2;
|
||||
@@ -2278,7 +2278,7 @@ message TimeCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
uint32 hour = 2;
|
||||
uint32 minute = 3;
|
||||
uint32 second = 4;
|
||||
@@ -2293,7 +2293,7 @@ message ListEntitiesEventResponse {
|
||||
option (ifdef) = "USE_EVENT";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -2311,7 +2311,7 @@ message EventResponse {
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_EVENT";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
string event_type = 2;
|
||||
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
@@ -2324,7 +2324,7 @@ message ListEntitiesValveResponse {
|
||||
option (ifdef) = "USE_VALVE";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -2351,7 +2351,7 @@ message ValveStateResponse {
|
||||
option (ifdef) = "USE_VALVE";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
float position = 2;
|
||||
ValveOperation current_operation = 3;
|
||||
uint32 device_id = 4 [(field_ifdef) = "USE_DEVICES"];
|
||||
@@ -2364,7 +2364,7 @@ message ValveCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bool has_position = 2;
|
||||
float position = 3;
|
||||
bool stop = 4;
|
||||
@@ -2379,7 +2379,7 @@ message ListEntitiesDateTimeResponse {
|
||||
option (ifdef) = "USE_DATETIME_DATETIME";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -2395,7 +2395,7 @@ message DateTimeStateResponse {
|
||||
option (ifdef) = "USE_DATETIME_DATETIME";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
// If the datetime does not have a valid state yet.
|
||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||
bool missing_state = 2;
|
||||
@@ -2409,7 +2409,7 @@ message DateTimeCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
fixed32 epoch_seconds = 2;
|
||||
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
@@ -2422,7 +2422,7 @@ message ListEntitiesUpdateResponse {
|
||||
option (ifdef) = "USE_UPDATE";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
@@ -2439,7 +2439,7 @@ message UpdateStateResponse {
|
||||
option (ifdef) = "USE_UPDATE";
|
||||
option (no_delay) = true;
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
bool missing_state = 2;
|
||||
bool in_progress = 3;
|
||||
bool has_progress = 4;
|
||||
@@ -2463,7 +2463,7 @@ message UpdateCommandRequest {
|
||||
option (no_delay) = true;
|
||||
option (base_class) = "CommandProtoMessage";
|
||||
|
||||
fixed32 key = 1;
|
||||
fixed32 key = 1 [(force) = true];
|
||||
UpdateCommand command = 2;
|
||||
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
@@ -2505,13 +2505,14 @@ message ListEntitiesInfraredResponse {
|
||||
option (ifdef) = "USE_INFRARED";
|
||||
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3;
|
||||
string icon = 4 [(field_ifdef) = "USE_ENTITY_ICON"];
|
||||
bool disabled_by_default = 5;
|
||||
EntityCategory entity_category = 6;
|
||||
uint32 device_id = 7 [(field_ifdef) = "USE_DEVICES"];
|
||||
uint32 capabilities = 8; // Bitfield of InfraredCapabilityFlags
|
||||
uint32 receiver_frequency = 9; // Demodulation frequency of the IR receiver in Hz (0 = unspecified)
|
||||
}
|
||||
|
||||
// Command to transmit infrared/RF data using raw timings
|
||||
@@ -2521,7 +2522,7 @@ message InfraredRFTransmitRawTimingsRequest {
|
||||
option (ifdef) = "USE_IR_RF";
|
||||
|
||||
uint32 device_id = 1 [(field_ifdef) = "USE_DEVICES"];
|
||||
fixed32 key = 2; // Key identifying the transmitter instance
|
||||
fixed32 key = 2 [(force) = true]; // Key identifying the transmitter instance
|
||||
uint32 carrier_frequency = 3; // Carrier frequency in Hz
|
||||
uint32 repeat_count = 4; // Number of times to transmit (1 = once, 2 = twice, etc.)
|
||||
repeated sint32 timings = 5 [packed = true, (packed_buffer) = true]; // Raw timings in microseconds (zigzag-encoded): positive = mark (LED/TX on), negative = space (LED/TX off)
|
||||
@@ -2535,7 +2536,7 @@ message InfraredRFReceiveEvent {
|
||||
option (no_delay) = true;
|
||||
|
||||
uint32 device_id = 1 [(field_ifdef) = "USE_DEVICES"];
|
||||
fixed32 key = 2; // Key identifying the receiver instance
|
||||
fixed32 key = 2 [(force) = true]; // Key identifying the receiver instance
|
||||
repeated sint32 timings = 3 [packed = true, (container_pointer_no_template) = "std::vector<int32_t>"]; // Raw timings in microseconds (zigzag-encoded): alternating mark/space periods
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,11 @@ static constexpr uint32_t KEEPALIVE_DISCONNECT_TIMEOUT = (KEEPALIVE_TIMEOUT_MS *
|
||||
// A stalled handshake from a buggy client or network glitch holds a connection
|
||||
// slot, which can prevent legitimate clients from reconnecting. Also hardens
|
||||
// against the less likely case of intentional connection slot exhaustion.
|
||||
static constexpr uint32_t HANDSHAKE_TIMEOUT_MS = 15000;
|
||||
//
|
||||
// 60s is intentionally high: on ESP8266 with power_save_mode: LIGHT and weak
|
||||
// WiFi (-70 dBm+), TCP retransmissions push real-world handshake times to
|
||||
// 28-30s. See https://github.com/esphome/esphome/issues/14999
|
||||
static constexpr uint32_t HANDSHAKE_TIMEOUT_MS = 60000;
|
||||
|
||||
static constexpr auto ESPHOME_VERSION_REF = StringRef::from_lit(ESPHOME_VERSION);
|
||||
|
||||
@@ -230,7 +234,7 @@ void APIConnection::loop() {
|
||||
this->last_traffic_ = now;
|
||||
}
|
||||
// read a packet
|
||||
this->read_message(buffer.data_len, buffer.type, buffer.data);
|
||||
this->read_message_(buffer.data_len, buffer.type, buffer.data);
|
||||
if (this->flags_.remove)
|
||||
return;
|
||||
}
|
||||
@@ -1515,16 +1519,16 @@ void APIConnection::on_serial_proxy_request(const SerialProxyRequest &msg) {
|
||||
resp.instance = msg.instance;
|
||||
resp.type = enums::SERIAL_PROXY_REQUEST_TYPE_FLUSH;
|
||||
switch (proxies[msg.instance]->flush_port()) {
|
||||
case uart::FlushResult::SUCCESS:
|
||||
case uart::UARTFlushResult::UART_FLUSH_RESULT_SUCCESS:
|
||||
resp.status = enums::SERIAL_PROXY_STATUS_OK;
|
||||
break;
|
||||
case uart::FlushResult::ASSUMED_SUCCESS:
|
||||
case uart::UARTFlushResult::UART_FLUSH_RESULT_ASSUMED_SUCCESS:
|
||||
resp.status = enums::SERIAL_PROXY_STATUS_ASSUMED_SUCCESS;
|
||||
break;
|
||||
case uart::FlushResult::TIMEOUT:
|
||||
case uart::UARTFlushResult::UART_FLUSH_RESULT_TIMEOUT:
|
||||
resp.status = enums::SERIAL_PROXY_STATUS_TIMEOUT;
|
||||
break;
|
||||
case uart::FlushResult::FAILED:
|
||||
case uart::UARTFlushResult::UART_FLUSH_RESULT_FAILED:
|
||||
resp.status = enums::SERIAL_PROXY_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
@@ -1545,6 +1549,7 @@ uint16_t APIConnection::try_send_infrared_info(EntityBase *entity, APIConnection
|
||||
auto *infrared = static_cast<infrared::Infrared *>(entity);
|
||||
ListEntitiesInfraredResponse msg;
|
||||
msg.capabilities = infrared->get_capability_flags();
|
||||
msg.receiver_frequency = infrared->get_traits().get_receiver_frequency_hz();
|
||||
return fill_and_encode_entity_info(infrared, msg, conn, remaining_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -49,11 +49,29 @@ class APIConnection final : public APIServerConnectionBase {
|
||||
friend class APIServer;
|
||||
friend class ListEntitiesIterator;
|
||||
APIConnection(std::unique_ptr<socket::Socket> socket, APIServer *parent);
|
||||
virtual ~APIConnection();
|
||||
~APIConnection();
|
||||
|
||||
void start();
|
||||
void loop();
|
||||
|
||||
protected:
|
||||
// read_message_ is defined here (instead of in APIServerConnectionBase) so the
|
||||
// compiler can devirtualize and inline on_* handler calls within this final class.
|
||||
void read_message_(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data);
|
||||
|
||||
// Auth helpers defined here (not in ProtoService) so the compiler can
|
||||
// devirtualize is_connection_setup()/on_no_setup_connection() calls
|
||||
// within this final class.
|
||||
inline bool check_connection_setup_() {
|
||||
if (!this->is_connection_setup()) {
|
||||
this->on_no_setup_connection();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
inline bool check_authenticated_() { return this->check_connection_setup_(); }
|
||||
|
||||
public:
|
||||
bool send_list_info_done() {
|
||||
return this->schedule_message_(nullptr, ListEntitiesDoneResponse::MESSAGE_TYPE,
|
||||
ListEntitiesDoneResponse::ESTIMATED_SIZE);
|
||||
@@ -63,72 +81,72 @@ class APIConnection final : public APIServerConnectionBase {
|
||||
#endif
|
||||
#ifdef USE_COVER
|
||||
bool send_cover_state(cover::Cover *cover);
|
||||
void on_cover_command_request(const CoverCommandRequest &msg) override;
|
||||
void on_cover_command_request(const CoverCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
bool send_fan_state(fan::Fan *fan);
|
||||
void on_fan_command_request(const FanCommandRequest &msg) override;
|
||||
void on_fan_command_request(const FanCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
bool send_light_state(light::LightState *light);
|
||||
void on_light_command_request(const LightCommandRequest &msg) override;
|
||||
void on_light_command_request(const LightCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
bool send_sensor_state(sensor::Sensor *sensor);
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
bool send_switch_state(switch_::Switch *a_switch);
|
||||
void on_switch_command_request(const SwitchCommandRequest &msg) override;
|
||||
void on_switch_command_request(const SwitchCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
bool send_text_sensor_state(text_sensor::TextSensor *text_sensor);
|
||||
#endif
|
||||
#ifdef USE_CAMERA
|
||||
void set_camera_state(std::shared_ptr<camera::CameraImage> image);
|
||||
void on_camera_image_request(const CameraImageRequest &msg) override;
|
||||
void on_camera_image_request(const CameraImageRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
bool send_climate_state(climate::Climate *climate);
|
||||
void on_climate_command_request(const ClimateCommandRequest &msg) override;
|
||||
void on_climate_command_request(const ClimateCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
bool send_number_state(number::Number *number);
|
||||
void on_number_command_request(const NumberCommandRequest &msg) override;
|
||||
void on_number_command_request(const NumberCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_DATETIME_DATE
|
||||
bool send_date_state(datetime::DateEntity *date);
|
||||
void on_date_command_request(const DateCommandRequest &msg) override;
|
||||
void on_date_command_request(const DateCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_DATETIME_TIME
|
||||
bool send_time_state(datetime::TimeEntity *time);
|
||||
void on_time_command_request(const TimeCommandRequest &msg) override;
|
||||
void on_time_command_request(const TimeCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_DATETIME_DATETIME
|
||||
bool send_datetime_state(datetime::DateTimeEntity *datetime);
|
||||
void on_date_time_command_request(const DateTimeCommandRequest &msg) override;
|
||||
void on_date_time_command_request(const DateTimeCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_TEXT
|
||||
bool send_text_state(text::Text *text);
|
||||
void on_text_command_request(const TextCommandRequest &msg) override;
|
||||
void on_text_command_request(const TextCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
bool send_select_state(select::Select *select);
|
||||
void on_select_command_request(const SelectCommandRequest &msg) override;
|
||||
void on_select_command_request(const SelectCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_BUTTON
|
||||
void on_button_command_request(const ButtonCommandRequest &msg) override;
|
||||
void on_button_command_request(const ButtonCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_LOCK
|
||||
bool send_lock_state(lock::Lock *a_lock);
|
||||
void on_lock_command_request(const LockCommandRequest &msg) override;
|
||||
void on_lock_command_request(const LockCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_VALVE
|
||||
bool send_valve_state(valve::Valve *valve);
|
||||
void on_valve_command_request(const ValveCommandRequest &msg) override;
|
||||
void on_valve_command_request(const ValveCommandRequest &msg);
|
||||
#endif
|
||||
#ifdef USE_MEDIA_PLAYER
|
||||
bool send_media_player_state(media_player::MediaPlayer *media_player);
|
||||
void on_media_player_command_request(const MediaPlayerCommandRequest &msg) override;
|
||||
void on_media_player_command_request(const MediaPlayerCommandRequest &msg);
|
||||
#endif
|
||||
bool try_send_log_message(int level, const char *tag, const char *line, size_t message_len);
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
@@ -138,23 +156,23 @@ class APIConnection final : public APIServerConnectionBase {
|
||||
this->send_message(call);
|
||||
}
|
||||
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
|
||||
void on_homeassistant_action_response(const HomeassistantActionResponse &msg) override;
|
||||
void on_homeassistant_action_response(const HomeassistantActionResponse &msg);
|
||||
#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES
|
||||
#endif // USE_API_HOMEASSISTANT_SERVICES
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override;
|
||||
void on_unsubscribe_bluetooth_le_advertisements_request() override;
|
||||
void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg);
|
||||
void on_unsubscribe_bluetooth_le_advertisements_request();
|
||||
|
||||
void on_bluetooth_device_request(const BluetoothDeviceRequest &msg) override;
|
||||
void on_bluetooth_gatt_read_request(const BluetoothGATTReadRequest &msg) override;
|
||||
void on_bluetooth_gatt_write_request(const BluetoothGATTWriteRequest &msg) override;
|
||||
void on_bluetooth_gatt_read_descriptor_request(const BluetoothGATTReadDescriptorRequest &msg) override;
|
||||
void on_bluetooth_gatt_write_descriptor_request(const BluetoothGATTWriteDescriptorRequest &msg) override;
|
||||
void on_bluetooth_gatt_get_services_request(const BluetoothGATTGetServicesRequest &msg) override;
|
||||
void on_bluetooth_gatt_notify_request(const BluetoothGATTNotifyRequest &msg) override;
|
||||
void on_subscribe_bluetooth_connections_free_request() override;
|
||||
void on_bluetooth_scanner_set_mode_request(const BluetoothScannerSetModeRequest &msg) override;
|
||||
void on_bluetooth_set_connection_params_request(const BluetoothSetConnectionParamsRequest &msg) override;
|
||||
void on_bluetooth_device_request(const BluetoothDeviceRequest &msg);
|
||||
void on_bluetooth_gatt_read_request(const BluetoothGATTReadRequest &msg);
|
||||
void on_bluetooth_gatt_write_request(const BluetoothGATTWriteRequest &msg);
|
||||
void on_bluetooth_gatt_read_descriptor_request(const BluetoothGATTReadDescriptorRequest &msg);
|
||||
void on_bluetooth_gatt_write_descriptor_request(const BluetoothGATTWriteDescriptorRequest &msg);
|
||||
void on_bluetooth_gatt_get_services_request(const BluetoothGATTGetServicesRequest &msg);
|
||||
void on_bluetooth_gatt_notify_request(const BluetoothGATTNotifyRequest &msg);
|
||||
void on_subscribe_bluetooth_connections_free_request();
|
||||
void on_bluetooth_scanner_set_mode_request(const BluetoothScannerSetModeRequest &msg);
|
||||
void on_bluetooth_set_connection_params_request(const BluetoothSetConnectionParamsRequest &msg);
|
||||
|
||||
#endif
|
||||
#ifdef USE_HOMEASSISTANT_TIME
|
||||
@@ -165,42 +183,42 @@ class APIConnection final : public APIServerConnectionBase {
|
||||
#endif
|
||||
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &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_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;
|
||||
void on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &msg) override;
|
||||
void on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) override;
|
||||
void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg);
|
||||
void on_voice_assistant_response(const VoiceAssistantResponse &msg);
|
||||
void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg);
|
||||
void on_voice_assistant_audio(const VoiceAssistantAudio &msg);
|
||||
void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg);
|
||||
void on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &msg);
|
||||
void on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &msg);
|
||||
void on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg);
|
||||
#endif
|
||||
|
||||
#ifdef USE_ZWAVE_PROXY
|
||||
void on_z_wave_proxy_frame(const ZWaveProxyFrame &msg) override;
|
||||
void on_z_wave_proxy_request(const ZWaveProxyRequest &msg) override;
|
||||
void on_z_wave_proxy_frame(const ZWaveProxyFrame &msg);
|
||||
void on_z_wave_proxy_request(const ZWaveProxyRequest &msg);
|
||||
#endif
|
||||
|
||||
#ifdef USE_ALARM_CONTROL_PANEL
|
||||
bool send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
|
||||
void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) override;
|
||||
void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg);
|
||||
#endif
|
||||
|
||||
#ifdef USE_WATER_HEATER
|
||||
bool send_water_heater_state(water_heater::WaterHeater *water_heater);
|
||||
void on_water_heater_command_request(const WaterHeaterCommandRequest &msg) override;
|
||||
void on_water_heater_command_request(const WaterHeaterCommandRequest &msg);
|
||||
#endif
|
||||
|
||||
#ifdef USE_IR_RF
|
||||
void on_infrared_rf_transmit_raw_timings_request(const InfraredRFTransmitRawTimingsRequest &msg) override;
|
||||
void on_infrared_rf_transmit_raw_timings_request(const InfraredRFTransmitRawTimingsRequest &msg);
|
||||
void send_infrared_rf_receive_event(const InfraredRFReceiveEvent &msg);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SERIAL_PROXY
|
||||
void on_serial_proxy_configure_request(const SerialProxyConfigureRequest &msg) override;
|
||||
void on_serial_proxy_write_request(const SerialProxyWriteRequest &msg) override;
|
||||
void on_serial_proxy_set_modem_pins_request(const SerialProxySetModemPinsRequest &msg) override;
|
||||
void on_serial_proxy_get_modem_pins_request(const SerialProxyGetModemPinsRequest &msg) override;
|
||||
void on_serial_proxy_request(const SerialProxyRequest &msg) override;
|
||||
void on_serial_proxy_configure_request(const SerialProxyConfigureRequest &msg);
|
||||
void on_serial_proxy_write_request(const SerialProxyWriteRequest &msg);
|
||||
void on_serial_proxy_set_modem_pins_request(const SerialProxySetModemPinsRequest &msg);
|
||||
void on_serial_proxy_get_modem_pins_request(const SerialProxyGetModemPinsRequest &msg);
|
||||
void on_serial_proxy_request(const SerialProxyRequest &msg);
|
||||
void send_serial_proxy_data(const SerialProxyDataReceived &msg);
|
||||
#endif
|
||||
|
||||
@@ -210,26 +228,26 @@ class APIConnection final : public APIServerConnectionBase {
|
||||
|
||||
#ifdef USE_UPDATE
|
||||
bool send_update_state(update::UpdateEntity *update);
|
||||
void on_update_command_request(const UpdateCommandRequest &msg) override;
|
||||
void on_update_command_request(const UpdateCommandRequest &msg);
|
||||
#endif
|
||||
|
||||
void on_disconnect_response() override;
|
||||
void on_ping_response() override {
|
||||
void on_disconnect_response();
|
||||
void on_ping_response() {
|
||||
// we initiated ping
|
||||
this->flags_.sent_ping = false;
|
||||
}
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
void on_home_assistant_state_response(const HomeAssistantStateResponse &msg) override;
|
||||
void on_home_assistant_state_response(const HomeAssistantStateResponse &msg);
|
||||
#endif
|
||||
#ifdef USE_HOMEASSISTANT_TIME
|
||||
void on_get_time_response(const GetTimeResponse &value) override;
|
||||
void on_get_time_response(const GetTimeResponse &value);
|
||||
#endif
|
||||
void on_hello_request(const HelloRequest &msg) override;
|
||||
void on_disconnect_request() override;
|
||||
void on_ping_request() override;
|
||||
void on_device_info_request() override;
|
||||
void on_list_entities_request() override { this->begin_iterator_(ActiveIterator::LIST_ENTITIES); }
|
||||
void on_subscribe_states_request() override {
|
||||
void on_hello_request(const HelloRequest &msg);
|
||||
void on_disconnect_request();
|
||||
void on_ping_request();
|
||||
void on_device_info_request();
|
||||
void on_list_entities_request() { this->begin_iterator_(ActiveIterator::LIST_ENTITIES); }
|
||||
void on_subscribe_states_request() {
|
||||
this->flags_.state_subscription = true;
|
||||
// Start initial state iterator only if no iterator is active
|
||||
// If list_entities is running, we'll start initial_state when it completes
|
||||
@@ -237,7 +255,7 @@ class APIConnection final : public APIServerConnectionBase {
|
||||
this->begin_iterator_(ActiveIterator::INITIAL_STATE);
|
||||
}
|
||||
}
|
||||
void on_subscribe_logs_request(const SubscribeLogsRequest &msg) override {
|
||||
void on_subscribe_logs_request(const SubscribeLogsRequest &msg) {
|
||||
this->flags_.log_subscription = msg.level;
|
||||
if (msg.dump_config)
|
||||
App.schedule_dump_config();
|
||||
@@ -249,13 +267,13 @@ class APIConnection final : public APIServerConnectionBase {
|
||||
#endif
|
||||
}
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
void on_subscribe_homeassistant_services_request() override { this->flags_.service_call_subscription = true; }
|
||||
void on_subscribe_homeassistant_services_request() { this->flags_.service_call_subscription = true; }
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
void on_subscribe_home_assistant_states_request() override;
|
||||
void on_subscribe_home_assistant_states_request();
|
||||
#endif
|
||||
#ifdef USE_API_USER_DEFINED_ACTIONS
|
||||
void on_execute_service_request(const ExecuteServiceRequest &msg) override;
|
||||
void on_execute_service_request(const ExecuteServiceRequest &msg);
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
|
||||
void send_execute_service_response(uint32_t call_id, bool success, StringRef error_message);
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
|
||||
@@ -265,13 +283,13 @@ class APIConnection final : public APIServerConnectionBase {
|
||||
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES
|
||||
#endif
|
||||
#ifdef USE_API_NOISE
|
||||
void on_noise_encryption_set_key_request(const NoiseEncryptionSetKeyRequest &msg) override;
|
||||
void on_noise_encryption_set_key_request(const NoiseEncryptionSetKeyRequest &msg);
|
||||
#endif
|
||||
|
||||
bool is_authenticated() override {
|
||||
bool is_authenticated() {
|
||||
return static_cast<ConnectionState>(this->flags_.connection_state) == ConnectionState::AUTHENTICATED;
|
||||
}
|
||||
bool is_connection_setup() override {
|
||||
bool is_connection_setup() {
|
||||
return static_cast<ConnectionState>(this->flags_.connection_state) == ConnectionState::CONNECTED ||
|
||||
this->is_authenticated();
|
||||
}
|
||||
@@ -284,8 +302,8 @@ class APIConnection final : public APIServerConnectionBase {
|
||||
(this->client_api_version_major_ == major && this->client_api_version_minor_ >= minor);
|
||||
}
|
||||
|
||||
void on_fatal_error() override;
|
||||
void on_no_setup_connection() override;
|
||||
void on_fatal_error();
|
||||
void on_no_setup_connection();
|
||||
|
||||
// Function pointer type for type-erased message encoding
|
||||
using MessageEncodeFn = void (*)(const void *, ProtoWriteBuffer &);
|
||||
@@ -324,7 +342,7 @@ class APIConnection final : public APIServerConnectionBase {
|
||||
return true;
|
||||
return this->try_to_clear_buffer_slow_(log_out_of_space);
|
||||
}
|
||||
bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) override;
|
||||
bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type);
|
||||
|
||||
const char *get_name() const { return this->helper_->get_client_name(); }
|
||||
/// Get peer name (IP address) into caller-provided buffer, returns buf for convenience
|
||||
|
||||
+109
-103
@@ -208,7 +208,7 @@ uint32_t DeviceInfoResponse::calculate_size() const {
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
buffer.encode_string(5, this->device_class);
|
||||
buffer.encode_bool(6, this->is_status_binary_sensor);
|
||||
@@ -224,7 +224,7 @@ void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesBinarySensorResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
size += ProtoSize::calc_length(1, this->device_class.size());
|
||||
size += ProtoSize::calc_bool(1, this->is_status_binary_sensor);
|
||||
@@ -239,7 +239,7 @@ uint32_t ListEntitiesBinarySensorResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void BinarySensorStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_bool(2, this->state);
|
||||
buffer.encode_bool(3, this->missing_state);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -248,7 +248,7 @@ void BinarySensorStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t BinarySensorStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_bool(1, this->state);
|
||||
size += ProtoSize::calc_bool(1, this->missing_state);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -260,7 +260,7 @@ uint32_t BinarySensorStateResponse::calculate_size() const {
|
||||
#ifdef USE_COVER
|
||||
void ListEntitiesCoverResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
buffer.encode_bool(5, this->assumed_state);
|
||||
buffer.encode_bool(6, this->supports_position);
|
||||
@@ -279,7 +279,7 @@ void ListEntitiesCoverResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesCoverResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
size += ProtoSize::calc_bool(1, this->assumed_state);
|
||||
size += ProtoSize::calc_bool(1, this->supports_position);
|
||||
@@ -297,7 +297,7 @@ uint32_t ListEntitiesCoverResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void CoverStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_float(3, this->position);
|
||||
buffer.encode_float(4, this->tilt);
|
||||
buffer.encode_uint32(5, static_cast<uint32_t>(this->current_operation));
|
||||
@@ -307,7 +307,7 @@ void CoverStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t CoverStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_float(1, this->position);
|
||||
size += ProtoSize::calc_float(1, this->tilt);
|
||||
size += ProtoSize::calc_uint32(1, static_cast<uint32_t>(this->current_operation));
|
||||
@@ -357,7 +357,7 @@ bool CoverCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_FAN
|
||||
void ListEntitiesFanResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
buffer.encode_bool(5, this->supports_oscillation);
|
||||
buffer.encode_bool(6, this->supports_speed);
|
||||
@@ -378,7 +378,7 @@ void ListEntitiesFanResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesFanResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
size += ProtoSize::calc_bool(1, this->supports_oscillation);
|
||||
size += ProtoSize::calc_bool(1, this->supports_speed);
|
||||
@@ -400,7 +400,7 @@ uint32_t ListEntitiesFanResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void FanStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_bool(2, this->state);
|
||||
buffer.encode_bool(3, this->oscillating);
|
||||
buffer.encode_uint32(5, static_cast<uint32_t>(this->direction));
|
||||
@@ -412,7 +412,7 @@ void FanStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t FanStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_bool(1, this->state);
|
||||
size += ProtoSize::calc_bool(1, this->oscillating);
|
||||
size += ProtoSize::calc_uint32(1, static_cast<uint32_t>(this->direction));
|
||||
@@ -487,7 +487,7 @@ bool FanCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_LIGHT
|
||||
void ListEntitiesLightResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
for (const auto &it : *this->supported_color_modes) {
|
||||
buffer.encode_uint32(12, static_cast<uint32_t>(it), true);
|
||||
@@ -509,7 +509,7 @@ void ListEntitiesLightResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesLightResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
if (!this->supported_color_modes->empty()) {
|
||||
for (const auto &it : *this->supported_color_modes) {
|
||||
@@ -534,7 +534,7 @@ uint32_t ListEntitiesLightResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void LightStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_bool(2, this->state);
|
||||
buffer.encode_float(3, this->brightness);
|
||||
buffer.encode_uint32(11, static_cast<uint32_t>(this->color_mode));
|
||||
@@ -553,7 +553,7 @@ void LightStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t LightStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_bool(1, this->state);
|
||||
size += ProtoSize::calc_float(1, this->brightness);
|
||||
size += ProtoSize::calc_uint32(1, static_cast<uint32_t>(this->color_mode));
|
||||
@@ -683,7 +683,7 @@ bool LightCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_SENSOR
|
||||
void ListEntitiesSensorResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -702,7 +702,7 @@ void ListEntitiesSensorResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesSensorResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -720,7 +720,7 @@ uint32_t ListEntitiesSensorResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void SensorStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_float(2, this->state);
|
||||
buffer.encode_bool(3, this->missing_state);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -729,7 +729,7 @@ void SensorStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t SensorStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_float(1, this->state);
|
||||
size += ProtoSize::calc_bool(1, this->missing_state);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -741,7 +741,7 @@ uint32_t SensorStateResponse::calculate_size() const {
|
||||
#ifdef USE_SWITCH
|
||||
void ListEntitiesSwitchResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -757,7 +757,7 @@ void ListEntitiesSwitchResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesSwitchResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -772,7 +772,7 @@ uint32_t ListEntitiesSwitchResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void SwitchStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_bool(2, this->state);
|
||||
#ifdef USE_DEVICES
|
||||
buffer.encode_uint32(3, this->device_id);
|
||||
@@ -780,7 +780,7 @@ void SwitchStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t SwitchStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_bool(1, this->state);
|
||||
#ifdef USE_DEVICES
|
||||
size += ProtoSize::calc_uint32(1, this->device_id);
|
||||
@@ -816,7 +816,7 @@ bool SwitchCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
void ListEntitiesTextSensorResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -831,7 +831,7 @@ void ListEntitiesTextSensorResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesTextSensorResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -845,7 +845,7 @@ uint32_t ListEntitiesTextSensorResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void TextSensorStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_string(2, this->state);
|
||||
buffer.encode_bool(3, this->missing_state);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -854,7 +854,7 @@ void TextSensorStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t TextSensorStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->state.size());
|
||||
size += ProtoSize::calc_bool(1, this->missing_state);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -1124,7 +1124,7 @@ uint32_t ListEntitiesServicesArgument::calculate_size() const {
|
||||
}
|
||||
void ListEntitiesServicesResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->name);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
for (auto &it : this->args) {
|
||||
buffer.encode_sub_message(3, it);
|
||||
}
|
||||
@@ -1133,7 +1133,7 @@ void ListEntitiesServicesResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesServicesResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
if (!this->args.empty()) {
|
||||
for (const auto &it : this->args) {
|
||||
size += ProtoSize::calc_message_force(1, it.calculate_size());
|
||||
@@ -1269,7 +1269,7 @@ uint32_t ExecuteServiceResponse::calculate_size() const {
|
||||
#ifdef USE_CAMERA
|
||||
void ListEntitiesCameraResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
buffer.encode_bool(5, this->disabled_by_default);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
@@ -1283,7 +1283,7 @@ void ListEntitiesCameraResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesCameraResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
size += ProtoSize::calc_bool(1, this->disabled_by_default);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
@@ -1296,7 +1296,7 @@ uint32_t ListEntitiesCameraResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void CameraImageResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_bytes(2, this->data_ptr_, this->data_len_);
|
||||
buffer.encode_bool(3, this->done);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -1305,7 +1305,7 @@ void CameraImageResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t CameraImageResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->data_len_);
|
||||
size += ProtoSize::calc_bool(1, this->done);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -1330,7 +1330,7 @@ bool CameraImageRequest::decode_varint(uint32_t field_id, proto_varint_value_t v
|
||||
#ifdef USE_CLIMATE
|
||||
void ListEntitiesClimateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
buffer.encode_bool(5, this->supports_current_temperature);
|
||||
buffer.encode_bool(6, this->supports_two_point_target_temperature);
|
||||
@@ -1374,7 +1374,7 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesClimateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
size += ProtoSize::calc_bool(1, this->supports_current_temperature);
|
||||
size += ProtoSize::calc_bool(1, this->supports_two_point_target_temperature);
|
||||
@@ -1429,7 +1429,7 @@ uint32_t ListEntitiesClimateResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void ClimateStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_uint32(2, static_cast<uint32_t>(this->mode));
|
||||
buffer.encode_float(3, this->current_temperature);
|
||||
buffer.encode_float(4, this->target_temperature);
|
||||
@@ -1449,7 +1449,7 @@ void ClimateStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t ClimateStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_uint32(1, static_cast<uint32_t>(this->mode));
|
||||
size += ProtoSize::calc_float(1, this->current_temperature);
|
||||
size += ProtoSize::calc_float(1, this->target_temperature);
|
||||
@@ -1563,7 +1563,7 @@ bool ClimateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_WATER_HEATER
|
||||
void ListEntitiesWaterHeaterResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(4, this->icon);
|
||||
@@ -1584,7 +1584,7 @@ void ListEntitiesWaterHeaterResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesWaterHeaterResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -1606,7 +1606,7 @@ uint32_t ListEntitiesWaterHeaterResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void WaterHeaterStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_float(2, this->current_temperature);
|
||||
buffer.encode_float(3, this->target_temperature);
|
||||
buffer.encode_uint32(4, static_cast<uint32_t>(this->mode));
|
||||
@@ -1619,7 +1619,7 @@ void WaterHeaterStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t WaterHeaterStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_float(1, this->current_temperature);
|
||||
size += ProtoSize::calc_float(1, this->target_temperature);
|
||||
size += ProtoSize::calc_uint32(1, static_cast<uint32_t>(this->mode));
|
||||
@@ -1675,7 +1675,7 @@ bool WaterHeaterCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value
|
||||
#ifdef USE_NUMBER
|
||||
void ListEntitiesNumberResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -1695,7 +1695,7 @@ void ListEntitiesNumberResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesNumberResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -1714,7 +1714,7 @@ uint32_t ListEntitiesNumberResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void NumberStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_float(2, this->state);
|
||||
buffer.encode_bool(3, this->missing_state);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -1723,7 +1723,7 @@ void NumberStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t NumberStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_float(1, this->state);
|
||||
size += ProtoSize::calc_bool(1, this->missing_state);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -1760,7 +1760,7 @@ bool NumberCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_SELECT
|
||||
void ListEntitiesSelectResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -1777,7 +1777,7 @@ void ListEntitiesSelectResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesSelectResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -1795,7 +1795,7 @@ uint32_t ListEntitiesSelectResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void SelectStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_string(2, this->state);
|
||||
buffer.encode_bool(3, this->missing_state);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -1804,7 +1804,7 @@ void SelectStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t SelectStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->state.size());
|
||||
size += ProtoSize::calc_bool(1, this->missing_state);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -1849,7 +1849,7 @@ bool SelectCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_SIREN
|
||||
void ListEntitiesSirenResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -1868,7 +1868,7 @@ void ListEntitiesSirenResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesSirenResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -1888,7 +1888,7 @@ uint32_t ListEntitiesSirenResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void SirenStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_bool(2, this->state);
|
||||
#ifdef USE_DEVICES
|
||||
buffer.encode_uint32(3, this->device_id);
|
||||
@@ -1896,7 +1896,7 @@ void SirenStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t SirenStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_bool(1, this->state);
|
||||
#ifdef USE_DEVICES
|
||||
size += ProtoSize::calc_uint32(1, this->device_id);
|
||||
@@ -1961,7 +1961,7 @@ bool SirenCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_LOCK
|
||||
void ListEntitiesLockResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -1979,7 +1979,7 @@ void ListEntitiesLockResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesLockResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -1996,7 +1996,7 @@ uint32_t ListEntitiesLockResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void LockStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_uint32(2, static_cast<uint32_t>(this->state));
|
||||
#ifdef USE_DEVICES
|
||||
buffer.encode_uint32(3, this->device_id);
|
||||
@@ -2004,7 +2004,7 @@ void LockStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t LockStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_uint32(1, static_cast<uint32_t>(this->state));
|
||||
#ifdef USE_DEVICES
|
||||
size += ProtoSize::calc_uint32(1, this->device_id);
|
||||
@@ -2054,7 +2054,7 @@ bool LockCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_BUTTON
|
||||
void ListEntitiesButtonResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -2069,7 +2069,7 @@ void ListEntitiesButtonResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesButtonResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -2124,7 +2124,7 @@ uint32_t MediaPlayerSupportedFormat::calculate_size() const {
|
||||
}
|
||||
void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -2143,7 +2143,7 @@ void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesMediaPlayerResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -2163,7 +2163,7 @@ uint32_t ListEntitiesMediaPlayerResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void MediaPlayerStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_uint32(2, static_cast<uint32_t>(this->state));
|
||||
buffer.encode_float(3, this->volume);
|
||||
buffer.encode_bool(4, this->muted);
|
||||
@@ -2173,7 +2173,7 @@ void MediaPlayerStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t MediaPlayerStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_uint32(1, static_cast<uint32_t>(this->state));
|
||||
size += ProtoSize::calc_float(1, this->volume);
|
||||
size += ProtoSize::calc_bool(1, this->muted);
|
||||
@@ -2249,10 +2249,14 @@ bool SubscribeBluetoothLEAdvertisementsRequest::decode_varint(uint32_t field_id,
|
||||
return true;
|
||||
}
|
||||
void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_uint64(1, this->address, true);
|
||||
buffer.encode_sint32(2, this->rssi, true);
|
||||
buffer.write_raw_byte(8);
|
||||
buffer.encode_varint_raw_64(this->address);
|
||||
buffer.write_raw_byte(16);
|
||||
buffer.encode_varint_raw(encode_zigzag32(this->rssi));
|
||||
buffer.encode_uint32(3, this->address_type);
|
||||
buffer.encode_bytes(4, this->data, this->data_len, true);
|
||||
buffer.write_raw_byte(34);
|
||||
buffer.encode_varint_raw(this->data_len);
|
||||
buffer.encode_raw(this->data, this->data_len);
|
||||
}
|
||||
uint32_t BluetoothLERawAdvertisement::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
@@ -2942,7 +2946,7 @@ bool VoiceAssistantSetConfiguration::decode_length(uint32_t field_id, ProtoLengt
|
||||
#ifdef USE_ALARM_CONTROL_PANEL
|
||||
void ListEntitiesAlarmControlPanelResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -2959,7 +2963,7 @@ void ListEntitiesAlarmControlPanelResponse::encode(ProtoWriteBuffer &buffer) con
|
||||
uint32_t ListEntitiesAlarmControlPanelResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -2975,7 +2979,7 @@ uint32_t ListEntitiesAlarmControlPanelResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void AlarmControlPanelStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_uint32(2, static_cast<uint32_t>(this->state));
|
||||
#ifdef USE_DEVICES
|
||||
buffer.encode_uint32(3, this->device_id);
|
||||
@@ -2983,7 +2987,7 @@ void AlarmControlPanelStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t AlarmControlPanelStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_uint32(1, static_cast<uint32_t>(this->state));
|
||||
#ifdef USE_DEVICES
|
||||
size += ProtoSize::calc_uint32(1, this->device_id);
|
||||
@@ -3030,7 +3034,7 @@ bool AlarmControlPanelCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit
|
||||
#ifdef USE_TEXT
|
||||
void ListEntitiesTextResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -3048,7 +3052,7 @@ void ListEntitiesTextResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesTextResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -3065,7 +3069,7 @@ uint32_t ListEntitiesTextResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void TextStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_string(2, this->state);
|
||||
buffer.encode_bool(3, this->missing_state);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -3074,7 +3078,7 @@ void TextStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t TextStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->state.size());
|
||||
size += ProtoSize::calc_bool(1, this->missing_state);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -3119,7 +3123,7 @@ bool TextCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_DATETIME_DATE
|
||||
void ListEntitiesDateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -3133,7 +3137,7 @@ void ListEntitiesDateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesDateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -3146,7 +3150,7 @@ uint32_t ListEntitiesDateResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void DateStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_bool(2, this->missing_state);
|
||||
buffer.encode_uint32(3, this->year);
|
||||
buffer.encode_uint32(4, this->month);
|
||||
@@ -3157,7 +3161,7 @@ void DateStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t DateStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_bool(1, this->missing_state);
|
||||
size += ProtoSize::calc_uint32(1, this->year);
|
||||
size += ProtoSize::calc_uint32(1, this->month);
|
||||
@@ -3202,7 +3206,7 @@ bool DateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_DATETIME_TIME
|
||||
void ListEntitiesTimeResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -3216,7 +3220,7 @@ void ListEntitiesTimeResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesTimeResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -3229,7 +3233,7 @@ uint32_t ListEntitiesTimeResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void TimeStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_bool(2, this->missing_state);
|
||||
buffer.encode_uint32(3, this->hour);
|
||||
buffer.encode_uint32(4, this->minute);
|
||||
@@ -3240,7 +3244,7 @@ void TimeStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t TimeStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_bool(1, this->missing_state);
|
||||
size += ProtoSize::calc_uint32(1, this->hour);
|
||||
size += ProtoSize::calc_uint32(1, this->minute);
|
||||
@@ -3285,7 +3289,7 @@ bool TimeCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_EVENT
|
||||
void ListEntitiesEventResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -3303,7 +3307,7 @@ void ListEntitiesEventResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesEventResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -3322,7 +3326,7 @@ uint32_t ListEntitiesEventResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void EventResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_string(2, this->event_type);
|
||||
#ifdef USE_DEVICES
|
||||
buffer.encode_uint32(3, this->device_id);
|
||||
@@ -3330,7 +3334,7 @@ void EventResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t EventResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->event_type.size());
|
||||
#ifdef USE_DEVICES
|
||||
size += ProtoSize::calc_uint32(1, this->device_id);
|
||||
@@ -3341,7 +3345,7 @@ uint32_t EventResponse::calculate_size() const {
|
||||
#ifdef USE_VALVE
|
||||
void ListEntitiesValveResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -3359,7 +3363,7 @@ void ListEntitiesValveResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesValveResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -3376,7 +3380,7 @@ uint32_t ListEntitiesValveResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void ValveStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_float(2, this->position);
|
||||
buffer.encode_uint32(3, static_cast<uint32_t>(this->current_operation));
|
||||
#ifdef USE_DEVICES
|
||||
@@ -3385,7 +3389,7 @@ void ValveStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t ValveStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_float(1, this->position);
|
||||
size += ProtoSize::calc_uint32(1, static_cast<uint32_t>(this->current_operation));
|
||||
#ifdef USE_DEVICES
|
||||
@@ -3428,7 +3432,7 @@ bool ValveCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_DATETIME_DATETIME
|
||||
void ListEntitiesDateTimeResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -3442,7 +3446,7 @@ void ListEntitiesDateTimeResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesDateTimeResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -3455,7 +3459,7 @@ uint32_t ListEntitiesDateTimeResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void DateTimeStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_bool(2, this->missing_state);
|
||||
buffer.encode_fixed32(3, this->epoch_seconds);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -3464,7 +3468,7 @@ void DateTimeStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t DateTimeStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_bool(1, this->missing_state);
|
||||
size += ProtoSize::calc_fixed32(1, this->epoch_seconds);
|
||||
#ifdef USE_DEVICES
|
||||
@@ -3501,7 +3505,7 @@ bool DateTimeCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
#ifdef USE_UPDATE
|
||||
void ListEntitiesUpdateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(5, this->icon);
|
||||
@@ -3516,7 +3520,7 @@ void ListEntitiesUpdateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
uint32_t ListEntitiesUpdateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -3530,7 +3534,7 @@ uint32_t ListEntitiesUpdateResponse::calculate_size() const {
|
||||
return size;
|
||||
}
|
||||
void UpdateStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.write_tag_and_fixed32(13, this->key);
|
||||
buffer.encode_bool(2, this->missing_state);
|
||||
buffer.encode_bool(3, this->in_progress);
|
||||
buffer.encode_bool(4, this->has_progress);
|
||||
@@ -3546,7 +3550,7 @@ void UpdateStateResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
}
|
||||
uint32_t UpdateStateResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_bool(1, this->missing_state);
|
||||
size += ProtoSize::calc_bool(1, this->in_progress);
|
||||
size += ProtoSize::calc_bool(1, this->has_progress);
|
||||
@@ -3642,7 +3646,7 @@ uint32_t ZWaveProxyRequest::calculate_size() const {
|
||||
#ifdef USE_INFRARED
|
||||
void ListEntitiesInfraredResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_string(1, this->object_id);
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
buffer.encode_string(3, this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
buffer.encode_string(4, this->icon);
|
||||
@@ -3653,11 +3657,12 @@ void ListEntitiesInfraredResponse::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.encode_uint32(7, this->device_id);
|
||||
#endif
|
||||
buffer.encode_uint32(8, this->capabilities);
|
||||
buffer.encode_uint32(9, this->receiver_frequency);
|
||||
}
|
||||
uint32_t ListEntitiesInfraredResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->object_id.size());
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
#ifdef USE_ENTITY_ICON
|
||||
size += ProtoSize::calc_length(1, this->icon.size());
|
||||
@@ -3668,6 +3673,7 @@ uint32_t ListEntitiesInfraredResponse::calculate_size() const {
|
||||
size += ProtoSize::calc_uint32(1, this->device_id);
|
||||
#endif
|
||||
size += ProtoSize::calc_uint32(1, this->capabilities);
|
||||
size += ProtoSize::calc_uint32(1, this->receiver_frequency);
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
@@ -3717,7 +3723,7 @@ void InfraredRFReceiveEvent::encode(ProtoWriteBuffer &buffer) const {
|
||||
#ifdef USE_DEVICES
|
||||
buffer.encode_uint32(1, this->device_id);
|
||||
#endif
|
||||
buffer.encode_fixed32(2, this->key);
|
||||
buffer.write_tag_and_fixed32(21, this->key);
|
||||
for (const auto &it : *this->timings) {
|
||||
buffer.encode_sint32(3, it, true);
|
||||
}
|
||||
@@ -3727,7 +3733,7 @@ uint32_t InfraredRFReceiveEvent::calculate_size() const {
|
||||
#ifdef USE_DEVICES
|
||||
size += ProtoSize::calc_uint32(1, this->device_id);
|
||||
#endif
|
||||
size += ProtoSize::calc_fixed32(1, this->key);
|
||||
size += 5;
|
||||
if (!this->timings->empty()) {
|
||||
for (const auto &it : *this->timings) {
|
||||
size += ProtoSize::calc_sint32_force(1, it);
|
||||
|
||||
+141
-140
File diff suppressed because it is too large
Load Diff
+1226
-1200
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
// This file was automatically generated with a tool.
|
||||
// See script/api_protobuf/api_protobuf.py
|
||||
#include "api_pb2_service.h"
|
||||
#include "api_connection.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::api {
|
||||
@@ -8,8 +9,8 @@ namespace esphome::api {
|
||||
static const char *const TAG = "api.service";
|
||||
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void APIServerConnectionBase::log_send_message_(const char *name, const char *dump) {
|
||||
ESP_LOGVV(TAG, "send_message %s: %s", name, dump);
|
||||
void APIServerConnectionBase::log_send_message_(const LogString *name, const char *dump) {
|
||||
ESP_LOGVV(TAG, "send_message %s: %s", LOG_STR_ARG(name), dump);
|
||||
}
|
||||
void APIServerConnectionBase::log_receive_message_(const LogString *name, const ProtoMessage &msg) {
|
||||
DumpBuffer dump_buf;
|
||||
@@ -20,7 +21,7 @@ void APIServerConnectionBase::log_receive_message_(const LogString *name) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) {
|
||||
void APIConnection::read_message_(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) {
|
||||
// Check authentication/connection requirements
|
||||
switch (msg_type) {
|
||||
case HelloRequest::MESSAGE_TYPE: // No setup required
|
||||
|
||||
@@ -8,238 +8,234 @@
|
||||
|
||||
namespace esphome::api {
|
||||
|
||||
class APIServerConnectionBase : public ProtoService {
|
||||
class APIServerConnectionBase {
|
||||
public:
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
protected:
|
||||
void log_send_message_(const char *name, const char *dump);
|
||||
void log_send_message_(const LogString *name, const char *dump);
|
||||
void log_receive_message_(const LogString *name, const ProtoMessage &msg);
|
||||
void log_receive_message_(const LogString *name);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
virtual void on_hello_request(const HelloRequest &value){};
|
||||
void on_hello_request(const HelloRequest &value){};
|
||||
|
||||
virtual void on_disconnect_request(){};
|
||||
virtual void on_disconnect_response(){};
|
||||
virtual void on_ping_request(){};
|
||||
virtual void on_ping_response(){};
|
||||
virtual void on_device_info_request(){};
|
||||
void on_disconnect_request(){};
|
||||
void on_disconnect_response(){};
|
||||
void on_ping_request(){};
|
||||
void on_ping_response(){};
|
||||
void on_device_info_request(){};
|
||||
|
||||
virtual void on_list_entities_request(){};
|
||||
void on_list_entities_request(){};
|
||||
|
||||
virtual void on_subscribe_states_request(){};
|
||||
void on_subscribe_states_request(){};
|
||||
|
||||
#ifdef USE_COVER
|
||||
virtual void on_cover_command_request(const CoverCommandRequest &value){};
|
||||
void on_cover_command_request(const CoverCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
virtual void on_fan_command_request(const FanCommandRequest &value){};
|
||||
void on_fan_command_request(const FanCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
virtual void on_light_command_request(const LightCommandRequest &value){};
|
||||
void on_light_command_request(const LightCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
virtual void on_switch_command_request(const SwitchCommandRequest &value){};
|
||||
void on_switch_command_request(const SwitchCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
virtual void on_subscribe_logs_request(const SubscribeLogsRequest &value){};
|
||||
void on_subscribe_logs_request(const SubscribeLogsRequest &value){};
|
||||
|
||||
#ifdef USE_API_NOISE
|
||||
virtual void on_noise_encryption_set_key_request(const NoiseEncryptionSetKeyRequest &value){};
|
||||
void on_noise_encryption_set_key_request(const NoiseEncryptionSetKeyRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
virtual void on_subscribe_homeassistant_services_request(){};
|
||||
void on_subscribe_homeassistant_services_request(){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
|
||||
virtual void on_homeassistant_action_response(const HomeassistantActionResponse &value){};
|
||||
void on_homeassistant_action_response(const HomeassistantActionResponse &value){};
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
virtual void on_subscribe_home_assistant_states_request(){};
|
||||
void on_subscribe_home_assistant_states_request(){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
virtual void on_home_assistant_state_response(const HomeAssistantStateResponse &value){};
|
||||
void on_home_assistant_state_response(const HomeAssistantStateResponse &value){};
|
||||
#endif
|
||||
|
||||
virtual void on_get_time_response(const GetTimeResponse &value){};
|
||||
void on_get_time_response(const GetTimeResponse &value){};
|
||||
|
||||
#ifdef USE_API_USER_DEFINED_ACTIONS
|
||||
virtual void on_execute_service_request(const ExecuteServiceRequest &value){};
|
||||
void on_execute_service_request(const ExecuteServiceRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_CAMERA
|
||||
virtual void on_camera_image_request(const CameraImageRequest &value){};
|
||||
void on_camera_image_request(const CameraImageRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_CLIMATE
|
||||
virtual void on_climate_command_request(const ClimateCommandRequest &value){};
|
||||
void on_climate_command_request(const ClimateCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_WATER_HEATER
|
||||
virtual void on_water_heater_command_request(const WaterHeaterCommandRequest &value){};
|
||||
void on_water_heater_command_request(const WaterHeaterCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_NUMBER
|
||||
virtual void on_number_command_request(const NumberCommandRequest &value){};
|
||||
void on_number_command_request(const NumberCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_SELECT
|
||||
virtual void on_select_command_request(const SelectCommandRequest &value){};
|
||||
void on_select_command_request(const SelectCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_SIREN
|
||||
virtual void on_siren_command_request(const SirenCommandRequest &value){};
|
||||
void on_siren_command_request(const SirenCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_LOCK
|
||||
virtual void on_lock_command_request(const LockCommandRequest &value){};
|
||||
void on_lock_command_request(const LockCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUTTON
|
||||
virtual void on_button_command_request(const ButtonCommandRequest &value){};
|
||||
void on_button_command_request(const ButtonCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_MEDIA_PLAYER
|
||||
virtual void on_media_player_command_request(const MediaPlayerCommandRequest &value){};
|
||||
void on_media_player_command_request(const MediaPlayerCommandRequest &value){};
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
virtual void on_subscribe_bluetooth_le_advertisements_request(
|
||||
const SubscribeBluetoothLEAdvertisementsRequest &value){};
|
||||
void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
virtual void on_bluetooth_device_request(const BluetoothDeviceRequest &value){};
|
||||
void on_bluetooth_device_request(const BluetoothDeviceRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
virtual void on_bluetooth_gatt_get_services_request(const BluetoothGATTGetServicesRequest &value){};
|
||||
void on_bluetooth_gatt_get_services_request(const BluetoothGATTGetServicesRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
virtual void on_bluetooth_gatt_read_request(const BluetoothGATTReadRequest &value){};
|
||||
void on_bluetooth_gatt_read_request(const BluetoothGATTReadRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
virtual void on_bluetooth_gatt_write_request(const BluetoothGATTWriteRequest &value){};
|
||||
void on_bluetooth_gatt_write_request(const BluetoothGATTWriteRequest &value){};
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
virtual void on_bluetooth_gatt_read_descriptor_request(const BluetoothGATTReadDescriptorRequest &value){};
|
||||
void on_bluetooth_gatt_read_descriptor_request(const BluetoothGATTReadDescriptorRequest &value){};
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
virtual void on_bluetooth_gatt_write_descriptor_request(const BluetoothGATTWriteDescriptorRequest &value){};
|
||||
void on_bluetooth_gatt_write_descriptor_request(const BluetoothGATTWriteDescriptorRequest &value){};
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
virtual void on_bluetooth_gatt_notify_request(const BluetoothGATTNotifyRequest &value){};
|
||||
void on_bluetooth_gatt_notify_request(const BluetoothGATTNotifyRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
virtual void on_subscribe_bluetooth_connections_free_request(){};
|
||||
void on_subscribe_bluetooth_connections_free_request(){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
virtual void on_unsubscribe_bluetooth_le_advertisements_request(){};
|
||||
void on_unsubscribe_bluetooth_le_advertisements_request(){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
virtual void on_bluetooth_scanner_set_mode_request(const BluetoothScannerSetModeRequest &value){};
|
||||
void on_bluetooth_scanner_set_mode_request(const BluetoothScannerSetModeRequest &value){};
|
||||
#endif
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
virtual void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &value){};
|
||||
void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
virtual void on_voice_assistant_response(const VoiceAssistantResponse &value){};
|
||||
void on_voice_assistant_response(const VoiceAssistantResponse &value){};
|
||||
#endif
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
virtual void on_voice_assistant_event_response(const VoiceAssistantEventResponse &value){};
|
||||
void on_voice_assistant_event_response(const VoiceAssistantEventResponse &value){};
|
||||
#endif
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
virtual void on_voice_assistant_audio(const VoiceAssistantAudio &value){};
|
||||
void on_voice_assistant_audio(const VoiceAssistantAudio &value){};
|
||||
#endif
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
virtual void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &value){};
|
||||
void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &value){};
|
||||
#endif
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
virtual void on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &value){};
|
||||
void on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
virtual void on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &value){};
|
||||
void on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
virtual void on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &value){};
|
||||
void on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_ALARM_CONTROL_PANEL
|
||||
virtual void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &value){};
|
||||
void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT
|
||||
virtual void on_text_command_request(const TextCommandRequest &value){};
|
||||
void on_text_command_request(const TextCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_DATE
|
||||
virtual void on_date_command_request(const DateCommandRequest &value){};
|
||||
void on_date_command_request(const DateCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_TIME
|
||||
virtual void on_time_command_request(const TimeCommandRequest &value){};
|
||||
void on_time_command_request(const TimeCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_VALVE
|
||||
virtual void on_valve_command_request(const ValveCommandRequest &value){};
|
||||
void on_valve_command_request(const ValveCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_DATETIME
|
||||
virtual void on_date_time_command_request(const DateTimeCommandRequest &value){};
|
||||
void on_date_time_command_request(const DateTimeCommandRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_UPDATE
|
||||
virtual void on_update_command_request(const UpdateCommandRequest &value){};
|
||||
void on_update_command_request(const UpdateCommandRequest &value){};
|
||||
#endif
|
||||
#ifdef USE_ZWAVE_PROXY
|
||||
virtual void on_z_wave_proxy_frame(const ZWaveProxyFrame &value){};
|
||||
void on_z_wave_proxy_frame(const ZWaveProxyFrame &value){};
|
||||
#endif
|
||||
#ifdef USE_ZWAVE_PROXY
|
||||
virtual void on_z_wave_proxy_request(const ZWaveProxyRequest &value){};
|
||||
void on_z_wave_proxy_request(const ZWaveProxyRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_IR_RF
|
||||
virtual void on_infrared_rf_transmit_raw_timings_request(const InfraredRFTransmitRawTimingsRequest &value){};
|
||||
void on_infrared_rf_transmit_raw_timings_request(const InfraredRFTransmitRawTimingsRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_SERIAL_PROXY
|
||||
virtual void on_serial_proxy_configure_request(const SerialProxyConfigureRequest &value){};
|
||||
void on_serial_proxy_configure_request(const SerialProxyConfigureRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_SERIAL_PROXY
|
||||
virtual void on_serial_proxy_write_request(const SerialProxyWriteRequest &value){};
|
||||
void on_serial_proxy_write_request(const SerialProxyWriteRequest &value){};
|
||||
#endif
|
||||
#ifdef USE_SERIAL_PROXY
|
||||
virtual void on_serial_proxy_set_modem_pins_request(const SerialProxySetModemPinsRequest &value){};
|
||||
void on_serial_proxy_set_modem_pins_request(const SerialProxySetModemPinsRequest &value){};
|
||||
#endif
|
||||
#ifdef USE_SERIAL_PROXY
|
||||
virtual void on_serial_proxy_get_modem_pins_request(const SerialProxyGetModemPinsRequest &value){};
|
||||
void on_serial_proxy_get_modem_pins_request(const SerialProxyGetModemPinsRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_SERIAL_PROXY
|
||||
virtual void on_serial_proxy_request(const SerialProxyRequest &value){};
|
||||
void on_serial_proxy_request(const SerialProxyRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
virtual void on_bluetooth_set_connection_params_request(const BluetoothSetConnectionParamsRequest &value){};
|
||||
void on_bluetooth_set_connection_params_request(const BluetoothSetConnectionParamsRequest &value){};
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) override;
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
|
||||
@@ -46,10 +46,8 @@ void APIServer::setup() {
|
||||
|
||||
#ifndef USE_API_NOISE_PSK_FROM_YAML
|
||||
// Only load saved PSK if not set from YAML
|
||||
SavedNoisePsk noise_pref_saved{};
|
||||
if (this->noise_pref_.load(&noise_pref_saved)) {
|
||||
if (this->load_and_apply_noise_psk_()) {
|
||||
ESP_LOGD(TAG, "Loaded saved Noise PSK");
|
||||
this->set_noise_psk(noise_pref_saved.psk);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -110,7 +108,7 @@ void APIServer::setup() {
|
||||
this->last_connected_ = App.get_loop_component_start_time();
|
||||
// Set warning status if reboot timeout is enabled
|
||||
if (this->reboot_timeout_ != 0) {
|
||||
this->status_set_warning();
|
||||
this->status_set_warning(LOG_STR("waiting for client connection"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +187,7 @@ void APIServer::remove_client_(size_t client_index) {
|
||||
|
||||
// Last client disconnected - set warning and start tracking for reboot timeout
|
||||
if (this->clients_.empty() && this->reboot_timeout_ != 0) {
|
||||
this->status_set_warning();
|
||||
this->status_set_warning(LOG_STR("waiting for client connection"));
|
||||
this->last_connected_ = App.get_loop_component_start_time();
|
||||
}
|
||||
|
||||
@@ -514,7 +512,7 @@ void APIServer::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeo
|
||||
|
||||
#ifdef USE_API_NOISE
|
||||
bool APIServer::update_noise_psk_(const SavedNoisePsk &new_psk, const LogString *save_log_msg,
|
||||
const LogString *fail_log_msg, const psk_t &active_psk, bool make_active) {
|
||||
const LogString *fail_log_msg, bool make_active) {
|
||||
if (!this->noise_pref_.save(&new_psk)) {
|
||||
ESP_LOGW(TAG, "%s", LOG_STR_ARG(fail_log_msg));
|
||||
return false;
|
||||
@@ -526,9 +524,14 @@ bool APIServer::update_noise_psk_(const SavedNoisePsk &new_psk, const LogString
|
||||
}
|
||||
ESP_LOGD(TAG, "%s", LOG_STR_ARG(save_log_msg));
|
||||
if (make_active) {
|
||||
this->set_timeout(100, [this, active_psk]() {
|
||||
this->set_timeout(100, [this]() {
|
||||
// Re-read the PSK from preferences rather than capturing the 32-byte array
|
||||
// in the lambda (which would exceed std::function SBO and heap-allocate).
|
||||
if (!this->load_and_apply_noise_psk_()) {
|
||||
ESP_LOGW(TAG, "Failed to load saved PSK for activation");
|
||||
return;
|
||||
}
|
||||
ESP_LOGW(TAG, "Disconnecting all clients to reset PSK");
|
||||
this->set_noise_psk(active_psk);
|
||||
for (auto &c : this->clients_) {
|
||||
DisconnectRequest req;
|
||||
c->send_message(req);
|
||||
@@ -538,6 +541,14 @@ bool APIServer::update_noise_psk_(const SavedNoisePsk &new_psk, const LogString
|
||||
return true;
|
||||
}
|
||||
|
||||
bool APIServer::load_and_apply_noise_psk_() {
|
||||
SavedNoisePsk saved{};
|
||||
if (!this->noise_pref_.load(&saved))
|
||||
return false;
|
||||
this->set_noise_psk(saved.psk);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool APIServer::save_noise_psk(psk_t psk, bool make_active) {
|
||||
#ifdef USE_API_NOISE_PSK_FROM_YAML
|
||||
// When PSK is set from YAML, this function should never be called
|
||||
@@ -552,7 +563,7 @@ bool APIServer::save_noise_psk(psk_t psk, bool make_active) {
|
||||
}
|
||||
|
||||
SavedNoisePsk new_saved_psk{psk};
|
||||
return this->update_noise_psk_(new_saved_psk, LOG_STR("Noise PSK saved"), LOG_STR("Failed to save Noise PSK"), psk,
|
||||
return this->update_noise_psk_(new_saved_psk, LOG_STR("Noise PSK saved"), LOG_STR("Failed to save Noise PSK"),
|
||||
make_active);
|
||||
#endif
|
||||
}
|
||||
@@ -564,8 +575,7 @@ bool APIServer::clear_noise_psk(bool make_active) {
|
||||
return false;
|
||||
#else
|
||||
SavedNoisePsk empty_psk{};
|
||||
psk_t empty{};
|
||||
return this->update_noise_psk_(empty_psk, LOG_STR("Noise PSK cleared"), LOG_STR("Failed to clear Noise PSK"), empty,
|
||||
return this->update_noise_psk_(empty_psk, LOG_STR("Noise PSK cleared"), LOG_STR("Failed to clear Noise PSK"),
|
||||
make_active);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -239,7 +239,9 @@ class APIServer final : public Component,
|
||||
|
||||
#ifdef USE_API_NOISE
|
||||
bool update_noise_psk_(const SavedNoisePsk &new_psk, const LogString *save_log_msg, const LogString *fail_log_msg,
|
||||
const psk_t &active_psk, bool make_active);
|
||||
bool make_active);
|
||||
// Load saved PSK from preferences and apply it. Returns true on success.
|
||||
bool load_and_apply_noise_psk_();
|
||||
#endif // USE_API_NOISE
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
// Helper methods to reduce code duplication
|
||||
|
||||
@@ -32,7 +32,11 @@ if TYPE_CHECKING:
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_run_logs(config: dict[str, Any], addresses: list[str]) -> None:
|
||||
async def async_run_logs(
|
||||
config: dict[str, Any],
|
||||
addresses: list[str],
|
||||
subscribe_states: bool = True,
|
||||
) -> None:
|
||||
"""Run the logs command in the event loop."""
|
||||
conf = config["api"]
|
||||
name = config["esphome"]["name"]
|
||||
@@ -89,14 +93,20 @@ async def async_run_logs(config: dict[str, Any], addresses: list[str]) -> None:
|
||||
config, raw_line, backtrace_state=backtrace_state
|
||||
)
|
||||
|
||||
stop = await async_run(cli, on_log, name=name)
|
||||
stop = await async_run(cli, on_log, name=name, subscribe_states=subscribe_states)
|
||||
try:
|
||||
await asyncio.Event().wait()
|
||||
finally:
|
||||
await stop()
|
||||
|
||||
|
||||
def run_logs(config: dict[str, Any], addresses: list[str]) -> None:
|
||||
def run_logs(
|
||||
config: dict[str, Any],
|
||||
addresses: list[str],
|
||||
subscribe_states: bool = True,
|
||||
) -> None:
|
||||
"""Run the logs command."""
|
||||
with contextlib.suppress(KeyboardInterrupt):
|
||||
asyncio.run(async_run_logs(config, addresses))
|
||||
asyncio.run(
|
||||
async_run_logs(config, addresses, subscribe_states=subscribe_states)
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/progmem.h"
|
||||
#include "esphome/core/string_ref.h"
|
||||
|
||||
#include <cassert>
|
||||
@@ -152,8 +153,7 @@ class ProtoVarInt {
|
||||
#endif
|
||||
};
|
||||
|
||||
// Forward declarations for decode_to_message and related encoding helpers
|
||||
class ProtoDecodableMessage;
|
||||
// Forward declarations for encoding helpers
|
||||
class ProtoMessage;
|
||||
class ProtoSize;
|
||||
|
||||
@@ -166,16 +166,9 @@ class ProtoLengthDelimited {
|
||||
const uint8_t *data() const { return this->value_; }
|
||||
size_t size() const { return this->length_; }
|
||||
|
||||
/**
|
||||
* Decode the length-delimited data into an existing ProtoDecodableMessage instance.
|
||||
*
|
||||
* This method allows decoding without templates, enabling use in contexts
|
||||
* where the message type is not known at compile time. The ProtoDecodableMessage's
|
||||
* decode() method will be called with the raw data and length.
|
||||
*
|
||||
* @param msg The ProtoDecodableMessage instance to decode into
|
||||
*/
|
||||
void decode_to_message(ProtoDecodableMessage &msg) const;
|
||||
/// Decode the length-delimited data into a message instance.
|
||||
/// Template preserves concrete type so decode() resolves statically.
|
||||
template<typename T> void decode_to_message(T &msg) const;
|
||||
|
||||
protected:
|
||||
const uint8_t *const value_;
|
||||
@@ -236,6 +229,32 @@ class ProtoWriteBuffer {
|
||||
* Following https://protobuf.dev/programming-guides/encoding/#structure
|
||||
*/
|
||||
void encode_field_raw(uint32_t field_id, uint32_t type) { this->encode_varint_raw((field_id << 3) | type); }
|
||||
/// Write a single precomputed tag byte. Tag must be < 128.
|
||||
inline void write_raw_byte(uint8_t b) ESPHOME_ALWAYS_INLINE {
|
||||
this->debug_check_bounds_(1);
|
||||
*this->pos_++ = b;
|
||||
}
|
||||
/// Write raw bytes to the buffer (no tag, no length prefix).
|
||||
inline void encode_raw(const void *data, size_t len) ESPHOME_ALWAYS_INLINE {
|
||||
this->debug_check_bounds_(len);
|
||||
std::memcpy(this->pos_, data, len);
|
||||
this->pos_ += len;
|
||||
}
|
||||
/// Write a precomputed tag byte + 32-bit value in one operation.
|
||||
/// Tag must be a single-byte varint (< 128). No zero check.
|
||||
inline void write_tag_and_fixed32(uint8_t tag, uint32_t value) ESPHOME_ALWAYS_INLINE {
|
||||
this->debug_check_bounds_(5);
|
||||
this->pos_[0] = tag;
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
std::memcpy(this->pos_ + 1, &value, 4);
|
||||
#else
|
||||
this->pos_[1] = static_cast<uint8_t>(value & 0xFF);
|
||||
this->pos_[2] = static_cast<uint8_t>((value >> 8) & 0xFF);
|
||||
this->pos_[3] = static_cast<uint8_t>((value >> 16) & 0xFF);
|
||||
this->pos_[4] = static_cast<uint8_t>((value >> 24) & 0xFF);
|
||||
#endif
|
||||
this->pos_ += 5;
|
||||
}
|
||||
void encode_string(uint32_t field_id, const char *string, size_t len, bool force = false) {
|
||||
if (len == 0 && !force)
|
||||
return;
|
||||
@@ -276,8 +295,7 @@ class ProtoWriteBuffer {
|
||||
this->debug_check_bounds_(1);
|
||||
*this->pos_++ = value ? 0x01 : 0x00;
|
||||
}
|
||||
// noinline: 51 call sites; inlining causes net code growth vs a single out-of-line copy
|
||||
__attribute__((noinline)) void encode_fixed32(uint32_t field_id, uint32_t value, bool force = false) {
|
||||
void encode_fixed32(uint32_t field_id, uint32_t value, bool force = false) {
|
||||
if (value == 0 && !force)
|
||||
return;
|
||||
|
||||
@@ -394,6 +412,23 @@ class DumpBuffer {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Append a PROGMEM string (flash-safe on ESP8266, regular append on other platforms)
|
||||
DumpBuffer &append_p(const char *str) {
|
||||
if (str) {
|
||||
#ifdef USE_ESP8266
|
||||
append_p_esp8266(str);
|
||||
#else
|
||||
append_impl_(str, strlen(str));
|
||||
#endif
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
/// Out-of-line ESP8266 PROGMEM append to avoid inlining strlen_P/memcpy_P at every call site
|
||||
void append_p_esp8266(const char *str);
|
||||
#endif
|
||||
|
||||
const char *c_str() const { return buf_; }
|
||||
size_t size() const { return pos_; }
|
||||
|
||||
@@ -439,7 +474,7 @@ class ProtoMessage {
|
||||
uint32_t calculate_size() const { return 0; }
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
virtual const char *dump_to(DumpBuffer &out) const = 0;
|
||||
virtual const char *message_name() const { return "unknown"; }
|
||||
virtual const LogString *message_name() const { return LOG_STR("unknown"); }
|
||||
#endif
|
||||
|
||||
#ifndef USE_HOST
|
||||
@@ -454,7 +489,7 @@ class ProtoMessage {
|
||||
// Base class for messages that support decoding
|
||||
class ProtoDecodableMessage : public ProtoMessage {
|
||||
public:
|
||||
virtual void decode(const uint8_t *buffer, size_t length);
|
||||
void decode(const uint8_t *buffer, size_t length);
|
||||
|
||||
/**
|
||||
* Count occurrences of a repeated field in a protobuf buffer.
|
||||
@@ -690,33 +725,14 @@ template<typename T> inline void ProtoWriteBuffer::encode_optional_sub_message(u
|
||||
this->encode_optional_sub_message(field_id, value.calculate_size(), &value, &proto_encode_msg<T>);
|
||||
}
|
||||
|
||||
// Implementation of decode_to_message - must be after ProtoDecodableMessage is defined
|
||||
inline void ProtoLengthDelimited::decode_to_message(ProtoDecodableMessage &msg) const {
|
||||
// Template decode_to_message - preserves concrete type so decode() resolves statically
|
||||
template<typename T> void ProtoLengthDelimited::decode_to_message(T &msg) const {
|
||||
msg.decode(this->value_, this->length_);
|
||||
}
|
||||
|
||||
template<typename T> const char *proto_enum_to_string(T value);
|
||||
|
||||
class ProtoService {
|
||||
public:
|
||||
protected:
|
||||
virtual bool is_authenticated() = 0;
|
||||
virtual bool is_connection_setup() = 0;
|
||||
virtual void on_fatal_error() = 0;
|
||||
virtual void on_no_setup_connection() = 0;
|
||||
virtual bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) = 0;
|
||||
virtual void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) = 0;
|
||||
|
||||
// Authentication helper methods
|
||||
inline bool check_connection_setup_() {
|
||||
if (!this->is_connection_setup()) {
|
||||
this->on_no_setup_connection();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool check_authenticated_() { return this->check_connection_setup_(); }
|
||||
};
|
||||
// ProtoService removed — its methods were inlined into APIConnection.
|
||||
// APIConnection is the concrete server-side implementation; the extra virtual layer was unnecessary.
|
||||
|
||||
} // namespace esphome::api
|
||||
|
||||
@@ -204,7 +204,7 @@ async def to_code(config):
|
||||
|
||||
add_idf_component(
|
||||
name="esphome/esp-audio-libs",
|
||||
ref="2.0.3",
|
||||
ref="2.0.4",
|
||||
)
|
||||
|
||||
data = _get_data()
|
||||
@@ -214,4 +214,4 @@ async def to_code(config):
|
||||
cg.add_define("USE_AUDIO_MP3_SUPPORT")
|
||||
if data.opus_support:
|
||||
cg.add_define("USE_AUDIO_OPUS_SUPPORT")
|
||||
add_idf_component(name="esphome/micro-opus", ref="0.3.5")
|
||||
add_idf_component(name="esphome/micro-opus", ref="0.3.6")
|
||||
|
||||
@@ -45,7 +45,7 @@ bool BinarySensor::set_new_state(const optional<bool> &new_state) {
|
||||
#if defined(USE_BINARY_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_binary_sensor_update(this);
|
||||
#endif
|
||||
ESP_LOGD(TAG, "'%s' >> %s", this->get_name().c_str(), ONOFFMAYBE(new_state));
|
||||
ESP_LOGV(TAG, "'%s' >> %s", this->get_name().c_str(), ONOFFMAYBE(new_state));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -103,17 +103,17 @@ size_t BLENUS::available() {
|
||||
#endif
|
||||
}
|
||||
|
||||
uart::FlushResult BLENUS::flush() {
|
||||
uart::UARTFlushResult BLENUS::flush() {
|
||||
constexpr uint32_t timeout_500ms = 500;
|
||||
uint32_t start = millis();
|
||||
while (atomic_get(&this->tx_status_) != TX_DISABLED && !ring_buf_is_empty(&global_ble_tx_ring_buf)) {
|
||||
if (millis() - start > timeout_500ms) {
|
||||
ESP_LOGW(TAG, "Flush timeout");
|
||||
return uart::FlushResult::TIMEOUT;
|
||||
return uart::UARTFlushResult::UART_FLUSH_RESULT_TIMEOUT;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
return uart::FlushResult::SUCCESS;
|
||||
return uart::UARTFlushResult::UART_FLUSH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void BLENUS::connected(bt_conn *conn, uint8_t err) {
|
||||
|
||||
@@ -26,7 +26,7 @@ class BLENUS : public uart::UARTComponent, public Component {
|
||||
bool peek_byte(uint8_t *data) override;
|
||||
bool read_array(uint8_t *data, size_t len) override;
|
||||
size_t available() override;
|
||||
uart::FlushResult flush() override;
|
||||
uart::UARTFlushResult flush() override;
|
||||
void check_logger_conflict() override {}
|
||||
void set_expose_log(bool expose_log) { this->expose_log_ = expose_log; }
|
||||
#ifdef USE_LOGGER
|
||||
|
||||
@@ -56,7 +56,6 @@ void BM8563::read_time() {
|
||||
ESPTime rtc_time;
|
||||
this->get_time_(rtc_time);
|
||||
this->get_date_(rtc_time);
|
||||
rtc_time.day_of_year = 1; // unused by recalc_timestamp_utc, but needs to be valid
|
||||
ESP_LOGD(TAG, "Read time: %i-%i-%i %i, %i:%i:%i", rtc_time.year, rtc_time.month, rtc_time.day_of_month,
|
||||
rtc_time.day_of_week, rtc_time.hour, rtc_time.minute, rtc_time.second);
|
||||
|
||||
|
||||
@@ -276,8 +276,8 @@ void BME68xBSEC2Component::run_() {
|
||||
}
|
||||
|
||||
if (this->bsec_settings_.trigger_measurement && this->bsec_settings_.op_mode != BME68X_SLEEP_MODE) {
|
||||
uint32_t meas_dur = 0;
|
||||
meas_dur = bme68x_get_meas_dur(this->op_mode_, &bme68x_conf, &this->bme68x_);
|
||||
bme68x_get_conf(&bme68x_conf, &this->bme68x_);
|
||||
uint32_t meas_dur = bme68x_get_meas_dur(this->op_mode_, &bme68x_conf, &this->bme68x_);
|
||||
ESP_LOGV(TAG, "Queueing read in %uus", meas_dur);
|
||||
this->trigger_time_ns_ = curr_time_ns;
|
||||
this->set_timeout("read", meas_dur / 1000, [this]() { this->read_(this->trigger_time_ns_); });
|
||||
|
||||
@@ -46,45 +46,45 @@ constexpr StringToUint8 CLIMATE_SWING_MODES_BY_STR[] = {
|
||||
|
||||
void ClimateCall::perform() {
|
||||
this->parent_->control_callback_.call(*this);
|
||||
ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
this->validate_();
|
||||
if (this->mode_.has_value()) {
|
||||
const LogString *mode_s = climate_mode_to_string(*this->mode_);
|
||||
ESP_LOGD(TAG, " Mode: %s", LOG_STR_ARG(mode_s));
|
||||
ESP_LOGV(TAG, " Mode: %s", LOG_STR_ARG(mode_s));
|
||||
}
|
||||
if (this->custom_fan_mode_ != nullptr) {
|
||||
this->fan_mode_.reset();
|
||||
ESP_LOGD(TAG, " Custom Fan: %s", this->custom_fan_mode_);
|
||||
ESP_LOGV(TAG, " Custom Fan: %s", this->custom_fan_mode_);
|
||||
}
|
||||
if (this->fan_mode_.has_value()) {
|
||||
this->custom_fan_mode_ = nullptr;
|
||||
const LogString *fan_mode_s = climate_fan_mode_to_string(*this->fan_mode_);
|
||||
ESP_LOGD(TAG, " Fan: %s", LOG_STR_ARG(fan_mode_s));
|
||||
ESP_LOGV(TAG, " Fan: %s", LOG_STR_ARG(fan_mode_s));
|
||||
}
|
||||
if (this->custom_preset_ != nullptr) {
|
||||
this->preset_.reset();
|
||||
ESP_LOGD(TAG, " Custom Preset: %s", this->custom_preset_);
|
||||
ESP_LOGV(TAG, " Custom Preset: %s", this->custom_preset_);
|
||||
}
|
||||
if (this->preset_.has_value()) {
|
||||
this->custom_preset_ = nullptr;
|
||||
const LogString *preset_s = climate_preset_to_string(*this->preset_);
|
||||
ESP_LOGD(TAG, " Preset: %s", LOG_STR_ARG(preset_s));
|
||||
ESP_LOGV(TAG, " Preset: %s", LOG_STR_ARG(preset_s));
|
||||
}
|
||||
if (this->swing_mode_.has_value()) {
|
||||
const LogString *swing_mode_s = climate_swing_mode_to_string(*this->swing_mode_);
|
||||
ESP_LOGD(TAG, " Swing: %s", LOG_STR_ARG(swing_mode_s));
|
||||
ESP_LOGV(TAG, " Swing: %s", LOG_STR_ARG(swing_mode_s));
|
||||
}
|
||||
if (this->target_temperature_.has_value()) {
|
||||
ESP_LOGD(TAG, " Target Temperature: %.2f", *this->target_temperature_);
|
||||
ESP_LOGV(TAG, " Target Temperature: %.2f", *this->target_temperature_);
|
||||
}
|
||||
if (this->target_temperature_low_.has_value()) {
|
||||
ESP_LOGD(TAG, " Target Temperature Low: %.2f", *this->target_temperature_low_);
|
||||
ESP_LOGV(TAG, " Target Temperature Low: %.2f", *this->target_temperature_low_);
|
||||
}
|
||||
if (this->target_temperature_high_.has_value()) {
|
||||
ESP_LOGD(TAG, " Target Temperature High: %.2f", *this->target_temperature_high_);
|
||||
ESP_LOGV(TAG, " Target Temperature High: %.2f", *this->target_temperature_high_);
|
||||
}
|
||||
if (this->target_humidity_.has_value()) {
|
||||
ESP_LOGD(TAG, " Target Humidity: %.0f", *this->target_humidity_);
|
||||
ESP_LOGV(TAG, " Target Humidity: %.0f", *this->target_humidity_);
|
||||
}
|
||||
this->parent_->control(*this);
|
||||
}
|
||||
@@ -435,43 +435,43 @@ void Climate::save_state_() {
|
||||
}
|
||||
|
||||
void Climate::publish_state() {
|
||||
ESP_LOGD(TAG, "'%s' >>", this->name_.c_str());
|
||||
ESP_LOGV(TAG, "'%s' >>", this->name_.c_str());
|
||||
auto traits = this->get_traits();
|
||||
|
||||
ESP_LOGD(TAG, " Mode: %s", LOG_STR_ARG(climate_mode_to_string(this->mode)));
|
||||
ESP_LOGV(TAG, " Mode: %s", LOG_STR_ARG(climate_mode_to_string(this->mode)));
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_ACTION)) {
|
||||
ESP_LOGD(TAG, " Action: %s", LOG_STR_ARG(climate_action_to_string(this->action)));
|
||||
ESP_LOGV(TAG, " Action: %s", LOG_STR_ARG(climate_action_to_string(this->action)));
|
||||
}
|
||||
if (traits.get_supports_fan_modes() && this->fan_mode.has_value()) {
|
||||
ESP_LOGD(TAG, " Fan Mode: %s", LOG_STR_ARG(climate_fan_mode_to_string(this->fan_mode.value())));
|
||||
ESP_LOGV(TAG, " Fan Mode: %s", LOG_STR_ARG(climate_fan_mode_to_string(this->fan_mode.value())));
|
||||
}
|
||||
if (!traits.get_supported_custom_fan_modes().empty() && this->has_custom_fan_mode()) {
|
||||
ESP_LOGD(TAG, " Custom Fan Mode: %s", this->custom_fan_mode_);
|
||||
ESP_LOGV(TAG, " Custom Fan Mode: %s", this->custom_fan_mode_);
|
||||
}
|
||||
if (traits.get_supports_presets() && this->preset.has_value()) {
|
||||
ESP_LOGD(TAG, " Preset: %s", LOG_STR_ARG(climate_preset_to_string(this->preset.value())));
|
||||
ESP_LOGV(TAG, " Preset: %s", LOG_STR_ARG(climate_preset_to_string(this->preset.value())));
|
||||
}
|
||||
if (!traits.get_supported_custom_presets().empty() && this->has_custom_preset()) {
|
||||
ESP_LOGD(TAG, " Custom Preset: %s", this->custom_preset_);
|
||||
ESP_LOGV(TAG, " Custom Preset: %s", this->custom_preset_);
|
||||
}
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
ESP_LOGD(TAG, " Swing Mode: %s", LOG_STR_ARG(climate_swing_mode_to_string(this->swing_mode)));
|
||||
ESP_LOGV(TAG, " Swing Mode: %s", LOG_STR_ARG(climate_swing_mode_to_string(this->swing_mode)));
|
||||
}
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE)) {
|
||||
ESP_LOGD(TAG, " Current Temperature: %.2f°C", this->current_temperature);
|
||||
ESP_LOGV(TAG, " Current Temperature: %.2f°C", this->current_temperature);
|
||||
}
|
||||
if (traits.has_feature_flags(CLIMATE_SUPPORTS_TWO_POINT_TARGET_TEMPERATURE |
|
||||
CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE)) {
|
||||
ESP_LOGD(TAG, " Target Temperature: Low: %.2f°C High: %.2f°C", this->target_temperature_low,
|
||||
ESP_LOGV(TAG, " Target Temperature: Low: %.2f°C High: %.2f°C", this->target_temperature_low,
|
||||
this->target_temperature_high);
|
||||
} else {
|
||||
ESP_LOGD(TAG, " Target Temperature: %.2f°C", this->target_temperature);
|
||||
ESP_LOGV(TAG, " Target Temperature: %.2f°C", this->target_temperature);
|
||||
}
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_HUMIDITY)) {
|
||||
ESP_LOGD(TAG, " Current Humidity: %.0f%%", this->current_humidity);
|
||||
ESP_LOGV(TAG, " Current Humidity: %.0f%%", this->current_humidity);
|
||||
}
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TARGET_HUMIDITY)) {
|
||||
ESP_LOGD(TAG, " Target Humidity: %.0f%%", this->target_humidity);
|
||||
ESP_LOGV(TAG, " Target Humidity: %.0f%%", this->target_humidity);
|
||||
}
|
||||
|
||||
// Send state to frontend
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace combination {
|
||||
@@ -20,12 +18,12 @@ void CombinationComponent::log_config_(const LogString *combo_type) {
|
||||
|
||||
void CombinationNoParameterComponent::add_source(Sensor *sensor) { this->sensors_.emplace_back(sensor); }
|
||||
|
||||
void CombinationOneParameterComponent::add_source(Sensor *sensor, std::function<float(float)> const &stddev) {
|
||||
this->sensor_pairs_.emplace_back(sensor, stddev);
|
||||
void CombinationOneParameterComponent::add_source(Sensor *sensor, std::function<float(float)> const &compute) {
|
||||
this->sensor_sources_.push_back({sensor, compute, this});
|
||||
}
|
||||
|
||||
void CombinationOneParameterComponent::add_source(Sensor *sensor, float stddev) {
|
||||
this->add_source(sensor, std::function<float(float)>{[stddev](float x) -> float { return stddev; }});
|
||||
void CombinationOneParameterComponent::add_source(Sensor *sensor, float value) {
|
||||
this->add_source(sensor, std::function<float(float)>{[value](float x) -> float { return value; }});
|
||||
}
|
||||
|
||||
void CombinationNoParameterComponent::log_source_sensors() {
|
||||
@@ -37,9 +35,8 @@ void CombinationNoParameterComponent::log_source_sensors() {
|
||||
|
||||
void CombinationOneParameterComponent::log_source_sensors() {
|
||||
ESP_LOGCONFIG(TAG, " Source Sensors:");
|
||||
for (const auto &sensor : this->sensor_pairs_) {
|
||||
auto &entity = *sensor.first;
|
||||
ESP_LOGCONFIG(TAG, " - %s", entity.get_name().c_str());
|
||||
for (const auto &source : this->sensor_sources_) {
|
||||
ESP_LOGCONFIG(TAG, " - %s", source.sensor->get_name().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,9 +59,12 @@ void KalmanCombinationComponent::dump_config() {
|
||||
}
|
||||
|
||||
void KalmanCombinationComponent::setup() {
|
||||
for (const auto &sensor : this->sensor_pairs_) {
|
||||
const auto stddev = sensor.second;
|
||||
sensor.first->add_on_state_callback([this, stddev](float x) -> void { this->correct_(x, stddev(x)); });
|
||||
for (auto &source : this->sensor_sources_) {
|
||||
// [&source] is safe: source refers to a FixedVector element that never reallocates,
|
||||
// so the reference remains valid for the component's lifetime.
|
||||
source.sensor->add_on_state_callback([&source](float x) -> void {
|
||||
static_cast<KalmanCombinationComponent *>(source.parent)->correct_(x, source.compute(x));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,10 +117,10 @@ void KalmanCombinationComponent::correct_(float value, float stddev) {
|
||||
}
|
||||
|
||||
void LinearCombinationComponent::setup() {
|
||||
for (const auto &sensor : this->sensor_pairs_) {
|
||||
for (auto &source : this->sensor_sources_) {
|
||||
// All sensor updates are deferred until the next loop. This avoids publishing the combined sensor's result
|
||||
// repeatedly in the same loop if multiple source senors update.
|
||||
sensor.first->add_on_state_callback(
|
||||
source.sensor->add_on_state_callback(
|
||||
[this](float value) -> void { this->defer("update", [this, value]() { this->handle_new_value(value); }); });
|
||||
}
|
||||
}
|
||||
@@ -133,10 +133,10 @@ void LinearCombinationComponent::handle_new_value(float value) {
|
||||
|
||||
float sum = 0.0;
|
||||
|
||||
for (const auto &sensor : this->sensor_pairs_) {
|
||||
const float sensor_state = sensor.first->state;
|
||||
for (const auto &source : this->sensor_sources_) {
|
||||
const float sensor_state = source.sensor->state;
|
||||
if (std::isfinite(sensor_state)) {
|
||||
sum += sensor_state * sensor.second(sensor_state);
|
||||
sum += sensor_state * source.compute(sensor_state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace esphome {
|
||||
namespace combination {
|
||||
@@ -41,14 +42,21 @@ class CombinationNoParameterComponent : public CombinationComponent {
|
||||
// Base class for opertions that require one parameter to compute the combination
|
||||
class CombinationOneParameterComponent : public CombinationComponent {
|
||||
public:
|
||||
void add_source(Sensor *sensor, std::function<float(float)> const &stddev);
|
||||
void add_source(Sensor *sensor, float stddev);
|
||||
void set_source_count(size_t count) { this->sensor_sources_.init(count); }
|
||||
void add_source(Sensor *sensor, std::function<float(float)> const &compute);
|
||||
void add_source(Sensor *sensor, float value);
|
||||
|
||||
/// @brief Logs all source sensor's names in sensor_pairs_
|
||||
/// @brief Logs all source sensors' names in sensor_sources_
|
||||
void log_source_sensors() override;
|
||||
|
||||
protected:
|
||||
std::vector<std::pair<Sensor *, std::function<float(float)>>> sensor_pairs_;
|
||||
struct SensorSource {
|
||||
sensor::Sensor *sensor;
|
||||
std::function<float(float)> compute;
|
||||
CombinationOneParameterComponent *parent;
|
||||
};
|
||||
|
||||
FixedVector<SensorSource> sensor_sources_;
|
||||
};
|
||||
|
||||
class KalmanCombinationComponent : public CombinationOneParameterComponent {
|
||||
|
||||
@@ -180,6 +180,9 @@ async def to_code(config):
|
||||
if proces_std_dev := config.get(CONF_PROCESS_STD_DEV):
|
||||
cg.add(var.set_process_std_dev(proces_std_dev))
|
||||
|
||||
if config[CONF_TYPE] in (CONF_KALMAN, CONF_LINEAR):
|
||||
cg.add(var.set_source_count(len(config[CONF_SOURCES])))
|
||||
|
||||
for source_conf in config[CONF_SOURCES]:
|
||||
source = await cg.get_variable(source_conf[CONF_SOURCE])
|
||||
if config[CONF_TYPE] == CONF_KALMAN:
|
||||
|
||||
@@ -13,10 +13,12 @@ CONF_DATA_BITS = "data_bits"
|
||||
CONF_DRAW_ROUNDING = "draw_rounding"
|
||||
CONF_ENABLED = "enabled"
|
||||
CONF_IGNORE_NOT_FOUND = "ignore_not_found"
|
||||
CONF_LIBRETINY = "libretiny"
|
||||
CONF_ON_PACKET = "on_packet"
|
||||
CONF_ON_RECEIVE = "on_receive"
|
||||
CONF_ON_STATE_CHANGE = "on_state_change"
|
||||
CONF_PARITY = "parity"
|
||||
CONF_RECEIVER_FREQUENCY = "receiver_frequency"
|
||||
CONF_REQUEST_HEADERS = "request_headers"
|
||||
CONF_ROWS = "rows"
|
||||
CONF_STOP_BITS = "stop_bits"
|
||||
|
||||
@@ -105,17 +105,18 @@ template<typename... Ts> using CoverIsClosedCondition = CoverPositionCondition<f
|
||||
|
||||
template<bool OPEN> class CoverPositionTrigger : public Trigger<> {
|
||||
public:
|
||||
CoverPositionTrigger(Cover *a_cover) {
|
||||
a_cover->add_on_state_callback([this, a_cover]() {
|
||||
if (a_cover->position != this->last_position_) {
|
||||
this->last_position_ = a_cover->position;
|
||||
if (a_cover->position == (OPEN ? COVER_OPEN : COVER_CLOSED))
|
||||
CoverPositionTrigger(Cover *a_cover) : cover_(a_cover) {
|
||||
a_cover->add_on_state_callback([this]() {
|
||||
if (this->cover_->position != this->last_position_) {
|
||||
this->last_position_ = this->cover_->position;
|
||||
if (this->cover_->position == (OPEN ? COVER_OPEN : COVER_CLOSED))
|
||||
this->trigger();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
Cover *cover_;
|
||||
float last_position_{NAN};
|
||||
};
|
||||
|
||||
@@ -124,9 +125,9 @@ using CoverClosedTrigger = CoverPositionTrigger<false>;
|
||||
|
||||
template<CoverOperation OP> class CoverTrigger : public Trigger<> {
|
||||
public:
|
||||
CoverTrigger(Cover *a_cover) {
|
||||
a_cover->add_on_state_callback([this, a_cover]() {
|
||||
auto current_op = a_cover->current_operation;
|
||||
CoverTrigger(Cover *a_cover) : cover_(a_cover) {
|
||||
a_cover->add_on_state_callback([this]() {
|
||||
auto current_op = this->cover_->current_operation;
|
||||
if (current_op == OP) {
|
||||
if (!this->last_operation_.has_value() || this->last_operation_.value() != OP) {
|
||||
this->trigger();
|
||||
@@ -137,6 +138,7 @@ template<CoverOperation OP> class CoverTrigger : public Trigger<> {
|
||||
}
|
||||
|
||||
protected:
|
||||
Cover *cover_;
|
||||
optional<CoverOperation> last_operation_{};
|
||||
};
|
||||
} // namespace esphome::cover
|
||||
|
||||
@@ -68,24 +68,24 @@ CoverCall &CoverCall::set_tilt(float tilt) {
|
||||
return *this;
|
||||
}
|
||||
void CoverCall::perform() {
|
||||
ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
auto traits = this->parent_->get_traits();
|
||||
this->validate_();
|
||||
if (this->stop_) {
|
||||
ESP_LOGD(TAG, " Command: STOP");
|
||||
ESP_LOGV(TAG, " Command: STOP");
|
||||
}
|
||||
if (this->position_.has_value()) {
|
||||
if (traits.get_supports_position()) {
|
||||
ESP_LOGD(TAG, " Position: %.0f%%", *this->position_ * 100.0f);
|
||||
ESP_LOGV(TAG, " Position: %.0f%%", *this->position_ * 100.0f);
|
||||
} else {
|
||||
ESP_LOGD(TAG, " Command: %s", LOG_STR_ARG(cover_command_to_str(*this->position_)));
|
||||
ESP_LOGV(TAG, " Command: %s", LOG_STR_ARG(cover_command_to_str(*this->position_)));
|
||||
}
|
||||
}
|
||||
if (this->tilt_.has_value()) {
|
||||
ESP_LOGD(TAG, " Tilt: %.0f%%", *this->tilt_ * 100.0f);
|
||||
ESP_LOGV(TAG, " Tilt: %.0f%%", *this->tilt_ * 100.0f);
|
||||
}
|
||||
if (this->toggle_.has_value()) {
|
||||
ESP_LOGD(TAG, " Command: TOGGLE");
|
||||
ESP_LOGV(TAG, " Command: TOGGLE");
|
||||
}
|
||||
this->parent_->control(*this);
|
||||
}
|
||||
@@ -143,23 +143,23 @@ void Cover::publish_state(bool save) {
|
||||
this->position = clamp(this->position, 0.0f, 1.0f);
|
||||
this->tilt = clamp(this->tilt, 0.0f, 1.0f);
|
||||
|
||||
ESP_LOGD(TAG, "'%s' >>", this->name_.c_str());
|
||||
ESP_LOGV(TAG, "'%s' >>", this->name_.c_str());
|
||||
auto traits = this->get_traits();
|
||||
if (traits.get_supports_position()) {
|
||||
ESP_LOGD(TAG, " Position: %.0f%%", this->position * 100.0f);
|
||||
ESP_LOGV(TAG, " Position: %.0f%%", this->position * 100.0f);
|
||||
} else {
|
||||
if (this->position == COVER_OPEN) {
|
||||
ESP_LOGD(TAG, " State: OPEN");
|
||||
ESP_LOGV(TAG, " State: OPEN");
|
||||
} else if (this->position == COVER_CLOSED) {
|
||||
ESP_LOGD(TAG, " State: CLOSED");
|
||||
ESP_LOGV(TAG, " State: CLOSED");
|
||||
} else {
|
||||
ESP_LOGD(TAG, " State: UNKNOWN");
|
||||
ESP_LOGV(TAG, " State: UNKNOWN");
|
||||
}
|
||||
}
|
||||
if (traits.get_supports_tilt()) {
|
||||
ESP_LOGD(TAG, " Tilt: %.0f%%", this->tilt * 100.0f);
|
||||
ESP_LOGV(TAG, " Tilt: %.0f%%", this->tilt * 100.0f);
|
||||
}
|
||||
ESP_LOGD(TAG, " Current Operation: %s", LOG_STR_ARG(cover_operation_to_str(this->current_operation)));
|
||||
ESP_LOGV(TAG, " Current Operation: %s", LOG_STR_ARG(cover_operation_to_str(this->current_operation)));
|
||||
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_COVER) && defined(USE_CONTROLLER_REGISTRY)
|
||||
|
||||
@@ -30,7 +30,7 @@ void DateEntity::publish_state() {
|
||||
return;
|
||||
}
|
||||
this->set_has_state(true);
|
||||
ESP_LOGD(TAG, "'%s' >> %d-%d-%d", this->get_name().c_str(), this->year_, this->month_, this->day_);
|
||||
ESP_LOGV(TAG, "'%s' >> %d-%d-%d", this->get_name().c_str(), this->year_, this->month_, this->day_);
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_DATETIME_DATE) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_date_update(this);
|
||||
@@ -83,16 +83,16 @@ void DateCall::validate_() {
|
||||
|
||||
void DateCall::perform() {
|
||||
this->validate_();
|
||||
ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
|
||||
if (this->year_.has_value()) {
|
||||
ESP_LOGD(TAG, " Year: %d", *this->year_);
|
||||
ESP_LOGV(TAG, " Year: %d", *this->year_);
|
||||
}
|
||||
if (this->month_.has_value()) {
|
||||
ESP_LOGD(TAG, " Month: %d", *this->month_);
|
||||
ESP_LOGV(TAG, " Month: %d", *this->month_);
|
||||
}
|
||||
if (this->day_.has_value()) {
|
||||
ESP_LOGD(TAG, " Day: %d", *this->day_);
|
||||
ESP_LOGV(TAG, " Day: %d", *this->day_);
|
||||
}
|
||||
this->parent_->control(*this);
|
||||
}
|
||||
|
||||
@@ -33,9 +33,12 @@ class DateTimeBase : public EntityBase {
|
||||
|
||||
class DateTimeStateTrigger : public Trigger<ESPTime> {
|
||||
public:
|
||||
explicit DateTimeStateTrigger(DateTimeBase *parent) {
|
||||
parent->add_on_state_callback([this, parent]() { this->trigger(parent->state_as_esptime()); });
|
||||
explicit DateTimeStateTrigger(DateTimeBase *parent) : parent_(parent) {
|
||||
parent->add_on_state_callback([this]() { this->trigger(this->parent_->state_as_esptime()); });
|
||||
}
|
||||
|
||||
protected:
|
||||
DateTimeBase *parent_;
|
||||
};
|
||||
|
||||
} // namespace esphome::datetime
|
||||
|
||||
@@ -45,7 +45,7 @@ void DateTimeEntity::publish_state() {
|
||||
return;
|
||||
}
|
||||
this->set_has_state(true);
|
||||
ESP_LOGD(TAG, "'%s' >> %04u-%02u-%02u %02d:%02d:%02d", this->get_name().c_str(), this->year_, this->month_,
|
||||
ESP_LOGV(TAG, "'%s' >> %04u-%02u-%02u %02d:%02d:%02d", this->get_name().c_str(), this->year_, this->month_,
|
||||
this->day_, this->hour_, this->minute_, this->second_);
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_DATETIME_DATETIME) && defined(USE_CONTROLLER_REGISTRY)
|
||||
@@ -60,6 +60,9 @@ ESPTime DateTimeEntity::state_as_esptime() const {
|
||||
obj.year = this->year_;
|
||||
obj.month = this->month_;
|
||||
obj.day_of_month = this->day_;
|
||||
obj.day_of_week = 0;
|
||||
obj.day_of_year = 0;
|
||||
obj.is_dst = false;
|
||||
obj.hour = this->hour_;
|
||||
obj.minute = this->minute_;
|
||||
obj.second = this->second_;
|
||||
@@ -124,25 +127,25 @@ void DateTimeCall::validate_() {
|
||||
|
||||
void DateTimeCall::perform() {
|
||||
this->validate_();
|
||||
ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
|
||||
if (this->year_.has_value()) {
|
||||
ESP_LOGD(TAG, " Year: %d", *this->year_);
|
||||
ESP_LOGV(TAG, " Year: %d", *this->year_);
|
||||
}
|
||||
if (this->month_.has_value()) {
|
||||
ESP_LOGD(TAG, " Month: %d", *this->month_);
|
||||
ESP_LOGV(TAG, " Month: %d", *this->month_);
|
||||
}
|
||||
if (this->day_.has_value()) {
|
||||
ESP_LOGD(TAG, " Day: %d", *this->day_);
|
||||
ESP_LOGV(TAG, " Day: %d", *this->day_);
|
||||
}
|
||||
if (this->hour_.has_value()) {
|
||||
ESP_LOGD(TAG, " Hour: %d", *this->hour_);
|
||||
ESP_LOGV(TAG, " Hour: %d", *this->hour_);
|
||||
}
|
||||
if (this->minute_.has_value()) {
|
||||
ESP_LOGD(TAG, " Minute: %d", *this->minute_);
|
||||
ESP_LOGV(TAG, " Minute: %d", *this->minute_);
|
||||
}
|
||||
if (this->second_.has_value()) {
|
||||
ESP_LOGD(TAG, " Second: %d", *this->second_);
|
||||
ESP_LOGV(TAG, " Second: %d", *this->second_);
|
||||
}
|
||||
this->parent_->control(*this);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ void TimeEntity::publish_state() {
|
||||
return;
|
||||
}
|
||||
this->set_has_state(true);
|
||||
ESP_LOGD(TAG, "'%s' >> %02d:%02d:%02d", this->get_name().c_str(), this->hour_, this->minute_, this->second_);
|
||||
ESP_LOGV(TAG, "'%s' >> %02d:%02d:%02d", this->get_name().c_str(), this->hour_, this->minute_, this->second_);
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_DATETIME_TIME) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_time_update(this);
|
||||
@@ -52,15 +52,15 @@ void TimeCall::validate_() {
|
||||
|
||||
void TimeCall::perform() {
|
||||
this->validate_();
|
||||
ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
if (this->hour_.has_value()) {
|
||||
ESP_LOGD(TAG, " Hour: %d", *this->hour_);
|
||||
ESP_LOGV(TAG, " Hour: %d", *this->hour_);
|
||||
}
|
||||
if (this->minute_.has_value()) {
|
||||
ESP_LOGD(TAG, " Minute: %d", *this->minute_);
|
||||
ESP_LOGV(TAG, " Minute: %d", *this->minute_);
|
||||
}
|
||||
if (this->second_.has_value()) {
|
||||
ESP_LOGD(TAG, " Second: %d", *this->second_);
|
||||
ESP_LOGV(TAG, " Second: %d", *this->second_);
|
||||
}
|
||||
this->parent_->control(*this);
|
||||
}
|
||||
|
||||
@@ -96,37 +96,52 @@ template<typename... Ts> class IsActiveCondition : public Condition<Ts...> {
|
||||
|
||||
class DisplayMenuOnEnterTrigger : public Trigger<const MenuItem *> {
|
||||
public:
|
||||
explicit DisplayMenuOnEnterTrigger(MenuItem *parent) {
|
||||
parent->add_on_enter_callback([this, parent]() { this->trigger(parent); });
|
||||
explicit DisplayMenuOnEnterTrigger(MenuItem *parent) : parent_(parent) {
|
||||
parent->add_on_enter_callback([this]() { this->trigger(this->parent_); });
|
||||
}
|
||||
|
||||
protected:
|
||||
MenuItem *parent_;
|
||||
};
|
||||
|
||||
class DisplayMenuOnLeaveTrigger : public Trigger<const MenuItem *> {
|
||||
public:
|
||||
explicit DisplayMenuOnLeaveTrigger(MenuItem *parent) {
|
||||
parent->add_on_leave_callback([this, parent]() { this->trigger(parent); });
|
||||
explicit DisplayMenuOnLeaveTrigger(MenuItem *parent) : parent_(parent) {
|
||||
parent->add_on_leave_callback([this]() { this->trigger(this->parent_); });
|
||||
}
|
||||
|
||||
protected:
|
||||
MenuItem *parent_;
|
||||
};
|
||||
|
||||
class DisplayMenuOnValueTrigger : public Trigger<const MenuItem *> {
|
||||
public:
|
||||
explicit DisplayMenuOnValueTrigger(MenuItem *parent) {
|
||||
parent->add_on_value_callback([this, parent]() { this->trigger(parent); });
|
||||
explicit DisplayMenuOnValueTrigger(MenuItem *parent) : parent_(parent) {
|
||||
parent->add_on_value_callback([this]() { this->trigger(this->parent_); });
|
||||
}
|
||||
|
||||
protected:
|
||||
MenuItem *parent_;
|
||||
};
|
||||
|
||||
class DisplayMenuOnNextTrigger : public Trigger<const MenuItem *> {
|
||||
public:
|
||||
explicit DisplayMenuOnNextTrigger(MenuItemCustom *parent) {
|
||||
parent->add_on_next_callback([this, parent]() { this->trigger(parent); });
|
||||
explicit DisplayMenuOnNextTrigger(MenuItemCustom *parent) : parent_(parent) {
|
||||
parent->add_on_next_callback([this]() { this->trigger(this->parent_); });
|
||||
}
|
||||
|
||||
protected:
|
||||
MenuItemCustom *parent_;
|
||||
};
|
||||
|
||||
class DisplayMenuOnPrevTrigger : public Trigger<const MenuItem *> {
|
||||
public:
|
||||
explicit DisplayMenuOnPrevTrigger(MenuItemCustom *parent) {
|
||||
parent->add_on_prev_callback([this, parent]() { this->trigger(parent); });
|
||||
explicit DisplayMenuOnPrevTrigger(MenuItemCustom *parent) : parent_(parent) {
|
||||
parent->add_on_prev_callback([this]() { this->trigger(this->parent_); });
|
||||
}
|
||||
|
||||
protected:
|
||||
MenuItemCustom *parent_;
|
||||
};
|
||||
|
||||
} // namespace display_menu_base
|
||||
|
||||
@@ -40,11 +40,8 @@ void DS1307Component::read_time() {
|
||||
.hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10),
|
||||
.day_of_week = uint8_t(ds1307_.reg.weekday),
|
||||
.day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10),
|
||||
.day_of_year = 1, // ignored by recalc_timestamp_utc(false)
|
||||
.month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10),
|
||||
.year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000),
|
||||
.is_dst = false, // not used
|
||||
.timestamp = 0 // overwritten by recalc_timestamp_utc(false)
|
||||
};
|
||||
rtc_time.recalc_timestamp_utc(false);
|
||||
if (!rtc_time.is_valid()) {
|
||||
|
||||
@@ -97,6 +97,7 @@ CONF_ENABLE_LWIP_ASSERT = "enable_lwip_assert"
|
||||
CONF_EXECUTE_FROM_PSRAM = "execute_from_psram"
|
||||
CONF_MINIMUM_CHIP_REVISION = "minimum_chip_revision"
|
||||
CONF_RELEASE = "release"
|
||||
CONF_SRAM1_AS_IRAM = "sram1_as_iram"
|
||||
CONF_SUBTYPE = "subtype"
|
||||
|
||||
ARDUINO_FRAMEWORK_NAME = "framework-arduinoespressif32"
|
||||
@@ -378,12 +379,11 @@ FULL_CPU_FREQUENCIES = set(itertools.chain.from_iterable(CPU_FREQUENCIES.values(
|
||||
def set_core_data(config):
|
||||
cpu_frequency = config.get(CONF_CPU_FREQUENCY, None)
|
||||
variant = config[CONF_VARIANT]
|
||||
# if not specified in config, set to 160MHz if supported, the fastest otherwise
|
||||
# if not specified in config, default to the maximum supported frequency
|
||||
# (ESP32-P4 engineering samples are limited to 360MHz, non-engineering can do 400MHz)
|
||||
if cpu_frequency is None:
|
||||
choices = CPU_FREQUENCIES[variant]
|
||||
if "160MHZ" in choices:
|
||||
cpu_frequency = "160MHZ"
|
||||
elif "360MHZ" in choices:
|
||||
if variant == VARIANT_ESP32P4 and config.get(CONF_ENGINEERING_SAMPLE):
|
||||
cpu_frequency = "360MHZ"
|
||||
else:
|
||||
cpu_frequency = choices[-1]
|
||||
@@ -884,6 +884,13 @@ def final_validate(config):
|
||||
path=[CONF_FRAMEWORK, CONF_ADVANCED, CONF_MINIMUM_CHIP_REVISION],
|
||||
)
|
||||
)
|
||||
if config[CONF_VARIANT] != VARIANT_ESP32 and advanced[CONF_SRAM1_AS_IRAM]:
|
||||
errs.append(
|
||||
cv.Invalid(
|
||||
f"'{CONF_SRAM1_AS_IRAM}' is only supported on {VARIANT_ESP32}",
|
||||
path=[CONF_FRAMEWORK, CONF_ADVANCED, CONF_SRAM1_AS_IRAM],
|
||||
)
|
||||
)
|
||||
if (
|
||||
config[CONF_VARIANT] != VARIANT_ESP32P4
|
||||
and config.get(CONF_ENGINEERING_SAMPLE) is not None
|
||||
@@ -1131,6 +1138,7 @@ FRAMEWORK_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_MINIMUM_CHIP_REVISION): cv.one_of(
|
||||
*ESP32_CHIP_REVISIONS
|
||||
),
|
||||
cv.Optional(CONF_SRAM1_AS_IRAM, default=False): cv.boolean,
|
||||
# DHCP server is needed for WiFi AP mode. When WiFi component is used,
|
||||
# it will handle disabling DHCP server when AP is not configured.
|
||||
# Default to false (disabled) when WiFi is not used.
|
||||
@@ -1579,7 +1587,7 @@ async def to_code(config):
|
||||
if conf[CONF_ADVANCED][CONF_ENABLE_FULL_PRINTF]:
|
||||
cg.add_define("USE_FULL_PRINTF")
|
||||
else:
|
||||
for symbol in ("vprintf", "printf", "fprintf"):
|
||||
for symbol in ("vprintf", "printf", "fprintf", "vfprintf"):
|
||||
cg.add_build_flag(f"-Wl,--wrap={symbol}")
|
||||
else:
|
||||
cg.add_build_flag("-DUSE_ARDUINO")
|
||||
@@ -1655,6 +1663,16 @@ async def to_code(config):
|
||||
for rev, flag in ESP32_CHIP_REVISIONS.items():
|
||||
add_idf_sdkconfig_option(flag, rev == min_rev)
|
||||
cg.add_define("USE_ESP32_MIN_CHIP_REVISION_SET")
|
||||
|
||||
# Use SRAM1 region as IRAM on ESP32 (original) variant
|
||||
# This provides an additional 40KB of IRAM by using SRAM1 memory that was previously
|
||||
# reserved for bootloader DRAM. Requires a bootloader from ESP-IDF v5.1 or later.
|
||||
# WARNING: If the device has an old bootloader (pre-v5.1), the app will fail to boot.
|
||||
# A USB flash will update the bootloader automatically. OTA updates do not.
|
||||
# See: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/performance/ram-usage.html
|
||||
if variant == VARIANT_ESP32 and conf[CONF_ADVANCED][CONF_SRAM1_AS_IRAM]:
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_SYSTEM_ESP32_SRAM1_REGION_AS_IRAM", True)
|
||||
cg.add_define("USE_ESP32_SRAM1_AS_IRAM")
|
||||
add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_SINGLE_APP", False)
|
||||
add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_CUSTOM", True)
|
||||
add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_CUSTOM_FILENAME", "partitions.csv")
|
||||
@@ -1920,6 +1938,18 @@ async def to_code(config):
|
||||
add_idf_sdkconfig_option("CONFIG_MBEDTLS_SHA384_C", False)
|
||||
add_idf_sdkconfig_option("CONFIG_MBEDTLS_SHA512_C", False)
|
||||
|
||||
# Disable PicolibC Newlib compatibility shim on IDF 6.0+
|
||||
# IDF 6.0 switched from Newlib to PicolibC. The shim provides thread-local
|
||||
# stdin/stdout/stderr and getreent() for code compiled against Newlib.
|
||||
# ESPHome doesn't link against Newlib-built libraries that use stdio.
|
||||
# If a component needs it (e.g. precompiled Newlib binaries), re-enable via:
|
||||
# esp32:
|
||||
# framework:
|
||||
# sdkconfig_options:
|
||||
# CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY: "y"
|
||||
if idf_version() >= cv.Version(6, 0, 0):
|
||||
add_idf_sdkconfig_option("CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY", False)
|
||||
|
||||
# Disable regi2c control functions in IRAM
|
||||
# Only needed if using analog peripherals (ADC, DAC, etc.) from ISRs while cache is disabled
|
||||
if advanced[CONF_DISABLE_REGI2C_IN_IRAM]:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "crash_handler.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "preferences.h"
|
||||
@@ -15,7 +16,6 @@
|
||||
#include <freertos/task.h>
|
||||
|
||||
void setup(); // NOLINT(readability-redundant-declaration)
|
||||
void loop(); // NOLINT(readability-redundant-declaration)
|
||||
|
||||
// Weak stub for initArduino - overridden when the Arduino component is present
|
||||
extern "C" __attribute__((weak)) void initArduino() {}
|
||||
@@ -65,7 +65,7 @@ TaskHandle_t loop_task_handle = nullptr; // NOLINT(cppcoreguidelines-avoid-non-
|
||||
void loop_task(void *pv_params) {
|
||||
setup();
|
||||
while (true) {
|
||||
loop();
|
||||
App.loop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,11 @@ def esp32_validate_gpio_pin(value: int) -> int:
|
||||
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-39)")
|
||||
if value in _ESP_SDIO_PINS:
|
||||
raise cv.Invalid(
|
||||
f"This pin cannot be used on ESP32s and is already used by the flash interface (function: {_ESP_SDIO_PINS[value]})"
|
||||
f"This pin cannot be used on ESP32s and is already used by the flash interface"
|
||||
f" (function: {_ESP_SDIO_PINS[value]})."
|
||||
f" If you are using an ESP32 module that uses a different flash pin"
|
||||
f" configuration (e.g. ESP32-PICO-V3-02), you can set"
|
||||
f" 'ignore_pin_validation_error: true' to bypass this check."
|
||||
)
|
||||
if 9 <= value <= 10:
|
||||
_LOGGER.warning(
|
||||
|
||||
@@ -14,6 +14,8 @@ _ESP32C3_SPI_PSRAM_PINS = {
|
||||
17: "SPIQ",
|
||||
}
|
||||
|
||||
_ESP32C3_USB_JTAG_PINS = {18, 19}
|
||||
|
||||
_ESP32C3_STRAPPING_PINS = {2, 8, 9}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -26,6 +28,12 @@ def esp32_c3_validate_gpio_pin(value: int) -> int:
|
||||
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]})"
|
||||
)
|
||||
if value in _ESP32C3_USB_JTAG_PINS:
|
||||
_LOGGER.warning(
|
||||
"GPIO%d is used by the USB-Serial-JTAG interface."
|
||||
" Using this pin as GPIO will conflict with USB-Serial-JTAG.",
|
||||
value,
|
||||
)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
@@ -18,7 +18,9 @@ _ESP32C6_SPI_PSRAM_PINS = {
|
||||
30: "SPID",
|
||||
}
|
||||
|
||||
_ESP32C6_STRAPPING_PINS = {8, 9, 15}
|
||||
_ESP32C6_USB_JTAG_PINS = {12, 13}
|
||||
|
||||
_ESP32C6_STRAPPING_PINS = {4, 5, 8, 9, 15}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -30,6 +32,12 @@ def esp32_c6_validate_gpio_pin(value: int) -> int:
|
||||
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]})"
|
||||
)
|
||||
if value in _ESP32C6_USB_JTAG_PINS:
|
||||
_LOGGER.warning(
|
||||
"GPIO%d is used by the USB-Serial-JTAG interface."
|
||||
" Using this pin as GPIO will conflict with USB-Serial-JTAG.",
|
||||
value,
|
||||
)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ _ESP32H2_SPI_FLASH_PINS = {6, 7, 15, 16, 17, 18, 19, 20, 21}
|
||||
|
||||
_ESP32H2_USB_JTAG_PINS = {26, 27}
|
||||
|
||||
_ESP32H2_STRAPPING_PINS = {2, 3, 8, 9, 25}
|
||||
_ESP32H2_STRAPPING_PINS = {8, 9, 25}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -26,8 +26,8 @@ def esp32_h2_validate_gpio_pin(value: int) -> int:
|
||||
)
|
||||
if value in _ESP32H2_USB_JTAG_PINS:
|
||||
_LOGGER.warning(
|
||||
"GPIO%d is reserved for the USB-Serial-JTAG interface.\n"
|
||||
"To use this pin as GPIO, USB-Serial-JTAG will be disabled.",
|
||||
"GPIO%d is used by the USB-Serial-JTAG interface."
|
||||
" Using this pin as GPIO will conflict with USB-Serial-JTAG.",
|
||||
value,
|
||||
)
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ def esp32_p4_validate_gpio_pin(value: int) -> int:
|
||||
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-54)")
|
||||
if value in _ESP32P4_USB_JTAG_PINS:
|
||||
_LOGGER.warning(
|
||||
"GPIO%d is reserved for the USB-Serial-JTAG interface.\n"
|
||||
"To use this pin as GPIO, USB-Serial-JTAG will be disabled.",
|
||||
"GPIO%d is used by the USB-Serial-JTAG interface."
|
||||
" Using this pin as GPIO will conflict with USB-Serial-JTAG.",
|
||||
value,
|
||||
)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import esphome.config_validation as cv
|
||||
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
|
||||
from esphome.pins import check_strapping_pin
|
||||
|
||||
_ESP_32S3_SPI_PSRAM_PINS = {
|
||||
_ESP32S3_SPI_PSRAM_PINS = {
|
||||
26: "SPICS1",
|
||||
27: "SPIHD",
|
||||
28: "SPIWP",
|
||||
@@ -15,7 +15,7 @@ _ESP_32S3_SPI_PSRAM_PINS = {
|
||||
32: "SPID",
|
||||
}
|
||||
|
||||
_ESP_32_ESP32_S3R8_PSRAM_PINS = {
|
||||
_ESP32S3R8_PSRAM_PINS = {
|
||||
33: "SPIIO4",
|
||||
34: "SPIIO5",
|
||||
35: "SPIIO6",
|
||||
@@ -23,7 +23,9 @@ _ESP_32_ESP32_S3R8_PSRAM_PINS = {
|
||||
37: "SPIDQS",
|
||||
}
|
||||
|
||||
_ESP_32S3_STRAPPING_PINS = {0, 3, 45, 46}
|
||||
_ESP32S3_USB_JTAG_PINS = {19, 20}
|
||||
|
||||
_ESP32S3_STRAPPING_PINS = {0, 3, 45, 46}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -32,11 +34,11 @@ def esp32_s3_validate_gpio_pin(value: int) -> int:
|
||||
if value < 0 or value > 48:
|
||||
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-48)")
|
||||
|
||||
if value in _ESP_32S3_SPI_PSRAM_PINS:
|
||||
if value in _ESP32S3_SPI_PSRAM_PINS:
|
||||
raise cv.Invalid(
|
||||
f"This pin cannot be used on ESP32-S3s and is already used by the SPI/PSRAM interface(function: {_ESP_32S3_SPI_PSRAM_PINS[value]})"
|
||||
f"This pin cannot be used on ESP32-S3s and is already used by the SPI/PSRAM interface(function: {_ESP32S3_SPI_PSRAM_PINS[value]})"
|
||||
)
|
||||
if value in _ESP_32_ESP32_S3R8_PSRAM_PINS:
|
||||
if value in _ESP32S3R8_PSRAM_PINS:
|
||||
_LOGGER.warning(
|
||||
"GPIO%d is used by the PSRAM interface on ESP32-S3R8 / ESP32-S3R8V and should be avoided on these models",
|
||||
value,
|
||||
@@ -46,6 +48,12 @@ def esp32_s3_validate_gpio_pin(value: int) -> int:
|
||||
# These pins are not exposed in GPIO mux (reason unknown)
|
||||
# but they're missing from IO_MUX list in datasheet
|
||||
raise cv.Invalid(f"The pin GPIO{value} is not usable on ESP32-S3s.")
|
||||
if value in _ESP32S3_USB_JTAG_PINS:
|
||||
_LOGGER.warning(
|
||||
"GPIO%d is used by the USB-Serial-JTAG interface."
|
||||
" Using this pin as GPIO will conflict with USB-Serial-JTAG.",
|
||||
value,
|
||||
)
|
||||
|
||||
return value
|
||||
|
||||
@@ -61,5 +69,5 @@ def esp32_s3_validate_supports(value: dict[str, Any]) -> dict[str, Any]:
|
||||
# All ESP32 pins support input mode
|
||||
pass
|
||||
|
||||
check_strapping_pin(value, _ESP_32S3_STRAPPING_PINS, _LOGGER)
|
||||
check_strapping_pin(value, _ESP32S3_STRAPPING_PINS, _LOGGER)
|
||||
return value
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/portmacro.h>
|
||||
#include "esphome/core/log.h"
|
||||
#include "esp_random.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
uint32_t random_uint32() { return esp_random(); }
|
||||
static const char *const TAG = "esp32";
|
||||
|
||||
bool random_bytes(uint8_t *data, size_t len) {
|
||||
esp_fill_random(data, len);
|
||||
return true;
|
||||
@@ -64,22 +66,43 @@ LwIPLock::~LwIPLock() {
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Read MAC and validate both the return code and content.
|
||||
static bool read_valid_mac(uint8_t *mac, esp_err_t err) { return err == ESP_OK && mac_address_is_valid(mac); }
|
||||
|
||||
static constexpr size_t MAC_ADDRESS_SIZE_BITS = MAC_ADDRESS_SIZE * 8; // 48 bits
|
||||
|
||||
void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter)
|
||||
#if defined(CONFIG_SOC_IEEE802154_SUPPORTED)
|
||||
// When CONFIG_SOC_IEEE802154_SUPPORTED is defined, esp_efuse_mac_get_default
|
||||
// returns the 802.15.4 EUI-64 address, so we read directly from eFuse instead.
|
||||
if (has_custom_mac_address()) {
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48);
|
||||
} else {
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, mac, 48);
|
||||
// Both paths already read raw eFuse bytes, so there is no CRC-bypass fallback
|
||||
// (unlike the non-IEEE802154 path where esp_efuse_mac_get_default does CRC checks).
|
||||
if (has_custom_mac_address() &&
|
||||
read_valid_mac(mac, esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, MAC_ADDRESS_SIZE_BITS))) {
|
||||
return;
|
||||
}
|
||||
if (read_valid_mac(mac, esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, mac, MAC_ADDRESS_SIZE_BITS))) {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (has_custom_mac_address()) {
|
||||
esp_efuse_mac_get_custom(mac);
|
||||
} else {
|
||||
esp_efuse_mac_get_default(mac);
|
||||
if (has_custom_mac_address() && read_valid_mac(mac, esp_efuse_mac_get_custom(mac))) {
|
||||
return;
|
||||
}
|
||||
if (read_valid_mac(mac, esp_efuse_mac_get_default(mac))) {
|
||||
return;
|
||||
}
|
||||
// Default MAC read failed (e.g., eFuse CRC error) - try reading raw eFuse bytes
|
||||
// directly, bypassing CRC validation. A MAC that passes mac_address_is_valid()
|
||||
// (non-zero, non-broadcast, unicast) is almost certainly the real factory MAC
|
||||
// with a corrupted CRC byte, which is far better than returning garbage or zeros.
|
||||
if (read_valid_mac(mac, esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, mac, MAC_ADDRESS_SIZE_BITS))) {
|
||||
ESP_LOGW(TAG, "eFuse MAC CRC failed but raw bytes appear valid - using raw eFuse MAC");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// All methods failed - zero the MAC rather than returning garbage
|
||||
ESP_LOGE(TAG, "Failed to read a valid MAC address from eFuse");
|
||||
memset(mac, 0, MAC_ADDRESS_SIZE);
|
||||
}
|
||||
|
||||
void set_mac_address(uint8_t *mac) { esp_base_mac_addr_set(mac); }
|
||||
@@ -89,9 +112,11 @@ bool has_custom_mac_address() {
|
||||
uint8_t mac[6];
|
||||
// do not use 'esp_efuse_mac_get_custom(mac)' because it drops an error in the logs whenever it fails
|
||||
#ifndef USE_ESP32_VARIANT_ESP32
|
||||
return (esp_efuse_read_field_blob(ESP_EFUSE_USER_DATA_MAC_CUSTOM, mac, 48) == ESP_OK) && mac_address_is_valid(mac);
|
||||
return (esp_efuse_read_field_blob(ESP_EFUSE_USER_DATA_MAC_CUSTOM, mac, MAC_ADDRESS_SIZE_BITS) == ESP_OK) &&
|
||||
mac_address_is_valid(mac);
|
||||
#else
|
||||
return (esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48) == ESP_OK) && mac_address_is_valid(mac);
|
||||
return (esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, MAC_ADDRESS_SIZE_BITS) == ESP_OK) &&
|
||||
mac_address_is_valid(mac);
|
||||
#endif
|
||||
#else
|
||||
return false;
|
||||
|
||||
@@ -4,12 +4,40 @@ import re
|
||||
# pylint: disable=E0602
|
||||
Import("env") # noqa
|
||||
|
||||
# IRAM size for testing mode (2MB - large enough to accommodate grouped tests)
|
||||
TESTING_IRAM_SIZE = 0x200000
|
||||
# Memory sizes for testing mode (large enough to accommodate grouped tests)
|
||||
TESTING_IRAM_SIZE = 0x200000 # 2MB
|
||||
TESTING_DRAM_SIZE = 0x200000 # 2MB
|
||||
|
||||
|
||||
def patch_segment(content, segment_name, new_size):
|
||||
"""Patch a memory segment's length in linker script content.
|
||||
|
||||
Handles both single-line and multi-line segment definitions, e.g.:
|
||||
iram0_0_seg (RX) : org = 0x40080000, len = 0x20000 + 0x0
|
||||
or split across lines:
|
||||
dram0_0_seg (RW) : org = 0x3FFB0000 + 0xdb5c,
|
||||
len = 0x2c200 - 0xdb5c
|
||||
|
||||
Args:
|
||||
content: Full linker script content as string
|
||||
segment_name: Name of the segment (e.g., 'iram0_0_seg')
|
||||
new_size: New size as integer
|
||||
|
||||
Returns:
|
||||
Tuple of (new_content, was_patched)
|
||||
"""
|
||||
# Match segment name through to "len = <value>" allowing newlines between org and len
|
||||
pattern = rf'({re.escape(segment_name)}\s*\([^)]*\)\s*:\s*org\s*=\s*.+?,\s*len\s*=\s*)(\S+[^\n]*)'
|
||||
if match := re.search(pattern, content, re.DOTALL):
|
||||
replacement = f"{match.group(1)}{new_size:#x}"
|
||||
new_content = content[:match.start()] + replacement + content[match.end():]
|
||||
if new_content != content:
|
||||
return new_content, True
|
||||
return content, False
|
||||
|
||||
|
||||
def patch_idf_linker_script(source, target, env):
|
||||
"""Patch ESP-IDF linker script to increase IRAM size for testing mode."""
|
||||
"""Patch ESP-IDF linker script to increase IRAM and DRAM size for testing mode."""
|
||||
# Check if we're in testing mode by looking for the define
|
||||
build_flags = env.get("BUILD_FLAGS", [])
|
||||
testing_mode = any("-DESPHOME_TESTING_MODE" in flag for flag in build_flags)
|
||||
@@ -34,36 +62,22 @@ def patch_idf_linker_script(source, target, env):
|
||||
print(f"ESPHome: Error reading linker script: {e}")
|
||||
return
|
||||
|
||||
# Check if this file contains iram0_0_seg
|
||||
if 'iram0_0_seg' not in content:
|
||||
print(f"ESPHome: Warning - iram0_0_seg not found in {memory_ld}")
|
||||
return
|
||||
patches = []
|
||||
|
||||
# Look for iram0_0_seg definition and increase its length
|
||||
# ESP-IDF format can be:
|
||||
# iram0_0_seg (RX) : org = 0x40080000, len = 0x20000 + 0x0
|
||||
# or more complex with nested parentheses:
|
||||
# iram0_0_seg (RX) : org = (0x40370000 + 0x4000), len = (((0x403CB700 - (0x40378000 - 0x3FC88000)) - 0x3FC88000) + 0x8000 - 0x4000)
|
||||
# We want to change len to TESTING_IRAM_SIZE for testing
|
||||
content, patched = patch_segment(content, 'iram0_0_seg', TESTING_IRAM_SIZE)
|
||||
if patched:
|
||||
patches.append(f"IRAM={TESTING_IRAM_SIZE:#x}")
|
||||
|
||||
# Use a more robust approach: find the line and manually parse it
|
||||
lines = content.split('\n')
|
||||
for i, line in enumerate(lines):
|
||||
if 'iram0_0_seg' in line and 'len' in line:
|
||||
# Find the position of "len = " and replace everything after it until the end of the statement
|
||||
match = re.search(r'(iram0_0_seg\s*\([^)]*\)\s*:\s*org\s*=\s*(?:\([^)]+\)|0x[0-9a-fA-F]+)\s*,\s*len\s*=\s*)(.+?)(\s*)$', line)
|
||||
if match:
|
||||
lines[i] = f"{match.group(1)}{TESTING_IRAM_SIZE:#x}{match.group(3)}"
|
||||
break
|
||||
content, patched = patch_segment(content, 'dram0_0_seg', TESTING_DRAM_SIZE)
|
||||
if patched:
|
||||
patches.append(f"DRAM={TESTING_DRAM_SIZE:#x}")
|
||||
|
||||
updated = '\n'.join(lines)
|
||||
|
||||
if updated != content:
|
||||
if patches:
|
||||
with open(memory_ld, "w") as f:
|
||||
f.write(updated)
|
||||
print(f"ESPHome: Patched IRAM size to {TESTING_IRAM_SIZE:#x} in {memory_ld} for testing mode")
|
||||
f.write(content)
|
||||
print(f"ESPHome: Patched {', '.join(patches)} in {memory_ld} for testing mode")
|
||||
else:
|
||||
print(f"ESPHome: Warning - could not patch iram0_0_seg in {memory_ld}")
|
||||
print(f"ESPHome: Warning - could not patch memory segments in {memory_ld}")
|
||||
|
||||
|
||||
# Hook into the build process before linking
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace esphome::esp32 {
|
||||
|
||||
static const char *const TAG = "esp32.preferences";
|
||||
static const char *const TAG = "preferences";
|
||||
|
||||
// Buffer size for converting uint32_t to string: max "4294967295" (10 chars) + null terminator + 1 padding
|
||||
static constexpr size_t KEY_BUFFER_SIZE = 12;
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
* Linker wrap stubs for FILE*-based printf functions.
|
||||
*
|
||||
* ESP-IDF SDK components (gpio driver, ringbuf, log_write) reference
|
||||
* fprintf(), printf(), and vprintf() which pull in newlib's _vfprintf_r
|
||||
* (~11 KB). This is a separate implementation from _svfprintf_r (used by
|
||||
* snprintf/vsnprintf) that handles FILE* stream I/O with buffering and
|
||||
* locking.
|
||||
* fprintf(), printf(), vprintf(), and vfprintf() which pull in the full
|
||||
* printf implementation (~11 KB on newlib's _vfprintf_r, ~2.8 KB on
|
||||
* picolibc's vfprintf). This is a separate implementation from the one
|
||||
* used by snprintf/vsnprintf that handles FILE* stream I/O with buffering
|
||||
* and locking.
|
||||
*
|
||||
* ESPHome replaces the ESP-IDF log handler via esp_log_set_vprintf_(),
|
||||
* so the SDK's vprintf() path is dead code at runtime. The fprintf()
|
||||
@@ -70,11 +71,15 @@ int __wrap_printf(const char *fmt, ...) {
|
||||
return len;
|
||||
}
|
||||
|
||||
int __wrap_vfprintf(FILE *stream, const char *fmt, va_list ap) {
|
||||
char buf[PRINTF_BUFFER_SIZE];
|
||||
return write_printf_buffer(stream, buf, vsnprintf(buf, sizeof(buf), fmt, ap));
|
||||
}
|
||||
|
||||
int __wrap_fprintf(FILE *stream, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
char buf[PRINTF_BUFFER_SIZE];
|
||||
int len = write_printf_buffer(stream, buf, vsnprintf(buf, sizeof(buf), fmt, ap));
|
||||
int len = __wrap_vfprintf(stream, fmt, ap);
|
||||
va_end(ap);
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -12,58 +12,73 @@ namespace esp32_improv {
|
||||
|
||||
class ESP32ImprovProvisionedTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit ESP32ImprovProvisionedTrigger(ESP32ImprovComponent *parent) {
|
||||
parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) {
|
||||
if (state == improv::STATE_PROVISIONED && !parent->is_failed()) {
|
||||
trigger();
|
||||
explicit ESP32ImprovProvisionedTrigger(ESP32ImprovComponent *parent) : parent_(parent) {
|
||||
parent->add_on_state_callback([this](improv::State state, improv::Error error) {
|
||||
if (state == improv::STATE_PROVISIONED && !this->parent_->is_failed()) {
|
||||
this->trigger();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
ESP32ImprovComponent *parent_;
|
||||
};
|
||||
|
||||
class ESP32ImprovProvisioningTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit ESP32ImprovProvisioningTrigger(ESP32ImprovComponent *parent) {
|
||||
parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) {
|
||||
if (state == improv::STATE_PROVISIONING && !parent->is_failed()) {
|
||||
trigger();
|
||||
explicit ESP32ImprovProvisioningTrigger(ESP32ImprovComponent *parent) : parent_(parent) {
|
||||
parent->add_on_state_callback([this](improv::State state, improv::Error error) {
|
||||
if (state == improv::STATE_PROVISIONING && !this->parent_->is_failed()) {
|
||||
this->trigger();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
ESP32ImprovComponent *parent_;
|
||||
};
|
||||
|
||||
class ESP32ImprovStartTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit ESP32ImprovStartTrigger(ESP32ImprovComponent *parent) {
|
||||
parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) {
|
||||
explicit ESP32ImprovStartTrigger(ESP32ImprovComponent *parent) : parent_(parent) {
|
||||
parent->add_on_state_callback([this](improv::State state, improv::Error error) {
|
||||
if ((state == improv::STATE_AUTHORIZED || state == improv::STATE_AWAITING_AUTHORIZATION) &&
|
||||
!parent->is_failed()) {
|
||||
trigger();
|
||||
!this->parent_->is_failed()) {
|
||||
this->trigger();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
ESP32ImprovComponent *parent_;
|
||||
};
|
||||
|
||||
class ESP32ImprovStateTrigger : public Trigger<improv::State, improv::Error> {
|
||||
public:
|
||||
explicit ESP32ImprovStateTrigger(ESP32ImprovComponent *parent) {
|
||||
parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) {
|
||||
if (!parent->is_failed()) {
|
||||
trigger(state, error);
|
||||
explicit ESP32ImprovStateTrigger(ESP32ImprovComponent *parent) : parent_(parent) {
|
||||
parent->add_on_state_callback([this](improv::State state, improv::Error error) {
|
||||
if (!this->parent_->is_failed()) {
|
||||
this->trigger(state, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
ESP32ImprovComponent *parent_;
|
||||
};
|
||||
|
||||
class ESP32ImprovStoppedTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit ESP32ImprovStoppedTrigger(ESP32ImprovComponent *parent) {
|
||||
parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) {
|
||||
if (state == improv::STATE_STOPPED && !parent->is_failed()) {
|
||||
trigger();
|
||||
explicit ESP32ImprovStoppedTrigger(ESP32ImprovComponent *parent) : parent_(parent) {
|
||||
parent->add_on_state_callback([this](improv::State state, improv::Error error) {
|
||||
if (state == improv::STATE_STOPPED && !this->parent_->is_failed()) {
|
||||
this->trigger();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
ESP32ImprovComponent *parent_;
|
||||
};
|
||||
|
||||
} // namespace esp32_improv
|
||||
|
||||
@@ -360,11 +360,16 @@ void ESP32TouchComponent::loop() {
|
||||
}
|
||||
|
||||
// Publish initial OFF state for sensors that haven't received events yet
|
||||
bool all_initial_published = true;
|
||||
for (auto *child : this->children_) {
|
||||
this->publish_initial_state_if_needed_(child, now);
|
||||
if (!child->initial_state_published_) {
|
||||
all_initial_published = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->setup_mode_) {
|
||||
// Only disable loop once all initial states are published
|
||||
if (!this->setup_mode_ && all_initial_published) {
|
||||
this->disable_loop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ extern "C" {
|
||||
|
||||
namespace esphome::esp8266 {
|
||||
|
||||
static const char *const TAG = "esp8266.preferences";
|
||||
static const char *const TAG = "preferences";
|
||||
|
||||
static constexpr uint32_t ESP_RTC_USER_MEM_START = 0x60001200;
|
||||
static constexpr uint32_t ESP_RTC_USER_MEM_SIZE_WORDS = 128;
|
||||
|
||||
@@ -115,10 +115,12 @@ ETHERNET_TYPES = {
|
||||
"JL1101": EthernetType.ETHERNET_TYPE_JL1101,
|
||||
"KSZ8081": EthernetType.ETHERNET_TYPE_KSZ8081,
|
||||
"KSZ8081RNA": EthernetType.ETHERNET_TYPE_KSZ8081RNA,
|
||||
"W5100": EthernetType.ETHERNET_TYPE_W5100,
|
||||
"W5500": EthernetType.ETHERNET_TYPE_W5500,
|
||||
"OPENETH": EthernetType.ETHERNET_TYPE_OPENETH,
|
||||
"DM9051": EthernetType.ETHERNET_TYPE_DM9051,
|
||||
"LAN8670": EthernetType.ETHERNET_TYPE_LAN8670,
|
||||
"ENC28J60": EthernetType.ETHERNET_TYPE_ENC28J60,
|
||||
}
|
||||
|
||||
# PHY types that need compile-time defines for conditional compilation
|
||||
@@ -131,9 +133,11 @@ _PHY_TYPE_TO_DEFINE = {
|
||||
"JL1101": "USE_ETHERNET_JL1101",
|
||||
"KSZ8081": "USE_ETHERNET_KSZ8081",
|
||||
"KSZ8081RNA": "USE_ETHERNET_KSZ8081",
|
||||
"W5100": "USE_ETHERNET_W5100",
|
||||
"W5500": "USE_ETHERNET_W5500",
|
||||
"DM9051": "USE_ETHERNET_DM9051",
|
||||
"LAN8670": "USE_ETHERNET_LAN8670",
|
||||
"ENC28J60": "USE_ETHERNET_ENC28J60",
|
||||
}
|
||||
|
||||
|
||||
@@ -155,11 +159,22 @@ _IDF6_ETHERNET_COMPONENTS: dict[str, IDFRegistryComponent] = {
|
||||
"KSZ8081RNA": IDFRegistryComponent("espressif/ksz80xx", "1.0.0"),
|
||||
"W5500": IDFRegistryComponent("espressif/w5500", "1.0.1"),
|
||||
"DM9051": IDFRegistryComponent("espressif/dm9051", "1.0.0"),
|
||||
"ENC28J60": IDFRegistryComponent("espressif/enc28j60", "1.0.1"),
|
||||
"LAN8670": IDFRegistryComponent("espressif/lan867x", "2.0.0"),
|
||||
}
|
||||
|
||||
SPI_ETHERNET_TYPES = ["W5500", "DM9051"]
|
||||
# These types are always external IDF components (never built-in to ESP-IDF)
|
||||
_ALWAYS_EXTERNAL_IDF_COMPONENTS = {"LAN8670", "ENC28J60"}
|
||||
|
||||
# ESP32-only SPI ethernet types (W5100 is RP2040-only, no ESP-IDF driver)
|
||||
SPI_ETHERNET_TYPES = {"W5500", "DM9051", "ENC28J60"}
|
||||
# RP2040-supported SPI ethernet types
|
||||
RP2040_SPI_ETHERNET_TYPES = ["W5500"]
|
||||
RP2040_SPI_ETHERNET_TYPES = {"W5100", "W5500", "ENC28J60"}
|
||||
_RP2040_SPI_LIBRARIES = {
|
||||
"W5100": "lwIP_w5100",
|
||||
"W5500": "lwIP_w5500",
|
||||
"ENC28J60": "lwIP_enc28j60",
|
||||
}
|
||||
SPI_ETHERNET_DEFAULT_POLLING_INTERVAL = TimePeriodMilliseconds(milliseconds=10)
|
||||
|
||||
emac_rmii_clock_mode_t = cg.global_ns.enum("emac_rmii_clock_mode_t")
|
||||
@@ -220,7 +235,18 @@ def _validate(config):
|
||||
|
||||
if CORE.is_esp32:
|
||||
if config[CONF_TYPE] in SPI_ETHERNET_TYPES:
|
||||
if _is_framework_spi_polling_mode_supported():
|
||||
# ENC28J60 driver does not support polling mode - interrupt is required
|
||||
if config[CONF_TYPE] == "ENC28J60":
|
||||
if CONF_POLLING_INTERVAL in config:
|
||||
raise cv.Invalid(
|
||||
f"'{CONF_POLLING_INTERVAL}' is not supported for ENC28J60. "
|
||||
f"'{CONF_INTERRUPT_PIN}' is required."
|
||||
)
|
||||
if CONF_INTERRUPT_PIN not in config:
|
||||
raise cv.Invalid(
|
||||
f"'{CONF_INTERRUPT_PIN}' is a required option for ENC28J60."
|
||||
)
|
||||
elif _is_framework_spi_polling_mode_supported():
|
||||
if CONF_POLLING_INTERVAL in config and CONF_INTERRUPT_PIN in config:
|
||||
raise cv.Invalid(
|
||||
f"Cannot specify more than one of {CONF_INTERRUPT_PIN}, {CONF_POLLING_INTERVAL}"
|
||||
@@ -277,7 +303,7 @@ def _validate(config):
|
||||
)
|
||||
elif CORE.is_rp2040 and config[CONF_TYPE] not in RP2040_SPI_ETHERNET_TYPES:
|
||||
raise cv.Invalid(
|
||||
f"Only {', '.join(RP2040_SPI_ETHERNET_TYPES)} are supported on RP2040, "
|
||||
f"Only {', '.join(sorted(RP2040_SPI_ETHERNET_TYPES))} are supported on RP2040, "
|
||||
f"not {config[CONF_TYPE]}"
|
||||
)
|
||||
return config
|
||||
@@ -364,9 +390,11 @@ CONFIG_SCHEMA = cv.All(
|
||||
"JL1101": RMII_SCHEMA,
|
||||
"KSZ8081": RMII_SCHEMA,
|
||||
"KSZ8081RNA": RMII_SCHEMA,
|
||||
"W5100": cv.All(SPI_SCHEMA, cv.only_on([Platform.RP2040])),
|
||||
"W5500": SPI_SCHEMA,
|
||||
"OPENETH": cv.All(BASE_SCHEMA, cv.only_on([Platform.ESP32])),
|
||||
"DM9051": SPI_SCHEMA,
|
||||
"ENC28J60": SPI_SCHEMA,
|
||||
"LAN8670": RMII_SCHEMA,
|
||||
},
|
||||
upper=True,
|
||||
@@ -502,7 +530,8 @@ async def _to_code_esp32(var: cg.Pvariable, config: ConfigType) -> None:
|
||||
cg.add_define("USE_ETHERNET_SPI")
|
||||
add_idf_sdkconfig_option("CONFIG_ETH_USE_SPI_ETHERNET", True)
|
||||
# CONFIG_ETH_SPI_ETHERNET_{TYPE} Kconfig options were removed in IDF 6.0
|
||||
if idf_version() < cv.Version(6, 0, 0):
|
||||
# ENC28J60 was never built-in to IDF, so it has no Kconfig option
|
||||
if idf_version() < cv.Version(6, 0, 0) and config[CONF_TYPE] != "ENC28J60":
|
||||
add_idf_sdkconfig_option(
|
||||
f"CONFIG_ETH_SPI_ETHERNET_{config[CONF_TYPE]}", True
|
||||
)
|
||||
@@ -533,12 +562,11 @@ async def _to_code_esp32(var: cg.Pvariable, config: ConfigType) -> None:
|
||||
# Re-enable ESP-IDF's Ethernet driver (excluded by default to save compile time)
|
||||
include_builtin_idf_component("esp_eth")
|
||||
|
||||
if config[CONF_TYPE] == "LAN8670":
|
||||
# Add LAN867x 10BASE-T1S PHY support component
|
||||
add_idf_component(name="espressif/lan867x", ref="2.0.0")
|
||||
|
||||
# IDF 6.0 moved per-chip PHY/MAC drivers to the Espressif Component Registry
|
||||
if idf_version() >= cv.Version(6, 0, 0) and (
|
||||
if config[CONF_TYPE] in _ALWAYS_EXTERNAL_IDF_COMPONENTS:
|
||||
component = _IDF6_ETHERNET_COMPONENTS[config[CONF_TYPE]]
|
||||
add_idf_component(name=component.name, ref=component.version)
|
||||
elif idf_version() >= cv.Version(6, 0, 0) and (
|
||||
# IDF 6.0 moved per-chip PHY/MAC drivers to the Espressif Component Registry
|
||||
component := _IDF6_ETHERNET_COMPONENTS.get(config[CONF_TYPE])
|
||||
):
|
||||
add_idf_component(name=component.name, ref=component.version)
|
||||
@@ -555,7 +583,7 @@ async def _to_code_rp2040(var: cg.Pvariable, config: ConfigType) -> None:
|
||||
cg.add(var.set_reset_pin(config[CONF_RESET_PIN]))
|
||||
|
||||
cg.add_define("USE_ETHERNET_SPI")
|
||||
cg.add_library("lwIP_w5500", None)
|
||||
cg.add_library(_RP2040_SPI_LIBRARIES[config[CONF_TYPE]], None)
|
||||
|
||||
|
||||
def _final_validate_rmii_pins(config: ConfigType) -> None:
|
||||
|
||||
@@ -18,12 +18,6 @@ void EthernetComponent::set_type(EthernetType type) { this->type_ = type; }
|
||||
void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; }
|
||||
#endif
|
||||
|
||||
// set_use_address() is guaranteed to be called during component setup by Python code generation,
|
||||
// so use_address_ will always be valid when get_use_address() is called - no fallback needed.
|
||||
const char *EthernetComponent::get_use_address() const { return this->use_address_; }
|
||||
|
||||
void EthernetComponent::set_use_address(const char *use_address) { this->use_address_ = use_address; }
|
||||
|
||||
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
|
||||
void EthernetComponent::notify_ip_state_listeners_() {
|
||||
auto ips = this->get_ip_addresses();
|
||||
|
||||
@@ -23,7 +23,15 @@ extern "C" eth_esp32_emac_config_t eth_esp32_emac_default_config(void);
|
||||
#endif // USE_ESP32
|
||||
|
||||
#ifdef USE_RP2040
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
#include <W5500lwIP.h>
|
||||
#elif defined(USE_ETHERNET_W5100)
|
||||
#include <W5100lwIP.h>
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
#include <ENC28J60lwIP.h>
|
||||
#else
|
||||
#error "Unsupported RP2040 SPI Ethernet type"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace esphome::ethernet {
|
||||
@@ -53,10 +61,12 @@ enum EthernetType : uint8_t {
|
||||
ETHERNET_TYPE_JL1101,
|
||||
ETHERNET_TYPE_KSZ8081,
|
||||
ETHERNET_TYPE_KSZ8081RNA,
|
||||
ETHERNET_TYPE_W5100,
|
||||
ETHERNET_TYPE_W5500,
|
||||
ETHERNET_TYPE_OPENETH,
|
||||
ETHERNET_TYPE_DM9051,
|
||||
ETHERNET_TYPE_LAN8670,
|
||||
ETHERNET_TYPE_ENC28J60,
|
||||
};
|
||||
|
||||
struct ManualIP {
|
||||
@@ -103,8 +113,8 @@ class EthernetComponent final : public Component {
|
||||
|
||||
network::IPAddresses get_ip_addresses();
|
||||
network::IPAddress get_dns_address(uint8_t num);
|
||||
const char *get_use_address() const;
|
||||
void set_use_address(const char *use_address);
|
||||
const char *get_use_address() const { return this->use_address_; }
|
||||
void set_use_address(const char *use_address) { this->use_address_ = use_address; }
|
||||
void get_eth_mac_address_raw(uint8_t *mac);
|
||||
// Remove before 2026.9.0
|
||||
ESPDEPRECATED("Use get_eth_mac_address_pretty_into_buffer() instead. Removed in 2026.9.0", "2026.3.0")
|
||||
@@ -215,7 +225,20 @@ class EthernetComponent final : public Component {
|
||||
|
||||
#ifdef USE_RP2040
|
||||
static constexpr uint32_t LINK_CHECK_INTERVAL = 500; // ms between link/IP polls
|
||||
#if defined(USE_ETHERNET_W5100)
|
||||
static constexpr uint32_t RESET_DELAY_MS = 150; // W5100S PLL lock time
|
||||
#else
|
||||
static constexpr uint32_t RESET_DELAY_MS = 10;
|
||||
#endif
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
Wiznet5500lwIP *eth_{nullptr};
|
||||
#elif defined(USE_ETHERNET_W5100)
|
||||
Wiznet5100lwIP *eth_{nullptr};
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
ENC28J60lwIP *eth_{nullptr};
|
||||
#else
|
||||
#error "Unsupported RP2040 SPI Ethernet type"
|
||||
#endif
|
||||
uint32_t last_link_check_{0};
|
||||
uint8_t clk_pin_;
|
||||
uint8_t miso_pin_;
|
||||
|
||||
@@ -44,6 +44,11 @@
|
||||
#include "esp_eth_phy_lan867x.h"
|
||||
#endif
|
||||
|
||||
// ENC28J60 header exists on all IDF versions (always an external component)
|
||||
#ifdef USE_ETHERNET_ENC28J60
|
||||
#include "esp_eth_enc28j60.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_ETHERNET_SPI
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
@@ -194,25 +199,27 @@ void EthernetComponent::setup() {
|
||||
.post_cb = nullptr,
|
||||
};
|
||||
|
||||
#ifdef USE_ETHERNET_W5500
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(host, &devcfg);
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_DM9051
|
||||
#elif defined(USE_ETHERNET_DM9051)
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(host, &devcfg);
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
eth_enc28j60_config_t enc28j60_config = ETH_ENC28J60_DEFAULT_CONFIG(host, &devcfg);
|
||||
#endif
|
||||
|
||||
#ifdef USE_ETHERNET_W5500
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
w5500_config.int_gpio_num = this->interrupt_pin_;
|
||||
#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
|
||||
w5500_config.poll_period_ms = this->polling_interval_;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_ETHERNET_DM9051
|
||||
#elif defined(USE_ETHERNET_DM9051)
|
||||
dm9051_config.int_gpio_num = this->interrupt_pin_;
|
||||
#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
|
||||
dm9051_config.poll_period_ms = this->polling_interval_;
|
||||
#endif
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
enc28j60_config.int_gpio_num = this->interrupt_pin_;
|
||||
// ENC28J60 does not support poll_period_ms
|
||||
#endif
|
||||
|
||||
phy_config.phy_addr = this->phy_addr_spi_;
|
||||
@@ -300,19 +307,24 @@ void EthernetComponent::setup() {
|
||||
#endif
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_SPI
|
||||
#ifdef USE_ETHERNET_W5500
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
case ETHERNET_TYPE_W5500: {
|
||||
mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
|
||||
this->phy_ = esp_eth_phy_new_w5500(&phy_config);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_DM9051
|
||||
#elif defined(USE_ETHERNET_DM9051)
|
||||
case ETHERNET_TYPE_DM9051: {
|
||||
mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
|
||||
this->phy_ = esp_eth_phy_new_dm9051(&phy_config);
|
||||
break;
|
||||
}
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
case ETHERNET_TYPE_ENC28J60: {
|
||||
mac = esp_eth_mac_new_enc28j60(&enc28j60_config, &mac_config);
|
||||
this->phy_ = esp_eth_phy_new_enc28j60(&phy_config);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
default: {
|
||||
@@ -405,15 +417,18 @@ void EthernetComponent::dump_config() {
|
||||
eth_type = "KSZ8081RNA";
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_W5500
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
case ETHERNET_TYPE_W5500:
|
||||
eth_type = "W5500";
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_DM9051
|
||||
#elif defined(USE_ETHERNET_DM9051)
|
||||
case ETHERNET_TYPE_DM9051:
|
||||
eth_type = "DM9051";
|
||||
break;
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
case ETHERNET_TYPE_ENC28J60:
|
||||
eth_type = "ENC28J60";
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_OPENETH
|
||||
case ETHERNET_TYPE_OPENETH:
|
||||
|
||||
@@ -31,11 +31,18 @@ void EthernetComponent::setup() {
|
||||
reset_pin.digital_write(false);
|
||||
delay(1); // NOLINT
|
||||
reset_pin.digital_write(true);
|
||||
delay(10); // NOLINT - wait for W5500 to initialize after reset
|
||||
// W5100S needs 150ms for PLL lock; W5500/ENC28J60 need ~10ms
|
||||
delay(RESET_DELAY_MS); // NOLINT
|
||||
}
|
||||
|
||||
// Create the W5500 device instance
|
||||
// Create the SPI Ethernet device instance
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
this->eth_ = new Wiznet5500lwIP(this->cs_pin_, SPI, this->interrupt_pin_); // NOLINT
|
||||
#elif defined(USE_ETHERNET_W5100)
|
||||
this->eth_ = new Wiznet5100lwIP(this->cs_pin_, SPI, this->interrupt_pin_); // NOLINT
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
this->eth_ = new ENC28J60lwIP(this->cs_pin_, SPI, this->interrupt_pin_); // NOLINT
|
||||
#endif
|
||||
|
||||
// Set hostname before begin() so the LWIP netif gets it
|
||||
this->eth_->hostname(App.get_name().c_str());
|
||||
@@ -61,7 +68,7 @@ void EthernetComponent::setup() {
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
ESP_LOGE(TAG, "Failed to initialize W5500 Ethernet");
|
||||
ESP_LOGE(TAG, "Failed to initialize Ethernet");
|
||||
delete this->eth_; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
this->eth_ = nullptr;
|
||||
this->mark_failed();
|
||||
@@ -76,8 +83,8 @@ void EthernetComponent::setup() {
|
||||
// or via GPIO interrupt when one is provided.
|
||||
|
||||
// Don't set started_ here — let the link polling in loop() set it
|
||||
// when the W5500 link is actually up. Setting it prematurely causes
|
||||
// a "Starting → Stopped → Starting" log sequence because the W5500
|
||||
// when the link is actually up. Setting it prematurely causes
|
||||
// a "Starting → Stopped → Starting" log sequence because the chip
|
||||
// needs time after begin() before the PHY link is ready.
|
||||
}
|
||||
|
||||
@@ -85,14 +92,21 @@ void EthernetComponent::loop() {
|
||||
// On RP2040, we need to poll connection state since there are no events.
|
||||
const uint32_t now = App.get_loop_component_start_time();
|
||||
|
||||
// Throttle link/IP polling to avoid excessive SPI transactions from linkStatus()
|
||||
// which reads the W5500 PHY register via SPI on every call.
|
||||
// Throttle link/IP polling to avoid excessive SPI transactions.
|
||||
// W5500/ENC28J60 read PHY register via SPI on every linkStatus() call.
|
||||
// W5100 can't detect link state, so we skip the SPI read and assume link-up.
|
||||
// connected() reads netif->ip_addr without LwIPLock, but this is a single
|
||||
// 32-bit aligned read (atomic on ARM) — worst case is a one-iteration-stale
|
||||
// value, which is benign for polling.
|
||||
if (this->eth_ != nullptr && now - this->last_link_check_ >= LINK_CHECK_INTERVAL) {
|
||||
this->last_link_check_ = now;
|
||||
#if defined(USE_ETHERNET_W5100)
|
||||
// W5100 can't detect link (isLinkDetectable() returns false), so linkStatus()
|
||||
// returns Unknown — assume link is up after successful begin()
|
||||
bool link_up = true;
|
||||
#else
|
||||
bool link_up = this->eth_->linkStatus() == LinkON;
|
||||
#endif
|
||||
bool has_ip = this->eth_->connected();
|
||||
|
||||
if (!link_up) {
|
||||
@@ -164,9 +178,17 @@ void EthernetComponent::loop() {
|
||||
}
|
||||
|
||||
void EthernetComponent::dump_config() {
|
||||
const char *type_str = "Unknown";
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
type_str = "W5500";
|
||||
#elif defined(USE_ETHERNET_W5100)
|
||||
type_str = "W5100";
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
type_str = "ENC28J60";
|
||||
#endif
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"Ethernet:\n"
|
||||
" Type: W5500\n"
|
||||
" Type: %s\n"
|
||||
" Connected: %s\n"
|
||||
" CLK Pin: %u\n"
|
||||
" MISO Pin: %u\n"
|
||||
@@ -174,7 +196,7 @@ void EthernetComponent::dump_config() {
|
||||
" CS Pin: %u\n"
|
||||
" IRQ Pin: %d\n"
|
||||
" Reset Pin: %d",
|
||||
YESNO(this->is_connected()), this->clk_pin_, this->miso_pin_, this->mosi_pin_, this->cs_pin_,
|
||||
type_str, YESNO(this->is_connected()), this->clk_pin_, this->miso_pin_, this->mosi_pin_, this->cs_pin_,
|
||||
this->interrupt_pin_, this->reset_pin_);
|
||||
this->dump_connect_params_();
|
||||
}
|
||||
@@ -216,13 +238,18 @@ const char *EthernetComponent::get_eth_mac_address_pretty_into_buffer(
|
||||
}
|
||||
|
||||
eth_duplex_t EthernetComponent::get_duplex_mode() {
|
||||
// W5500 is always full duplex
|
||||
// W5100, W5500, and ENC28J60 are full-duplex on RP2040
|
||||
return ETH_DUPLEX_FULL;
|
||||
}
|
||||
|
||||
eth_speed_t EthernetComponent::get_link_speed() {
|
||||
// W5500 is always 100Mbps
|
||||
#ifdef USE_ETHERNET_ENC28J60
|
||||
// ENC28J60 is 10Mbps only
|
||||
return ETH_SPEED_10M;
|
||||
#else
|
||||
// W5100 and W5500 are 100Mbps
|
||||
return ETH_SPEED_100M;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EthernetComponent::powerdown() {
|
||||
|
||||
@@ -22,7 +22,7 @@ void Event::trigger(const std::string &event_type) {
|
||||
return;
|
||||
}
|
||||
this->last_event_type_ = found;
|
||||
ESP_LOGD(TAG, "'%s' >> '%s'", this->get_name().c_str(), this->last_event_type_);
|
||||
ESP_LOGV(TAG, "'%s' >> '%s'", this->get_name().c_str(), this->last_event_type_);
|
||||
this->event_callback_.call(StringRef(found));
|
||||
#if defined(USE_EVENT) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_event(this);
|
||||
|
||||
@@ -113,16 +113,19 @@ template<typename... Ts> class FanIsOffCondition : public Condition<Ts...> {
|
||||
|
||||
class FanStateTrigger : public Trigger<Fan *> {
|
||||
public:
|
||||
FanStateTrigger(Fan *state) {
|
||||
state->add_on_state_callback([this, state]() { this->trigger(state); });
|
||||
FanStateTrigger(Fan *state) : fan_(state) {
|
||||
state->add_on_state_callback([this]() { this->trigger(this->fan_); });
|
||||
}
|
||||
|
||||
protected:
|
||||
Fan *fan_;
|
||||
};
|
||||
|
||||
class FanTurnOnTrigger : public Trigger<> {
|
||||
public:
|
||||
FanTurnOnTrigger(Fan *state) {
|
||||
state->add_on_state_callback([this, state]() {
|
||||
auto is_on = state->state;
|
||||
FanTurnOnTrigger(Fan *state) : fan_(state) {
|
||||
state->add_on_state_callback([this]() {
|
||||
auto is_on = this->fan_->state;
|
||||
auto should_trigger = is_on && !this->last_on_;
|
||||
this->last_on_ = is_on;
|
||||
if (should_trigger) {
|
||||
@@ -133,14 +136,15 @@ class FanTurnOnTrigger : public Trigger<> {
|
||||
}
|
||||
|
||||
protected:
|
||||
Fan *fan_;
|
||||
bool last_on_;
|
||||
};
|
||||
|
||||
class FanTurnOffTrigger : public Trigger<> {
|
||||
public:
|
||||
FanTurnOffTrigger(Fan *state) {
|
||||
state->add_on_state_callback([this, state]() {
|
||||
auto is_on = state->state;
|
||||
FanTurnOffTrigger(Fan *state) : fan_(state) {
|
||||
state->add_on_state_callback([this]() {
|
||||
auto is_on = this->fan_->state;
|
||||
auto should_trigger = !is_on && this->last_on_;
|
||||
this->last_on_ = is_on;
|
||||
if (should_trigger) {
|
||||
@@ -151,14 +155,15 @@ class FanTurnOffTrigger : public Trigger<> {
|
||||
}
|
||||
|
||||
protected:
|
||||
Fan *fan_;
|
||||
bool last_on_;
|
||||
};
|
||||
|
||||
class FanDirectionSetTrigger : public Trigger<FanDirection> {
|
||||
public:
|
||||
FanDirectionSetTrigger(Fan *state) {
|
||||
state->add_on_state_callback([this, state]() {
|
||||
auto direction = state->direction;
|
||||
FanDirectionSetTrigger(Fan *state) : fan_(state) {
|
||||
state->add_on_state_callback([this]() {
|
||||
auto direction = this->fan_->direction;
|
||||
auto should_trigger = direction != this->last_direction_;
|
||||
this->last_direction_ = direction;
|
||||
if (should_trigger) {
|
||||
@@ -169,14 +174,15 @@ class FanDirectionSetTrigger : public Trigger<FanDirection> {
|
||||
}
|
||||
|
||||
protected:
|
||||
Fan *fan_;
|
||||
FanDirection last_direction_;
|
||||
};
|
||||
|
||||
class FanOscillatingSetTrigger : public Trigger<bool> {
|
||||
public:
|
||||
FanOscillatingSetTrigger(Fan *state) {
|
||||
state->add_on_state_callback([this, state]() {
|
||||
auto oscillating = state->oscillating;
|
||||
FanOscillatingSetTrigger(Fan *state) : fan_(state) {
|
||||
state->add_on_state_callback([this]() {
|
||||
auto oscillating = this->fan_->oscillating;
|
||||
auto should_trigger = oscillating != this->last_oscillating_;
|
||||
this->last_oscillating_ = oscillating;
|
||||
if (should_trigger) {
|
||||
@@ -187,14 +193,15 @@ class FanOscillatingSetTrigger : public Trigger<bool> {
|
||||
}
|
||||
|
||||
protected:
|
||||
Fan *fan_;
|
||||
bool last_oscillating_;
|
||||
};
|
||||
|
||||
class FanSpeedSetTrigger : public Trigger<int> {
|
||||
public:
|
||||
FanSpeedSetTrigger(Fan *state) {
|
||||
state->add_on_state_callback([this, state]() {
|
||||
auto speed = state->speed;
|
||||
FanSpeedSetTrigger(Fan *state) : fan_(state) {
|
||||
state->add_on_state_callback([this]() {
|
||||
auto speed = this->fan_->speed;
|
||||
auto should_trigger = speed != this->last_speed_;
|
||||
this->last_speed_ = speed;
|
||||
if (should_trigger) {
|
||||
@@ -205,14 +212,15 @@ class FanSpeedSetTrigger : public Trigger<int> {
|
||||
}
|
||||
|
||||
protected:
|
||||
Fan *fan_;
|
||||
int last_speed_;
|
||||
};
|
||||
|
||||
class FanPresetSetTrigger : public Trigger<StringRef> {
|
||||
public:
|
||||
FanPresetSetTrigger(Fan *state) {
|
||||
state->add_on_state_callback([this, state]() {
|
||||
auto preset_mode = state->get_preset_mode();
|
||||
FanPresetSetTrigger(Fan *state) : fan_(state) {
|
||||
state->add_on_state_callback([this]() {
|
||||
auto preset_mode = this->fan_->get_preset_mode();
|
||||
auto should_trigger = preset_mode != this->last_preset_mode_;
|
||||
this->last_preset_mode_ = preset_mode;
|
||||
if (should_trigger) {
|
||||
@@ -223,6 +231,7 @@ class FanPresetSetTrigger : public Trigger<StringRef> {
|
||||
}
|
||||
|
||||
protected:
|
||||
Fan *fan_;
|
||||
StringRef last_preset_mode_{};
|
||||
};
|
||||
|
||||
|
||||
@@ -44,22 +44,22 @@ FanCall &FanCall::set_preset_mode(const char *preset_mode, size_t len) {
|
||||
}
|
||||
|
||||
void FanCall::perform() {
|
||||
ESP_LOGD(TAG, "'%s' - Setting:", this->parent_.get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting:", this->parent_.get_name().c_str());
|
||||
this->validate_();
|
||||
if (this->binary_state_.has_value()) {
|
||||
ESP_LOGD(TAG, " State: %s", ONOFF(*this->binary_state_));
|
||||
ESP_LOGV(TAG, " State: %s", ONOFF(*this->binary_state_));
|
||||
}
|
||||
if (this->oscillating_.has_value()) {
|
||||
ESP_LOGD(TAG, " Oscillating: %s", YESNO(*this->oscillating_));
|
||||
ESP_LOGV(TAG, " Oscillating: %s", YESNO(*this->oscillating_));
|
||||
}
|
||||
if (this->speed_.has_value()) {
|
||||
ESP_LOGD(TAG, " Speed: %d", *this->speed_);
|
||||
ESP_LOGV(TAG, " Speed: %d", *this->speed_);
|
||||
}
|
||||
if (this->direction_.has_value()) {
|
||||
ESP_LOGD(TAG, " Direction: %s", LOG_STR_ARG(fan_direction_to_string(*this->direction_)));
|
||||
ESP_LOGV(TAG, " Direction: %s", LOG_STR_ARG(fan_direction_to_string(*this->direction_)));
|
||||
}
|
||||
if (this->preset_mode_ != nullptr) {
|
||||
ESP_LOGD(TAG, " Preset Mode: %s", this->preset_mode_);
|
||||
ESP_LOGV(TAG, " Preset Mode: %s", this->preset_mode_);
|
||||
}
|
||||
this->parent_.control(*this);
|
||||
}
|
||||
@@ -196,21 +196,21 @@ void Fan::apply_preset_mode_(const FanCall &call) {
|
||||
void Fan::publish_state() {
|
||||
auto traits = this->get_traits();
|
||||
|
||||
ESP_LOGD(TAG,
|
||||
ESP_LOGV(TAG,
|
||||
"'%s' >>\n"
|
||||
" State: %s",
|
||||
this->name_.c_str(), ONOFF(this->state));
|
||||
if (traits.supports_speed()) {
|
||||
ESP_LOGD(TAG, " Speed: %d", this->speed);
|
||||
ESP_LOGV(TAG, " Speed: %d", this->speed);
|
||||
}
|
||||
if (traits.supports_oscillation()) {
|
||||
ESP_LOGD(TAG, " Oscillating: %s", YESNO(this->oscillating));
|
||||
ESP_LOGV(TAG, " Oscillating: %s", YESNO(this->oscillating));
|
||||
}
|
||||
if (traits.supports_direction()) {
|
||||
ESP_LOGD(TAG, " Direction: %s", LOG_STR_ARG(fan_direction_to_string(this->direction)));
|
||||
ESP_LOGV(TAG, " Direction: %s", LOG_STR_ARG(fan_direction_to_string(this->direction)));
|
||||
}
|
||||
if (this->preset_mode_ != nullptr) {
|
||||
ESP_LOGD(TAG, " Preset Mode: %s", this->preset_mode_);
|
||||
ESP_LOGV(TAG, " Preset Mode: %s", this->preset_mode_);
|
||||
}
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_FAN) && defined(USE_CONTROLLER_REGISTRY)
|
||||
|
||||
@@ -23,9 +23,8 @@ static const LogString *gpio_mode_to_string(bool use_interrupt) {
|
||||
|
||||
void IRAM_ATTR GPIOBinarySensorStore::gpio_intr(GPIOBinarySensorStore *arg) {
|
||||
bool new_state = arg->isr_pin_.digital_read();
|
||||
if (new_state != arg->last_state_) {
|
||||
if (new_state != arg->state_) {
|
||||
arg->state_ = new_state;
|
||||
arg->last_state_ = new_state;
|
||||
arg->changed_ = true;
|
||||
// Wake up the component from its disabled loop state
|
||||
if (arg->component_ != nullptr) {
|
||||
@@ -34,28 +33,27 @@ void IRAM_ATTR GPIOBinarySensorStore::gpio_intr(GPIOBinarySensorStore *arg) {
|
||||
}
|
||||
}
|
||||
|
||||
void GPIOBinarySensorStore::setup(InternalGPIOPin *pin, gpio::InterruptType type, Component *component) {
|
||||
void GPIOBinarySensorStore::setup(InternalGPIOPin *pin, Component *component) {
|
||||
pin->setup();
|
||||
this->isr_pin_ = pin->to_isr();
|
||||
this->component_ = component;
|
||||
|
||||
// Read initial state
|
||||
this->last_state_ = pin->digital_read();
|
||||
this->state_ = this->last_state_;
|
||||
this->state_ = pin->digital_read();
|
||||
|
||||
// Attach interrupt - from this point on, any changes will be caught by the interrupt
|
||||
pin->attach_interrupt(&GPIOBinarySensorStore::gpio_intr, this, type);
|
||||
pin->attach_interrupt(&GPIOBinarySensorStore::gpio_intr, this, this->interrupt_type_);
|
||||
}
|
||||
|
||||
void GPIOBinarySensor::setup() {
|
||||
if (this->use_interrupt_ && !this->pin_->is_internal()) {
|
||||
if (this->store_.use_interrupt_ && !this->pin_->is_internal()) {
|
||||
ESP_LOGD(TAG, "GPIO is not internal, falling back to polling mode");
|
||||
this->use_interrupt_ = false;
|
||||
this->store_.use_interrupt_ = false;
|
||||
}
|
||||
|
||||
if (this->use_interrupt_) {
|
||||
if (this->store_.use_interrupt_) {
|
||||
auto *internal_pin = static_cast<InternalGPIOPin *>(this->pin_);
|
||||
this->store_.setup(internal_pin, this->interrupt_type_, this);
|
||||
this->store_.setup(internal_pin, this);
|
||||
this->publish_initial_state(this->store_.get_state());
|
||||
} else {
|
||||
this->pin_->setup();
|
||||
@@ -66,14 +64,14 @@ void GPIOBinarySensor::setup() {
|
||||
void GPIOBinarySensor::dump_config() {
|
||||
LOG_BINARY_SENSOR("", "GPIO Binary Sensor", this);
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
ESP_LOGCONFIG(TAG, " Mode: %s", LOG_STR_ARG(gpio_mode_to_string(this->use_interrupt_)));
|
||||
if (this->use_interrupt_) {
|
||||
ESP_LOGCONFIG(TAG, " Interrupt Type: %s", LOG_STR_ARG(interrupt_type_to_string(this->interrupt_type_)));
|
||||
ESP_LOGCONFIG(TAG, " Mode: %s", LOG_STR_ARG(gpio_mode_to_string(this->store_.use_interrupt_)));
|
||||
if (this->store_.use_interrupt_) {
|
||||
ESP_LOGCONFIG(TAG, " Interrupt Type: %s", LOG_STR_ARG(interrupt_type_to_string(this->store_.interrupt_type_)));
|
||||
}
|
||||
}
|
||||
|
||||
void GPIOBinarySensor::loop() {
|
||||
if (this->use_interrupt_) {
|
||||
if (this->store_.use_interrupt_) {
|
||||
if (this->store_.is_changed()) {
|
||||
// Clear the flag immediately to minimize the window where we might miss changes
|
||||
this->store_.clear_changed();
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
namespace esphome {
|
||||
namespace gpio {
|
||||
|
||||
// Store class for ISR data (no vtables, ISR-safe)
|
||||
// Store class for ISR data and configuration (no vtables, ISR-safe)
|
||||
class GPIOBinarySensorStore {
|
||||
public:
|
||||
void setup(InternalGPIOPin *pin, gpio::InterruptType type, Component *component);
|
||||
void setup(InternalGPIOPin *pin, Component *component);
|
||||
|
||||
static void gpio_intr(GPIOBinarySensorStore *arg);
|
||||
|
||||
@@ -32,11 +32,13 @@ class GPIOBinarySensorStore {
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class GPIOBinarySensor;
|
||||
ISRInternalGPIOPin isr_pin_;
|
||||
volatile bool state_{false};
|
||||
volatile bool last_state_{false};
|
||||
volatile bool changed_{false};
|
||||
Component *component_{nullptr}; // Pointer to the component for enable_loop_soon_any_context()
|
||||
volatile bool state_{false};
|
||||
volatile bool changed_{false};
|
||||
bool use_interrupt_{true};
|
||||
gpio::InterruptType interrupt_type_{gpio::INTERRUPT_ANY_EDGE};
|
||||
};
|
||||
|
||||
class GPIOBinarySensor final : public binary_sensor::BinarySensor, public Component {
|
||||
@@ -44,9 +46,9 @@ class GPIOBinarySensor final : public binary_sensor::BinarySensor, public Compon
|
||||
// No destructor needed: ESPHome components are created at boot and live forever.
|
||||
// Interrupts are only detached on reboot when memory is cleared anyway.
|
||||
|
||||
void set_pin(GPIOPin *pin) { pin_ = pin; }
|
||||
void set_use_interrupt(bool use_interrupt) { use_interrupt_ = use_interrupt; }
|
||||
void set_interrupt_type(gpio::InterruptType type) { interrupt_type_ = type; }
|
||||
void set_pin(GPIOPin *pin) { this->pin_ = pin; }
|
||||
void set_use_interrupt(bool use_interrupt) { this->store_.use_interrupt_ = use_interrupt; }
|
||||
void set_interrupt_type(gpio::InterruptType type) { this->store_.interrupt_type_ = type; }
|
||||
// ========== INTERNAL METHODS ==========
|
||||
// (In most use cases you won't need these)
|
||||
/// Setup pin
|
||||
@@ -59,8 +61,6 @@ class GPIOBinarySensor final : public binary_sensor::BinarySensor, public Compon
|
||||
|
||||
protected:
|
||||
GPIOPin *pin_;
|
||||
bool use_interrupt_{true};
|
||||
gpio::InterruptType interrupt_type_{gpio::INTERRUPT_ANY_EDGE};
|
||||
GPIOBinarySensorStore store_;
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ async def to_code(config):
|
||||
cg.add(var.set_pin(pin))
|
||||
|
||||
if CONF_INTERLOCK in config:
|
||||
cg.add_define("USE_GPIO_SWITCH_INTERLOCK")
|
||||
interlock = []
|
||||
for it in config[CONF_INTERLOCK]:
|
||||
lock = await cg.get_variable(it)
|
||||
|
||||
@@ -5,6 +5,9 @@ namespace esphome {
|
||||
namespace gpio {
|
||||
|
||||
static const char *const TAG = "switch.gpio";
|
||||
#ifdef USE_GPIO_SWITCH_INTERLOCK
|
||||
static constexpr uint32_t INTERLOCK_TIMEOUT_ID = 0;
|
||||
#endif
|
||||
|
||||
float GPIOSwitch::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
void GPIOSwitch::setup() {
|
||||
@@ -27,6 +30,7 @@ void GPIOSwitch::setup() {
|
||||
void GPIOSwitch::dump_config() {
|
||||
LOG_SWITCH("", "GPIO Switch", this);
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
#ifdef USE_GPIO_SWITCH_INTERLOCK
|
||||
if (!this->interlock_.empty()) {
|
||||
ESP_LOGCONFIG(TAG, " Interlocks:");
|
||||
for (auto *lock : this->interlock_) {
|
||||
@@ -35,8 +39,10 @@ void GPIOSwitch::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " %s", lock->get_name().c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void GPIOSwitch::write_state(bool state) {
|
||||
#ifdef USE_GPIO_SWITCH_INTERLOCK
|
||||
if (state != this->inverted_) {
|
||||
// Turning ON, check interlocking
|
||||
|
||||
@@ -51,7 +57,7 @@ void GPIOSwitch::write_state(bool state) {
|
||||
}
|
||||
}
|
||||
if (found && this->interlock_wait_time_ != 0) {
|
||||
this->set_timeout("interlock", this->interlock_wait_time_, [this, state] {
|
||||
this->set_timeout(INTERLOCK_TIMEOUT_ID, this->interlock_wait_time_, [this, state] {
|
||||
// Don't write directly, call the function again
|
||||
// (some other switch may have changed state while we were waiting)
|
||||
this->write_state(state);
|
||||
@@ -61,13 +67,17 @@ void GPIOSwitch::write_state(bool state) {
|
||||
} else if (this->interlock_wait_time_ != 0) {
|
||||
// If we are switched off during the interlock wait time, cancel any pending
|
||||
// re-activations
|
||||
this->cancel_timeout("interlock");
|
||||
this->cancel_timeout(INTERLOCK_TIMEOUT_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
this->pin_->digital_write(state);
|
||||
this->publish_state(state);
|
||||
}
|
||||
|
||||
#ifdef USE_GPIO_SWITCH_INTERLOCK
|
||||
void GPIOSwitch::set_interlock(const std::initializer_list<Switch *> &interlock) { this->interlock_ = interlock; }
|
||||
#endif
|
||||
|
||||
} // namespace gpio
|
||||
} // namespace esphome
|
||||
|
||||
@@ -18,15 +18,19 @@ class GPIOSwitch final : public switch_::Switch, public Component {
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
#ifdef USE_GPIO_SWITCH_INTERLOCK
|
||||
void set_interlock(const std::initializer_list<Switch *> &interlock);
|
||||
void set_interlock_wait_time(uint32_t interlock_wait_time) { interlock_wait_time_ = interlock_wait_time; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void write_state(bool state) override;
|
||||
|
||||
GPIOPin *pin_;
|
||||
#ifdef USE_GPIO_SWITCH_INTERLOCK
|
||||
FixedVector<Switch *> interlock_;
|
||||
uint32_t interlock_wait_time_{0};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace gpio
|
||||
|
||||
@@ -16,10 +16,6 @@ void GPSTime::from_tiny_gps_(TinyGPSPlus &tiny_gps) {
|
||||
val.year = tiny_gps.date.year();
|
||||
val.month = tiny_gps.date.month();
|
||||
val.day_of_month = tiny_gps.date.day();
|
||||
// Set these to valid value for recalc_timestamp_utc - it's not used for calculation
|
||||
val.day_of_week = 1;
|
||||
val.day_of_year = 1;
|
||||
|
||||
val.hour = tiny_gps.time.hour();
|
||||
val.minute = tiny_gps.time.minute();
|
||||
val.second = tiny_gps.time.second();
|
||||
|
||||
@@ -75,9 +75,12 @@ class GraphicalDisplayMenu : public display_menu_base::DisplayMenuComponent {
|
||||
|
||||
class GraphicalDisplayMenuOnRedrawTrigger : public Trigger<const GraphicalDisplayMenu *> {
|
||||
public:
|
||||
explicit GraphicalDisplayMenuOnRedrawTrigger(GraphicalDisplayMenu *parent) {
|
||||
parent->add_on_redraw_callback([this, parent]() { this->trigger(parent); });
|
||||
explicit GraphicalDisplayMenuOnRedrawTrigger(GraphicalDisplayMenu *parent) : parent_(parent) {
|
||||
parent->add_on_redraw_callback([this]() { this->trigger(this->parent_); });
|
||||
}
|
||||
|
||||
protected:
|
||||
GraphicalDisplayMenu *parent_;
|
||||
};
|
||||
|
||||
} // namespace graphical_display_menu
|
||||
|
||||
@@ -748,7 +748,7 @@ void HonClimate::update_sub_sensor_(SubSensorType type, float value) {
|
||||
if (type < SubSensorType::SUB_SENSOR_TYPE_COUNT) {
|
||||
size_t index = (size_t) type;
|
||||
if ((this->sub_sensors_[index] != nullptr) &&
|
||||
((!this->sub_sensors_[index]->has_state()) || (this->sub_sensors_[index]->raw_state != value)))
|
||||
((!this->sub_sensors_[index]->has_state()) || (this->sub_sensors_[index]->get_raw_state() != value)))
|
||||
this->sub_sensors_[index]->publish_state(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <limits>
|
||||
#include <random>
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/log.h"
|
||||
@@ -18,13 +16,6 @@ namespace esphome {
|
||||
|
||||
static const char *const TAG = "helpers.host";
|
||||
|
||||
uint32_t random_uint32() {
|
||||
std::random_device dev;
|
||||
std::mt19937 rng(dev());
|
||||
std::uniform_int_distribution<uint32_t> dist(0, std::numeric_limits<uint32_t>::max());
|
||||
return dist(rng);
|
||||
}
|
||||
|
||||
bool random_bytes(uint8_t *data, size_t len) {
|
||||
FILE *fp = fopen("/dev/urandom", "r");
|
||||
if (fp == nullptr) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace esphome::host {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static const char *const TAG = "host.preferences";
|
||||
static const char *const TAG = "preferences";
|
||||
|
||||
void HostPreferences::setup_() {
|
||||
if (this->setup_complete_)
|
||||
|
||||
@@ -128,6 +128,7 @@ SCAN_WIRINGS = {
|
||||
"STANDARD_TWO_SCAN": Hub75ScanWiring.STANDARD_TWO_SCAN,
|
||||
"SCAN_1_4_16PX_HIGH": Hub75ScanWiring.SCAN_1_4_16PX_HIGH,
|
||||
"SCAN_1_8_32PX_HIGH": Hub75ScanWiring.SCAN_1_8_32PX_HIGH,
|
||||
"SCAN_1_8_32PX_FULL": Hub75ScanWiring.SCAN_1_8_32PX_FULL,
|
||||
"SCAN_1_8_40PX_HIGH": Hub75ScanWiring.SCAN_1_8_40PX_HIGH,
|
||||
"SCAN_1_8_64PX_HIGH": Hub75ScanWiring.SCAN_1_8_64PX_HIGH,
|
||||
}
|
||||
|
||||
@@ -101,9 +101,13 @@ class InfraredTraits {
|
||||
bool get_supports_receiver() const { return this->supports_receiver_; }
|
||||
void set_supports_receiver(bool supports) { this->supports_receiver_ = supports; }
|
||||
|
||||
uint32_t get_receiver_frequency_hz() const { return this->receiver_frequency_hz_; }
|
||||
void set_receiver_frequency_hz(uint32_t freq) { this->receiver_frequency_hz_ = freq; }
|
||||
|
||||
protected:
|
||||
bool supports_transmitter_{false};
|
||||
bool supports_receiver_{false};
|
||||
uint32_t receiver_frequency_hz_{0}; // Demodulation frequency of the IR receiver in Hz (0 = unspecified)
|
||||
};
|
||||
|
||||
/// Infrared - Base class for infrared remote control implementations
|
||||
|
||||
@@ -229,7 +229,7 @@ void Inkplate::eink_off_() {
|
||||
this->oe_pin_->digital_write(false);
|
||||
this->gmod_pin_->digital_write(false);
|
||||
|
||||
GPIO.out &= ~(this->get_data_pin_mask_() | (1UL << this->cl_pin_->get_pin()) | (1UL << this->le_pin_->get_pin()));
|
||||
GPIO.out_w1tc = this->get_data_pin_mask_() | (1UL << this->cl_pin_->get_pin()) | (1UL << this->le_pin_->get_pin());
|
||||
this->ckv_pin_->digital_write(false);
|
||||
this->sph_pin_->digital_write(false);
|
||||
this->spv_pin_->digital_write(false);
|
||||
|
||||
@@ -4,6 +4,7 @@ from typing import Any
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import infrared, remote_receiver, remote_transmitter
|
||||
from esphome.components.const import CONF_RECEIVER_FREQUENCY
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_CARRIER_DUTY_PERCENT, CONF_FREQUENCY
|
||||
import esphome.final_validate as fv
|
||||
@@ -19,6 +20,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
infrared.infrared_schema(IrRfProxy).extend(
|
||||
{
|
||||
cv.Optional(CONF_FREQUENCY, default=0): cv.frequency,
|
||||
cv.Optional(CONF_RECEIVER_FREQUENCY): cv.frequency,
|
||||
cv.Optional(CONF_REMOTE_RECEIVER_ID): cv.use_id(
|
||||
remote_receiver.RemoteReceiverComponent
|
||||
),
|
||||
@@ -33,7 +35,14 @@ CONFIG_SCHEMA = cv.All(
|
||||
|
||||
def _final_validate(config: dict[str, Any]) -> None:
|
||||
"""Validate that transmitters have a proper carrier duty cycle."""
|
||||
# Only validate if this is an infrared (not RF) configuration with a transmitter
|
||||
# receiver_frequency is only meaningful for receiver configurations
|
||||
if CONF_RECEIVER_FREQUENCY in config and CONF_REMOTE_RECEIVER_ID not in config:
|
||||
raise cv.Invalid(
|
||||
f"'{CONF_RECEIVER_FREQUENCY}' can only be used with '{CONF_REMOTE_RECEIVER_ID}', "
|
||||
"not with a transmitter"
|
||||
)
|
||||
|
||||
# Only validate duty cycle if this is an infrared (not RF) configuration with a transmitter
|
||||
if config.get(CONF_FREQUENCY, 0) != 0 or CONF_REMOTE_TRANSMITTER_ID not in config:
|
||||
return
|
||||
|
||||
@@ -75,3 +84,7 @@ async def to_code(config: dict[str, Any]) -> None:
|
||||
if CONF_REMOTE_RECEIVER_ID in config:
|
||||
receiver = await cg.get_variable(config[CONF_REMOTE_RECEIVER_ID])
|
||||
cg.add(var.set_receiver(receiver))
|
||||
|
||||
# Set receiver demodulation frequency if specified (metadata only, no hardware effect)
|
||||
if CONF_RECEIVER_FREQUENCY in config:
|
||||
cg.add(var.set_receiver_frequency(config[CONF_RECEIVER_FREQUENCY]))
|
||||
|
||||
@@ -22,6 +22,9 @@ class IrRfProxy : public infrared::Infrared {
|
||||
/// Check if this is RF mode (non-zero frequency)
|
||||
bool is_rf() const { return this->frequency_khz_ > 0; }
|
||||
|
||||
/// Set the receiver's hardware demodulation frequency in Hz (metadata only, does not affect hardware)
|
||||
void set_receiver_frequency(uint32_t frequency_hz) { this->get_traits().set_receiver_frequency_hz(frequency_hz); }
|
||||
|
||||
protected:
|
||||
// RF frequency in kHz (Hz / 1000); 0 = infrared, non-zero = RF
|
||||
uint32_t frequency_khz_{0};
|
||||
|
||||
@@ -530,10 +530,11 @@ void LD2450Component::handle_periodic_data_() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Store target info for zone target count
|
||||
this->target_info_[index].x = tx;
|
||||
this->target_info_[index].y = ty;
|
||||
this->target_info_[index].is_moving = is_moving;
|
||||
// Store target info for zone target count. Zero out untracked targets (td==0)
|
||||
// so stale coordinates don't produce ghost counts in count_targets_in_zone_().
|
||||
this->target_info_[index].x = (td > 0) ? tx : 0;
|
||||
this->target_info_[index].y = (td > 0) ? ty : 0;
|
||||
this->target_info_[index].is_moving = (td > 0) && is_moving;
|
||||
|
||||
} // End loop thru targets
|
||||
|
||||
|
||||
@@ -193,7 +193,9 @@ void LEDCOutput::setup() {
|
||||
chan_conf.gpio_num = static_cast<gpio_num_t>(this->pin_->get_pin());
|
||||
chan_conf.speed_mode = speed_mode;
|
||||
chan_conf.channel = chan_num;
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(6, 0, 0)
|
||||
chan_conf.intr_type = LEDC_INTR_DISABLE;
|
||||
#endif
|
||||
chan_conf.timer_sel = timer_num;
|
||||
chan_conf.duty = this->inverted_ == this->pin_->is_inverted() ? 0 : (1U << this->bit_depth_);
|
||||
chan_conf.hpoint = hpoint;
|
||||
|
||||
@@ -14,7 +14,6 @@ class LibreTinyComponent:
|
||||
supports_atomics: bool = False # True for Cortex-M4(F) with LDREX/STREX
|
||||
|
||||
|
||||
CONF_LIBRETINY = "libretiny"
|
||||
CONF_LOGLEVEL = "loglevel"
|
||||
CONF_SDK_SILENT = "sdk_silent"
|
||||
CONF_GPIO_RECOVER = "gpio_recover"
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
namespace esphome {
|
||||
|
||||
uint32_t random_uint32() { return rand(); }
|
||||
|
||||
bool random_bytes(uint8_t *data, size_t len) {
|
||||
lt_rand_bytes(data, len);
|
||||
return true;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace esphome::libretiny {
|
||||
|
||||
static const char *const TAG = "lt.preferences";
|
||||
static const char *const TAG = "preferences";
|
||||
|
||||
// Buffer size for converting uint32_t to string: max "4294967295" (10 chars) + null terminator + 1 padding
|
||||
static constexpr size_t KEY_BUFFER_SIZE = 12;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import text_sensor
|
||||
from esphome.components.const import CONF_LIBRETINY
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_VERSION,
|
||||
@@ -7,7 +8,7 @@ from esphome.const import (
|
||||
ICON_CELLPHONE_ARROW_DOWN,
|
||||
)
|
||||
|
||||
from .const import CONF_LIBRETINY, LTComponent
|
||||
from .const import LTComponent
|
||||
|
||||
DEPENDENCIES = ["libretiny"]
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ from esphome.const import (
|
||||
CONF_WEB_SERVER,
|
||||
CONF_WHITE,
|
||||
)
|
||||
from esphome.core import CORE, ID, CoroPriority, HexInt, coroutine_with_priority
|
||||
from esphome.core import CORE, ID, CoroPriority, HexInt, Lambda, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
|
||||
@@ -81,18 +81,32 @@ def _get_data() -> LightData:
|
||||
return CORE.data[DOMAIN]
|
||||
|
||||
|
||||
def generate_gamma_table(gamma_correct: float) -> list[HexInt]:
|
||||
"""Generate a 256-entry uint16 gamma lookup table.
|
||||
|
||||
For gamma > 0, non-zero indices are clamped to a minimum of 1 to preserve
|
||||
the invariant that non-zero input always produces non-zero output. Without
|
||||
this, small brightness values (e.g. 1%) get quantized to exactly 0.0,
|
||||
which breaks zero_means_zero logic in FloatOutput.
|
||||
"""
|
||||
if gamma_correct > 0:
|
||||
return [
|
||||
HexInt(
|
||||
max(1, min(65535, int(round((i / 255.0) ** gamma_correct * 65535))))
|
||||
if i > 0
|
||||
else HexInt(0)
|
||||
)
|
||||
for i in range(256)
|
||||
]
|
||||
return [HexInt(int(round(i / 255.0 * 65535))) for i in range(256)]
|
||||
|
||||
|
||||
def _get_or_create_gamma_table(gamma_correct):
|
||||
data = _get_data()
|
||||
if gamma_correct in data.gamma_tables:
|
||||
return data.gamma_tables[gamma_correct]
|
||||
|
||||
if gamma_correct > 0:
|
||||
forward = [
|
||||
HexInt(min(65535, int(round((i / 255.0) ** gamma_correct * 65535))))
|
||||
for i in range(256)
|
||||
]
|
||||
else:
|
||||
forward = [HexInt(int(round(i / 255.0 * 65535))) for i in range(256)]
|
||||
forward = generate_gamma_table(gamma_correct)
|
||||
|
||||
gamma_str = f"{gamma_correct}".replace(".", "_")
|
||||
fwd_id = ID(f"gamma_{gamma_str}_fwd", is_declaration=True, type=cg.uint16)
|
||||
@@ -248,6 +262,8 @@ async def setup_light_core_(light_var, config, output_var):
|
||||
cg.add(light_var.set_restore_mode(config[CONF_RESTORE_MODE]))
|
||||
|
||||
if (initial_state_config := config.get(CONF_INITIAL_STATE)) is not None:
|
||||
# Emit a stateless lambda that constructs the initial state — values live
|
||||
# in flash as code, not stored in the LightState object (~40 bytes saved).
|
||||
initial_state = LightStateRTCState(
|
||||
initial_state_config.get(CONF_COLOR_MODE, ColorMode.UNKNOWN),
|
||||
initial_state_config.get(CONF_STATE, False),
|
||||
@@ -261,7 +277,13 @@ async def setup_light_core_(light_var, config, output_var):
|
||||
initial_state_config.get(CONF_COLD_WHITE, 1.0),
|
||||
initial_state_config.get(CONF_WARM_WHITE, 1.0),
|
||||
)
|
||||
cg.add(light_var.set_initial_state(initial_state))
|
||||
args = [(LightStateRTCState.operator("ref"), "s")]
|
||||
lamb = await cg.process_lambda(
|
||||
Lambda(f"s = {initial_state};"),
|
||||
args,
|
||||
return_type=cg.void,
|
||||
)
|
||||
cg.add(light_var.set_initial_state(lamb))
|
||||
|
||||
if (
|
||||
default_transition_length := config.get(CONF_DEFAULT_TRANSITION_LENGTH)
|
||||
|
||||
@@ -62,9 +62,9 @@ static const LogString *color_mode_to_human(ColorMode color_mode) {
|
||||
}
|
||||
|
||||
// Helper to log percentage values
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
static void log_percent(const LogString *param, float value) {
|
||||
ESP_LOGD(TAG, " %s: %.0f%%", LOG_STR_ARG(param), value * 100.0f);
|
||||
ESP_LOGV(TAG, " %s: %.0f%%", LOG_STR_ARG(param), value * 100.0f);
|
||||
}
|
||||
#else
|
||||
#define log_percent(param, value)
|
||||
@@ -76,20 +76,20 @@ void LightCall::perform() {
|
||||
const bool publish = this->get_publish_();
|
||||
|
||||
if (publish) {
|
||||
ESP_LOGD(TAG, "'%s' Setting:", name);
|
||||
ESP_LOGV(TAG, "'%s' Setting:", name);
|
||||
|
||||
// Only print color mode when it's being changed
|
||||
ColorMode current_color_mode = this->parent_->remote_values.get_color_mode();
|
||||
ColorMode target_color_mode = this->has_color_mode() ? this->color_mode_ : current_color_mode;
|
||||
if (target_color_mode != current_color_mode) {
|
||||
ESP_LOGD(TAG, " Color mode: %s", LOG_STR_ARG(color_mode_to_human(v.get_color_mode())));
|
||||
ESP_LOGV(TAG, " Color mode: %s", LOG_STR_ARG(color_mode_to_human(v.get_color_mode())));
|
||||
}
|
||||
|
||||
// Only print state when it's being changed
|
||||
bool current_state = this->parent_->remote_values.is_on();
|
||||
bool target_state = this->has_state() ? this->state_ : current_state;
|
||||
if (target_state != current_state) {
|
||||
ESP_LOGD(TAG, " State: %s", ONOFF(v.is_on()));
|
||||
ESP_LOGV(TAG, " State: %s", ONOFF(v.is_on()));
|
||||
}
|
||||
|
||||
if (this->has_brightness()) {
|
||||
@@ -100,7 +100,7 @@ void LightCall::perform() {
|
||||
log_percent(LOG_STR("Color brightness"), v.get_color_brightness());
|
||||
}
|
||||
if (this->has_red() || this->has_green() || this->has_blue()) {
|
||||
ESP_LOGD(TAG, " Red: %.0f%%, Green: %.0f%%, Blue: %.0f%%", v.get_red() * 100.0f, v.get_green() * 100.0f,
|
||||
ESP_LOGV(TAG, " Red: %.0f%%, Green: %.0f%%, Blue: %.0f%%", v.get_red() * 100.0f, v.get_green() * 100.0f,
|
||||
v.get_blue() * 100.0f);
|
||||
}
|
||||
|
||||
@@ -108,11 +108,11 @@ void LightCall::perform() {
|
||||
log_percent(LOG_STR("White"), v.get_white());
|
||||
}
|
||||
if (this->has_color_temperature()) {
|
||||
ESP_LOGD(TAG, " Color temperature: %.1f mireds", v.get_color_temperature());
|
||||
ESP_LOGV(TAG, " Color temperature: %.1f mireds", v.get_color_temperature());
|
||||
}
|
||||
|
||||
if (this->has_cold_white() || this->has_warm_white()) {
|
||||
ESP_LOGD(TAG, " Cold white: %.0f%%, warm white: %.0f%%", v.get_cold_white() * 100.0f,
|
||||
ESP_LOGV(TAG, " Cold white: %.0f%%, warm white: %.0f%%", v.get_cold_white() * 100.0f,
|
||||
v.get_warm_white() * 100.0f);
|
||||
}
|
||||
}
|
||||
@@ -120,20 +120,20 @@ void LightCall::perform() {
|
||||
if (this->has_flash_()) {
|
||||
// FLASH
|
||||
if (publish) {
|
||||
ESP_LOGD(TAG, " Flash length: %.1fs", this->flash_length_ / 1e3f);
|
||||
ESP_LOGV(TAG, " Flash length: %.1fs", this->flash_length_ / 1e3f);
|
||||
}
|
||||
|
||||
this->parent_->start_flash_(v, this->flash_length_, publish);
|
||||
} else if (this->has_transition_()) {
|
||||
// TRANSITION
|
||||
if (publish) {
|
||||
ESP_LOGD(TAG, " Transition length: %.1fs", this->transition_length_ / 1e3f);
|
||||
ESP_LOGV(TAG, " Transition length: %.1fs", this->transition_length_ / 1e3f);
|
||||
}
|
||||
|
||||
// Special case: Transition and effect can be set when turning off
|
||||
if (this->has_effect_()) {
|
||||
if (publish) {
|
||||
ESP_LOGD(TAG, " Effect: 'None'");
|
||||
ESP_LOGV(TAG, " Effect: 'None'");
|
||||
}
|
||||
this->parent_->stop_effect_();
|
||||
}
|
||||
@@ -150,7 +150,7 @@ void LightCall::perform() {
|
||||
}
|
||||
|
||||
if (publish) {
|
||||
ESP_LOGD(TAG, " Effect: '%.*s'", (int) effect_s.size(), effect_s.c_str());
|
||||
ESP_LOGV(TAG, " Effect: '%.*s'", (int) effect_s.size(), effect_s.c_str());
|
||||
}
|
||||
|
||||
this->parent_->start_effect_(this->effect_);
|
||||
@@ -385,7 +385,7 @@ void LightCall::transform_parameters_() {
|
||||
!(this->color_mode_ & ColorCapability::WHITE) && //
|
||||
!(this->color_mode_ & ColorCapability::COLOR_TEMPERATURE) && //
|
||||
min_mireds > 0.0f && max_mireds > 0.0f) {
|
||||
ESP_LOGD(TAG, "'%s': setting cold/warm white channels using white/color temperature values",
|
||||
ESP_LOGV(TAG, "'%s': setting cold/warm white channels using white/color temperature values",
|
||||
this->parent_->get_name().c_str());
|
||||
// Only compute cold_white/warm_white from color_temperature if they're not already explicitly set.
|
||||
// This is important for state restoration, where both color_temperature and cold_white/warm_white
|
||||
@@ -432,7 +432,7 @@ ColorMode LightCall::compute_color_mode_() {
|
||||
|
||||
// Don't change if the current mode is in the intersection (suitable AND supported)
|
||||
if (ColorModeMask::mask_contains(intersection, current_mode)) {
|
||||
ESP_LOGI(TAG, "'%s': color mode not specified; retaining %s", this->parent_->get_name().c_str(),
|
||||
ESP_LOGV(TAG, "'%s': color mode not specified; retaining %s", this->parent_->get_name().c_str(),
|
||||
LOG_STR_ARG(color_mode_to_human(current_mode)));
|
||||
return current_mode;
|
||||
}
|
||||
@@ -440,7 +440,7 @@ ColorMode LightCall::compute_color_mode_() {
|
||||
// Use the preferred suitable mode.
|
||||
if (intersection != 0) {
|
||||
ColorMode mode = ColorModeMask::first_value_from_mask(intersection);
|
||||
ESP_LOGI(TAG, "'%s': color mode not specified; using %s", this->parent_->get_name().c_str(),
|
||||
ESP_LOGV(TAG, "'%s': color mode not specified; using %s", this->parent_->get_name().c_str(),
|
||||
LOG_STR_ARG(color_mode_to_human(mode)));
|
||||
return mode;
|
||||
}
|
||||
|
||||
@@ -154,6 +154,16 @@ class LightColorValues {
|
||||
}
|
||||
|
||||
/// Convert these light color values to an CWWW representation with the given parameters.
|
||||
///
|
||||
/// Note on gamma and constant_brightness: This method operates on the raw/internal channel
|
||||
/// values stored in this object. For cold_white_ and warm_white_ specifically, these
|
||||
/// may already be gamma-uncorrected when derived from a color_temperature value.
|
||||
/// For constant_brightness=false, additional gamma for the output can be applied after
|
||||
/// this method since gamma commutes with simple multiplication. For constant_brightness=true,
|
||||
/// the caller (LightState::current_values_as_cwww) must apply gamma to the individual
|
||||
/// channel values BEFORE the balancing formula, because the nonlinear max/sum ratio does
|
||||
/// not commute with gamma. See LightState::current_values_as_cwww() for the correct
|
||||
/// implementation.
|
||||
void as_cwww(float *cold_white, float *warm_white, bool constant_brightness = false) const {
|
||||
if (this->color_mode_ & ColorCapability::COLD_WARM_WHITE) {
|
||||
const float cw_level = this->cold_white_;
|
||||
|
||||
@@ -37,8 +37,9 @@ void LightState::setup() {
|
||||
|
||||
auto call = this->make_call();
|
||||
LightStateRTCState recovered{};
|
||||
if (this->initial_state_.has_value()) {
|
||||
recovered = *this->initial_state_;
|
||||
if (this->initial_state_callback_) {
|
||||
this->initial_state_callback_(recovered);
|
||||
this->initial_state_callback_ = nullptr; // One-shot — no longer needed
|
||||
}
|
||||
switch (this->restore_mode_) {
|
||||
case LIGHT_RESTORE_DEFAULT_OFF:
|
||||
@@ -195,7 +196,7 @@ void LightState::set_flash_transition_length(uint32_t flash_transition_length) {
|
||||
uint32_t LightState::get_flash_transition_length() const { return this->flash_transition_length_; }
|
||||
void LightState::set_gamma_correct(float gamma_correct) { this->gamma_correct_ = gamma_correct; }
|
||||
void LightState::set_restore_mode(LightRestoreMode restore_mode) { this->restore_mode_ = restore_mode; }
|
||||
void LightState::set_initial_state(const LightStateRTCState &initial_state) { this->initial_state_ = initial_state; }
|
||||
void LightState::set_initial_state(void (*callback)(LightStateRTCState &)) { this->initial_state_callback_ = callback; }
|
||||
bool LightState::supports_effects() { return !this->effects_.empty(); }
|
||||
const FixedVector<LightEffect *> &LightState::get_effects() const { return this->effects_; }
|
||||
void LightState::add_effects(const std::initializer_list<LightEffect *> &effects) {
|
||||
@@ -223,12 +224,11 @@ void LightState::current_values_as_rgbw(float *red, float *green, float *blue, f
|
||||
}
|
||||
void LightState::current_values_as_rgbww(float *red, float *green, float *blue, float *cold_white, float *warm_white,
|
||||
bool constant_brightness) {
|
||||
this->current_values.as_rgbww(red, green, blue, cold_white, warm_white, constant_brightness);
|
||||
this->current_values.as_rgb(red, green, blue);
|
||||
*red = this->gamma_correct_lut(*red);
|
||||
*green = this->gamma_correct_lut(*green);
|
||||
*blue = this->gamma_correct_lut(*blue);
|
||||
*cold_white = this->gamma_correct_lut(*cold_white);
|
||||
*warm_white = this->gamma_correct_lut(*warm_white);
|
||||
this->current_values_as_cwww(cold_white, warm_white, constant_brightness);
|
||||
}
|
||||
void LightState::current_values_as_rgbct(float *red, float *green, float *blue, float *color_temperature,
|
||||
float *white_brightness) {
|
||||
@@ -241,9 +241,45 @@ void LightState::current_values_as_rgbct(float *red, float *green, float *blue,
|
||||
*white_brightness = this->gamma_correct_lut(*white_brightness);
|
||||
}
|
||||
void LightState::current_values_as_cwww(float *cold_white, float *warm_white, bool constant_brightness) {
|
||||
this->current_values.as_cwww(cold_white, warm_white, constant_brightness);
|
||||
*cold_white = this->gamma_correct_lut(*cold_white);
|
||||
*warm_white = this->gamma_correct_lut(*warm_white);
|
||||
if (!constant_brightness) {
|
||||
// Without constant_brightness, gamma commutes with simple multiplication:
|
||||
// gamma(white_level * cw) = gamma(white_level) * gamma(cw)
|
||||
// (since gamma(a*b) = (a*b)^g = a^g * b^g = gamma(a) * gamma(b))
|
||||
// so applying gamma after is mathematically equivalent and simpler.
|
||||
this->current_values.as_cwww(cold_white, warm_white, false);
|
||||
*cold_white = this->gamma_correct_lut(*cold_white);
|
||||
*warm_white = this->gamma_correct_lut(*warm_white);
|
||||
return;
|
||||
}
|
||||
|
||||
// For constant_brightness mode, gamma MUST be applied to the individual
|
||||
// channel values BEFORE the balancing formula (max/sum ratio), not after.
|
||||
//
|
||||
// Why: The cold_white_ and warm_white_ values stored in LightColorValues
|
||||
// are gamma-uncorrected (see transform_parameters_() which applies
|
||||
// gamma_uncorrect to the linear CW/WW fractions derived from color
|
||||
// temperature). Applying gamma_correct here recovers the original linear
|
||||
// fractions, which the constant_brightness formula then uses to distribute
|
||||
// power evenly. The max/sum formula ensures cold+warm PWM output sums to
|
||||
// a constant, keeping total power (and perceived brightness) the same
|
||||
// across all color temperatures.
|
||||
//
|
||||
// Applying gamma AFTER the formula would be incorrect because gamma is
|
||||
// nonlinear: gamma(a/b) != gamma(a)/gamma(b), so the carefully balanced
|
||||
// ratio would be distorted, causing a severe brightness dip at mid-range
|
||||
// color temperatures.
|
||||
const auto &v = this->current_values;
|
||||
if (!(v.get_color_mode() & ColorCapability::COLD_WARM_WHITE)) {
|
||||
*cold_white = *warm_white = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const float cw_level = this->gamma_correct_lut(v.get_cold_white());
|
||||
const float ww_level = this->gamma_correct_lut(v.get_warm_white());
|
||||
const float white_level = this->gamma_correct_lut(v.get_state() * v.get_brightness());
|
||||
const float sum = cw_level > 0 || ww_level > 0 ? cw_level + ww_level : 1; // Don't divide by zero.
|
||||
*cold_white = white_level * std::max(cw_level, ww_level) * cw_level / sum;
|
||||
*warm_white = white_level * std::max(cw_level, ww_level) * ww_level / sum;
|
||||
}
|
||||
void LightState::current_values_as_ct(float *color_temperature, float *white_brightness) {
|
||||
auto traits = this->get_traits();
|
||||
|
||||
@@ -188,8 +188,9 @@ class LightState : public EntityBase, public Component {
|
||||
/// Set the restore mode of this light
|
||||
void set_restore_mode(LightRestoreMode restore_mode);
|
||||
|
||||
/// Set the initial state of this light
|
||||
void set_initial_state(const LightStateRTCState &initial_state);
|
||||
/// Set a callback to populate the initial state defaults during setup.
|
||||
/// The callback is called once, then cleared. Values live in flash as code.
|
||||
void set_initial_state(void (*callback)(LightStateRTCState &));
|
||||
|
||||
/// Return whether the light has any effects that meet the trait requirements.
|
||||
bool supports_effects();
|
||||
@@ -322,22 +323,6 @@ class LightState : public EntityBase, public Component {
|
||||
FixedVector<LightEffect *> effects_;
|
||||
/// Object used to store the persisted values of the light.
|
||||
ESPPreferenceObject rtc_;
|
||||
/// Value for storing the index of the currently active effect. 0 if no effect is active
|
||||
uint32_t active_effect_index_{};
|
||||
/// Default transition length for all transitions in ms.
|
||||
uint32_t default_transition_length_{};
|
||||
/// Transition length to use for flash transitions.
|
||||
uint32_t flash_transition_length_{};
|
||||
/// Gamma correction factor for the light.
|
||||
float gamma_correct_{};
|
||||
#ifdef USE_LIGHT_GAMMA_LUT
|
||||
const uint16_t *gamma_table_{nullptr};
|
||||
#endif // USE_LIGHT_GAMMA_LUT
|
||||
|
||||
/// Whether the light value should be written in the next cycle.
|
||||
bool next_write_{true};
|
||||
// for effects, true if a transformer (transition) is active.
|
||||
bool is_transformer_active_ = false;
|
||||
|
||||
/** Listeners for remote values changes.
|
||||
*
|
||||
@@ -358,9 +343,26 @@ class LightState : public EntityBase, public Component {
|
||||
*/
|
||||
std::unique_ptr<std::vector<LightTargetStateReachedListener *>> target_state_reached_listeners_;
|
||||
|
||||
/// Initial state of the light.
|
||||
optional<LightStateRTCState> initial_state_{};
|
||||
/// Callback to populate initial state defaults — called once during setup, then cleared.
|
||||
/// Values live in flash as function body; no per-instance data storage beyond this pointer.
|
||||
void (*initial_state_callback_)(LightStateRTCState &){nullptr};
|
||||
|
||||
/// Value for storing the index of the currently active effect. 0 if no effect is active
|
||||
uint32_t active_effect_index_{};
|
||||
/// Default transition length for all transitions in ms.
|
||||
uint32_t default_transition_length_{};
|
||||
/// Transition length to use for flash transitions.
|
||||
uint32_t flash_transition_length_{};
|
||||
/// Gamma correction factor for the light.
|
||||
float gamma_correct_{};
|
||||
#ifdef USE_LIGHT_GAMMA_LUT
|
||||
const uint16_t *gamma_table_{nullptr};
|
||||
#endif // USE_LIGHT_GAMMA_LUT
|
||||
|
||||
/// Whether the light value should be written in the next cycle.
|
||||
bool next_write_{true};
|
||||
// for effects, true if a transformer (transition) is active.
|
||||
bool is_transformer_active_{false};
|
||||
/// Restore mode of the light.
|
||||
LightRestoreMode restore_mode_;
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ class LightTransitionTransformer : public LightTransformer {
|
||||
}
|
||||
|
||||
// When changing color mode, go through off state, as color modes are orthogonal and there can't be two active.
|
||||
if (this->start_values_.get_color_mode() != this->target_values_.get_color_mode()) {
|
||||
if (this->start_values_.get_color_mode() != this->end_values_.get_color_mode()) {
|
||||
this->changing_color_mode_ = true;
|
||||
this->intermediate_values_ = this->start_values_;
|
||||
this->intermediate_values_.set_state(false);
|
||||
@@ -39,8 +39,8 @@ class LightTransitionTransformer : public LightTransformer {
|
||||
|
||||
// Halfway through, when intermediate state (off) is reached, flip it to the target, but remain off.
|
||||
if (this->changing_color_mode_ && p > 0.5f &&
|
||||
this->intermediate_values_.get_color_mode() != this->target_values_.get_color_mode()) {
|
||||
this->intermediate_values_ = this->target_values_;
|
||||
this->intermediate_values_.get_color_mode() != this->end_values_.get_color_mode()) {
|
||||
this->intermediate_values_ = this->end_values_;
|
||||
this->intermediate_values_.set_state(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,13 +51,16 @@ template<typename... Ts> class LockCondition : public Condition<Ts...> {
|
||||
|
||||
template<LockState State> class LockStateTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit LockStateTrigger(Lock *a_lock) {
|
||||
a_lock->add_on_state_callback([this, a_lock]() {
|
||||
if (a_lock->state == State) {
|
||||
explicit LockStateTrigger(Lock *a_lock) : lock_(a_lock) {
|
||||
a_lock->add_on_state_callback([this]() {
|
||||
if (this->lock_->state == State) {
|
||||
this->trigger();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
Lock *lock_;
|
||||
};
|
||||
|
||||
using LockLockTrigger = LockStateTrigger<LockState::LOCK_STATE_LOCKED>;
|
||||
|
||||
@@ -41,7 +41,7 @@ void Lock::publish_state(LockState state) {
|
||||
|
||||
this->state = state;
|
||||
this->rtc_.save(&this->state);
|
||||
ESP_LOGD(TAG, "'%s' >> %s", this->name_.c_str(), LOG_STR_ARG(lock_state_to_string(state)));
|
||||
ESP_LOGV(TAG, "'%s' >> %s", this->name_.c_str(), LOG_STR_ARG(lock_state_to_string(state)));
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_LOCK) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_lock_update(this);
|
||||
@@ -49,10 +49,10 @@ void Lock::publish_state(LockState state) {
|
||||
}
|
||||
|
||||
void LockCall::perform() {
|
||||
ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
this->validate_();
|
||||
if (this->state_.has_value()) {
|
||||
ESP_LOGD(TAG, " State: %s", LOG_STR_ARG(lock_state_to_string(*this->state_)));
|
||||
ESP_LOGV(TAG, " State: %s", LOG_STR_ARG(lock_state_to_string(*this->state_)));
|
||||
}
|
||||
this->parent_->control(*this);
|
||||
}
|
||||
|
||||
@@ -331,11 +331,21 @@ async def to_code(config: ConfigType) -> None:
|
||||
CORE.data.setdefault(CONF_LOGGER, {})[CONF_LEVEL] = level
|
||||
tx_buffer_size = config[CONF_TX_BUFFER_SIZE]
|
||||
cg.add_define("ESPHOME_LOGGER_TX_BUFFER_SIZE", tx_buffer_size)
|
||||
# Determine task log buffer size. The buffer is a direct member of Logger
|
||||
# (no separate heap allocation).
|
||||
task_log_buffer_size = 0
|
||||
if CORE.is_esp32 or CORE.is_libretiny or CORE.is_nrf52:
|
||||
task_log_buffer_size = config[CONF_TASK_LOG_BUFFER_SIZE]
|
||||
elif CORE.is_host:
|
||||
task_log_buffer_size = 64 # Fixed 64 slots for host
|
||||
if task_log_buffer_size > 0:
|
||||
cg.add_define("USE_ESPHOME_TASK_LOG_BUFFER")
|
||||
cg.add_define("ESPHOME_TASK_LOG_BUFFER_SIZE", task_log_buffer_size)
|
||||
log = cg.new_Pvariable(
|
||||
config[CONF_ID],
|
||||
baud_rate,
|
||||
)
|
||||
if CORE.is_esp32:
|
||||
if CORE.is_esp32 or CORE.is_host:
|
||||
cg.add(log.create_pthread_key())
|
||||
# set_uart_selection() must be called before pre_setup() because
|
||||
# pre_setup() switches on uart_ to decide which hardware to initialize
|
||||
@@ -364,17 +374,10 @@ async def _late_logger_init(config: ConfigType) -> None:
|
||||
log = await cg.get_variable(config[CONF_ID])
|
||||
level = config[CONF_LEVEL]
|
||||
baud_rate: int = config[CONF_BAUD_RATE]
|
||||
if CORE.is_esp32 or CORE.is_libretiny or CORE.is_nrf52:
|
||||
task_log_buffer_size = config[CONF_TASK_LOG_BUFFER_SIZE]
|
||||
if CORE.using_zephyr:
|
||||
task_log_buffer_size = config.get(CONF_TASK_LOG_BUFFER_SIZE, 0)
|
||||
if task_log_buffer_size > 0:
|
||||
cg.add_define("USE_ESPHOME_TASK_LOG_BUFFER")
|
||||
cg.add(log.init_log_buffer(task_log_buffer_size))
|
||||
if CORE.using_zephyr:
|
||||
zephyr_add_prj_conf("MPSC_PBUF", True)
|
||||
elif CORE.is_host:
|
||||
cg.add(log.create_pthread_key())
|
||||
cg.add_define("USE_ESPHOME_TASK_LOG_BUFFER")
|
||||
cg.add(log.init_log_buffer(64)) # Fixed 64 slots for host
|
||||
zephyr_add_prj_conf("MPSC_PBUF", True)
|
||||
|
||||
# Enable runtime tag levels if logs are configured or explicitly enabled
|
||||
logs_config = config[CONF_LOGS]
|
||||
@@ -605,6 +608,7 @@ FILTER_SOURCE_FILES = filter_source_files_from_platform(
|
||||
PlatformFramework.RTL87XX_ARDUINO,
|
||||
PlatformFramework.LN882X_ARDUINO,
|
||||
},
|
||||
"task_log_buffer_zephyr.cpp": {PlatformFramework.NRF52_ZEPHYR},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
@@ -8,8 +9,8 @@ namespace esphome::logger {
|
||||
// Maximum header size: 35 bytes fixed + 32 bytes tag + 16 bytes thread name = 83 bytes (45 byte safety margin)
|
||||
static constexpr uint16_t MAX_HEADER_SIZE = 128;
|
||||
|
||||
// ANSI color code last digit (30-38 range, store only last digit to save RAM)
|
||||
static constexpr char LOG_LEVEL_COLOR_DIGIT[] = {
|
||||
// ANSI color code last digit (30-38 range, store only last digit to save RAM on ESP8266)
|
||||
static const char LOG_LEVEL_COLOR_DIGIT[] PROGMEM = {
|
||||
'\0', // NONE
|
||||
'1', // ERROR (31 = red)
|
||||
'3', // WARNING (33 = yellow)
|
||||
@@ -20,7 +21,7 @@ static constexpr char LOG_LEVEL_COLOR_DIGIT[] = {
|
||||
'8', // VERY_VERBOSE (38 = white)
|
||||
};
|
||||
|
||||
static constexpr char LOG_LEVEL_LETTER_CHARS[] = {
|
||||
static const char LOG_LEVEL_LETTER_CHARS[] PROGMEM = {
|
||||
'\0', // NONE
|
||||
'E', // ERROR
|
||||
'W', // WARNING
|
||||
@@ -64,7 +65,7 @@ struct LogBuffer {
|
||||
*p++ = 'V'; // VERY_VERBOSE = "VV"
|
||||
*p++ = 'V';
|
||||
} else {
|
||||
*p++ = LOG_LEVEL_LETTER_CHARS[level];
|
||||
*p++ = static_cast<char>(progmem_read_byte(reinterpret_cast<const uint8_t *>(&LOG_LEVEL_LETTER_CHARS[level])));
|
||||
}
|
||||
}
|
||||
*p++ = ']';
|
||||
@@ -184,7 +185,7 @@ struct LogBuffer {
|
||||
*p++ = (level == 1) ? '1' : '0'; // Only ERROR is bold
|
||||
*p++ = ';';
|
||||
*p++ = '3';
|
||||
*p++ = LOG_LEVEL_COLOR_DIGIT[level];
|
||||
*p++ = static_cast<char>(progmem_read_byte(reinterpret_cast<const uint8_t *>(&LOG_LEVEL_COLOR_DIGIT[level])));
|
||||
*p++ = 'm';
|
||||
}
|
||||
// Copy string without null terminator, updates pointer in place
|
||||
|
||||
@@ -83,7 +83,7 @@ void Logger::log_vprintf_non_main_thread_(uint8_t level, const char *tag, int li
|
||||
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
|
||||
// For non-main threads/tasks, queue the message for callbacks
|
||||
message_sent =
|
||||
this->log_buffer_->send_message_thread_safe(level, tag, static_cast<uint16_t>(line), thread_name, format, args);
|
||||
this->log_buffer_.send_message_thread_safe(level, tag, static_cast<uint16_t>(line), thread_name, format, args);
|
||||
if (message_sent) {
|
||||
// Enable logger loop to process the buffered message
|
||||
// This is safe to call from any context including ISRs
|
||||
@@ -161,20 +161,6 @@ Logger::Logger(uint32_t baud_rate) : baud_rate_(baud_rate) {
|
||||
this->main_thread_ = pthread_self();
|
||||
#endif
|
||||
}
|
||||
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
|
||||
void Logger::init_log_buffer(size_t total_buffer_size) {
|
||||
// Host uses slot count instead of byte size
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - allocated once, never freed
|
||||
this->log_buffer_ = new logger::TaskLogBuffer(total_buffer_size);
|
||||
|
||||
#if !(defined(USE_ZEPHYR) && defined(USE_LOGGER_UART_SELECTION_USB_CDC))
|
||||
// Start with loop disabled when using task buffer
|
||||
// The loop will be enabled automatically when messages arrive
|
||||
// Zephyr with USB CDC needs loop active to poll port readiness via cdc_loop_()
|
||||
this->disable_loop_when_buffer_empty_();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_ESPHOME_TASK_LOG_BUFFER) || (defined(USE_ZEPHYR) && defined(USE_LOGGER_UART_SELECTION_USB_CDC))
|
||||
void Logger::loop() {
|
||||
@@ -188,16 +174,16 @@ void Logger::loop() {
|
||||
void Logger::process_messages_() {
|
||||
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
|
||||
// Process any buffered messages when available
|
||||
if (this->log_buffer_->has_messages()) {
|
||||
if (this->log_buffer_.has_messages()) {
|
||||
logger::TaskLogBuffer::LogMessage *message;
|
||||
uint16_t text_length;
|
||||
while (this->log_buffer_->borrow_message_main_loop(message, text_length)) {
|
||||
while (this->log_buffer_.borrow_message_main_loop(message, text_length)) {
|
||||
const char *thread_name = message->thread_name[0] != '\0' ? message->thread_name : nullptr;
|
||||
LogBuffer buf{this->tx_buffer_, ESPHOME_LOGGER_TX_BUFFER_SIZE};
|
||||
this->format_buffered_message_and_notify_(message->level, message->tag, message->line, thread_name,
|
||||
message->text_data(), text_length, buf);
|
||||
// Release the message to allow other tasks to use it as soon as possible
|
||||
this->log_buffer_->release_message_main_loop();
|
||||
this->log_buffer_.release_message_main_loop();
|
||||
this->write_log_buffer_to_console_(buf);
|
||||
}
|
||||
}
|
||||
@@ -243,13 +229,11 @@ void Logger::dump_config() {
|
||||
this->baud_rate_, LOG_STR_ARG(get_uart_selection_()));
|
||||
#endif
|
||||
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
|
||||
if (this->log_buffer_) {
|
||||
#ifdef USE_HOST
|
||||
ESP_LOGCONFIG(TAG, " Task Log Buffer Slots: %u", static_cast<unsigned int>(this->log_buffer_->size()));
|
||||
ESP_LOGCONFIG(TAG, " Task Log Buffer Slots: %u", static_cast<unsigned int>(this->log_buffer_.size()));
|
||||
#else
|
||||
ESP_LOGCONFIG(TAG, " Task Log Buffer Size: %u bytes", static_cast<unsigned int>(this->log_buffer_->size()));
|
||||
ESP_LOGCONFIG(TAG, " Task Log Buffer Size: %u bytes", static_cast<unsigned int>(this->log_buffer_.size()));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LOGGER_RUNTIME_TAG_LEVELS
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user