Compare commits

..
1160 changed files with 3026 additions and 6500 deletions
+22 -24
View File
@@ -893,20 +893,14 @@ jobs:
matrix:
include:
- id: clang-tidy
name: Run script/clang-tidy for ESP32 IDF 1/5
options: --environment esp32-idf-tidy --split-num 5 --split-at 1
name: Run script/clang-tidy for ESP32 IDF 1/3
options: --environment esp32-idf-tidy --split-num 3 --split-at 1
- id: clang-tidy
name: Run script/clang-tidy for ESP32 IDF 2/5
options: --environment esp32-idf-tidy --split-num 5 --split-at 2
name: Run script/clang-tidy for ESP32 IDF 2/3
options: --environment esp32-idf-tidy --split-num 3 --split-at 2
- id: clang-tidy
name: Run script/clang-tidy for ESP32 IDF 3/5
options: --environment esp32-idf-tidy --split-num 5 --split-at 3
- id: clang-tidy
name: Run script/clang-tidy for ESP32 IDF 4/5
options: --environment esp32-idf-tidy --split-num 5 --split-at 4
- id: clang-tidy
name: Run script/clang-tidy for ESP32 IDF 5/5
options: --environment esp32-idf-tidy --split-num 5 --split-at 5
name: Run script/clang-tidy for ESP32 IDF 3/3
options: --environment esp32-idf-tidy --split-num 3 --split-at 3
steps:
- name: Check out code from GitHub
@@ -1422,27 +1416,31 @@ jobs:
echo "::warning::ci_memory_impact_extract.py not found on target branch, skipping memory impact analysis"
fi
# The build below uses --base-only, so skip unless the target branch has
# test.<platform>.yaml for every requested component (test-*.yaml
# variants alone compile nothing, and a partial set would compare a
# smaller target build against the PR build). Checked here, not in
# determine-jobs.py, because determine-jobs runs on the PR branch and
# cannot see the target branch.
# Check if test files exist on the target branch for the requested
# components and platform. When a PR adds new test files for a platform,
# the target branch won't have them yet, so skip instead of failing.
# This check must be done here (not in determine-jobs.py) because
# determine-jobs runs on the PR branch and cannot see what the target
# branch has.
- name: Check for test files on target branch
id: check-tests
if: steps.check-script.outputs.skip != 'true'
run: |
components='${{ toJSON(fromJSON(needs.determine-jobs.outputs.memory_impact).components) }}'
platform="${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}"
missing=""
found=false
for component in $(echo "$components" | jq -r '.[]'); do
if [ ! -f "tests/components/${component}/test.${platform}.yaml" ]; then
missing="${missing} ${component}"
fi
# Check for test files matching the platform (test.platform.yaml or test-*.platform.yaml)
for f in tests/components/${component}/test*.${platform}.yaml; do
if [ -f "$f" ]; then
found=true
break 2
fi
done
done
if [ -n "$missing" ]; then
if [ "$found" = false ]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "::warning::No test.${platform}.yaml on target branch for${missing}, skipping memory impact analysis"
echo "::warning::No test files found on target branch for platform ${platform}, skipping memory impact analysis"
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
-31
View File
@@ -177,13 +177,6 @@ file does, and it is the authority when they disagree. The most useful starting
Pick the primitive by cadence: under 250 ms use a gated `loop()`; 500 ms and above use
`set_interval`. Full reasoning, including why `set_interval` costs more below 500 ms:
https://developers.esphome.io/architecture/components/advanced/#quick-rule-of-thumb
* **Scheduler ids:** name a timer only when it must be cancelled or replaced, and use a
`static constexpr uint32_t` id, never a string. Ids are per component instance and cannot clash with other
components, so number them from 0 and keep all of a component's ids together in one place.
```cpp
static constexpr uint32_t READ_TIMEOUT_ID = 0;
this->set_timeout(READ_TIMEOUT_ID, 50, [this]() { this->read_(); });
```
* **Don't override a default with the same value:** if a base class method already returns what you
want, do not override it. `Component::get_setup_priority()` returns `setup_priority::DATA`, so a
component that wants `DATA` should simply leave it alone.
@@ -237,10 +230,6 @@ file does, and it is the authority when they disagree. The most useful starting
```
* **Component Metadata:**
- `DOMAIN`: Required in every component's `__init__.py`, set to the component's own name as a plain
string (e.g. `DOMAIN = "my_component"`). Other code refers to the component through it, e.g.
`from esphome.components.my_component import DOMAIN`. Keep it in alphabetical order with the other
metadata constants. CI (`lint_component_domain`) fails without it.
- `DEPENDENCIES`: List of required components
- `AUTO_LOAD`: Components to automatically load
- `CONFLICTS_WITH`: Incompatible components
@@ -254,7 +243,6 @@ file does, and it is the authority when they disagree. The most useful starting
import esphome.config_validation as cv
from esphome.const import CONF_KEY, CONF_ID
DOMAIN = "my_component"
CONF_PARAM = "param" # A constant that does not yet exist in esphome/const.py
my_component_ns = cg.esphome_ns.namespace("my_component")
@@ -396,25 +384,6 @@ file does, and it is the authority when they disagree. The most useful starting
)
```
When the callback's parameters differ from the automation's arguments, or the trigger should only
fire for some values, pass `params`, `forward` and `when`; the helper then generates a capture-less
lambda (stored inline, nothing allocated). Name the parent with `automation.parent_ref(var)` and build
`forward` from `MockObj` calls, not f-strings of C++:
```python
parent = automation.parent_ref(var)
index = cg.RawExpression("index")
await automation.build_callback_automation(
var,
"add_on_state_callback",
[(cg.StringRef, "x"), (cg.size_t, "i")],
conf,
params=[(cg.size_t, "index")],
forward=[cg.StringRef(parent.option_at(index)), index],
)
```
`build_parent_callback_automation`, `build_trigger_callback`, `build_callback_automations` and
`build_trigger_automations` cover the other shapes; see their docstrings in `esphome/automation.py`.
**C++ -- no trigger class needed.** The callback registration method must be templatized to accept both `std::function` and lightweight forwarder structs (which avoid heap allocation):
```cpp
class MyComponent : public Component {
-2
View File
@@ -188,7 +188,6 @@ esphome/components/esp32_rmt_led_strip/* @jesserockz
esphome/components/esp8266/* @esphome/core
esphome/components/esp_ldo/* @clydebarrow
esphome/components/espectre/* @francescopace
esphome/components/esphome/ota/* @esphome/core
esphome/components/espnow/* @jesserockz
esphome/components/espnow/packet_transport/* @EasilyBoredEngineer
esphome/components/ethernet_info/* @gtjadsonsantos
@@ -519,7 +518,6 @@ 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/spd2010/* @grischard
esphome/components/speaker/* @jesserockz @kahrendt
esphome/components/speaker/media_player/* @kahrendt @synesthesiam
esphome/components/speaker_source/* @kahrendt
+1 -1
View File
@@ -22,7 +22,7 @@ RUN \
-r /requirements.txt
# Install the ESPHome Device Builder dashboard.
RUN uv pip install --no-cache-dir esphome-device-builder==1.23.0
RUN uv pip install --no-cache-dir esphome-device-builder==1.22.0
RUN \
platformio settings set enable_telemetry No \
+3 -3
View File
@@ -49,9 +49,9 @@ class FrameworkRelease(NamedTuple):
# Arduino core version -> its build in esphome-libs/arduino-esp8266
FRAMEWORK_RELEASES: dict[Version, FrameworkRelease] = {
Version(3, 1, 2): FrameworkRelease(
"3.1.2-esphome.3",
"3af533a85163804e164500a5b254dc23b922080e25ecb7dc37b3dd8ac84651db",
37185650,
"3.1.2-esphome.2",
"9377d63f569c524823199b1897ed7fde2063e50e2676dd519a0d758ab73678f7",
37192128,
),
}
+89 -179
View File
@@ -1,4 +1,4 @@
from collections.abc import Callable, Sequence
from collections.abc import Callable
from dataclasses import dataclass, field
import logging
import string
@@ -23,7 +23,7 @@ from esphome.const import (
)
from esphome.core import CORE, ID, EsphomeError, HexInt, Lambda
from esphome.cpp_generator import (
Expression,
FlashStringLiteral,
LambdaExpression,
MockObj,
MockObjClass,
@@ -245,7 +245,9 @@ ApplyCondition = cg.esphome_ns.class_("ApplyCondition", Condition)
def flash_string(config: ConfigType, value: str) -> str:
"""Default renderer for ``std::string`` constants; copies the literal out of flash on ESP8266."""
return str(cg.progmem_string(value))
if CORE.is_esp8266:
return f"progmem_string({FlashStringLiteral(value)})"
return str(cg.safe_exp(value))
def literal_with_length(config: ConfigType, value: str) -> str:
@@ -257,24 +259,13 @@ def literal_with_length(config: ConfigType, value: str) -> str:
return f"{cg.safe_exp(value)}, {len(value.encode('utf-8'))}"
def string_ref_literal(config: ConfigType, value: str) -> str:
"""Renderer for a ``StringRef`` comparison: a flash literal on ESP8266, else ``StringRef(literal, length)``."""
if CORE.is_esp8266:
return str(cg.FlashStringLiteral(value))
return f"StringRef({literal_with_length(config, value)})"
def _names_parent(text: str) -> bool:
return any(f == "parent" for _, f, _, _ in string.Formatter().parse(text))
@dataclass(frozen=True)
class ApplyCall:
"""One statement from config keys, e.g. ``"set_range({}, {})"`` with ``((CONF_LOW, cg.float_), ...)``.
Each arg is ``(conf_key, type_)`` or ``(conf_key, type_, const_fn)``. A ``conf_key`` may be a
path into nested sections. ``target`` and a plain ``str`` ``type_`` (raw C++ type text) may
name the parent object as ``{parent}``. ``const_fn(config, value)`` renders a constant's argument text; a lambda or an
path into nested sections. A plain ``str`` ``type_`` is raw C++ type text and may use
``{parent}``. ``const_fn(config, value)`` renders a constant's argument text; a lambda or an
id bypasses it. The statement is skipped when none of its keys is set, always emitted when it
has no keys, and a partial set is a config error.
"""
@@ -286,13 +277,13 @@ class ApplyCall:
fields = [
f for _, f, _, _ in string.Formatter().parse(self.target) if f is not None
]
if any(f not in ("", "parent") for f in fields):
if any(fields):
raise ValueError(
f"apply target {self.target!r}: only {{}} and {{parent}} placeholders"
f"apply target {self.target!r}: only bare {{}} placeholders"
)
if (count := fields.count("")) != len(self.args):
if len(fields) != len(self.args):
raise ValueError(
f"apply target {self.target!r} has {count} "
f"apply target {self.target!r} has {len(fields)} "
f"placeholder(s) for {len(self.args)} config key(s)"
)
if any(len(arg) not in (2, 3) for arg in self.args):
@@ -300,12 +291,6 @@ class ApplyCall:
f"apply target {self.target!r}: each arg is (conf_key, type_[, const_fn])"
)
@property
def names_parent(self) -> bool:
return _names_parent(self.target) or any(
isinstance(arg[1], str) and _names_parent(arg[1]) for arg in self.args
)
@property
def members(self) -> list[tuple[Any, Any, Any]]:
"""Each arg as ``(conf_key, type_, const_fn or None)``."""
@@ -380,16 +365,9 @@ def _check_key_in_schema(
schema = schema.schema[markers[part]]
def parent_ref(var: MockObj) -> MockObj:
"""``var`` named from global scope, so a trigger argument cannot shadow it.
Also how a generated callback names its Automation.
"""
return MockObj(f"::{var}", "->")
async def _apply_parent(config: ConfigType, id_key: str = CONF_ID) -> str:
return str(parent_ref(await cg.get_variable(config[id_key])))
# Global-scope qualified so a trigger arg named like the id cannot shadow it.
return f"::{await cg.get_variable(config[id_key])}"
def _apply_lambda_args(args: TemplateArgsType) -> TemplateArgsType:
@@ -421,7 +399,7 @@ async def _render_values(
members: list[tuple[Any, Any, Any]],
values: list[Any],
config: ConfigType,
parent: str | None,
parent: str,
lambda_args: TemplateArgsType,
compare: bool = False,
) -> list[str]:
@@ -499,12 +477,12 @@ def register_apply_action(
statements: list[str] = []
for target, members in statements_spec:
values = _apply_values(config, members)
if not _apply_call_active(members, values):
if members and all(value is None for value in values):
continue
exprs = await _render_values(
name, target, members, values, config, parent, lambda_args
)
statements.append(f"{receiver}{target.format(*exprs, parent=parent)};")
statements.append(f"{receiver}{target.format(*exprs)};")
if call:
statements = [
f"auto apply_call = {parent}->{call}();",
@@ -518,27 +496,6 @@ def register_apply_action(
register_action(name, ApplyAction, schema, synchronous=True)(builder)
def _apply_call_active(members: list[tuple[Any, Any, Any]], values: list[Any]) -> bool:
"""An ``ApplyCall`` is emitted unless it has keys and none of them is set."""
return not members or any(value is not None for value in values)
async def _render_check(
name: str,
target: str,
members: list[tuple[Any, Any, Any]],
values: list[Any],
config: ConfigType,
parent: str | None,
lambda_args: TemplateArgsType,
) -> str:
"""Render a boolean check with ``values`` compared against config."""
exprs = await _render_values(
name, target, members, values, config, parent, lambda_args, compare=True
)
return target.format(*exprs, parent=parent)
def register_apply_condition(
name: str, schema: cv.Schema, check: str | ApplyCall, id_key: str = CONF_ID
) -> None:
@@ -564,16 +521,22 @@ def register_apply_condition(
) -> MockObj:
parent = await _apply_parent(config, id_key)
lambda_args = _apply_lambda_args(args)
values = _apply_values(config, members)
check = await _render_check(
name, call.target, members, values, config, parent, lambda_args
exprs = await _render_values(
name,
call.target,
members,
_apply_values(config, members),
config,
parent,
lambda_args,
compare=True,
)
return _apply_function(
condition_id,
cg.bool_,
template_arg,
lambda_args,
[f"return {parent}->{check};"],
[f"return {parent}->{call.target.format(*exprs)};"],
)
register_condition(name, ApplyCondition, schema)(builder)
@@ -709,20 +672,52 @@ XorCondition = cg.esphome_ns.class_("XorCondition", Condition)
@register_condition("and", AndCondition, validate_condition_list)
async def and_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(
condition_id, cg.TemplateArguments(len(conditions), *template_arg), conditions
)
@register_condition("or", OrCondition, validate_condition_list)
async def or_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(
condition_id, cg.TemplateArguments(len(conditions), *template_arg), conditions
)
@register_condition("all", AndCondition, validate_condition_list)
@register_condition("or", OrCondition, validate_condition_list)
async def all_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(
condition_id, cg.TemplateArguments(len(conditions), *template_arg), conditions
)
@register_condition("any", OrCondition, validate_condition_list)
@register_condition("xor", XorCondition, validate_condition_list)
async def condition_group_to_code(
async def any_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args)
# A group of one is that condition for and, or and xor; skip the wrapper.
if len(conditions) == 1:
return conditions[0]
return cg.new_Pvariable(
condition_id, cg.TemplateArguments(len(conditions), *template_arg), conditions
)
@@ -739,6 +734,19 @@ async def not_condition_to_code(
return cg.new_Pvariable(condition_id, template_arg, condition)
@register_condition("xor", XorCondition, validate_condition_list)
async def xor_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(
condition_id, cg.TemplateArguments(len(conditions), *template_arg), conditions
)
@register_condition("lambda", LambdaCondition, cv.returning_lambda)
async def lambda_condition_to_code(
config: ConfigType,
@@ -1048,67 +1056,15 @@ def has_non_synchronous_actions(actions: ConfigType) -> bool:
return False
async def _new_automation(
args: TemplateArgsType, config: ConfigType, *ctor_args: MockObj
) -> MockObj:
"""Create the Automation for ``config`` with its actions."""
templ = cg.TemplateArguments(*(arg[0] for arg in args))
obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ, *ctor_args)
actions = await build_action_list(config[CONF_THEN], templ, args)
cg.add(obj.add_actions(actions))
return obj
async def build_automation(
trigger: MockObj, args: TemplateArgsType, config: ConfigType
) -> MockObj:
return await _new_automation(args, config, trigger)
async def build_trigger_callback(
args: TemplateArgsType,
config: ConfigType,
params: TemplateArgsType,
forward: Sequence[str | Expression] | None = None,
when: str | ApplyCall | None = None,
parent: MockObj | None = None,
) -> LambdaExpression:
"""Build the Automation for ``config`` and return a stateless callback that triggers it.
``params`` are the parent callback's parameters, ``forward`` the expressions passed to
``trigger()`` (default: the parameter names; write the parent as ``parent_ref(var)``),
``when`` a filter the callback returns early on, skipped like any ``ApplyCall`` when none
of its keys is set. ``when`` may name ``parent`` as ``{parent}``, e.g.
``"{parent}->is_fully_open()"``.
"""
members: list[tuple[Any, Any, Any]] = []
if when is not None:
call = when if isinstance(when, ApplyCall) else ApplyCall(when)
members = call.members
if parent is None and call.names_parent:
raise ValueError(f"trigger filter {call.target!r} names {{parent}}")
obj = await _new_automation(args, config)
lambda_args = _apply_lambda_args(params)
statements: list[str] = []
if when is not None:
values = _apply_values(config, members)
if _apply_call_active(members, values):
check = await _render_check(
"trigger filter",
call.target,
members,
values,
config,
None if parent is None else str(parent_ref(parent)),
lambda_args,
)
statements.append(f"if (!({check}))\n return;")
if forward is None:
forward = [name for _, name in params]
statements.append(f"{parent_ref(obj)}->trigger({', '.join(map(str, forward))});")
return LambdaExpression(
["\n".join(statements)], lambda_args, capture="", return_type=cg.void
)
arg_types = [arg[0] for arg in args]
templ = cg.TemplateArguments(*arg_types)
obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ, trigger)
actions = await build_action_list(config[CONF_THEN], templ, args)
cg.add(obj.add_actions(actions))
return obj
async def build_callback_automation(
@@ -1117,9 +1073,6 @@ async def build_callback_automation(
args: TemplateArgsType,
config: ConfigType,
forwarder: MockObj | MockObjClass | None = None,
params: TemplateArgsType | None = None,
forward: Sequence[str | Expression] | None = None,
when: str | ApplyCall | None = None,
) -> None:
"""Build an Automation and register it as a callback on the parent.
@@ -1131,9 +1084,6 @@ async def build_callback_automation(
pointer-sized (single Automation* field) to fit inline in Callback::ctx_
and avoid heap allocation.
With ``params``, ``forward`` or ``when`` the callback is instead the stateless
lambda of ``build_trigger_callback``; ``forwarder`` cannot be combined with them.
:param parent: The component object (e.g., button, sensor).
:param callback_method: Name of the callback method (e.g., "add_on_press_callback").
:param args: Automation template args as list of (type, name) tuples.
@@ -1142,56 +1092,22 @@ async def build_callback_automation(
TriggerForwarder<Ts...>. Pass any struct type whose aggregate init takes
a single Automation pointer (e.g., TriggerOnTrueForwarder).
"""
if params is not None or forward is not None or when is not None:
if forwarder is not None:
raise ValueError(
"forwarder cannot be combined with params, forward or when"
)
callback = await build_trigger_callback(
args, config, args if params is None else params, forward, when, parent
)
cg.add(getattr(parent, callback_method)(callback))
return
obj = await _new_automation(args, config)
arg_types = [arg[0] for arg in args]
templ = cg.TemplateArguments(*arg_types)
obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ)
actions = await build_action_list(config[CONF_THEN], templ, args)
cg.add(obj.add_actions(actions))
# Use template forwarder structs for deduplication. The compiler generates
# one operator() per forwarder type; different automation pointers are just
# data in the struct.
if forwarder is None:
forwarder = TriggerForwarder.template(*(arg[0] for arg in args))
forwarder = TriggerForwarder.template(templ)
# RawExpression for aggregate init — both forwarder and obj are codegen
# MockObjs (not user input), and there's no Expression type for positional
# aggregate initialization (StructInitializer uses named fields).
cg.add(getattr(parent, callback_method)(cg.RawExpression(f"{forwarder}{{{obj}}}")))
async def build_parent_callback_automation(
parent: MockObj, callback_method: str, arg: tuple[Any, str], config: ConfigType
) -> None:
"""Register an Automation that receives ``parent`` from a callback that carries nothing.
``arg`` is the automation's ``(type, name)``, e.g. ``(Fan.operator("ptr"), "x")``.
"""
await build_callback_automation(
parent, callback_method, [arg], config, params=[], forward=[parent_ref(parent)]
)
async def build_trigger_automations(
parent: MockObj | None,
config: ConfigType,
entries: tuple[tuple[str, TemplateArgsType], ...],
) -> None:
"""Instantiate each entry's Trigger class, with ``parent`` when given, and build its automations.
``entries`` are ``(conf_key, args)`` pairs; the class comes from the entry's ``CONF_TRIGGER_ID``.
"""
ctor_args = () if parent is None else (parent,)
for conf_key, args in entries:
for conf in config.get(conf_key, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], *ctor_args)
await build_automation(trigger, args, conf)
@dataclass(frozen=True, slots=True)
class CallbackAutomation:
"""A single callback automation entry for build_callback_automations."""
@@ -1200,9 +1116,6 @@ class CallbackAutomation:
callback_method: str
args: TemplateArgsType = field(default_factory=list)
forwarder: MockObj | MockObjClass | None = None
params: TemplateArgsType | None = None
forward: Sequence[str | Expression] | None = None
when: str | ApplyCall | None = None
async def build_callback_automations(
@@ -1224,7 +1137,4 @@ async def build_callback_automations(
entry.args,
conf,
forwarder=entry.forwarder,
params=entry.params,
forward=entry.forward,
when=entry.when,
)
+15 -51
View File
@@ -237,35 +237,6 @@ def idf_macro_matches(idf_path: Path) -> bool:
return live == _EXPECTED_MACRO
def _cmake_args_for_write(minimal: bool) -> dict[str, str]:
"""The cg.add_cmake_arg() values for one project write.
The discovery (minimal) write lets every built-in component register so
the list it finds, cached per target, serves any exclusion set; the full
write drops the excluded names from that list and passes all of them to
IDF. Names outside the framework's components directory (managed
components) stay excluded on the discovery write too, since the list
only holds built-in ones. A checkout supplied through IDF_PATH caches
nothing, so its discovery keeps every exclusion.
"""
from esphome.espidf.toolchain import _esphome_manages_idf, _get_idf_path
args = dict(CORE.cmake_args)
if (
not minimal
or not _esphome_manages_idf()
or not (excluded := args.get("EXCLUDE_COMPONENTS"))
):
return args
root = _get_idf_path() / "components"
outside = [name for name in excluded.split(";") if not (root / name).is_dir()]
if outside:
args["EXCLUDE_COMPONENTS"] = ";".join(outside)
else:
del args["EXCLUDE_COMPONENTS"]
return args
def get_project_cmakelists(
minimal: bool = False, builtin_components: list[str] | None = None
) -> str:
@@ -329,10 +300,11 @@ def get_project_cmakelists(
# CMake variables registered via cg.add_cmake_arg(). Emitted before
# include(project.cmake) so values like EXCLUDE_COMPONENTS are already
# set when project.cmake seeds the component list.
# set when project.cmake seeds the component list, and on minimal
# (discovery) writes too so excluded components never register.
cmake_args = "\n".join(
f"set({name} {_cmake_quote(value)})"
for name, value in sorted(_cmake_args_for_write(minimal).items())
for name, value in sorted(CORE.cmake_args.items())
)
# Per-project list exposed as a CMake variable so converted PIO libs
@@ -355,10 +327,10 @@ def get_project_cmakelists(
# component's REQUIRES including real IDF components). Referenced by
# src/CMakeLists and by each converted PIO lib's CMakeLists. Skipped
# on minimal writes because project_description.json may be stale.
# Excluded components are dropped here as well: the discovery list
# (cached per target) still holds them, and requiring an excluded
# component pulls it back into the build (IDF requirement expansion
# overrides EXCLUDE_COMPONENTS).
# Excluded components are dropped here as well: a stale
# project_description.json from a build without exclusions may still
# list them, and requiring an excluded component pulls it back into
# the build (IDF requirement expansion overrides EXCLUDE_COMPONENTS).
# Derived from the EXCLUDE_COMPONENTS cmake arg emitted above so the
# two can never disagree within one generated file.
builtin_components_property = (
@@ -425,24 +397,15 @@ project({CORE.name})
# Emit per-memory-type JSON size data for ESPHome to read post-build.
# json2 stays small; raw dumps every symbol (~2s on a large map) and
# this command runs inside the link edge, blocking everything downstream.
# IDF's size target depends on the map, so ninja has to know the link
# writes it for size to build in the same run as all. IDF declares the
# map itself since espressif/esp-idf#19201 (and in cmakev2), and ninja
# rejects two rules for one output, so declare it here only when IDF has
# not. add_custom_command(OUTPUT) marks its outputs GENERATED.
get_source_file_property(esphome_map_declared
${{CMAKE_BINARY_DIR}}/${{CMAKE_PROJECT_NAME}}.map GENERATED)
if(esphome_map_declared)
set(esphome_map_byproducts)
else()
set(esphome_map_byproducts BYPRODUCTS ${{CMAKE_BINARY_DIR}}/${{CMAKE_PROJECT_NAME}}.map)
endif()
# The map is a BYPRODUCT so ninja knows the link writes it; IDF's size
# target depends on the map and can then be built in the same run as all.
# IDF's cmakev2 declares the map itself, so drop this line on that switch.
add_custom_command(
TARGET ${{CMAKE_PROJECT_NAME}}.elf POST_BUILD
COMMAND ${{PYTHON}} -m esp_idf_size {size_ng_flag} --format=json2
-o ${{CMAKE_BINARY_DIR}}/esp_idf_size.json
${{CMAKE_PROJECT_NAME}}.map
${{esphome_map_byproducts}}
BYPRODUCTS ${{CMAKE_BINARY_DIR}}/${{CMAKE_PROJECT_NAME}}.map
WORKING_DIRECTORY ${{CMAKE_BINARY_DIR}}
VERBATIM
)
@@ -591,9 +554,10 @@ def write_project(
)
# Snapshot the exclusion set so has_outdated_files() can trigger a
# reconfigure when it changes. The ESPHOME_PROJECT_BUILTIN_COMPONENTS
# property drops excluded names, so re-including one (e.g. a config
# gains mqtt) needs a reconfigure to rebuild it from the discovery list.
# discovery reconfigure when it changes. Excluded components never
# register in project_description.json, so re-including one (e.g. a
# config gains mqtt) requires a fresh discovery pass before the
# ESPHOME_PROJECT_BUILTIN_COMPONENTS property can list it.
write_file_if_changed(
CORE.relative_build_path("exclude_components.esphomeinternal"),
";".join(get_excluded_builtin_components()),
-2
View File
@@ -34,13 +34,11 @@ from esphome.cpp_generator import ( # noqa: F401
extern_progmem_array,
get_variable,
get_variable_with_full_id,
is_static_pointer,
is_template,
new_Pvariable,
new_variable,
process_lambda,
progmem_array,
progmem_string,
safe_exp,
set_cpp_standard,
shared_progmem_array,
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@MrSuicideParrot"]
DOMAIN = "a01nyub"
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@TH-Braemer"]
DOMAIN = "a02yyuw"
-1
View File
@@ -1 +0,0 @@
DOMAIN = "a4988"
@@ -1,2 +1 @@
CODEOWNERS = ["@DAVe3283"]
DOMAIN = "absolute_humidity"
-1
View File
@@ -1 +0,0 @@
DOMAIN = "ac_dimmer"
-1
View File
@@ -9,7 +9,6 @@ from esphome.cpp_generator import MockObj
from esphome.types import ConfigType
DEPENDENCIES = ["uart"]
DOMAIN = "adalight"
adalight_ns = cg.esphome_ns.namespace("adalight")
AdalightLightEffect = adalight_ns.class_(
-1
View File
@@ -22,7 +22,6 @@ from esphome.core import CORE
from esphome.types import ConfigType
CODEOWNERS = ["@esphome/core"]
DOMAIN = "adc"
adc_ns = cg.esphome_ns.namespace("adc")
@@ -5,7 +5,6 @@ from esphome.const import CONF_ID
from esphome.types import ConfigType
DEPENDENCIES = ["spi"]
DOMAIN = "adc128s102"
MULTI_CONF = True
CODEOWNERS = ["@DeerMaximum"]
@@ -1 +0,0 @@
DOMAIN = "addressable_light"
-1
View File
@@ -1 +0,0 @@
DOMAIN = "ade7880"
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@angelnu"]
DOMAIN = "ade7953"
@@ -27,7 +27,6 @@ from esphome.cpp_generator import MockObj
from esphome.types import ConfigType
CODEOWNERS = ["@angelnu"]
DOMAIN = "ade7953_base"
CONF_CURRENT_A = "current_a"
CONF_CURRENT_B = "current_b"
@@ -1,2 +1 @@
CODEOWNERS = ["@angelnu"]
DOMAIN = "ade7953_i2c"
@@ -1,2 +1 @@
CODEOWNERS = ["@angelnu"]
DOMAIN = "ade7953_spi"
-1
View File
@@ -5,7 +5,6 @@ from esphome.const import CONF_ID
from esphome.types import ConfigType
DEPENDENCIES = ["i2c"]
DOMAIN = "ads1115"
MULTI_CONF = True
ads1115_ns = cg.esphome_ns.namespace("ads1115")
-1
View File
@@ -6,7 +6,6 @@ from esphome.types import ConfigType
CODEOWNERS = ["@solomondg1"]
DEPENDENCIES = ["spi"]
DOMAIN = "ads1118"
MULTI_CONF = True
CONF_ADS1118_ID = "ads1118_id"
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@mak-42"]
DOMAIN = "ags10"
-1
View File
@@ -1 +0,0 @@
DOMAIN = "aht10"
-1
View File
@@ -1 +0,0 @@
DOMAIN = "aic3204"
@@ -6,7 +6,6 @@ from esphome.types import ConfigType
AUTO_LOAD = ["ble_device_base"]
CODEOWNERS = ["@jeromelaban"]
DOMAIN = "airthings_ble"
airthings_ble_ns = cg.esphome_ns.namespace("airthings_ble")
AirthingsListener = airthings_ble_ns.class_(
@@ -24,7 +24,6 @@ from esphome.cpp_generator import MockObj
from esphome.types import ConfigType
CODEOWNERS = ["@ncareau", "@jeromelaban"]
DOMAIN = "airthings_wave_base"
DEPENDENCIES = ["ble_client"]
@@ -10,9 +10,6 @@ namespace esphome::airthings_wave_base {
ESPHOME_LOG_TAG(TAG, "airthings_wave_base");
static constexpr uint32_t BATTERY_READ_TIMEOUT_ID = 0;
static constexpr uint32_t RESPONSE_TIMEOUT_ID = 1;
void AirthingsWaveBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) {
switch (event) {
@@ -184,7 +181,7 @@ void AirthingsWaveBase::read_battery_(uint8_t *raw_value, uint16_t value_len) {
// read the battery again at the configured update interval
if (this->battery_update_interval_ != this->update_interval_) {
this->read_battery_next_update_ = false;
this->set_timeout(BATTERY_READ_TIMEOUT_ID, this->battery_update_interval_,
this->set_timeout("battery", this->battery_update_interval_,
[this]() { this->read_battery_next_update_ = true; });
}
}
@@ -207,7 +204,7 @@ void AirthingsWaveBase::response_received_() {
}
void AirthingsWaveBase::set_response_timeout_() {
this->set_timeout(RESPONSE_TIMEOUT_ID, 30 * 1000, [this]() {
this->set_timeout("response_timeout", 30 * 1000, [this]() {
this->responses_pending_ = 1;
this->response_received_();
});
@@ -1,2 +1 @@
CODEOWNERS = ["@ncareau"]
DOMAIN = "airthings_wave_mini"
@@ -1,2 +1 @@
CODEOWNERS = ["@jeromelaban", "@precurse"]
DOMAIN = "airthings_wave_plus"
@@ -21,7 +21,6 @@ from esphome.core.entity_helpers import (
from esphome.cpp_generator import MockObjClass
CODEOWNERS = ["@grahambrown11", "@hwstar"]
DOMAIN = "alarm_control_panel"
IS_PLATFORM_COMPONENT = True
CONF_ON_TRIGGERED = "on_triggered"
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@jan-hofmeier"]
DOMAIN = "alpha3"
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@swoboda1337"]
DOMAIN = "am2315c"
-1
View File
@@ -1 +0,0 @@
DOMAIN = "am2320"
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@buxtronix"]
DOMAIN = "am43"
@@ -1,2 +1 @@
CODEOWNERS = ["@ianchi"]
DOMAIN = "analog_threshold"
-1
View File
@@ -1 +0,0 @@
DOMAIN = "anova"
-1
View File
@@ -2,4 +2,3 @@
# https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf
CODEOWNERS = ["@aodrenah"]
DOMAIN = "apds9306"
-1
View File
@@ -5,7 +5,6 @@ from esphome.const import CONF_ID
from esphome.types import ConfigType
DEPENDENCIES = ["i2c"]
DOMAIN = "apds9960"
MULTI_CONF = True
CONF_APDS9960_ID = "apds9960_id"
+1 -2
View File
@@ -8,7 +8,6 @@ from esphome.automation import Condition
import esphome.codegen as cg
from esphome.components.const import CONF_DESCRIPTION, CONF_HOST
from esphome.components.logger import request_log_listener
from esphome.components.network import DOMAIN as NETWORK_DOMAIN
# ENCRYPTION_SCHEMA and validate_encryption_key are re-exported for external
# components and downstream consumers that import them from api
@@ -515,7 +514,7 @@ def _validate_outgoing_host_ipv6(config: ConfigType) -> ConfigType:
or host.version != 6
):
return config
network_conf = fv.full_config.get().get(NETWORK_DOMAIN) or {}
network_conf = fv.full_config.get().get("network") or {}
if not network_conf.get(CONF_ENABLE_IPV6):
raise cv.Invalid(
"outgoing_connection host is an IPv6 address but IPv6 is not "
+1 -1
View File
@@ -760,7 +760,7 @@ message ListEntitiesLightResponse {
bool legacy_supports_color_temperature = 8 [deprecated=true];
float min_mireds = 9;
float max_mireds = 10;
repeated string effects = 11 [(container_pointer_no_template) = "light::LightEffectNames"];
repeated string effects = 11 [(container_pointer_no_template) = "FixedVector<const char *>"];
bool disabled_by_default = 13;
string icon = 14 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
EntityCategory entity_category = 15;
+10 -1
View File
@@ -644,7 +644,16 @@ uint16_t APIConnection::try_send_light_info(EntityBase *entity, APIConnection *c
msg.min_mireds = traits.get_min_mireds();
msg.max_mireds = traits.get_max_mireds();
}
light::LightEffectNames effects_list(light->get_effects());
FixedVector<const char *> effects_list;
if (light->supports_effects()) {
auto &light_effects = light->get_effects();
effects_list.init(light_effects.size() + 1);
effects_list.push_back("None");
for (auto *effect : light_effects) {
// c_str() is safe as effect names are null-terminated strings from codegen
effects_list.push_back(effect->get_name().c_str());
}
}
msg.effects = &effects_list;
return fill_and_encode_entity_info(light, msg, conn, remaining_size);
}
+4 -4
View File
@@ -688,8 +688,8 @@ uint8_t *ListEntitiesLightResponse::encode_msg(const void *self, uint8_t *__rest
if (uint32_t raw = float_to_raw(msg.max_mireds); raw != 0) [[likely]] {
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 85, raw);
}
for (const auto &it : *msg.effects) {
pos = ProtoEncode::encode_string_force(pos PROTO_ENCODE_DEBUG_ARG, 11, it);
for (const char *it : *msg.effects) {
pos = ProtoEncode::encode_string_force(pos PROTO_ENCODE_DEBUG_ARG, 11, it, strlen(it));
}
pos = ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 13, msg.disabled_by_default);
#ifdef USE_ENTITY_ICON
@@ -713,8 +713,8 @@ uint32_t ListEntitiesLightResponse::calc_size_msg(const void *self) {
size += ProtoSize::calc_float(1, msg.min_mireds);
size += ProtoSize::calc_float(1, msg.max_mireds);
if (!msg.effects->empty()) {
for (const auto &it : *msg.effects) {
size += ProtoSize::calc_length_force(1, it.size());
for (const char *it : *msg.effects) {
size += ProtoSize::calc_length_force(1, strlen(it));
}
}
size += ProtoSize::calc_bool(1, msg.disabled_by_default);
+1 -1
View File
@@ -1059,7 +1059,7 @@ class ListEntitiesLightResponse final : public InfoResponseProtoMessage {
const light::ColorModeMask *supported_color_modes{};
float min_mireds{0.0f};
float max_mireds{0.0f};
const light::LightEffectNames *effects{};
const FixedVector<const char *> *effects{};
static uint8_t *encode_msg(const void *self, uint8_t *pos PROTO_ENCODE_DEBUG_PARAM);
uint8_t *encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM) const {
return encode_msg(this, buffer.get_pos() PROTO_ENCODE_DEBUG_ARG);
@@ -15,7 +15,6 @@
#endif
#ifdef USE_LIGHT
#include "esphome/components/light/light_effect_names.h"
#include "esphome/components/light/light_traits.h"
#endif
+1 -2
View File
@@ -11,7 +11,6 @@ from typing import Any
from esphome import automation
import esphome.codegen as cg
from esphome.components.const import CONF_DESCRIPTION
from esphome.components.homeassistant import DOMAIN as HOMEASSISTANT_DOMAIN
import esphome.config_validation as cv
from esphome.const import (
CONF_DEVICE_CLASS,
@@ -266,7 +265,7 @@ def _validate_wizard_input(conf: ConfigType) -> ConfigType:
fv.full_config.get(), conf[CONF_ENTITY]
)
if (
declaration.get(CONF_PLATFORM) != HOMEASSISTANT_DOMAIN
declaration.get(CONF_PLATFORM) != "homeassistant"
or domain not in WIZARD_INPUT_DOMAINS
):
raise cv.Invalid(
-1
View File
@@ -1,7 +1,6 @@
import esphome.codegen as cg
CODEOWNERS = ["@jasstrong", "@ximex", "@freekode"]
DOMAIN = "aqi"
aqi_ns = cg.esphome_ns.namespace("aqi")
AQICalculatorType = aqi_ns.enum("AQICalculatorType")
+2 -4
View File
@@ -5,20 +5,18 @@ namespace esphome::aqi {
ESPHOME_LOG_TAG(TAG, "aqi");
static constexpr uint32_t CALCULATE_DEFER_ID = 0;
void AQISensor::setup() {
if (this->pm_2_5_sensor_ != nullptr) {
this->pm_2_5_sensor_->add_on_state_callback([this](float value) {
this->pm_2_5_value_ = value;
// Defer calculation to avoid double-publishing if both sensors update in the same loop
this->defer(CALCULATE_DEFER_ID, [this]() { this->calculate_aqi_(); });
this->defer("update", [this]() { this->calculate_aqi_(); });
});
}
if (this->pm_10_0_sensor_ != nullptr) {
this->pm_10_0_sensor_->add_on_state_callback([this](float value) {
this->pm_10_0_value_ = value;
this->defer(CALCULATE_DEFER_ID, [this]() { this->calculate_aqi_(); });
this->defer("update", [this]() { this->calculate_aqi_(); });
});
}
}
-1
View File
@@ -17,7 +17,6 @@ from esphome.const import (
from esphome.cpp_generator import MockObj
from esphome.types import ConfigType
DOMAIN = "as3935"
MULTI_CONF = True
CONF_AS3935_ID = "as3935_id"
@@ -6,7 +6,6 @@ from esphome.types import ConfigType
AUTO_LOAD = ["as3935"]
DEPENDENCIES = ["i2c"]
DOMAIN = "as3935_i2c"
as3935_i2c_ns = cg.esphome_ns.namespace("as3935_i2c")
I2CAS3935 = as3935_i2c_ns.class_("I2CAS3935Component", as3935.AS3935, i2c.I2CDevice)
@@ -6,7 +6,6 @@ from esphome.types import ConfigType
AUTO_LOAD = ["as3935"]
DEPENDENCIES = ["spi"]
DOMAIN = "as3935_spi"
as3935_spi_ns = cg.esphome_ns.namespace("as3935_spi")
SPIAS3935 = as3935_spi_ns.class_("SPIAS3935Component", as3935.AS3935, spi.SPIDevice)
-1
View File
@@ -18,7 +18,6 @@ from esphome.types import ConfigType
CODEOWNERS = ["@ammmze"]
DEPENDENCIES = ["i2c"]
DOMAIN = "as5600"
MULTI_CONF = True
as5600_ns = cg.esphome_ns.namespace("as5600")
-1
View File
@@ -1 +0,0 @@
DOMAIN = "as7341"
-1
View File
@@ -6,7 +6,6 @@ from esphome.types import ConfigType
CODEOWNERS = ["@esphome/core"]
DEPENDENCIES = ["network"]
DOMAIN = "async_tcp"
def AUTO_LOAD() -> list[str]:
-1
View File
@@ -8,7 +8,6 @@ from esphome.types import ConfigType
CODEOWNERS = ["@X-Ryl669"]
DEPENDENCIES = ["i2c"]
DOMAIN = "at581x"
MULTI_CONF = True
@@ -1 +0,0 @@
DOMAIN = "atc_mithermometer"
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@danieltwagner"]
DOMAIN = "atm90e26"
-1
View File
@@ -1,7 +1,6 @@
import esphome.codegen as cg
CODEOWNERS = ["@circuitsetup", "@descipher"]
DOMAIN = "atm90e32"
atm90e32_ns = cg.esphome_ns.namespace("atm90e32")
ATM90E32Component = atm90e32_ns.class_("ATM90E32Component", cg.Component)
-1
View File
@@ -6,7 +6,6 @@ from esphome.core import CoroPriority, coroutine_with_priority
from esphome.types import ConfigType
CODEOWNERS = ["@kbx81"]
DOMAIN = "audio_adc"
IS_PLATFORM_COMPONENT = True
audio_adc_ns = cg.esphome_ns.namespace("audio_adc")
-1
View File
@@ -7,7 +7,6 @@ from esphome.core import CoroPriority, coroutine_with_priority
from esphome.types import ConfigType
CODEOWNERS = ["@kbx81"]
DOMAIN = "audio_dac"
IS_PLATFORM_COMPONENT = True
audio_dac_ns = cg.esphome_ns.namespace("audio_dac")
@@ -1 +0,0 @@
DOMAIN = "audio_http"
-1
View File
@@ -2,6 +2,5 @@ import esphome.codegen as cg
CODEOWNERS = ["@clydebarrow"]
DEPENDENCIES = ["i2c"]
DOMAIN = "axs15231"
axs15231_ns = cg.esphome_ns.namespace("axs15231")
@@ -1 +0,0 @@
DOMAIN = "b_parasite"
-1
View File
@@ -1 +0,0 @@
DOMAIN = "ballu"
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@OttoWinter"]
DOMAIN = "bang_bang"
-1
View File
@@ -7,7 +7,6 @@ from esphome.types import ConfigType
CODEOWNERS = ["@jhansche"]
DEPENDENCIES = ["ble_client"]
DOMAIN = "bedjet"
MULTI_CONF = True
CONF_BEDJET_ID = "bedjet_id"
@@ -1 +0,0 @@
DOMAIN = "beken_spi_led_strip"
-1
View File
@@ -1 +0,0 @@
DOMAIN = "bh1750"
-1
View File
@@ -1 +0,0 @@
DOMAIN = "bh1900nux"
-2
View File
@@ -1,5 +1,3 @@
import esphome.codegen as cg
DOMAIN = "binary"
binary_ns = cg.esphome_ns.namespace("binary")
@@ -106,7 +106,6 @@ DEVICE_CLASSES = [
DEVICE_CLASS_VIBRATION,
DEVICE_CLASS_WINDOW,
]
DOMAIN = "binary_sensor"
IS_PLATFORM_COMPONENT = True
@@ -1 +0,0 @@
DOMAIN = "binary_sensor_map"
-1
View File
@@ -35,7 +35,6 @@ from .boards import BK72XX_BOARD_PINS, BK72XX_BOARDS
CODEOWNERS = ["@kuba2k2"]
AUTO_LOAD = ["libretiny"]
DOMAIN = "bk72xx"
IS_TARGET_PLATFORM = True
COMPONENT_DATA = LibreTinyComponent(
@@ -38,7 +38,6 @@ from esphome.types import ConfigType
DEPENDENCIES = ["bk72xx"]
CODEOWNERS = ["@Bl00d-B0b"]
DOMAIN = "bk72xx_ble"
_LOGGER = logging.getLogger(__name__)
@@ -44,7 +44,6 @@ CONF_BK72XX_BLE_ID = "bk72xx_ble_id"
DEPENDENCIES = ["bk72xx"]
AUTO_LOAD = ["ble_device_base", "bk72xx_ble"]
CODEOWNERS = ["@Bl00d-B0b"]
DOMAIN = "bk72xx_ble_tracker"
ble_device_base.register_hub_provider("bk72xx_ble_tracker")
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@athom-tech", "@tarontop", "@jesserockz"]
DOMAIN = "bl0906"
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@ziceva"]
DOMAIN = "bl0939"
-1
View File
@@ -1,7 +1,6 @@
import esphome.codegen as cg
CODEOWNERS = ["@tobias-", "@dan-s-github"]
DOMAIN = "bl0940"
CONF_BL0940_ID = "bl0940_id"
bl0940_ns = cg.esphome_ns.namespace("bl0940")
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@dbuezas", "@dwmw2"]
DOMAIN = "bl0942"
@@ -22,7 +22,6 @@ from esphome.types import ConfigType
AUTO_LOAD = ["esp32_ble_client"]
CODEOWNERS = ["@buxtronix", "@clydebarrow"]
DEPENDENCIES = ["esp32_ble_tracker"]
DOMAIN = "ble_client"
CONF_DESCRIPTOR_UUID = "descriptor_uuid"
CONF_ON_NOTIFY = "on_notify"
@@ -41,7 +41,6 @@ from esphome.core import CORE, ID, KEY_CORE, TimePeriod
from esphome.types import ConfigType
CODEOWNERS = ["@Bl00d-B0b"]
DOMAIN = "ble_device_base"
CONF_BLE_HUB_ID = "ble_hub_id"
-1
View File
@@ -21,7 +21,6 @@ from esphome.types import ConfigType
AUTO_LOAD = ["zephyr_ble_server", "uart"]
CODEOWNERS = ["@tomaszduda23"]
DOMAIN = "ble_nus"
ble_nus_ns = cg.esphome_ns.namespace("ble_nus")
BLENUS = ble_nus_ns.class_("BLENUS", cg.Component, UARTComponent)
@@ -1 +0,0 @@
DOMAIN = "ble_presence"
-1
View File
@@ -1 +0,0 @@
DOMAIN = "ble_rssi"
@@ -1 +0,0 @@
DOMAIN = "ble_scanner"
@@ -58,7 +58,6 @@ _HUB_PLATFORMS = (PLATFORM_BK72XX, PLATFORM_LN882X, PLATFORM_RP2)
DEPENDENCIES = ["api"]
CODEOWNERS = ["@jesserockz", "@bdraco"]
DOMAIN = "bluetooth_proxy"
_LOGGER = logging.getLogger(__name__)
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@abmantis"]
DOMAIN = "bm8563"
@@ -20,7 +20,6 @@ from esphome.cpp_generator import MockObj
from esphome.types import ConfigType
CODEOWNERS = ["@esphome/core"]
DOMAIN = "bme280_base"
bme280_ns = cg.esphome_ns.namespace("bme280_base")
BME280Oversampling = bme280_ns.enum("BME280Oversampling")
@@ -13,8 +13,6 @@ namespace esphome::bme280_base {
ESPHOME_LOG_TAG(TAG, "bme280.sensor");
static constexpr uint32_t DATA_TIMEOUT_ID = 0;
static const uint8_t BME280_REGISTER_DIG_T1 = 0x88;
static const uint8_t BME280_REGISTER_DIG_T2 = 0x8A;
static const uint8_t BME280_REGISTER_DIG_T3 = 0x8C;
@@ -223,7 +221,7 @@ void BME280Component::update() {
meas_time += 2.3f * oversampling_to_time(this->pressure_oversampling_) + 0.575f;
meas_time += 2.3f * oversampling_to_time(this->humidity_oversampling_) + 0.575f;
this->set_timeout(DATA_TIMEOUT_ID, uint32_t(ceilf(meas_time)), [this]() {
this->set_timeout("data", uint32_t(ceilf(meas_time)), [this]() {
uint8_t data[8];
if (!this->read_bytes(BME280_REGISTER_MEASUREMENTS, data, 8)) {
ESP_LOGW(TAG, "Error reading registers");
@@ -1 +0,0 @@
DOMAIN = "bme280_i2c"
@@ -1 +0,0 @@
DOMAIN = "bme280_spi"
-1
View File
@@ -1 +0,0 @@
DOMAIN = "bme680"
+1 -3
View File
@@ -6,8 +6,6 @@ namespace esphome::bme680 {
ESPHOME_LOG_TAG(TAG, "bme680.sensor");
static constexpr uint32_t DATA_TIMEOUT_ID = 0;
static const uint8_t BME680_REGISTER_COEFF1 = 0x89;
static const uint8_t BME680_REGISTER_COEFF2 = 0xE1;
@@ -244,7 +242,7 @@ void BME680Component::update() {
return;
}
this->set_timeout(DATA_TIMEOUT_ID, this->calc_meas_duration_(), [this]() { this->read_data_(); });
this->set_timeout("data", this->calc_meas_duration_(), [this]() { this->read_data_(); });
}
uint8_t BME680Component::calc_heater_resistance_(uint16_t temperature) {
@@ -9,7 +9,6 @@ CODEOWNERS = ["@trvrnrth"]
DEPENDENCIES = ["i2c"]
AUTO_LOAD = ["sensor", "text_sensor"]
CONFLICTS_WITH = ["bme68x_bsec2"]
DOMAIN = "bme680_bsec"
MULTI_CONF = True
CONF_BME680_BSEC_ID = "bme680_bsec_id"
@@ -7,8 +7,6 @@ namespace esphome::bme680_bsec {
#ifdef USE_BSEC
ESPHOME_LOG_TAG(TAG, "bme680_bsec.sensor");
static constexpr uint32_t READ_TIMEOUT_ID = 0;
static const std::string IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"};
std::vector<BME680BSECComponent *>
@@ -261,7 +259,7 @@ void BME680BSECComponent::run_() {
this->snapshot_state_();
ESP_LOGV(TAG, "Queueing read in %ums", meas_dur);
this->set_timeout(READ_TIMEOUT_ID, meas_dur, [this]() { this->read_(); });
this->set_timeout("read", meas_dur, [this]() { this->read_(); });
} else {
ESP_LOGV(TAG, "Measurement not required");
this->read_();
@@ -15,8 +15,6 @@ namespace esphome::bme68x_bsec2 {
ESPHOME_LOG_TAG(TAG, "bme68x_bsec2.sensor");
static constexpr uint32_t READ_TIMEOUT_ID = 0;
static constexpr const char *const IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"};
static bool is_no_new_data_warning(int8_t status) {
@@ -287,11 +285,11 @@ void BME68xBSEC2Component::run_() {
uint32_t meas_dur = bme68x_get_meas_dur(this->op_mode_, &bme68x_conf, &this->bme68x_);
ESP_LOGV(TAG, "Queueing read in %" PRIu32 "us", meas_dur);
this->trigger_time_ns_ = curr_time_ns;
this->set_timeout(READ_TIMEOUT_ID, meas_dur / 1000, [this]() { this->read_(this->trigger_time_ns_); });
this->set_timeout("read", meas_dur / 1000, [this]() { this->read_(this->trigger_time_ns_); });
} else {
ESP_LOGV(TAG, "Measurement not required, queueing immediate read");
this->trigger_time_ns_ = curr_time_ns;
this->set_timeout(READ_TIMEOUT_ID, 0, [this]() { this->read_(this->trigger_time_ns_); });
this->set_timeout("read", 0, [this]() { this->read_(this->trigger_time_ns_); });
}
}
@@ -9,7 +9,6 @@ import esphome.config_validation as cv
from esphome.types import ConfigType
CODEOWNERS = ["@neffs", "@kbx81"]
DOMAIN = "bme68x_bsec2_i2c"
AUTO_LOAD = ["bme68x_bsec2"]
DEPENDENCIES = ["i2c"]
-1
View File
@@ -1,2 +1 @@
CODEOWNERS = ["@flaviut"]
DOMAIN = "bmi160"

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