Merge branch 'dev' into ota-idf-lazy-erase

This commit is contained in:
J. Nick Koston
2026-08-22 21:17:43 -05:00
committed by GitHub
195 changed files with 1681 additions and 938 deletions
+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.12.2
RUN uv pip install --no-cache-dir esphome-device-builder==1.12.4
RUN \
platformio settings set enable_telemetry No \
+4 -2
View File
@@ -762,9 +762,11 @@ def _wrap_to_code(name, comp, yaml_util):
async def wrapped(conf):
cg.add(cg.LineComment(f"{name}:"))
if comp.config_schema is not None:
conf_str = yaml_util.dump(conf)
# sort_keys: voluptuous fills defaults in set order, so an
# unsorted dump would churn main.cpp and relink every run
conf_str = yaml_util.dump(conf, sort_keys=True)
conf_str = conf_str.replace("//", "")
# remove tailing \ to avoid multi-line comment warning
# remove trailing \ to avoid multi-line comment warning
conf_str = conf_str.replace("\\\n", "\n")
cg.add(cg.LineComment(indent(conf_str)))
await coro(conf)
+4 -1
View File
@@ -1,3 +1,5 @@
from typing import Any
from esphome import pins
import esphome.codegen as cg
from esphome.components.esp32 import (
@@ -16,6 +18,7 @@ from esphome.components.esp32 import (
import esphome.config_validation as cv
from esphome.const import CONF_ANALOG, CONF_INPUT, CONF_NUMBER, PLATFORM_ESP8266
from esphome.core import CORE
from esphome.types import ConfigType
CODEOWNERS = ["@esphome/core"]
@@ -225,7 +228,7 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
}
def validate_adc_pin(value):
def validate_adc_pin(value: Any) -> ConfigType | str:
if str(value).upper() == "VCC":
if CORE.is_rp2:
return pins.internal_gpio_input_pin_schema(29)
+3 -3
View File
@@ -52,7 +52,7 @@ _attenuation = cv.enum(ATTENUATION_MODES, lower=True)
_sampling_mode = cv.enum(SAMPLING_MODES, lower=True)
def validate_config(config):
def validate_config(config: ConfigType) -> ConfigType:
if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto":
raise cv.Invalid("Automatic attenuation cannot be used when raw output is set")
@@ -120,7 +120,7 @@ CONFIG_SCHEMA = cv.All(
CONF_ADC_CHANNEL_ID = "adc_channel_id"
def _overlay_io_channels():
def _overlay_io_channels() -> str:
channel_count = CORE.data[CONF_ADC_CHANNEL_ID]
entries = ", ".join(f"<&adc {channel_id}>" for channel_id in range(channel_count))
return f"""
@@ -132,7 +132,7 @@ def _overlay_io_channels():
"""
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await sensor.register_sensor(var, config)
+16 -3
View File
@@ -17,6 +17,9 @@ from esphome.const import (
UNIT_OHM,
UNIT_PARTS_PER_BILLION,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CONF_RESISTANCE = "resistance"
@@ -62,7 +65,7 @@ CONFIG_SCHEMA = (
FINAL_VALIDATE_SCHEMA = i2c.final_validate_device_schema("ags10", max_frequency="15khz")
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
@@ -94,7 +97,12 @@ AGS10_NEW_I2C_ADDRESS_SCHEMA = cv.maybe_simple_value(
AGS10_NEW_I2C_ADDRESS_SCHEMA,
synchronous=True,
)
async def ags10newi2caddress_to_code(config, action_id, template_arg, args):
async def ags10newi2caddress_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
address = await cg.templatable(config[CONF_ADDRESS], args, cg.uint8)
@@ -126,7 +134,12 @@ AGS10_SET_ZERO_POINT_SCHEMA = cv.Schema(
AGS10_SET_ZERO_POINT_SCHEMA,
synchronous=True,
)
async def ags10setzeropoint_to_code(config, action_id, template_arg, args):
async def ags10setzeropoint_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
mode = await cg.templatable(
+26 -10
View File
@@ -1,5 +1,6 @@
import base64
import logging
from typing import Any
from esphome import automation
from esphome.automation import Condition
@@ -129,7 +130,7 @@ def _register_provisioning_source(config: ConfigType) -> ConfigType:
return config
def validate_encryption_key(value):
def validate_encryption_key(value: Any) -> str:
value = cv.string_strict(value)
try:
decoded = base64.b64decode(value, validate=True)
@@ -217,7 +218,7 @@ def _auto_detect_supports_response(config: ConfigType) -> ConfigType:
return config
def _validate_supports_response(value):
def _validate_supports_response(value: Any) -> str:
"""Validate supports_response after auto-detection has set the value."""
return cv.enum(SUPPORTS_RESPONSE_OPTIONS, lower=True)(value)
@@ -256,7 +257,7 @@ ENCRYPTION_SCHEMA = cv.Schema(
)
def _encryption_schema(config):
def _encryption_schema(config: ConfigType | None) -> ConfigType:
if config is None:
config = {}
return ENCRYPTION_SCHEMA(config)
@@ -393,7 +394,7 @@ async def to_code(config: ConfigType) -> None:
if actions := config.get(CONF_ACTIONS, []):
# Collect all triggers first, then register all at once with initializer_list
triggers: list[cg.Pvariable] = []
triggers: list[cg.MockObj] = []
for conf in actions:
func_args: list[tuple[MockObj, str]] = []
service_template_args: list[MockObj] = [] # User service argument types
@@ -581,7 +582,7 @@ async def homeassistant_service_to_code(
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
):
) -> MockObj:
cg.add_define("USE_API_HOMEASSISTANT_SERVICES")
serv = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, serv, False)
@@ -647,7 +648,7 @@ async def homeassistant_service_to_code(
return var
def validate_homeassistant_event(value):
def validate_homeassistant_event(value: Any) -> str:
value = cv.string(value)
if not value.startswith("esphome."):
raise cv.Invalid(
@@ -676,7 +677,12 @@ HOMEASSISTANT_EVENT_ACTION_SCHEMA = cv.Schema(
HOMEASSISTANT_EVENT_ACTION_SCHEMA,
synchronous=True,
)
async def homeassistant_event_to_code(config, action_id, template_arg, args):
async def homeassistant_event_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
cg.add_define("USE_API_HOMEASSISTANT_SERVICES")
serv = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, serv, True)
@@ -724,7 +730,12 @@ HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA = cv.maybe_simple_value(
HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA,
synchronous=True,
)
async def homeassistant_tag_scanned_to_code(config, action_id, template_arg, args):
async def homeassistant_tag_scanned_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
cg.add_define("USE_API_HOMEASSISTANT_SERVICES")
serv = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, serv, True)
@@ -740,7 +751,7 @@ CONF_SUCCESS = "success"
CONF_ERROR_MESSAGE = "error_message"
def _validate_api_respond_data(config):
def _validate_api_respond_data(config: ConfigType) -> ConfigType:
"""Set flag during validation so AUTO_LOAD can include json component."""
if CONF_DATA in config:
CORE.data.setdefault(DOMAIN, {})[CONF_CAPTURE_RESPONSE] = True
@@ -824,7 +835,12 @@ API_CONNECTED_CONDITION_SCHEMA = cv.Schema(
@automation.register_condition(
"api.connected", APIConnectedCondition, API_CONNECTED_CONDITION_SCHEMA
)
async def api_connected_to_code(config, condition_id, template_arg, args):
async def api_connected_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(condition_id, template_arg)
templ = await cg.templatable(config[CONF_STATE_SUBSCRIPTION_ONLY], args, cg.bool_)
cg.add(var.set_state_subscription_only(templ))
-10
View File
@@ -423,12 +423,6 @@ void APIServer::send_infrared_rf_receive_event([[maybe_unused]] uint32_t device_
API_DISPATCH_UPDATE(alarm_control_panel::AlarmControlPanel, alarm_control_panel)
#endif
float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
void APIServer::set_port(uint16_t port) { this->port_ = port; }
void APIServer::set_batch_delay(uint16_t batch_delay) { this->batch_delay_ = batch_delay; }
#ifdef USE_API_HOMEASSISTANT_SERVICES
void APIServer::send_homeassistant_action(const HomeassistantActionRequest &call) {
bool has_subscriber = false;
@@ -553,10 +547,6 @@ const std::vector<APIServer::HomeAssistantStateSubscription> &APIServer::get_sta
}
#endif
uint16_t APIServer::get_port() const { return this->port_; }
void APIServer::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
#ifdef USE_API_NOISE
bool APIServer::update_noise_psk_(const SavedNoisePsk &new_psk, const LogString *save_log_msg,
const LogString *fail_log_msg, bool make_active) {
+5 -5
View File
@@ -51,8 +51,8 @@ class APIServer final : public Component,
public:
APIServer();
void setup() override;
uint16_t get_port() const;
float get_setup_priority() const override;
uint16_t get_port() const { return this->port_; }
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
void loop() override;
void dump_config() override;
void on_shutdown() override;
@@ -63,9 +63,9 @@ class APIServer final : public Component,
#ifdef USE_CAMERA
void on_camera_image(const std::shared_ptr<camera::CameraImage> &image) override;
#endif
void set_port(uint16_t port);
void set_reboot_timeout(uint32_t reboot_timeout);
void set_batch_delay(uint16_t batch_delay);
void set_port(uint16_t port) { this->port_ = port; }
void set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
void set_batch_delay(uint16_t batch_delay) { this->batch_delay_ = batch_delay; }
uint16_t get_batch_delay() const { return batch_delay_; }
void set_listen_backlog(uint8_t listen_backlog) { this->listen_backlog_ = listen_backlog; }
+16 -3
View File
@@ -4,6 +4,9 @@ import esphome.codegen as cg
from esphome.components import i2c
import esphome.config_validation as cv
from esphome.const import CONF_FREQUENCY, CONF_ID
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@X-Ryl669"]
DEPENDENCIES = ["i2c"]
@@ -70,7 +73,7 @@ CONFIG_SCHEMA = cv.All(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
@@ -91,7 +94,12 @@ AT581XSettingsAction = at581x_ns.class_("AT581XSettingsAction", automation.Actio
),
synchronous=True,
)
async def at581x_reset_to_code(config, action_id, template_arg, args):
async def at581x_reset_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
@@ -163,7 +171,12 @@ RADAR_SETTINGS_SCHEMA = cv.Schema(
RADAR_SETTINGS_SCHEMA,
synchronous=True,
)
async def at581x_settings_to_code(config, action_id, template_arg, args):
async def at581x_settings_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
+2 -1
View File
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import switch
import esphome.config_validation as cv
from esphome.const import DEVICE_CLASS_SWITCH, ICON_WIFI
from esphome.types import ConfigType
from .. import CONF_AT581X_ID, AT581XComponent, at581x_ns
@@ -22,7 +23,7 @@ CONFIG_SCHEMA = switch.switch_schema(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
at581x_component = await cg.get_variable(config[CONF_AT581X_ID])
s = await switch.new_switch(config)
await cg.register_parented(s, config[CONF_AT581X_ID])
+15 -15
View File
@@ -4,9 +4,12 @@ The platform analog of esp32_ble / rp2040_ble: owns the Beken BDK BLE stack
bring-up and the controller BLE address. Consumers (bk72xx_ble_tracker) build
on this component and contain no SDK calls of their own.
Supported SoCs (BLE 5.x): BK7231N/BK7236 (BLE 5.1), BK7238/BK7252N/BK7253
(BLE 5.2), and any future BLE-5.x SoC. Known non-5.x families are rejected in
to_code; unknown families are capability-checked at compile time via
Supported SoCs (BLE 5.x): BK7231N/BK7236 (BLE 5.1), BK7252N/BK7253 (BLE 5.2),
and any future BLE-5.x SoC. BK7238 (BLE 5.2) is blocked for now: with BLE
compiled in, the Beken SDK erases the bootloader flash sector at boot because
LibreTiny's partition table has no BLE bonding entry (esphome#18646,
libretiny-eu/libretiny#408). Known non-5.x families and BK7238 are rejected in
to_code. Unknown families are capability-checked at compile time via
`__has_include("app_ble.h")`, a header only on the BLE 5.x include path
(ble_api.h ships for every SoC, so it cannot be the probe). A non-5.x build
fails with a clear #error.
@@ -65,6 +68,14 @@ def _unsupported_family_message(family: str) -> str | None:
)
if family == FAMILY_BK7231Q:
return "bk72xx_ble does not support BK7231Q: this SoC has no BLE"
if family == FAMILY_BK7238:
return (
"bk72xx_ble is disabled on BK7238: with BLE compiled in, the Beken SDK "
"erases the bootloader flash sector at boot and the device can no longer "
"start (see https://github.com/esphome/esphome/issues/18646); support "
"returns once the LibreTiny partition table fix "
"(libretiny-eu/libretiny#408) is released"
)
return None
@@ -113,18 +124,7 @@ async def to_code(config: ConfigType) -> None:
# BK7231N, but NOT on BK7238 (its BLE stack has no such symbol; the address is
# derived from the WiFi MAC instead — the BDK's own fallback). Tell the C++
# which path is available so it doesn't reference a missing symbol.
family = libretiny.get_libretiny_family()
if family == FAMILY_BK7231N:
if libretiny.get_libretiny_family() == FAMILY_BK7231N:
cg.add_define("BK72XX_BLE_HAS_COMMON_BDADDR")
elif family == FAMILY_BK7238:
# ESPHome's LibreTiny disables BLE on BK7238 because the SDK can hang at
# WiFi STA startup when BLE init runs. This component re-enables BLE, so
# warn loudly: BK7238 is accepted but not hardware-verified and may be
# WiFi-unstable with BLE on.
_LOGGER.warning(
"bk72xx_ble on BK7238: enabling BLE is known to risk a WiFi STA startup "
"hang on this family and is not yet hardware-verified. Expect possible "
"instability."
)
cg.add_define("USE_BK72XX_BLE")
+13 -7
View File
@@ -16,14 +16,15 @@ from esphome.const import (
DEVICE_CLASS_RESTART,
DEVICE_CLASS_UPDATE,
)
from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core import CORE, ID, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import (
entity_duplicate_validator,
queue_entity_register,
setup_device_class,
setup_entity,
)
from esphome.cpp_generator import MockObjClass
from esphome.cpp_generator import MockObj, MockObjClass, TemplateArgsType
from esphome.types import ConfigType, SafeExpType
CODEOWNERS = ["@esphome/core"]
IS_PLATFORM_COMPONENT = True
@@ -88,7 +89,7 @@ _CALLBACK_AUTOMATIONS = (
@setup_entity("button")
async def setup_button_core_(var, config):
async def setup_button_core_(var: MockObj, config: ConfigType) -> None:
await automation.build_callback_automations(var, config, _CALLBACK_AUTOMATIONS)
setup_device_class(config)
@@ -101,7 +102,7 @@ async def setup_button_core_(var, config):
await web_server.add_entity_config(var, web_server_config)
async def register_button(var, config):
async def register_button(var: MockObj, config: ConfigType) -> None:
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
queue_entity_register("button", config)
@@ -109,7 +110,7 @@ async def register_button(var, config):
await setup_button_core_(var, config)
async def new_button(config, *args):
async def new_button(config: ConfigType, *args: SafeExpType) -> MockObj:
var = cg.new_Pvariable(config[CONF_ID], *args)
await register_button(var, config)
return var
@@ -125,11 +126,16 @@ BUTTON_PRESS_SCHEMA = maybe_simple_id(
@automation.register_action(
"button.press", PressAction, BUTTON_PRESS_SCHEMA, synchronous=True
)
async def button_press_to_code(config, action_id, template_arg, args):
async def button_press_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
cg.add_global(button_ns.using)
+14 -6
View File
@@ -1,10 +1,13 @@
import re
from typing import Any
from esphome import automation
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_DATA, CONF_ID, CONF_TRIGGER_ID
from esphome.core import CORE, ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@mvturnho", "@danielschramm"]
IS_PLATFORM_COMPONENT = True
@@ -18,7 +21,7 @@ CONF_BIT_RATE = "bit_rate"
CONF_ON_FRAME = "on_frame"
def validate_id(config):
def validate_id(config: ConfigType) -> ConfigType:
if CONF_CAN_ID in config:
can_id = config[CONF_CAN_ID]
id_ext = config[CONF_USE_EXTENDED_ID]
@@ -27,7 +30,7 @@ def validate_id(config):
return config
def validate_raw_data(value):
def validate_raw_data(value: Any) -> bytes | list:
if isinstance(value, str):
return value.encode("utf-8")
if isinstance(value, list):
@@ -71,7 +74,7 @@ CAN_SPEEDS = {
}
def get_rate(value):
def get_rate(value: str) -> int:
match = re.match(r"(\d+)(?:K(\d+)?)?BPS", value, re.IGNORECASE)
if not match:
raise ValueError(f"Invalid rate format: {value}")
@@ -103,7 +106,7 @@ CANBUS_SCHEMA = cv.Schema(
CANBUS_SCHEMA.add_extra(validate_id)
async def setup_canbus_core_(var, config):
async def setup_canbus_core_(var: MockObj, config: ConfigType) -> None:
await cg.register_component(var, config)
cg.add(var.set_can_id([config[CONF_CAN_ID]]))
cg.add(var.set_use_extended_id([config[CONF_USE_EXTENDED_ID]]))
@@ -134,7 +137,7 @@ async def setup_canbus_core_(var, config):
)
async def register_canbus(var, config):
async def register_canbus(var: MockObj, config: ConfigType) -> None:
if not CORE.has_id(config[CONF_ID]):
var = cg.new_Pvariable(config[CONF_ID], var)
await setup_canbus_core_(var, config)
@@ -157,7 +160,12 @@ async def register_canbus(var, config):
),
synchronous=True,
)
async def canbus_action_to_code(config, action_id, template_arg, args):
async def canbus_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_CANBUS_ID])
@@ -6,6 +6,7 @@
#include "esphome/core/string_ref.h"
#include "esphome/components/wifi/wifi_component.h"
#include "captive_index.h"
#include "scan_list.h"
namespace esphome::captive_portal {
@@ -33,8 +34,10 @@ void CaptivePortal::handle_config(AsyncWebServerRequest *request) {
// Invariant: only bounded in-memory work under the lock; the network send
// happens later in request->send()
wifi::ScanResultsLock lock(wifi::global_wifi_component);
for (const auto &scan : wifi::global_wifi_component->get_scan_result()) {
if (scan.get_is_hidden())
const auto &results = wifi::global_wifi_component->get_scan_result();
for (const auto &scan : results) {
bool with_auth = false;
if (!should_show_scan_entry(results, scan, with_auth))
continue;
json_escape_into_buffer(escaped_ssid, scan.get_ssid());
@@ -44,10 +47,10 @@ void CaptivePortal::handle_config(AsyncWebServerRequest *request) {
stream->print(ESPHOME_F("\",\"rssi\":"));
stream->print(scan.get_rssi());
stream->print(ESPHOME_F(",\"lock\":"));
stream->print(scan.get_with_auth());
stream->print(with_auth);
stream->print(ESPHOME_F("}"));
#else
stream->printf(R"(,{"ssid":"%s","rssi":%d,"lock":%d})", escaped_ssid, scan.get_rssi(), scan.get_with_auth());
stream->printf(R"(,{"ssid":"%s","rssi":%d,"lock":%d})", escaped_ssid, scan.get_rssi(), with_auth);
#endif
}
}
@@ -0,0 +1,28 @@
#pragma once
#include <cstdint>
namespace esphome::captive_portal {
// A scan lists every BSSID, so one SSID can appear several times. Returns true for
// the strongest entry per SSID (earliest on ties), never for hidden entries. scan
// must be an element of results. with_auth is written only when returning true and
// is set if any entry with that SSID needs a key. Templated for host tests.
template<typename Results, typename Entry>
bool should_show_scan_entry(const Results &results, const Entry &scan, bool &with_auth) {
if (scan.get_is_hidden())
return false;
const int8_t rssi = scan.get_rssi();
bool any_auth = false;
for (const auto &other : results) {
if (other.get_is_hidden() || !other.ssid_equals(scan))
continue;
// Same array, so address order is index order. scan fails both checks against itself.
if (other.get_rssi() > rssi || (other.get_rssi() == rssi && &other < &scan))
return false;
any_auth |= other.get_with_auth();
}
with_auth = any_auth;
return true;
}
} // namespace esphome::captive_portal
+21 -8
View File
@@ -1,3 +1,5 @@
from typing import Any
from esphome import automation
import esphome.codegen as cg
from esphome.components import mqtt, web_server
@@ -48,13 +50,19 @@ from esphome.const import (
CONF_VISUAL,
CONF_WEB_SERVER,
)
from esphome.core import CORE, CoroPriority, Lambda, coroutine_with_priority
from esphome.core import CORE, ID, CoroPriority, Lambda, coroutine_with_priority
from esphome.core.entity_helpers import (
entity_duplicate_validator,
queue_entity_register,
setup_entity,
)
from esphome.cpp_generator import LambdaExpression, MockObjClass
from esphome.cpp_generator import (
LambdaExpression,
MockObj,
MockObjClass,
TemplateArgsType,
)
from esphome.types import ConfigType, SafeExpType
IS_PLATFORM_COMPONENT = True
@@ -132,7 +140,7 @@ VISUAL_TEMPERATURE_STEP_SCHEMA = cv.Schema(
)
def visual_temperature_step(value):
def visual_temperature_step(value: Any) -> ConfigType:
# Allow defining target/current temperature steps separately
if isinstance(value, dict):
return VISUAL_TEMPERATURE_STEP_SCHEMA(value)
@@ -273,7 +281,7 @@ def climate_schema(
@setup_entity("climate")
async def setup_climate_core_(var, config):
async def setup_climate_core_(var: MockObj, config: ConfigType) -> None:
visual = config.get(CONF_VISUAL, {})
if (min_temp := visual.get(CONF_MIN_TEMPERATURE)) is not None:
cg.add_define("USE_CLIMATE_VISUAL_OVERRIDES")
@@ -443,7 +451,7 @@ async def setup_climate_core_(var, config):
await web_server.add_entity_config(var, web_server_config)
async def register_climate(var, config):
async def register_climate(var: MockObj, config: ConfigType) -> None:
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
queue_entity_register("climate", config)
@@ -451,7 +459,7 @@ async def register_climate(var, config):
await setup_climate_core_(var, config)
async def new_climate(config, *args):
async def new_climate(config: ConfigType, *args: SafeExpType) -> MockObj:
var = cg.new_Pvariable(config[CONF_ID], *args)
await register_climate(var, config)
return var
@@ -485,7 +493,12 @@ CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema(
CLIMATE_CONTROL_ACTION_SCHEMA,
synchronous=True,
)
async def climate_control_to_code(config, action_id, template_arg, args):
async def climate_control_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
# All configured fields are folded into a single stateless lambda whose
@@ -549,5 +562,5 @@ async def climate_control_to_code(config, action_id, template_arg, args):
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
cg.add_global(climate_ns.using)
-23
View File
@@ -511,29 +511,6 @@ ClimateTraits Climate::get_traits() {
return traits;
}
#ifdef USE_CLIMATE_VISUAL_OVERRIDES
void Climate::set_visual_min_temperature_override(float visual_min_temperature_override) {
this->visual_min_temperature_override_ = visual_min_temperature_override;
}
void Climate::set_visual_max_temperature_override(float visual_max_temperature_override) {
this->visual_max_temperature_override_ = visual_max_temperature_override;
}
void Climate::set_visual_temperature_step_override(float target, float current) {
this->visual_target_temperature_step_override_ = target;
this->visual_current_temperature_step_override_ = current;
}
void Climate::set_visual_min_humidity_override(float visual_min_humidity_override) {
this->visual_min_humidity_override_ = visual_min_humidity_override;
}
void Climate::set_visual_max_humidity_override(float visual_max_humidity_override) {
this->visual_max_humidity_override_ = visual_max_humidity_override;
}
#endif
ClimateCall Climate::make_call() { return ClimateCall(this); }
ClimateCall ClimateDeviceRestoreState::to_call(Climate *climate) {
+16 -5
View File
@@ -228,11 +228,22 @@ class Climate : public EntityBase {
ClimateTraits get_traits();
#ifdef USE_CLIMATE_VISUAL_OVERRIDES
void set_visual_min_temperature_override(float visual_min_temperature_override);
void set_visual_max_temperature_override(float visual_max_temperature_override);
void set_visual_temperature_step_override(float target, float current);
void set_visual_min_humidity_override(float visual_min_humidity_override);
void set_visual_max_humidity_override(float visual_max_humidity_override);
void set_visual_min_temperature_override(float visual_min_temperature_override) {
this->visual_min_temperature_override_ = visual_min_temperature_override;
}
void set_visual_max_temperature_override(float visual_max_temperature_override) {
this->visual_max_temperature_override_ = visual_max_temperature_override;
}
void set_visual_temperature_step_override(float target, float current) {
this->visual_target_temperature_step_override_ = target;
this->visual_current_temperature_step_override_ = current;
}
void set_visual_min_humidity_override(float visual_min_humidity_override) {
this->visual_min_humidity_override_ = visual_min_humidity_override;
}
void set_visual_max_humidity_override(float visual_max_humidity_override) {
this->visual_max_humidity_override_ = visual_max_humidity_override;
}
#endif
/// Set the supported custom fan modes (stored on Climate, referenced by ClimateTraits).
+30 -10
View File
@@ -46,7 +46,7 @@ from esphome.core.entity_helpers import (
setup_entity,
)
from esphome.cpp_generator import LambdaExpression, MockObj, MockObjClass
from esphome.types import ConfigType, TemplateArgsType
from esphome.types import ConfigType, SafeExpType, TemplateArgsType
IS_PLATFORM_COMPONENT = True
@@ -162,7 +162,7 @@ _COVER_SCHEMA = (
_COVER_SCHEMA.add_extra(entity_duplicate_validator("cover"))
def _validate_mqtt_state_topics(config):
def _validate_mqtt_state_topics(config: ConfigType) -> ConfigType:
if config.get(CONF_MQTT_JSON_STATE_PAYLOAD):
if CONF_POSITION_STATE_TOPIC in config:
raise cv.Invalid(
@@ -201,7 +201,7 @@ def cover_schema(
@setup_entity("cover")
async def setup_cover_core_(var, config):
async def setup_cover_core_(var: MockObj, config: ConfigType) -> None:
setup_device_class(config)
if CONF_ON_OPEN in config:
@@ -235,7 +235,7 @@ async def setup_cover_core_(var, config):
await web_server.add_entity_config(var, web_server_config)
async def register_cover(var, config):
async def register_cover(var: MockObj, config: ConfigType) -> None:
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
queue_entity_register("cover", config)
@@ -243,7 +243,7 @@ async def register_cover(var, config):
await setup_cover_core_(var, config)
async def new_cover(config, *args):
async def new_cover(config: ConfigType, *args: SafeExpType) -> MockObj:
var = cg.new_Pvariable(config[CONF_ID], *args)
await register_cover(var, config)
return var
@@ -259,7 +259,12 @@ COVER_ACTION_SCHEMA = maybe_simple_id(
@automation.register_action(
"cover.open", OpenAction, COVER_ACTION_SCHEMA, synchronous=True
)
async def cover_open_to_code(config, action_id, template_arg, args):
async def cover_open_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
@@ -267,7 +272,12 @@ async def cover_open_to_code(config, action_id, template_arg, args):
@automation.register_action(
"cover.close", CloseAction, COVER_ACTION_SCHEMA, synchronous=True
)
async def cover_close_to_code(config, action_id, template_arg, args):
async def cover_close_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
@@ -275,7 +285,12 @@ async def cover_close_to_code(config, action_id, template_arg, args):
@automation.register_action(
"cover.stop", StopAction, COVER_ACTION_SCHEMA, synchronous=True
)
async def cover_stop_to_code(config, action_id, template_arg, args):
async def cover_stop_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
@@ -283,7 +298,12 @@ async def cover_stop_to_code(config, action_id, template_arg, args):
@automation.register_action(
"cover.toggle", ToggleAction, COVER_ACTION_SCHEMA, synchronous=True
)
async def cover_toggle_to_code(config, action_id, template_arg, args):
async def cover_toggle_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
@@ -421,5 +441,5 @@ automation.register_condition(
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
cg.add_global(cover_ns.using)
-7
View File
@@ -135,10 +135,6 @@ CoverCall &CoverCall::set_stop(bool stop) {
this->stop_ = stop;
return *this;
}
bool CoverCall::get_stop() const { return this->stop_; }
CoverCall Cover::make_call() { return {this}; }
void Cover::publish_state(bool save) {
this->position = clamp(this->position, 0.0f, 1.0f);
this->tilt = clamp(this->tilt, 0.0f, 1.0f);
@@ -184,9 +180,6 @@ optional<CoverRestoreState> Cover::restore_state_() {
return recovered;
}
bool Cover::is_fully_open() const { return this->position == COVER_OPEN; }
bool Cover::is_fully_closed() const { return this->position == COVER_CLOSED; }
CoverCall CoverRestoreState::to_call(Cover *cover) {
auto call = cover->make_call();
auto traits = cover->get_traits();
+4 -4
View File
@@ -50,7 +50,7 @@ class CoverCall {
void perform();
const optional<float> &get_position() const;
bool get_stop() const;
bool get_stop() const { return this->stop_; }
const optional<float> &get_tilt() const;
const optional<bool> &get_toggle() const;
@@ -123,7 +123,7 @@ class Cover : public EntityBase {
float tilt{COVER_OPEN};
/// Construct a new cover call used to control the cover.
CoverCall make_call();
CoverCall make_call() { return {this}; }
template<typename F> void add_on_state_callback(F &&f) { this->state_callback_.add(std::forward<F>(f)); }
@@ -139,9 +139,9 @@ class Cover : public EntityBase {
virtual CoverTraits get_traits() = 0;
/// Helper method to check if the cover is fully open. Equivalent to comparing .position against 1.0
bool is_fully_open() const;
bool is_fully_open() const { return this->position == COVER_OPEN; }
/// Helper method to check if the cover is fully closed. Equivalent to comparing .position against 0.0
bool is_fully_closed() const;
bool is_fully_closed() const { return this->position == COVER_CLOSED; }
protected:
friend CoverCall;
+2 -1
View File
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import uart
import esphome.config_validation as cv
from esphome.const import CONF_ADDRESS, CONF_ID
from esphome.types import ConfigType
CODEOWNERS = ["@s1lvi0"]
MULTI_CONF = True
@@ -26,7 +27,7 @@ CONFIG_SCHEMA = (
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await uart.register_uart_device(var, config)
+4 -2
View File
@@ -1,6 +1,8 @@
import esphome.codegen as cg
from esphome.components import binary_sensor
import esphome.config_validation as cv
from esphome.cpp_generator import MockObj
from esphome.types import ConfigType
from . import CONF_BMS_DALY_ID, DalyBmsComponent
@@ -27,13 +29,13 @@ CONFIG_SCHEMA = cv.All(
)
async def setup_conf(config, key, hub):
async def setup_conf(config: ConfigType, key: str, hub: MockObj) -> None:
if sensor_config := config.get(key):
var = await binary_sensor.new_binary_sensor(sensor_config)
cg.add(getattr(hub, f"set_{key}_binary_sensor")(var))
async def to_code(config):
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_BMS_DALY_ID])
for key in TYPES:
await setup_conf(config, key, hub)
+4 -2
View File
@@ -23,6 +23,8 @@ from esphome.const import (
UNIT_PERCENT,
UNIT_VOLT,
)
from esphome.cpp_generator import MockObj
from esphome.types import ConfigType
from . import CONF_BMS_DALY_ID, DalyBmsComponent
@@ -222,13 +224,13 @@ CONFIG_SCHEMA = cv.All(
)
async def setup_conf(config, key, hub):
async def setup_conf(config: ConfigType, key: str, hub: MockObj) -> None:
if sensor_config := config.get(key):
sens = await sensor.new_sensor(sensor_config)
cg.add(getattr(hub, f"set_{key}_sensor")(sens))
async def to_code(config):
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_BMS_DALY_ID])
for key in TYPES:
await setup_conf(config, key, hub)
+4 -2
View File
@@ -2,6 +2,8 @@ import esphome.codegen as cg
from esphome.components import text_sensor
import esphome.config_validation as cv
from esphome.const import CONF_STATUS
from esphome.cpp_generator import MockObj
from esphome.types import ConfigType
from . import CONF_BMS_DALY_ID, DalyBmsComponent
@@ -23,13 +25,13 @@ CONFIG_SCHEMA = cv.All(
)
async def setup_conf(config, key, hub):
async def setup_conf(config: ConfigType, key: str, hub: MockObj) -> None:
if sensor_config := config.get(key):
sens = await text_sensor.new_text_sensor(sensor_config)
cg.add(getattr(hub, f"set_{key}_text_sensor")(sens))
async def to_code(config):
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_BMS_DALY_ID])
for key in TYPES:
await setup_conf(config, key, hub)
@@ -2,6 +2,7 @@ import base64
from pathlib import Path
import re
import secrets
from typing import Any
import requests
from ruamel.yaml import YAML
@@ -13,6 +14,7 @@ import esphome.config_validation as cv
from esphome.const import CONF_ESPHOME, CONF_PROJECT, CONF_REF, CONF_WIFI
import esphome.final_validate as fv
from esphome.happy_eyeballs import ensure_happy_eyeballs
from esphome.types import ConfigType
from esphome.yaml_util import dump
dashboard_import_ns = cg.esphome_ns.namespace("dashboard_import")
@@ -23,14 +25,14 @@ DEPENDENCIES = ["api"]
CODEOWNERS = ["@esphome/core"]
def validate_import_url(value):
def validate_import_url(value: Any) -> str:
value = cv.string_strict(value)
value = cv.Length(max=255)(value)
validate_source_shorthand(value)
return value
def validate_full_url(config):
def validate_full_url(config: ConfigType) -> ConfigType:
if not config[CONF_IMPORT_FULL_CONFIG]:
return config
source = validate_source_shorthand(config[CONF_PACKAGE_IMPORT_URL])
@@ -55,7 +57,7 @@ CONFIG_SCHEMA = cv.All(
)
def _final_validate(config):
def _final_validate(config: ConfigType) -> None:
full_config = fv.full_config.get()[CONF_ESPHOME]
if CONF_PROJECT not in full_config:
raise cv.Invalid(
@@ -73,7 +75,7 @@ wifi:
"""
async def to_code(config):
async def to_code(config: ConfigType) -> None:
cg.add_define("USE_DASHBOARD_IMPORT")
url = config[CONF_PACKAGE_IMPORT_URL]
if config[CONF_IMPORT_FULL_CONFIG]:
@@ -37,8 +37,6 @@ void DateEntity::publish_state() {
#endif
}
DateCall DateEntity::make_call() { return DateCall(this); }
void DateCall::validate_() {
if (this->year_.has_value() && (this->year_ < 1970 || this->year_ > 3000)) {
ESP_LOGE(TAG, "Year must be between 1970 and 3000");
@@ -96,6 +96,8 @@ class DateCall {
optional<uint8_t> day_;
};
inline DateCall DateEntity::make_call() { return DateCall(this); }
template<typename... Ts> class DateSetAction final : public Action<Ts...>, public Parented<DateEntity> {
public:
TEMPLATABLE_VALUE(ESPTime, date)
@@ -53,8 +53,6 @@ void DateTimeEntity::publish_state() {
#endif
}
DateTimeCall DateTimeEntity::make_call() { return DateTimeCall(this); }
ESPTime DateTimeEntity::state_as_esptime() const {
ESPTime obj;
obj.year = this->year_;
@@ -121,6 +121,8 @@ class DateTimeCall {
optional<uint8_t> second_;
};
inline DateTimeCall DateTimeEntity::make_call() { return DateTimeCall(this); }
template<typename... Ts> class DateTimeSetAction final : public Action<Ts...>, public Parented<DateTimeEntity> {
public:
TEMPLATABLE_VALUE(ESPTime, datetime)
@@ -33,8 +33,6 @@ void TimeEntity::publish_state() {
#endif
}
TimeCall TimeEntity::make_call() { return TimeCall(this); }
void TimeCall::validate_() {
if (this->hour_.has_value() && this->hour_ > 23) {
ESP_LOGE(TAG, "Hour must be between 0 and 23");
@@ -98,6 +98,8 @@ class TimeCall {
optional<uint8_t> second_;
};
inline TimeCall TimeEntity::make_call() { return TimeCall(this); }
template<typename... Ts> class TimeSetAction final : public Action<Ts...>, public Parented<TimeEntity> {
public:
TEMPLATABLE_VALUE(ESPTime, time)
+2 -1
View File
@@ -12,6 +12,7 @@ from esphome.const import (
PlatformFramework,
)
from esphome.core import CORE
from esphome.types import ConfigType
CODEOWNERS = ["@esphome/core"]
DEPENDENCIES = ["logger"]
@@ -45,7 +46,7 @@ CONFIG_SCHEMA = cv.All(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
if CORE.using_zephyr:
zephyr_add_prj_conf("HWINFO", True)
# gdb thread support
+2 -1
View File
@@ -21,6 +21,7 @@ from esphome.const import (
UNIT_MILLISECOND,
UNIT_PERCENT,
)
from esphome.types import ConfigType
from . import ( # noqa: F401 pylint: disable=unused-import
CONF_DEBUG_ID,
@@ -111,7 +112,7 @@ CONFIG_SCHEMA = {
}
async def to_code(config):
async def to_code(config: ConfigType) -> None:
debug_component = await cg.get_variable(config[CONF_DEBUG_ID])
if free_conf := config.get(CONF_FREE):
+2 -1
View File
@@ -7,6 +7,7 @@ from esphome.const import (
ICON_CHIP,
ICON_RESTART,
)
from esphome.types import ConfigType
from . import ( # noqa: F401 pylint: disable=unused-import
CONF_DEBUG_ID,
@@ -33,7 +34,7 @@ CONFIG_SCHEMA = cv.Schema(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
debug_component = await cg.get_variable(config[CONF_DEBUG_ID])
if CONF_DEVICE in config:
+21 -5
View File
@@ -38,7 +38,8 @@ from esphome.const import (
PLATFORM_NRF52,
PlatformFramework,
)
from esphome.core import CORE
from esphome.core import CORE, ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
WAKEUP_PINS = {
@@ -162,6 +163,11 @@ def validate_config(config: ConfigType) -> ConfigType:
"You need to remove the global wakeup_pin_mode and define it per pin"
)
if wakeup_pins:
if CONF_WAKEUP_PIN_MODE in wakeup_pins[0]:
raise cv.Invalid(
"Specify wakeup_pin_mode either at the top level under deep_sleep "
"or under the pin entry, not both"
)
wakeup_pins[0][CONF_WAKEUP_PIN_MODE] = config.pop(CONF_WAKEUP_PIN_MODE)
elif (
isinstance(config.get(CONF_WAKEUP_PIN), list)
@@ -174,7 +180,7 @@ def validate_config(config: ConfigType) -> ConfigType:
return config
def _validate_ex1_wakeup_mode(value):
def _validate_ex1_wakeup_mode(value: str) -> str:
if value == "ALL_LOW":
esp32.only_on_variant(supported=[VARIANT_ESP32], msg_prefix="ALL_LOW")(value)
if value == "ANY_LOW":
@@ -345,7 +351,7 @@ CONFIG_SCHEMA = cv.All(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
@@ -458,7 +464,12 @@ DEEP_SLEEP_ENTER_SCHEMA = cv.All(
DEEP_SLEEP_ENTER_SCHEMA,
synchronous=True,
)
async def deep_sleep_enter_to_code(config, action_id, template_arg, args):
async def deep_sleep_enter_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
if CONF_SLEEP_DURATION in config:
@@ -487,7 +498,12 @@ async def deep_sleep_enter_to_code(config, action_id, template_arg, args):
automation.maybe_simple_id(DEEP_SLEEP_ACTION_SCHEMA),
synchronous=True,
)
async def deep_sleep_action_to_code(config, action_id, template_arg, args):
async def deep_sleep_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
@@ -43,10 +43,6 @@ void DeepSleepComponent::loop() {
this->begin_sleep();
}
void DeepSleepComponent::set_sleep_duration(uint32_t time_ms) { this->sleep_duration_ = uint64_t(time_ms) * 1000; }
void DeepSleepComponent::set_run_duration(uint32_t time_ms) { this->run_duration_ = time_ms; }
void DeepSleepComponent::begin_sleep(bool manual) {
if (this->prevent_ && !manual) {
this->next_enter_deep_sleep_ = true;
@@ -76,8 +72,4 @@ void DeepSleepComponent::begin_sleep(bool manual) {
float DeepSleepComponent::get_setup_priority() const { return setup_priority::LATE; }
void DeepSleepComponent::prevent_deep_sleep() { this->prevent_ = true; }
void DeepSleepComponent::allow_deep_sleep() { this->prevent_ = false; }
} // namespace esphome::deep_sleep
@@ -132,7 +132,7 @@ template<typename... Ts> class PreventDeepSleepAction;
class DeepSleepComponent final : public Component {
public:
/// Set the duration in ms the component should sleep once it's in deep sleep mode.
void set_sleep_duration(uint32_t time_ms);
void set_sleep_duration(uint32_t time_ms) { this->sleep_duration_ = uint64_t(time_ms) * 1000; }
#if defined(USE_ESP32)
/** Set the pin to wake up to on the ESP32 once it's in deep sleep mode.
* Use the inverted property to set the wakeup level.
@@ -157,7 +157,7 @@ class DeepSleepComponent final : public Component {
#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) && \
!defined(USE_ESP32_VARIANT_ESP32C5) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
!defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2)
void set_touch_wakeup(bool touch_wakeup);
void set_touch_wakeup(bool touch_wakeup) { this->touch_wakeup_ = touch_wakeup; }
#endif
// Set the duration in ms for how long the code should run before entering
@@ -166,7 +166,7 @@ class DeepSleepComponent final : public Component {
#endif // USE_ESP32
/// Set a duration in ms for how long the code should run before entering deep sleep mode.
void set_run_duration(uint32_t time_ms);
void set_run_duration(uint32_t time_ms) { this->run_duration_ = time_ms; }
void setup() override;
void dump_config() override;
@@ -176,8 +176,8 @@ class DeepSleepComponent final : public Component {
/// Helper to enter deep sleep mode
void begin_sleep(bool manual = false);
void prevent_deep_sleep();
void allow_deep_sleep();
void prevent_deep_sleep() { this->prevent_ = true; }
void allow_deep_sleep() { this->prevent_ = false; }
protected:
// Returns nullopt if no run duration is set. Otherwise, returns the run
@@ -74,12 +74,6 @@ void DeepSleepComponent::set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode) {
void DeepSleepComponent::set_ext1_wakeup(Ext1Wakeup ext1_wakeup) { this->ext1_wakeup_ = ext1_wakeup; }
#endif
#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) && \
!defined(USE_ESP32_VARIANT_ESP32C5) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
!defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2)
void DeepSleepComponent::set_touch_wakeup(bool touch_wakeup) { this->touch_wakeup_ = touch_wakeup; }
#endif
void DeepSleepComponent::set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration) {
wakeup_cause_to_run_duration_ = wakeup_cause_to_run_duration;
}
-6
View File
@@ -685,9 +685,6 @@ void Display::show_page(DisplayPage *page) {
}
}
void Display::show_next_page() { this->page_->show_next(); }
void Display::show_prev_page() { this->page_->show_prev(); }
void Display::do_update_() {
if (this->auto_clear_enabled_) {
this->clear();
@@ -892,9 +889,6 @@ void DisplayPage::show_prev() {
this->prev_->show();
}
void DisplayPage::set_parent(Display *parent) { this->parent_ = parent; }
void DisplayPage::set_prev(DisplayPage *prev) { this->prev_ = prev; }
void DisplayPage::set_next(DisplayPage *next) { this->next_ = next; }
const display_writer_t &DisplayPage::get_writer() const { return this->writer_; }
const LogString *text_align_to_string(TextAlign textalign) {
+6 -3
View File
@@ -802,9 +802,9 @@ class DisplayPage final {
void show();
void show_next();
void show_prev();
void set_parent(Display *parent);
void set_prev(DisplayPage *prev);
void set_next(DisplayPage *next);
void set_parent(Display *parent) { this->parent_ = parent; }
void set_prev(DisplayPage *prev) { this->prev_ = prev; }
void set_next(DisplayPage *next) { this->next_ = next; }
const display_writer_t &get_writer() const;
protected:
@@ -814,6 +814,9 @@ class DisplayPage final {
DisplayPage *next_{nullptr};
};
inline void Display::show_next_page() { this->page_->show_next(); }
inline void Display::show_prev_page() { this->page_->show_prev(); }
template<typename... Ts> class DisplayPageShowAction final : public Action<Ts...> {
public:
TEMPLATABLE_VALUE(DisplayPage *, page)
+16 -3
View File
@@ -3,6 +3,9 @@ import esphome.codegen as cg
from esphome.components import i2c, time
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@badbadc0ffee"]
DEPENDENCIES = ["i2c"]
@@ -29,7 +32,12 @@ CONFIG_SCHEMA = time.TIME_SCHEMA.extend(
),
synchronous=True,
)
async def ds1307_write_time_to_code(config, action_id, template_arg, args):
async def ds1307_write_time_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
@@ -45,13 +53,18 @@ async def ds1307_write_time_to_code(config, action_id, template_arg, args):
),
synchronous=True,
)
async def ds1307_read_time_to_code(config, action_id, template_arg, args):
async def ds1307_read_time_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
+37 -26
View File
@@ -68,6 +68,7 @@ PATTERN_CONFIGS = {
"PULSE": {
CONF_UNIT_OF_MEASUREMENT: UNIT_PULSES,
CONF_DEVICE_CLASS: DEVICE_CLASS_ENERGY,
CONF_STATE_CLASS: STATE_CLASS_TOTAL_INCREASING,
CONF_ACCURACY_DECIMALS: 0,
},
"PF": {
@@ -78,12 +79,13 @@ PATTERN_CONFIGS = {
},
}
# Create a base schema that's flexible for any tag
BASE_SCHEMA = sensor.sensor_schema(
EmonTxSensor,
state_class=STATE_CLASS_MEASUREMENT,
accuracy_decimals=0,
).extend(
# BASE_SCHEMA intentionally omits state_class and accuracy_decimals defaults.
# Passing them to sensor_schema() would register them via cv.Optional(key, default=...),
# making them always present in the validated config dict and preventing
# apply_tag_defaults from overriding them with the correct per-prefix values.
# They are injected by apply_tag_defaults below, after running through
# sensor.validate_state_class() so the value is code-generation-ready.
BASE_SCHEMA = sensor.sensor_schema(EmonTxSensor).extend(
{
cv.GenerateID(CONF_EMONTX_ID): cv.use_id(EmonTx),
cv.Required(CONF_TAG_NAME): cv.string,
@@ -91,34 +93,43 @@ BASE_SCHEMA = sensor.sensor_schema(
)
def _apply_defaults(config: ConfigType, defaults: dict) -> None:
"""Inject defaults into config, skipping keys already set by the user.
state_class values are run through validate_state_class so they are
code-generation-ready, matching what sensor_schema() would normally do."""
for key, value in defaults.items():
if key not in config:
if key == CONF_STATE_CLASS:
value = sensor.validate_state_class(value)
config[key] = value
def apply_tag_defaults(config: ConfigType) -> ConfigType:
"""Apply defaults based on tag prefix if applicable, but don't restrict any tags."""
tag = config[CONF_TAG_NAME]
# Skip if tag is too short
if len(tag) < 2:
return config
if len(tag) >= 2:
tag_upper = tag.upper()
# Check if this tag starts with a known prefix
tag_upper = tag.upper()
for pattern, pattern_config in PATTERN_CONFIGS.items():
if tag_upper.startswith(pattern):
_apply_defaults(config, pattern_config)
return config
for pattern, pattern_config in PATTERN_CONFIGS.items():
if tag_upper.startswith(pattern):
# Apply pattern defaults if not overridden by user
for key, value in pattern_config.items():
if key not in config:
config[key] = value
# Only apply defaults for known prefixes with numeric indices (e.g. E1, V2, T3)
prefix = tag_upper[0]
if prefix in SENSOR_CONFIGS and tag[1:].isdigit():
_apply_defaults(config, SENSOR_CONFIGS[prefix])
return config
# Only apply defaults for known prefixes with numeric indices
prefix = tag_upper[0]
if prefix in SENSOR_CONFIGS and len(tag) > 1 and tag[1:].isdigit():
# Apply defaults for known tag types, but only if not overridden by user
defaults = SENSOR_CONFIGS[prefix]
for key, value in defaults.items():
if key not in config:
config[key] = value
# Fall back to generic defaults for tags with no known prefix
_apply_defaults(
config,
{
CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT,
CONF_ACCURACY_DECIMALS: 0,
},
)
return config
+1
View File
@@ -233,6 +233,7 @@ DEFAULT_EXCLUDED_IDF_COMPONENTS = (
"esp_driver_touch_sens", # Touch sensor driver - only needed by esp32_touch
"esp_driver_twai", # TWAI/CAN driver - only needed by esp32_can component
"esp_eth", # Ethernet driver - only needed by ethernet component
"esp_gdbstub", # GDB stub panic handler - unused by ESPHome; bt pulls it back
"esp_hid", # HID host/device support - ESPHome doesn't implement HID functionality
"esp_http_client", # HTTP client - only needed by http_request component
"esp_https_ota", # ESP-IDF HTTPS OTA - ESPHome has its own OTA implementation
+21 -1
View File
@@ -643,8 +643,28 @@ void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_pa
App.wake_loop_threadsafe();
return;
// Log the result of connection parameter updates: a peer can reject or
// never answer an update, and without this the link silently stays on the
// old parameters (visible only as unexplained supervision timeouts).
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT: {
if (param->update_conn_params.status != ESP_BT_STATUS_SUCCESS) {
char mac_s[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
format_mac_addr_upper(param->update_conn_params.bda, mac_s);
ESP_LOGW(TAG, "[%s] Conn param update failed, status=%d", mac_s, param->update_conn_params.status);
}
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
else {
char mac_s[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
format_mac_addr_upper(param->update_conn_params.bda, mac_s);
ESP_LOGV(TAG, "[%s] Conn params updated: interval=%u (x1.25ms) latency=%u timeout=%u (x10ms)", mac_s,
param->update_conn_params.conn_int, param->update_conn_params.latency,
param->update_conn_params.timeout);
}
#endif
return;
}
// Ignore these GAP events as they are not relevant for our use case
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
case ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT:
case ESP_GAP_BLE_PHY_UPDATE_COMPLETE_EVT: // BLE 5.0 PHY update complete
case ESP_GAP_BLE_CHANNEL_SELECT_ALGORITHM_EVT: // BLE 5.0 channel selection algorithm
@@ -38,7 +38,8 @@ from esphome.const import (
CONF_SERVICE_UUID,
CONF_TRIGGER_ID,
)
from esphome.core import CORE, CoroPriority, TimePeriod, coroutine_with_priority
from esphome.core import CORE, ID, CoroPriority, TimePeriod, coroutine_with_priority
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.enum import StrEnum
from esphome.types import ConfigType
@@ -262,7 +263,7 @@ ESP_BLE_DEVICE_SCHEMA = cv.Schema(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
# Register the loggers this component needs
esp32_ble.register_bt_logger(BTLoggers.BLE_SCAN)
@@ -360,7 +361,7 @@ async def to_code(config):
# chance to call register_ble_tracker and register_client before the list is checked
# and added to the global defines list.
@coroutine_with_priority(CoroPriority.FINAL)
async def _add_ble_features():
async def _add_ble_features() -> None:
# Add feature-specific defines based on what's needed
required_features = _get_required_features()
# Sensors registered through the neutral ble_device_base path (BLEHub) need
@@ -389,8 +390,11 @@ ESP32_BLE_START_SCAN_ACTION_SCHEMA = cv.Schema(
synchronous=True,
)
async def esp32_ble_tracker_start_scan_action_to_code(
config, action_id, template_arg, args
):
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_CONTINUOUS], args, cg.bool_)
@@ -414,8 +418,11 @@ ESP32_BLE_STOP_SCAN_ACTION_SCHEMA = automation.maybe_simple_id(
synchronous=True,
)
async def esp32_ble_tracker_stop_scan_action_to_code(
config, action_id, template_arg, args
):
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
@@ -135,6 +135,10 @@ void Esp32HostedUpdate::setup() {
// Publish state
this->status_clear_error();
this->publish_state();
// Defer so the automation runs on the main loop after setup, not during App.setup()
if (this->state_ == update::UPDATE_STATE_AVAILABLE && this->update_available_trigger_) {
this->defer([this]() { this->update_available_trigger_->trigger(this->update_info_); });
}
#else
// HTTP mode: check every 10s until network is ready (max 6 attempts)
// Only if update interval is > 1 minute to avoid redundant checks
@@ -185,6 +189,8 @@ void Esp32HostedUpdate::check() {
return;
}
const bool was_available = this->state_ == update::UPDATE_STATE_AVAILABLE;
// Compare versions
if (this->update_info_.latest_version.empty() ||
this->update_info_.latest_version == this->update_info_.current_version) {
@@ -197,6 +203,9 @@ void Esp32HostedUpdate::check() {
this->update_info_.progress = 0.0f;
this->status_clear_error();
this->publish_state();
if (this->state_ == update::UPDATE_STATE_AVAILABLE && !was_available && this->update_available_trigger_) {
this->update_available_trigger_->trigger(this->update_info_);
}
#endif
}
+10 -8
View File
@@ -3,6 +3,7 @@ from pathlib import Path
import platform
import re
import subprocess
from typing import Any
import esphome.codegen as cg
import esphome.config_validation as cv
@@ -31,6 +32,7 @@ from esphome.core import (
from esphome.core.config import BOARD_MAX_LENGTH
from esphome.helpers import IS_MACOS, copy_file_if_changed
from esphome.platformio.toolchain import copy_ccache_script
from esphome.storage_json import StorageJSON
from esphome.types import ConfigType
from .boards import BOARDS, ESP8266_LD_SCRIPTS
@@ -88,7 +90,7 @@ def lambdas_use_scanf_float(config: ConfigType) -> bool:
return False
def set_core_data(config):
def set_core_data(config: ConfigType) -> ConfigType:
CORE.data[KEY_ESP8266] = {}
CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_ESP8266
CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "arduino"
@@ -102,7 +104,7 @@ def set_core_data(config):
return config
def get_download_types(storage_json):
def get_download_types(storage_json: StorageJSON) -> list[dict[str, str]]:
"""Binary-download entries for a built ESP8266 firmware.
Used by device-builder (esphome/device-builder), via
@@ -157,7 +159,7 @@ ARDUINO_3_PLATFORM_VERSION = cv.Version(3, 2, 0)
ARDUINO_4_PLATFORM_VERSION = cv.Version(4, 2, 1)
def _arduino_check_versions(value):
def _arduino_check_versions(value: ConfigType) -> ConfigType:
value = value.copy()
lookups = {
"dev": (cv.Version(3, 1, 2), "https://github.com/esp8266/Arduino.git"),
@@ -200,7 +202,7 @@ def _arduino_check_versions(value):
return value
def _parse_platform_version(value):
def _parse_platform_version(value: Any) -> str:
try:
# if platform version is a valid version constraint, prefix the default package
cv.platformio_version_constraint(value)
@@ -275,7 +277,7 @@ def check_rosetta() -> None:
@coroutine_with_priority(CoroPriority.PLATFORM)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
cg.add(esp8266_ns.setup_preferences())
cg.add_platformio_option("lib_ldf_mode", "off")
@@ -504,7 +506,7 @@ ESP8266_EXCEPTION_CODES = {
}
def _decode_pc(config, addr):
def _decode_pc(config: ConfigType, addr: str) -> None:
from esphome.platformio import toolchain
idedata = toolchain.get_idedata(config)
@@ -525,7 +527,7 @@ def _decode_pc(config, addr):
_LOGGER.warning("Decoded %s", translation)
def _parse_register(config, regex, line):
def _parse_register(config: ConfigType, regex: re.Pattern[str], line: str) -> None:
match = regex.match(line)
if match is not None:
_decode_pc(config, match.group(1))
@@ -549,7 +551,7 @@ STACKTRACE_BAD_ALLOC_RE = re.compile(
STACKTRACE_ESP8266_BACKTRACE_PC_RE = re.compile(r"4[0-9a-f]{7}")
def process_stacktrace(config, line, backtrace_state):
def process_stacktrace(config: ConfigType, line: str, backtrace_state: bool) -> bool:
line = line.strip()
# ESP8266 Exception type
match = re.match(STACKTRACE_ESP8266_EXCEPTION_TYPE_RE, line)
+9 -4
View File
@@ -118,8 +118,6 @@ static const LogString *get_exception_cause(uint32_t cause) {
}
static const LogString *get_reset_reason(uint32_t reason) {
if (reason == REASON_WDT_RST)
return LOG_STR("Hardware WDT");
if (reason == REASON_EXCEPTION_RST)
return LOG_STR("Exception");
if (reason == REASON_SOFT_WDT_RST)
@@ -162,13 +160,20 @@ void crash_handler_log() {
if (!is_crash_reason(resetInfo.reason))
return;
ESP_LOGE(TAG, "*** CRASH DETECTED ON PREVIOUS BOOT ***");
if (resetInfo.reason == REASON_WDT_RST) {
// A hardware WDT reset happens entirely in hardware: the postmortem hook
// never runs, so rst_info epc1/exccause and the RTC backtrace are
// leftovers from an earlier crash. Don't misattribute them (#18596).
ESP_LOGE(TAG, " Reason: Hardware WDT (no crash state is recorded for hardware WDT resets)");
return;
}
// Read and filter backtrace from RTC into stack-local buffer (no persistent RAM cost).
// Both resetInfo and RTC data survive until the next reset, so this can be
// called multiple times (logger init + API subscribe) with the same result.
uint32_t backtrace[MAX_BACKTRACE];
uint8_t bt_count = read_rtc_backtrace(backtrace, MAX_BACKTRACE);
ESP_LOGE(TAG, "*** CRASH DETECTED ON PREVIOUS BOOT ***");
// GCC's ROM divide routine triggers IllegalInstruction (exccause=0) at specific
// ROM addresses instead of IntegerDivideByZero (exccause=6). Patch to match
// the Arduino core's postmortem handler behavior.
+9 -6
View File
@@ -1,5 +1,6 @@
from dataclasses import dataclass
import logging
from typing import Any
from esphome import pins
import esphome.codegen as cg
@@ -18,6 +19,8 @@ from esphome.const import (
PLATFORM_ESP8266,
)
from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.cpp_generator import MockObj
from esphome.types import ConfigType
from . import boards
from .const import KEY_BOARD, KEY_ESP8266, KEY_PIN_INITIAL_STATES, esp8266_ns
@@ -27,7 +30,7 @@ _LOGGER = logging.getLogger(__name__)
ESP8266GPIOPin = esp8266_ns.class_("ESP8266GPIOPin", cg.InternalGPIOPin)
def _lookup_pin(value):
def _lookup_pin(value: str) -> int:
board = CORE.data[KEY_ESP8266][KEY_BOARD]
board_pins = boards.ESP8266_BOARD_PINS.get(board, {})
@@ -42,7 +45,7 @@ def _lookup_pin(value):
raise cv.Invalid(f"Cannot resolve pin name '{value}' for board {board}.")
def _translate_pin(value):
def _translate_pin(value: Any) -> int:
if isinstance(value, dict) or value is None:
raise cv.Invalid(
"This variable only supports pin numbers, not full pin schemas "
@@ -69,7 +72,7 @@ _ESP_SDIO_PINS = {
}
def validate_gpio_pin(value):
def validate_gpio_pin(value: Any) -> int:
value = _translate_pin(value)
if value < 0 or value > 17:
raise cv.Invalid(f"ESP8266: Invalid pin number: {value}")
@@ -86,7 +89,7 @@ def validate_gpio_pin(value):
return value
def validate_supports(value):
def validate_supports(value: ConfigType) -> ConfigType:
num = value[CONF_NUMBER]
mode = value[CONF_MODE]
is_input = mode[CONF_INPUT]
@@ -160,7 +163,7 @@ class PinInitialState:
@pins.PIN_SCHEMA_REGISTRY.register(PLATFORM_ESP8266, ESP8266_PIN_SCHEMA)
async def esp8266_pin_to_code(config):
async def esp8266_pin_to_code(config: ConfigType) -> MockObj:
var = cg.new_Pvariable(config[CONF_ID])
num = config[CONF_NUMBER]
mode = config[CONF_MODE]
@@ -192,7 +195,7 @@ async def esp8266_pin_to_code(config):
@coroutine_with_priority(CoroPriority.WORKAROUNDS)
async def add_pin_initial_states_array():
async def add_pin_initial_states_array() -> None:
# Add includes at the very end, so that they override everything
initial_states: list[PinInitialState] = CORE.data[KEY_ESP8266][
KEY_PIN_INITIAL_STATES
@@ -588,8 +588,6 @@ bool ESPHomeOTAComponent::writeall_(const uint8_t *buf, size_t len) {
}
float ESPHomeOTAComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
uint16_t ESPHomeOTAComponent::get_port() const { return this->port_; }
void ESPHomeOTAComponent::set_port(uint16_t port) { this->port_ = port; }
void ESPHomeOTAComponent::log_socket_error_(const LogString *msg) {
ESP_LOGW(TAG, "Socket %s: errno %d", LOG_STR_ARG(msg), errno);
+2 -2
View File
@@ -39,14 +39,14 @@ class ESPHomeOTAComponent final : public ota::OTAComponent {
#endif // USE_OTA_PASSWORD
/// Manually set the port OTA should listen on
void set_port(uint16_t port);
void set_port(uint16_t port) { this->port_ = port; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
void loop() override;
uint16_t get_port() const;
uint16_t get_port() const { return this->port_; }
protected:
void handle_handshake_();
+17 -10
View File
@@ -48,10 +48,12 @@ from esphome.const import (
)
from esphome.core import (
CORE,
ID,
CoroPriority,
TimePeriodMilliseconds,
coroutine_with_priority,
)
from esphome.cpp_generator import MockObj, TemplateArgsType
import esphome.final_validate as fv
from esphome.types import ConfigType
@@ -276,7 +278,7 @@ def _validate_spi_interface(config: ConfigType) -> ConfigType:
return config
def _validate(config):
def _validate(config: ConfigType) -> ConfigType:
if CONF_USE_ADDRESS not in config:
if CONF_MANUAL_IP in config:
use_address = str(config[CONF_MANUAL_IP][CONF_STATIC_IP])
@@ -441,7 +443,7 @@ GENERIC_SCHEMA = cv.All(
)
def _spi_schema(default_clock: str = "26.67MHz", max_clock: int = int(80e6)):
def _spi_schema(default_clock: str = "26.67MHz", max_clock: int = int(80e6)) -> cv.All:
return cv.All(
BASE_SCHEMA.extend(
cv.Schema(
@@ -517,7 +519,7 @@ CONFIG_SCHEMA = cv.All(
)
def _final_validate_spi(config):
def _final_validate_spi(config: ConfigType) -> None:
if not CORE.is_esp32:
return # SPI interface validation is ESP32-only
if config[CONF_TYPE] not in SPI_ETHERNET_TYPES:
@@ -537,7 +539,7 @@ def _final_validate_spi(config):
)
def manual_ip(config):
def manual_ip(config: ConfigType) -> cg.StructInitializer:
return cg.StructInitializer(
ManualIP,
("static_ip", ip_address_literal(config[CONF_STATIC_IP])),
@@ -548,7 +550,7 @@ def manual_ip(config):
)
def phy_register(address: int, value: int, page: int):
def phy_register(address: int, value: int, page: int) -> cg.StructInitializer:
return cg.StructInitializer(
PHYRegister,
("address", address),
@@ -558,7 +560,7 @@ def phy_register(address: int, value: int, page: int):
@coroutine_with_priority(CoroPriority.COMMUNICATION)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
# Apply network priority before register_component (which emits the user's
@@ -610,7 +612,7 @@ async def to_code(config):
CORE.add_job(final_step)
async def _to_code_esp32(var: cg.Pvariable, config: ConfigType) -> None:
async def _to_code_esp32(var: cg.MockObj, config: ConfigType) -> None:
from esphome.components.esp32 import (
add_idf_component,
add_idf_sdkconfig_option,
@@ -698,7 +700,7 @@ async def _to_code_esp32(var: cg.Pvariable, config: ConfigType) -> None:
add_idf_component(name=component.name, ref=component.version)
async def _to_code_rp2040(var: cg.Pvariable, config: ConfigType) -> None:
async def _to_code_rp2040(var: cg.MockObj, config: ConfigType) -> None:
cg.add(var.set_clk_pin(config[CONF_CLK_PIN]))
cg.add(var.set_miso_pin(config[CONF_MISO_PIN]))
cg.add(var.set_mosi_pin(config[CONF_MOSI_PIN]))
@@ -793,7 +795,7 @@ FINAL_VALIDATE_SCHEMA = _final_validate
@coroutine_with_priority(CoroPriority.FINAL)
async def final_step():
async def final_step() -> None:
"""Final code generation step to configure optional Ethernet features."""
if ip_state_count := CORE.data.get(ETHERNET_IP_STATE_LISTENERS_KEY, 0):
cg.add_define("USE_ETHERNET_IP_STATE_LISTENERS")
@@ -845,7 +847,12 @@ def _filter_source_files() -> list[str]:
FILTER_SOURCE_FILES = _filter_source_files
async def _new_pvariable_to_code(config, id_, template_arg, args):
async def _new_pvariable_to_code(
config: ConfigType,
id_: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
return cg.new_Pvariable(id_, template_arg)
@@ -10,14 +10,6 @@ EthernetComponent *global_eth_component; // NOLINT(cppcoreguidelines-avoid-non-
EthernetComponent::EthernetComponent() { global_eth_component = this; }
float EthernetComponent::get_setup_priority() const { return setup_priority::WIFI; }
void EthernetComponent::set_type(EthernetType type) { this->type_ = type; }
#ifdef USE_ETHERNET_MANUAL_IP
void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; }
#endif
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
void EthernetComponent::notify_ip_state_listeners_() {
auto ips = this->get_ip_addresses();
@@ -125,7 +125,7 @@ class EthernetComponent final : public Component {
void setup() override;
void loop() override;
void dump_config() override;
float get_setup_priority() const override;
float get_setup_priority() const override { return setup_priority::ETHERNET; }
void on_powerdown() override { powerdown(); }
bool is_connected() { return this->state_ == EthernetComponentState::CONNECTED; }
@@ -146,9 +146,9 @@ class EthernetComponent final : public Component {
esp_netif_t *get_esp_netif() { return this->eth_netif_; }
#endif
void set_type(EthernetType type);
void set_type(EthernetType type) { this->type_ = type; }
#ifdef USE_ETHERNET_MANUAL_IP
void set_manual_ip(const ManualIP &manual_ip);
void set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; }
#endif
void set_fixed_mac(const std::array<uint8_t, MAC_ADDRESS_SIZE> &mac) { this->fixed_mac_ = mac; }
@@ -171,35 +171,35 @@ class EthernetComponent final : public Component {
esp_eth_handle_t get_eth_handle() const { return this->eth_handle_; }
#ifdef USE_ETHERNET_SPI
void set_clk_pin(uint8_t clk_pin);
void set_miso_pin(uint8_t miso_pin);
void set_mosi_pin(uint8_t mosi_pin);
void set_cs_pin(uint8_t cs_pin);
void set_interrupt_pin(uint8_t interrupt_pin);
void set_reset_pin(uint8_t reset_pin);
void set_clock_speed(int clock_speed);
void set_interface(spi_host_device_t interface);
void set_clk_pin(uint8_t clk_pin) { this->clk_pin_ = clk_pin; }
void set_miso_pin(uint8_t miso_pin) { this->miso_pin_ = miso_pin; }
void set_mosi_pin(uint8_t mosi_pin) { this->mosi_pin_ = mosi_pin; }
void set_cs_pin(uint8_t cs_pin) { this->cs_pin_ = cs_pin; }
void set_interrupt_pin(uint8_t interrupt_pin) { this->interrupt_pin_ = interrupt_pin; }
void set_reset_pin(uint8_t reset_pin) { this->reset_pin_ = reset_pin; }
void set_clock_speed(int clock_speed) { this->clock_speed_ = clock_speed; }
void set_interface(spi_host_device_t interface) { this->interface_ = interface; }
#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
void set_polling_interval(uint32_t polling_interval);
void set_polling_interval(uint32_t polling_interval) { this->polling_interval_ = polling_interval; }
#endif
#else
void set_phy_addr(uint8_t phy_addr);
void set_power_pin(int power_pin);
void set_mdc_pin(uint8_t mdc_pin);
void set_mdio_pin(uint8_t mdio_pin);
void set_clk_pin(uint8_t clk_pin);
void set_clk_mode(emac_rmii_clock_mode_t clk_mode);
void set_phy_addr(uint8_t phy_addr) { this->phy_addr_ = phy_addr; }
void set_power_pin(int power_pin) { this->power_pin_ = power_pin; }
void set_mdc_pin(uint8_t mdc_pin) { this->mdc_pin_ = mdc_pin; }
void set_mdio_pin(uint8_t mdio_pin) { this->mdio_pin_ = mdio_pin; }
void set_clk_pin(uint8_t clk_pin) { this->clk_pin_ = clk_pin; }
void set_clk_mode(emac_rmii_clock_mode_t clk_mode) { this->clk_mode_ = clk_mode; }
void add_phy_register(PHYRegister register_value);
#endif // USE_ETHERNET_SPI
#endif // USE_ESP32
#ifdef USE_RP2
void set_clk_pin(uint8_t clk_pin);
void set_miso_pin(uint8_t miso_pin);
void set_mosi_pin(uint8_t mosi_pin);
void set_cs_pin(uint8_t cs_pin);
void set_interrupt_pin(int8_t interrupt_pin);
void set_reset_pin(int8_t reset_pin);
void set_clk_pin(uint8_t clk_pin) { this->clk_pin_ = clk_pin; }
void set_miso_pin(uint8_t miso_pin) { this->miso_pin_ = miso_pin; }
void set_mosi_pin(uint8_t mosi_pin) { this->mosi_pin_ = mosi_pin; }
void set_cs_pin(uint8_t cs_pin) { this->cs_pin_ = cs_pin; }
void set_interrupt_pin(int8_t interrupt_pin) { this->interrupt_pin_ = interrupt_pin; }
void set_reset_pin(int8_t reset_pin) { this->reset_pin_ = reset_pin; }
#endif // USE_RP2
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
@@ -908,25 +908,7 @@ void EthernetComponent::dump_connect_params_() {
#endif /* USE_NETWORK_IPV6 */
}
#ifdef USE_ETHERNET_SPI
void EthernetComponent::set_clk_pin(uint8_t clk_pin) { this->clk_pin_ = clk_pin; }
void EthernetComponent::set_miso_pin(uint8_t miso_pin) { this->miso_pin_ = miso_pin; }
void EthernetComponent::set_mosi_pin(uint8_t mosi_pin) { this->mosi_pin_ = mosi_pin; }
void EthernetComponent::set_cs_pin(uint8_t cs_pin) { this->cs_pin_ = cs_pin; }
void EthernetComponent::set_interrupt_pin(uint8_t interrupt_pin) { this->interrupt_pin_ = interrupt_pin; }
void EthernetComponent::set_reset_pin(uint8_t reset_pin) { this->reset_pin_ = reset_pin; }
void EthernetComponent::set_clock_speed(int clock_speed) { this->clock_speed_ = clock_speed; }
void EthernetComponent::set_interface(spi_host_device_t interface) { this->interface_ = interface; }
#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
void EthernetComponent::set_polling_interval(uint32_t polling_interval) { this->polling_interval_ = polling_interval; }
#endif
#else
void EthernetComponent::set_phy_addr(uint8_t phy_addr) { this->phy_addr_ = phy_addr; }
void EthernetComponent::set_power_pin(int power_pin) { this->power_pin_ = power_pin; }
void EthernetComponent::set_mdc_pin(uint8_t mdc_pin) { this->mdc_pin_ = mdc_pin; }
void EthernetComponent::set_mdio_pin(uint8_t mdio_pin) { this->mdio_pin_ = mdio_pin; }
void EthernetComponent::set_clk_pin(uint8_t clk_pin) { this->clk_pin_ = clk_pin; }
void EthernetComponent::set_clk_mode(emac_rmii_clock_mode_t clk_mode) { this->clk_mode_ = clk_mode; }
#ifndef USE_ETHERNET_SPI
void EthernetComponent::add_phy_register(PHYRegister register_value) { this->phy_registers_.push_back(register_value); }
#endif
@@ -355,13 +355,6 @@ void EthernetComponent::dump_connect_params_() {
this->get_eth_mac_address_pretty_into_buffer(mac_buf));
}
void EthernetComponent::set_clk_pin(uint8_t clk_pin) { this->clk_pin_ = clk_pin; }
void EthernetComponent::set_miso_pin(uint8_t miso_pin) { this->miso_pin_ = miso_pin; }
void EthernetComponent::set_mosi_pin(uint8_t mosi_pin) { this->mosi_pin_ = mosi_pin; }
void EthernetComponent::set_cs_pin(uint8_t cs_pin) { this->cs_pin_ = cs_pin; }
void EthernetComponent::set_interrupt_pin(int8_t interrupt_pin) { this->interrupt_pin_ = interrupt_pin; }
void EthernetComponent::set_reset_pin(int8_t reset_pin) { this->reset_pin_ = reset_pin; }
void EthernetComponent::enable() {
// RP2040 uses arduino-pico's LwipIntfDev which manages link state internally;
// there is no clean enable/disable hook today. The YAML option is accepted on
-5
View File
@@ -153,11 +153,6 @@ void FanRestoreState::apply(Fan &fan) {
fan.publish_state();
}
FanCall Fan::turn_on() { return this->make_call().set_state(true); }
FanCall Fan::turn_off() { return this->make_call().set_state(false); }
FanCall Fan::toggle() { return this->make_call().set_state(!this->state); }
FanCall Fan::make_call() { return FanCall(*this); }
const char *Fan::find_preset_mode_(const char *preset_mode) {
return this->find_preset_mode_(preset_mode, preset_mode ? strlen(preset_mode) : 0);
}
+4 -4
View File
@@ -115,10 +115,10 @@ class Fan : public EntityBase {
/// The current direction of the fan
FanDirection direction{FanDirection::FORWARD};
FanCall turn_on();
FanCall turn_off();
FanCall toggle();
FanCall make_call();
FanCall turn_on() { return this->make_call().set_state(true); }
FanCall turn_off() { return this->make_call().set_state(false); }
FanCall toggle() { return this->make_call().set_state(!this->state); }
FanCall make_call() { return FanCall(*this); }
/// Register a callback that will be called each time the state changes.
template<typename F> void add_on_state_callback(F &&callback) {
+10 -7
View File
@@ -5,6 +5,7 @@ import io
import logging
from pathlib import Path
import re
from typing import Any
from PIL import Image, UnidentifiedImageError
@@ -75,12 +76,12 @@ def compute_local_image_path(value: str | ConfigType) -> Path:
return external_files.compute_local_file_path(DOMAIN, url)
def local_path(value):
def local_path(value: str | ConfigType) -> str:
value = value[CONF_PATH] if isinstance(value, dict) else value
return str(CORE.relative_config_path(value))
def download_file(url, path):
def download_file(url: str, path: Path) -> str:
# The shared NETWORK_TIMEOUT applies; a per-caller timeout would be
# silently ignored on a per-run memo hit anyway (memos key by path).
external_files.download_content(url, path)
@@ -98,7 +99,7 @@ def download_gh_svg(value: str | ConfigType, source: str) -> str:
return download_file(url, path)
def download_image(value):
def download_image(value: str | ConfigType) -> str:
value = value[CONF_URL] if isinstance(value, dict) else value
return download_file(value, compute_local_image_path(value))
@@ -146,7 +147,7 @@ def _extract_entry_ref(entry: ConfigType) -> RemoteFile | None:
PREFETCH_FILES = external_files.single_stage_prefetch(_extract_entry_ref)
def validate_file_shorthand(value):
def validate_file_shorthand(value: Any) -> str:
value = cv.string_strict(value)
if (remote := _parse_remote_shorthand(value)) is not None:
return download_file(remote.url, remote.path)
@@ -163,8 +164,8 @@ LOCAL_SCHEMA = cv.All(
)
def mdi_schema(source):
def validate_mdi(value):
def mdi_schema(source: str) -> cv.All:
def validate_mdi(value: ConfigType) -> str:
return download_gh_svg(value, source)
return cv.All(
@@ -259,7 +260,9 @@ async def new_image(config: ConfigType) -> MockObj:
return var
async def write_image(config, all_frames=False):
async def write_image(
config: ConfigType, all_frames: bool = False
) -> tuple[MockObj, int, int, MockObj, MockObj, int]:
path = Path(config[CONF_FILE])
if not path.is_file():
raise core.EsphomeError(f"Could not load image file {path}")
+9 -3
View File
@@ -8,7 +8,8 @@ from esphome.const import (
CONF_TYPE,
CONF_VALUE,
)
from esphome.core import CoroPriority, coroutine_with_priority
from esphome.core import ID, CoroPriority, coroutine_with_priority
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@esphome/core"]
@@ -62,7 +63,7 @@ CONFIG_SCHEMA = _globals_schema
# Run with low priority so that namespaces are registered first
@coroutine_with_priority(CoroPriority.LATE)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
type_ = cg.RawExpression(config[CONF_TYPE])
restore = config[CONF_RESTORE_VALUE]
@@ -104,7 +105,12 @@ async def to_code(config):
),
synchronous=True,
)
async def globals_set_to_code(config, action_id, template_arg, args):
async def globals_set_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
full_id, paren = await cg.get_variable_with_full_id(config[CONF_ID])
template_arg = cg.TemplateArguments(full_id.type, *template_arg)
var = cg.new_Pvariable(action_id, template_arg, paren)
@@ -12,6 +12,7 @@ from esphome.const import (
CONF_PIN,
)
from esphome.core import CORE
from esphome.types import ConfigType
from .. import gpio_ns
@@ -68,7 +69,7 @@ def _pin_shared_only_with_deep_sleep(pin_num: int) -> bool:
return any(path and path[0] == "deep_sleep" for path, _, _ in pin_users)
def _final_validate(config) -> None:
def _final_validate(config: ConfigType) -> None:
use_interrupt = config[CONF_USE_INTERRUPT]
if not use_interrupt:
return
@@ -124,7 +125,7 @@ def _final_validate(config) -> None:
FINAL_VALIDATE_SCHEMA = _final_validate
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = await binary_sensor.new_binary_sensor(config)
await cg.register_component(var, config)
+2 -1
View File
@@ -3,6 +3,7 @@ import esphome.codegen as cg
from esphome.components.one_wire import OneWireBus
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_PIN
from esphome.types import ConfigType
from .. import gpio_ns
@@ -18,7 +19,7 @@ CONFIG_SCHEMA = cv.Schema(
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
+2 -1
View File
@@ -3,6 +3,7 @@ import esphome.codegen as cg
from esphome.components import output
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_PIN
from esphome.types import ConfigType
from .. import gpio_ns
@@ -16,7 +17,7 @@ CONFIG_SCHEMA = output.BINARY_OUTPUT_SCHEMA.extend(
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await output.register_output(var, config)
await cg.register_component(var, config)
+2 -1
View File
@@ -3,6 +3,7 @@ import esphome.codegen as cg
from esphome.components import switch
import esphome.config_validation as cv
from esphome.const import CONF_INTERLOCK, CONF_PIN
from esphome.types import ConfigType
from .. import gpio_ns
@@ -24,7 +25,7 @@ CONFIG_SCHEMA = (
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = await switch.new_switch(config)
await cg.register_component(var, config)
+19 -4
View File
@@ -1,3 +1,5 @@
from typing import Any
from esphome import automation
from esphome.automation import maybe_simple_id
import esphome.codegen as cg
@@ -16,6 +18,9 @@ from esphome.const import (
UNIT_CELSIUS,
UNIT_PERCENT,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
DEPENDENCIES = ["i2c"]
@@ -62,7 +67,7 @@ CONFIG_SCHEMA = (
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
@@ -86,7 +91,7 @@ HDC302X_HEATER_POWER_MAP = {
}
def heater_power_value(value):
def heater_power_value(value: Any) -> cv.Lambda | int:
"""Accept enum names or raw uint16 values"""
if isinstance(value, cv.Lambda):
return value
@@ -119,7 +124,12 @@ HDC302X_HEATER_ON_ACTION_SCHEMA = maybe_simple_id(
HDC302X_HEATER_ON_ACTION_SCHEMA,
synchronous=True,
)
async def hdc302x_heater_on_to_code(config, action_id, template_arg, args):
async def hdc302x_heater_on_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
template_ = await cg.templatable(config[CONF_POWER], args, cg.uint16)
@@ -135,7 +145,12 @@ async def hdc302x_heater_on_to_code(config, action_id, template_arg, args):
HDC302X_ACTION_SCHEMA,
synchronous=True,
)
async def hdc302x_heater_off_to_code(config, action_id, template_arg, args):
async def hdc302x_heater_off_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
+9 -3
View File
@@ -1,13 +1,19 @@
from collections.abc import Callable, Iterable
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_ATTRIBUTE, CONF_ENTITY_ID, CONF_INTERNAL
from esphome.cpp_generator import MockObj
from esphome.types import ConfigType
CODEOWNERS = ["@OttoWinter", "@esphome/core"]
homeassistant_ns = cg.esphome_ns.namespace("homeassistant")
def validate_entity_domain(platform, supported_domains):
def validator(config):
def validate_entity_domain(
platform: str, supported_domains: Iterable[str]
) -> Callable[[ConfigType], ConfigType]:
def validator(config: ConfigType) -> ConfigType:
domain = config[CONF_ENTITY_ID].split(".", 1)[0]
if domain not in supported_domains:
raise cv.Invalid(
@@ -34,7 +40,7 @@ HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA = cv.Schema(
)
def setup_home_assistant_entity(var, config):
def setup_home_assistant_entity(var: MockObj, config: ConfigType) -> None:
cg.add(var.set_entity_id(config[CONF_ENTITY_ID]))
if CONF_ATTRIBUTE in config:
cg.add(var.set_attribute(config[CONF_ATTRIBUTE]))
@@ -1,5 +1,6 @@
import esphome.codegen as cg
from esphome.components import binary_sensor
from esphome.types import ConfigType
from .. import (
HOME_ASSISTANT_IMPORT_SCHEMA,
@@ -18,7 +19,7 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(HomeassistantBinarySensor).ex
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = await binary_sensor.new_binary_sensor(config)
await cg.register_component(var, config)
setup_home_assistant_entity(var, config)
@@ -1,6 +1,7 @@
import esphome.codegen as cg
from esphome.components import number
import esphome.config_validation as cv
from esphome.types import ConfigType
from .. import (
HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA,
@@ -22,7 +23,7 @@ CONFIG_SCHEMA = (
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
cg.add_define("USE_API_HOMEASSISTANT_SERVICES")
var = await number.new_number(
config,
@@ -1,5 +1,6 @@
import esphome.codegen as cg
from esphome.components import sensor
from esphome.types import ConfigType
from .. import (
HOME_ASSISTANT_IMPORT_SCHEMA,
@@ -18,7 +19,7 @@ CONFIG_SCHEMA = sensor.sensor_schema(HomeassistantSensor, accuracy_decimals=1).e
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = await sensor.new_sensor(config)
await cg.register_component(var, config)
setup_home_assistant_entity(var, config)
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import switch
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.types import ConfigType
from .. import (
HOME_ASSISTANT_IMPORT_CONTROL_SCHEMA,
@@ -36,7 +37,7 @@ CONFIG_SCHEMA = cv.All(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
cg.add_define("USE_API_HOMEASSISTANT_SERVICES")
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
@@ -1,5 +1,6 @@
import esphome.codegen as cg
from esphome.components import text_sensor
from esphome.types import ConfigType
from .. import (
HOME_ASSISTANT_IMPORT_SCHEMA,
@@ -18,7 +19,7 @@ CONFIG_SCHEMA = text_sensor.text_sensor_schema(HomeassistantTextSensor).extend(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = await text_sensor.new_text_sensor(config)
await cg.register_component(var, config)
setup_home_assistant_entity(var, config)
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import time as time_
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_TIMEZONE
from esphome.types import ConfigType
from .. import homeassistant_ns
@@ -16,7 +17,7 @@ CONFIG_SCHEMA = time_.TIME_SCHEMA.extend(
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await time_.register_time(var, config)
await cg.register_component(var, config)
+3 -2
View File
@@ -11,6 +11,7 @@ from esphome.const import (
)
from esphome.core import CORE
from esphome.platformio.toolchain import copy_ccache_script
from esphome.types import ConfigType
from .const import KEY_HOST
@@ -22,7 +23,7 @@ AUTO_LOAD = ["network", "preferences"]
IS_TARGET_PLATFORM = True
def set_core_data(config):
def set_core_data(config: ConfigType) -> ConfigType:
CORE.data[KEY_HOST] = {}
CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_HOST
CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "host"
@@ -40,7 +41,7 @@ CONFIG_SCHEMA = cv.All(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
cg.add_build_flag("-DUSE_HOST")
cg.add_define("USE_NATIVE_64BIT_TIME")
# The prefs file finds stored preferences by key, so key migration is possible
+6 -3
View File
@@ -1,4 +1,5 @@
import logging
from typing import Any
from esphome import pins
import esphome.codegen as cg
@@ -14,6 +15,8 @@ from esphome.const import (
CONF_PULLDOWN,
CONF_PULLUP,
)
from esphome.cpp_generator import MockObj
from esphome.types import ConfigType
from .const import host_ns
@@ -22,7 +25,7 @@ _LOGGER = logging.getLogger(__name__)
HostGPIOPin = host_ns.class_("HostGPIOPin", cg.InternalGPIOPin)
def _translate_pin(value):
def _translate_pin(value: Any) -> int | str:
if isinstance(value, dict) or value is None:
raise cv.Invalid(
"This variable only supports pin numbers, not full pin schemas "
@@ -41,7 +44,7 @@ def _translate_pin(value):
return value
def validate_gpio_pin(value):
def validate_gpio_pin(value: Any) -> int | str:
return _translate_pin(value)
@@ -53,7 +56,7 @@ HOST_PIN_SCHEMA = pins.gpio_base_schema(
@pins.PIN_SCHEMA_REGISTRY.register("host", HOST_PIN_SCHEMA)
async def host_pin_to_code(config):
async def host_pin_to_code(config: ConfigType) -> MockObj:
var = cg.new_Pvariable(config[CONF_ID])
num = config[CONF_NUMBER]
cg.add(var.set_pin(num))
+2 -1
View File
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import time as time_
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.types import ConfigType
CODEOWNERS = ["@clydebarrow"]
@@ -14,7 +15,7 @@ CONFIG_SCHEMA = time_.TIME_SCHEMA.extend(
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await time_.register_time(var, config)
+16 -3
View File
@@ -17,6 +17,9 @@ from esphome.const import (
UNIT_EMPTY,
UNIT_PERCENT,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
DEPENDENCIES = ["i2c"]
@@ -63,7 +66,7 @@ CONFIG_SCHEMA = (
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
@@ -95,7 +98,12 @@ async def to_code(config):
),
synchronous=True,
)
async def set_heater_level_to_code(config, action_id, template_arg, args):
async def set_heater_level_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
level_ = await cg.templatable(config[CONF_LEVEL], args, cg.uint8)
@@ -115,7 +123,12 @@ async def set_heater_level_to_code(config, action_id, template_arg, args):
),
synchronous=True,
)
async def set_heater_to_code(config, action_id, template_arg, args):
async def set_heater_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
status_ = await cg.templatable(config[CONF_STATUS], args, cg.bool_)
+17 -15
View File
@@ -1,6 +1,7 @@
import logging
import re
import sys
from typing import Any
from esphome import pins
import esphome.codegen as cg
@@ -52,9 +53,10 @@ from esphome.const import (
PLATFORM_RP2,
PlatformFramework,
)
from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core import CORE, ID, CoroPriority, coroutine_with_priority
from esphome.cpp_generator import MockObj
import esphome.final_validate as fv
from esphome.types import ConfigType
LOGGER = logging.getLogger(__name__)
CODEOWNERS = ["@esphome/core"]
@@ -96,13 +98,13 @@ CONF_SCL_PULLUP_ENABLED = "scl_pullup_enabled"
MULTI_CONF = True
def validate_device(value):
def validate_device(value: str) -> str:
if not re.match(r"^/(?:[^/]+/)*[^/]+$", value):
raise cv.Invalid("Device must be an absolute device path (e.g., /dev/i2c-0)")
return value
def _bus_declare_type(value):
def _bus_declare_type(value: Any) -> ID:
if CORE.is_esp32:
return cv.declare_id(IDFI2CBus)(value)
if CORE.using_arduino:
@@ -114,7 +116,7 @@ def _bus_declare_type(value):
raise NotImplementedError
def _rp2040_i2c_controller(pin):
def _rp2040_i2c_controller(pin: int) -> int:
"""Return the I2C controller number (0 or 1) for a given RP2040/RP2350 GPIO pin.
See RP2040 datasheet Table 2 (section 1.4.3, "GPIO Functions"):
@@ -125,7 +127,7 @@ def _rp2040_i2c_controller(pin):
return (pin // 2) % 2
def validate_config(config):
def validate_config(config: ConfigType) -> ConfigType:
if CORE.is_esp32:
return cv.require_framework_version(
esp_idf=cv.Version(5, 4, 2), esp32_arduino=cv.Version(3, 2, 1)
@@ -142,7 +144,7 @@ def validate_config(config):
return config
def validate_host_config(config):
def validate_host_config(config: ConfigType) -> ConfigType:
if CORE.is_host:
# Host I2C is currently only supported on Linux
if not sys.platform.lower().startswith("linux"):
@@ -229,7 +231,7 @@ CONFIG_SCHEMA = cv.All(
)
def _final_validate(config):
def _final_validate(config: ConfigType) -> None:
full_config = fv.full_config.get()[CONF_I2C]
if CORE.using_zephyr and len(full_config) > 1:
raise cv.Invalid("Second i2c is not implemented on Zephyr yet")
@@ -281,7 +283,7 @@ FINAL_VALIDATE_SCHEMA = _final_validate
@coroutine_with_priority(CoroPriority.BUS)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
cg.add_global(i2c_ns.using)
cg.add_define("USE_I2C")
if CORE.is_esp32:
@@ -358,7 +360,7 @@ async def to_code(config):
cg.add(var.set_lp_mode(bool(config[CONF_LOW_POWER_MODE])))
def i2c_device_schema(default_address):
def i2c_device_schema(default_address: int | None) -> cv.Schema:
"""Create a schema for a i2c device.
:param default_address: The default address of the i2c device, can be None to represent
@@ -375,7 +377,7 @@ def i2c_device_schema(default_address):
return cv.Schema(schema)
async def register_i2c_device(var, config):
async def register_i2c_device(var: MockObj, config: ConfigType) -> None:
"""Register an i2c device with the given config.
Sets the i2c bus to use and the i2c address.
@@ -390,11 +392,11 @@ async def register_i2c_device(var, config):
def final_validate_device_schema(
name: str,
*,
min_frequency: cv.frequency = None,
max_frequency: cv.frequency = None,
min_timeout: cv.time_period = None,
max_timeout: cv.time_period = None,
):
min_frequency: Any = None,
max_frequency: Any = None,
min_timeout: Any = None,
max_timeout: Any = None,
) -> cv.Schema:
hub_schema = {}
if (min_frequency is not None) and (max_frequency is not None):
hub_schema[cv.Required(CONF_FREQUENCY)] = cv.Range(
-2
View File
@@ -75,8 +75,6 @@ void Infrared::dump_config() {
YESNO(this->traits_.get_supports_receiver()));
}
InfraredCall Infrared::make_call() { return InfraredCall(this); }
void Infrared::control(const InfraredCall &call) {
if (this->transmitter_ == nullptr) {
ESP_LOGW(TAG, "No transmitter configured");
+1 -1
View File
@@ -134,7 +134,7 @@ class Infrared : public Component, public EntityBase, public remote_base::Remote
const InfraredTraits &get_traits() const { return this->traits_; }
/// Create a call object for transmitting
InfraredCall make_call();
InfraredCall make_call() { return InfraredCall(this); }
/// Get capability flags for this infrared instance
uint32_t get_capability_flags() const;
+1 -1
View File
@@ -60,7 +60,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await uart.register_uart_device(var, config)
+2 -1
View File
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import binary_sensor
import esphome.config_validation as cv
from esphome.const import CONF_TARGET, DEVICE_CLASS_OCCUPANCY
from esphome.types import ConfigType
from . import LD6002BComponent
from .const import AREA_COUNT, CONF_LD6002B_ID, MAX_TARGETS
@@ -36,7 +37,7 @@ CONFIG_SCHEMA = (
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_LD6002B_ID])
if target_config := config.get(CONF_TARGET):
@@ -129,7 +129,7 @@ BUTTON_MAP = {
}
async def to_code(config):
async def to_code(config: ConfigType) -> None:
for key, button_type in BUTTON_MAP.items():
if button_config := config.get(key):
b = cg.new_Pvariable(button_config[CONF_ID], button_type)
@@ -136,7 +136,7 @@ def final_validate(config: ConfigType) -> None:
FINAL_VALIDATE_SCHEMA = final_validate
async def to_code(config):
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_LD6002B_ID])
for key, number_type, setter, min_value, max_value, step in (
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import select
import esphome.config_validation as cv
from esphome.const import CONF_AREA_ID, CONF_SENSITIVITY, ENTITY_CATEGORY_CONFIG
from esphome.types import ConfigType
from .. import LD6002BComponent, ld6002b_ns
from ..const import CONF_INSTALLATION_MODE, CONF_LD6002B_ID, CONF_TRIGGER_SPEED
@@ -64,7 +65,7 @@ SELECT_MAP = (
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_LD6002B_ID])
for key, select_type, setter, options in SELECT_MAP:
+2 -1
View File
@@ -9,6 +9,7 @@ from esphome.const import (
STATE_CLASS_MEASUREMENT,
UNIT_METER,
)
from esphome.types import ConfigType
from . import LD6002BComponent
from .const import (
@@ -150,7 +151,7 @@ CONFIG_SCHEMA = (
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_LD6002B_ID])
if target_count_config := config.get(CONF_TARGET_COUNT):
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import switch
import esphome.config_validation as cv
from esphome.const import DEVICE_CLASS_SWITCH, ENTITY_CATEGORY_CONFIG
from esphome.types import ConfigType
from .. import LD6002BComponent, ld6002b_ns
from ..const import (
@@ -46,7 +47,7 @@ CONFIG_SCHEMA = cv.Schema(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_LD6002B_ID])
for key, switch_type, setter in (
+2 -1
View File
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import text_sensor
import esphome.config_validation as cv
from esphome.const import ENTITY_CATEGORY_DIAGNOSTIC
from esphome.types import ConfigType
from . import LD6002BComponent
from .const import CONF_LD6002B_ID, CONF_OTA_VERSION, CONF_WORK_MODE
@@ -21,7 +22,7 @@ CONFIG_SCHEMA = cv.Schema(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_LD6002B_ID])
if work_mode_config := config.get(CONF_WORK_MODE):
sens = await text_sensor.new_text_sensor(work_mode_config)
@@ -13,8 +13,6 @@ ESPColorView ESPRangeView::operator[](int32_t index) const {
index = interpret_index(index, this->size()) + this->begin_;
return (*this->parent_)[index];
}
ESPRangeIterator ESPRangeView::begin() { return {*this, this->begin_}; }
ESPRangeIterator ESPRangeView::end() { return {*this, this->end_}; }
void ESPRangeView::set(const Color &color) {
for (int32_t i = this->begin_; i < this->end_; i++) {
@@ -75,4 +75,7 @@ class ESPRangeIterator {
int32_t i_;
};
inline ESPRangeIterator ESPRangeView::begin() { return {*this, this->begin_}; }
inline ESPRangeIterator ESPRangeView::end() { return {*this, this->end_}; }
} // namespace esphome::light
-18
View File
@@ -157,8 +157,6 @@ void LightState::loop() {
}
}
float LightState::get_setup_priority() const { return setup_priority::HARDWARE - 1.0f; }
void LightState::publish_state() {
if (this->remote_values_listeners_) {
for (auto *listener : *this->remote_values_listeners_) {
@@ -194,25 +192,11 @@ void LightState::add_target_state_reached_listener(LightTargetStateReachedListen
this->target_state_reached_listeners_->push_back(listener);
}
void LightState::set_default_transition_length(uint32_t default_transition_length) {
this->default_transition_length_ = default_transition_length;
}
uint32_t LightState::get_default_transition_length() const { return this->default_transition_length_; }
void LightState::set_flash_transition_length(uint32_t flash_transition_length) {
this->flash_transition_length_ = 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(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) {
// Called once from Python codegen during setup with all effects from YAML config
this->effects_ = effects;
}
void LightState::current_values_as_binary(bool *binary) { this->current_values.as_binary(binary); }
void LightState::current_values_as_brightness(float *brightness) {
this->current_values.as_brightness(brightness);
*brightness = this->gamma_correct_lut(*brightness);
@@ -333,8 +317,6 @@ float LightState::gamma_uncorrect_lut(float value) const {
}
#endif // USE_LIGHT_GAMMA_LUT
bool LightState::is_transformer_active() { return this->is_transformer_active_; }
void LightState::start_effect_(uint32_t effect_index) {
this->stop_effect_();
if (effect_index == 0)
+16 -12
View File
@@ -109,7 +109,7 @@ class LightState : public EntityBase, public Component {
void dump_config() override;
void loop() override;
/// Shortly after HARDWARE.
float get_setup_priority() const override;
float get_setup_priority() const override { return setup_priority::HARDWARE - 1.0f; }
/** The current values of the light as outputted to the light.
*
@@ -157,15 +157,19 @@ class LightState : public EntityBase, public Component {
void add_target_state_reached_listener(LightTargetStateReachedListener *listener);
/// Set the default transition length, i.e. the transition length when no transition is provided.
void set_default_transition_length(uint32_t default_transition_length);
uint32_t get_default_transition_length() const;
void set_default_transition_length(uint32_t default_transition_length) {
this->default_transition_length_ = default_transition_length;
}
uint32_t get_default_transition_length() const { return this->default_transition_length_; }
/// Set the flash transition length
void set_flash_transition_length(uint32_t flash_transition_length);
uint32_t get_flash_transition_length() const;
void set_flash_transition_length(uint32_t flash_transition_length) {
this->flash_transition_length_ = flash_transition_length;
}
uint32_t get_flash_transition_length() const { return this->flash_transition_length_; }
/// Set the gamma correction factor
void set_gamma_correct(float gamma_correct);
void set_gamma_correct(float gamma_correct) { this->gamma_correct_ = gamma_correct; }
float get_gamma_correct() const { return this->gamma_correct_; }
#ifdef USE_LIGHT_GAMMA_LUT
@@ -186,17 +190,17 @@ class LightState : public EntityBase, public Component {
#endif // USE_LIGHT_GAMMA_LUT
/// Set the restore mode of this light
void set_restore_mode(LightRestoreMode restore_mode);
void set_restore_mode(LightRestoreMode restore_mode) { this->restore_mode_ = restore_mode; }
/// 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 &));
void set_initial_state(void (*callback)(LightStateRTCState &)) { this->initial_state_callback_ = callback; }
/// Return whether the light has any effects that meet the trait requirements.
bool supports_effects();
bool supports_effects() const { return !this->effects_.empty(); }
/// Get all effects for this light state.
const FixedVector<LightEffect *> &get_effects() const;
const FixedVector<LightEffect *> &get_effects() const { return this->effects_; }
/// Add effects for this light state.
void add_effects(const std::initializer_list<LightEffect *> &effects);
@@ -254,7 +258,7 @@ class LightState : public EntityBase, public Component {
}
/// The result of all the current_values_as_* methods have gamma correction applied.
void current_values_as_binary(bool *binary);
void current_values_as_binary(bool *binary) { this->current_values.as_binary(binary); }
void current_values_as_brightness(float *brightness);
@@ -281,7 +285,7 @@ class LightState : public EntityBase, public Component {
* return;
* }
*/
bool is_transformer_active();
bool is_transformer_active() const { return this->is_transformer_active_; }
protected:
friend LightOutput;
+25 -9
View File
@@ -12,13 +12,14 @@ from esphome.const import (
CONF_ON_UNLOCK,
CONF_WEB_SERVER,
)
from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core import CORE, ID, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import (
entity_duplicate_validator,
queue_entity_register,
setup_entity,
)
from esphome.cpp_generator import MockObjClass
from esphome.cpp_generator import MockObj, MockObjClass, TemplateArgsType
from esphome.types import ConfigType, SafeExpType
CODEOWNERS = ["@esphome/core"]
IS_PLATFORM_COMPONENT = True
@@ -102,7 +103,7 @@ _CALLBACK_AUTOMATIONS = (
@setup_entity("lock")
async def _setup_lock_core(var, config):
async def _setup_lock_core(var: MockObj, config: ConfigType) -> None:
await automation.build_callback_automations(var, config, _CALLBACK_AUTOMATIONS)
if mqtt_id := config.get(CONF_MQTT_ID):
@@ -113,7 +114,7 @@ async def _setup_lock_core(var, config):
await web_server.add_entity_config(var, web_server_config)
async def register_lock(var, config):
async def register_lock(var: MockObj, config: ConfigType) -> None:
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
queue_entity_register("lock", config)
@@ -121,7 +122,7 @@ async def register_lock(var, config):
await _setup_lock_core(var, config)
async def new_lock(config, *args):
async def new_lock(config: ConfigType, *args: SafeExpType) -> MockObj:
var = cg.new_Pvariable(config[CONF_ID], *args)
await register_lock(var, config)
return var
@@ -143,23 +144,38 @@ LOCK_ACTION_SCHEMA = maybe_simple_id(
@automation.register_action(
"lock.open", OpenAction, LOCK_ACTION_SCHEMA, synchronous=True
)
async def lock_action_to_code(config, action_id, template_arg, args):
async def lock_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
@automation.register_condition("lock.is_locked", LockCondition, LOCK_ACTION_SCHEMA)
async def lock_is_on_to_code(config, condition_id, template_arg, args):
async def lock_is_on_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(condition_id, template_arg, paren, True)
@automation.register_condition("lock.is_unlocked", LockCondition, LOCK_ACTION_SCHEMA)
async def lock_is_off_to_code(config, condition_id, template_arg, args):
async def lock_is_off_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(condition_id, template_arg, paren, False)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
cg.add_global(lock_ns.using)
-7
View File
@@ -201,17 +201,10 @@ void Logger::process_messages_() {
#endif // USE_ESPHOME_TASK_LOG_BUFFER
}
void Logger::set_baud_rate(uint32_t baud_rate) { this->baud_rate_ = baud_rate; }
#ifdef USE_LOGGER_RUNTIME_TAG_LEVELS
void Logger::set_log_level(const char *tag, uint8_t log_level) { this->log_levels_[tag] = log_level; }
#endif
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
UARTSelection Logger::get_uart() const { return this->uart_; }
#endif
float Logger::get_setup_priority() const { return setup_priority::BUS + 500.0f; }
// Log level strings - packed into flash on ESP8266, indexed by log level (0-7)
PROGMEM_STRING_TABLE(LogLevelStrings, "NONE", "ERROR", "WARN", "INFO", "CONFIG", "DEBUG", "VERBOSE", "VERY_VERBOSE");
+3 -3
View File
@@ -148,7 +148,7 @@ class Logger final : public Component {
void loop() override;
#endif
/// Manually set the baud rate for serial, set to 0 to disable.
void set_baud_rate(uint32_t baud_rate);
void set_baud_rate(uint32_t baud_rate) { this->baud_rate_ = baud_rate; }
uint32_t get_baud_rate() const { return baud_rate_; }
#if defined(USE_ARDUINO) && !defined(USE_ESP32)
Stream *get_hw_serial() const { return hw_serial_; }
@@ -163,7 +163,7 @@ class Logger final : public Component {
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
void set_uart_selection(UARTSelection uart_selection) { uart_ = uart_selection; }
/// Get the UART used by the logger.
UARTSelection get_uart() const;
UARTSelection get_uart() const { return this->uart_; }
#endif
/// Set the default log level for this logger.
@@ -197,7 +197,7 @@ class Logger final : public Component {
void add_level_listener(LoggerLevelListener *listener) { this->level_listeners_.push_back(listener); }
#endif
float get_setup_priority() const override;
float get_setup_priority() const override { return setup_priority::BUS + 500.0f; }
void log_vprintf_(uint8_t level, const char *tag, int line, const char *format, va_list args); // NOLINT
#ifdef USE_STORE_LOG_STR_IN_FLASH
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import i2c
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.types import ConfigType
DEPENDENCIES = ["i2c"]
CODEOWNERS = ["@rnauber"]
@@ -26,7 +27,7 @@ CONFIG_SCHEMA = cv.Schema(
).extend(i2c.i2c_device_schema(0x43))
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
@@ -1,6 +1,7 @@
import esphome.codegen as cg
from esphome.components import binary_sensor
import esphome.config_validation as cv
from esphome.types import ConfigType
from .. import CONF_M5STACK_8ANGLE_ID, M5Stack8AngleComponent, m5stack_8angle_ns
@@ -22,7 +23,7 @@ CONFIG_SCHEMA = cv.All(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_M5STACK_8ANGLE_ID])
sens = await binary_sensor.new_binary_sensor(config)
cg.add(sens.set_parent(hub))
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import light
import esphome.config_validation as cv
from esphome.const import CONF_OUTPUT_ID
from esphome.types import ConfigType
from .. import CONF_M5STACK_8ANGLE_ID, M5Stack8AngleComponent, m5stack_8angle_ns
@@ -21,7 +22,7 @@ CONFIG_SCHEMA = cv.All(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_M5STACK_8ANGLE_ID])
lights = cg.new_Pvariable(config[CONF_OUTPUT_ID])
await light.register_light(lights, config)
@@ -8,6 +8,7 @@ from esphome.const import (
ICON_ROTATE_RIGHT,
STATE_CLASS_MEASUREMENT,
)
from esphome.types import ConfigType
from .. import (
CONF_M5STACK_8ANGLE_ID,
@@ -55,7 +56,7 @@ CONFIG_SCHEMA = cv.All(
)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = await sensor.new_sensor(config)
await cg.register_component(var, config)
await cg.register_parented(var, config[CONF_M5STACK_8ANGLE_ID])
@@ -8,6 +8,7 @@ from esphome.const import (
CONF_ON_STATE,
CONF_TEMPERATURE,
CONF_UPDATE_INTERVAL,
CONF_USE_FAHRENHEIT,
)
from esphome.core import ID, Lambda
from esphome.cpp_generator import LambdaExpression, MockObj
@@ -71,6 +72,7 @@ CONFIG_SCHEMA = (
cv.Optional(
CONF_TELEMETRY_REQUEST_MIN_INTERVAL, default="60s"
): cv.update_interval,
cv.Optional(CONF_USE_FAHRENHEIT, default=False): cv.boolean,
cv.Optional(CONF_VANE): cv.Schema(
{
cv.Optional(CONF_ON_STATE): automation.validate_automation({}),
@@ -114,6 +116,7 @@ async def to_code(config: ConfigType) -> None:
config[CONF_TELEMETRY_REQUEST_MIN_INTERVAL]
)
)
cg.add(var.set_use_fahrenheit(config[CONF_USE_FAHRENHEIT]))
if on_state := config.get(CONF_VANE, {}).get(CONF_ON_STATE):
cg.add_global(mitsubishi_ns.using)
for conf in on_state:

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