mirror of
https://github.com/esphome/esphome.git
synced 2026-02-18 23:45:40 -07:00
Merge branch 'dev' into copilot/update-cover-component-triggers
This commit is contained in:
@@ -1 +1 @@
|
||||
a172e2f65981e98354cc6b5ecf69bdb055dd13602226042ab2c7acd037a2bf41
|
||||
cf3d341206b4184ec8b7fe85141aef4fe4696aa720c3f8a06d4e57930574bdab
|
||||
|
||||
@@ -38,8 +38,10 @@ async def to_code(config):
|
||||
# https://github.com/ESP32Async/ESPAsyncTCP
|
||||
cg.add_library("ESP32Async/ESPAsyncTCP", "2.0.0")
|
||||
elif CORE.is_rp2040:
|
||||
# https://github.com/khoih-prog/AsyncTCP_RP2040W
|
||||
cg.add_library("khoih-prog/AsyncTCP_RP2040W", "1.2.0")
|
||||
# https://github.com/ayushsharma82/RPAsyncTCP
|
||||
# RPAsyncTCP is a drop-in replacement for AsyncTCP_RP2040W with better
|
||||
# ESPAsyncWebServer compatibility
|
||||
cg.add_library("ayushsharma82/RPAsyncTCP", "1.3.2")
|
||||
# Other platforms (host, etc) use socket-based implementation
|
||||
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
// Use ESPAsyncTCP library for ESP8266 (always Arduino)
|
||||
#include <ESPAsyncTCP.h>
|
||||
#elif defined(USE_RP2040)
|
||||
// Use AsyncTCP_RP2040W library for RP2040
|
||||
#include <AsyncTCP_RP2040W.h>
|
||||
// Use RPAsyncTCP library for RP2040
|
||||
#include <RPAsyncTCP.h>
|
||||
#else
|
||||
// Use socket-based implementation for other platforms
|
||||
#include "async_tcp_socket.h"
|
||||
|
||||
@@ -14,10 +14,7 @@ void log_binary_sensor(const char *tag, const char *prefix, const char *type, Bi
|
||||
}
|
||||
|
||||
ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str());
|
||||
|
||||
if (!obj->get_device_class_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Device Class: '%s'", prefix, obj->get_device_class_ref().c_str());
|
||||
}
|
||||
LOG_ENTITY_DEVICE_CLASS(tag, prefix, *obj);
|
||||
}
|
||||
|
||||
void BinarySensor::publish_state(bool new_state) {
|
||||
|
||||
@@ -12,10 +12,7 @@ void log_button(const char *tag, const char *prefix, const char *type, Button *o
|
||||
}
|
||||
|
||||
ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str());
|
||||
|
||||
if (!obj->get_icon_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
|
||||
}
|
||||
LOG_ENTITY_ICON(tag, prefix, *obj);
|
||||
}
|
||||
|
||||
void Button::press() {
|
||||
|
||||
@@ -96,10 +96,16 @@ void CaptivePortal::start() {
|
||||
}
|
||||
|
||||
void CaptivePortal::handleRequest(AsyncWebServerRequest *req) {
|
||||
if (req->url() == ESPHOME_F("/config.json")) {
|
||||
#ifdef USE_ESP32
|
||||
char url_buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||
StringRef url = req->url_to(url_buf);
|
||||
#else
|
||||
const auto &url = req->url();
|
||||
#endif
|
||||
if (url == ESPHOME_F("/config.json")) {
|
||||
this->handle_config(req);
|
||||
return;
|
||||
} else if (req->url() == ESPHOME_F("/wifisave")) {
|
||||
} else if (url == ESPHOME_F("/wifisave")) {
|
||||
this->handle_wifisave(req);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,9 +20,7 @@ static constexpr const float COVER_CLOSED = 0.0f;
|
||||
if (traits_.get_is_assumed_state()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Assumed State: YES", prefix); \
|
||||
} \
|
||||
if (!(obj)->get_device_class_ref().empty()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, (obj)->get_device_class_ref().c_str()); \
|
||||
} \
|
||||
LOG_ENTITY_DEVICE_CLASS(TAG, prefix, *(obj)); \
|
||||
}
|
||||
|
||||
class Cover;
|
||||
|
||||
@@ -15,9 +15,7 @@ namespace esphome::datetime {
|
||||
#define LOG_DATETIME_DATE(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
if (!(obj)->get_icon_ref().empty()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
|
||||
} \
|
||||
LOG_ENTITY_ICON(TAG, prefix, *(obj)); \
|
||||
}
|
||||
|
||||
class DateCall;
|
||||
|
||||
@@ -15,9 +15,7 @@ namespace esphome::datetime {
|
||||
#define LOG_DATETIME_DATETIME(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
if (!(obj)->get_icon_ref().empty()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
|
||||
} \
|
||||
LOG_ENTITY_ICON(TAG, prefix, *(obj)); \
|
||||
}
|
||||
|
||||
class DateTimeCall;
|
||||
|
||||
@@ -15,9 +15,7 @@ namespace esphome::datetime {
|
||||
#define LOG_DATETIME_TIME(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
if (!(obj)->get_icon_ref().empty()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
|
||||
} \
|
||||
LOG_ENTITY_ICON(TAG, prefix, *(obj)); \
|
||||
}
|
||||
|
||||
class TimeCall;
|
||||
|
||||
@@ -55,6 +55,7 @@ from .const import ( # noqa
|
||||
KEY_ESP32,
|
||||
KEY_EXTRA_BUILD_FILES,
|
||||
KEY_FLASH_SIZE,
|
||||
KEY_FULL_CERT_BUNDLE,
|
||||
KEY_PATH,
|
||||
KEY_REF,
|
||||
KEY_REPO,
|
||||
@@ -670,6 +671,7 @@ CONF_FREERTOS_IN_IRAM = "freertos_in_iram"
|
||||
CONF_RINGBUF_IN_IRAM = "ringbuf_in_iram"
|
||||
CONF_HEAP_IN_IRAM = "heap_in_iram"
|
||||
CONF_LOOP_TASK_STACK_SIZE = "loop_task_stack_size"
|
||||
CONF_USE_FULL_CERTIFICATE_BUNDLE = "use_full_certificate_bundle"
|
||||
|
||||
# VFS requirement tracking
|
||||
# Components that need VFS features can call require_vfs_select() or require_vfs_dir()
|
||||
@@ -695,6 +697,18 @@ def require_vfs_dir() -> None:
|
||||
CORE.data[KEY_VFS_DIR_REQUIRED] = True
|
||||
|
||||
|
||||
def require_full_certificate_bundle() -> None:
|
||||
"""Request the full certificate bundle instead of the common-CAs-only bundle.
|
||||
|
||||
By default, ESPHome uses CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN which
|
||||
includes only CAs with >1% market share (~51 KB smaller than full bundle).
|
||||
This covers ~99% of websites including Let's Encrypt, DigiCert, Google, Amazon.
|
||||
|
||||
Call this from components that need to connect to services using uncommon CAs.
|
||||
"""
|
||||
CORE.data[KEY_ESP32][KEY_FULL_CERT_BUNDLE] = True
|
||||
|
||||
|
||||
def _parse_idf_component(value: str) -> ConfigType:
|
||||
"""Parse IDF component shorthand syntax like 'owner/component^version'"""
|
||||
# Match operator followed by version-like string (digit or *)
|
||||
@@ -776,6 +790,9 @@ FRAMEWORK_SCHEMA = cv.Schema(
|
||||
min=8192, max=32768
|
||||
),
|
||||
cv.Optional(CONF_ENABLE_OTA_ROLLBACK, default=True): cv.boolean,
|
||||
cv.Optional(
|
||||
CONF_USE_FULL_CERTIFICATE_BUNDLE, default=False
|
||||
): cv.boolean,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_COMPONENTS, default=[]): cv.ensure_list(
|
||||
@@ -1093,6 +1110,18 @@ async def to_code(config):
|
||||
|
||||
cg.add_build_flag("-Wno-nonnull-compare")
|
||||
|
||||
# Use CMN (common CAs) bundle by default to save ~51KB flash
|
||||
# CMN covers CAs with >1% market share (~99% of websites)
|
||||
# Components needing uncommon CAs can call require_full_certificate_bundle()
|
||||
use_full_bundle = conf[CONF_ADVANCED].get(
|
||||
CONF_USE_FULL_CERTIFICATE_BUNDLE, False
|
||||
) or CORE.data[KEY_ESP32].get(KEY_FULL_CERT_BUNDLE, False)
|
||||
add_idf_sdkconfig_option(
|
||||
"CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL", use_full_bundle
|
||||
)
|
||||
if not use_full_bundle:
|
||||
add_idf_sdkconfig_option("CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN", True)
|
||||
|
||||
add_idf_sdkconfig_option(f"CONFIG_IDF_TARGET_{variant}", True)
|
||||
add_idf_sdkconfig_option(
|
||||
f"CONFIG_ESPTOOLPY_FLASHSIZE_{config[CONF_FLASH_SIZE]}", True
|
||||
|
||||
@@ -12,6 +12,7 @@ KEY_REFRESH = "refresh"
|
||||
KEY_PATH = "path"
|
||||
KEY_SUBMODULES = "submodules"
|
||||
KEY_EXTRA_BUILD_FILES = "extra_build_files"
|
||||
KEY_FULL_CERT_BUNDLE = "full_cert_bundle"
|
||||
|
||||
VARIANT_ESP32 = "ESP32"
|
||||
VARIANT_ESP32C2 = "ESP32C2"
|
||||
|
||||
@@ -16,12 +16,8 @@ namespace event {
|
||||
#define LOG_EVENT(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
if (!(obj)->get_icon_ref().empty()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
|
||||
} \
|
||||
if (!(obj)->get_device_class_ref().empty()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, (obj)->get_device_class_ref().c_str()); \
|
||||
} \
|
||||
LOG_ENTITY_ICON(TAG, prefix, *(obj)); \
|
||||
LOG_ENTITY_DEVICE_CLASS(TAG, prefix, *(obj)); \
|
||||
}
|
||||
|
||||
class Event : public EntityBase, public EntityBase_DeviceClass {
|
||||
|
||||
@@ -165,6 +165,16 @@ async def to_code(config):
|
||||
ca_cert_content = f.read()
|
||||
cg.add(var.set_ca_certificate(ca_cert_content))
|
||||
else:
|
||||
# Uses the certificate bundle configured in esp32 component.
|
||||
# By default, ESPHome uses the CMN (common CAs) bundle which covers
|
||||
# ~99% of websites including GitHub, Let's Encrypt, DigiCert, etc.
|
||||
# If connecting to services with uncommon CAs, components can call:
|
||||
# esp32.require_full_certificate_bundle()
|
||||
# Or users can set in their config:
|
||||
# esp32:
|
||||
# framework:
|
||||
# advanced:
|
||||
# use_full_certificate_bundle: true
|
||||
esp32.add_idf_sdkconfig_option(
|
||||
"CONFIG_MBEDTLS_CERTIFICATE_BUNDLE", True
|
||||
)
|
||||
|
||||
@@ -14,9 +14,7 @@ class Lock;
|
||||
#define LOG_LOCK(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
if (!(obj)->get_icon_ref().empty()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
|
||||
} \
|
||||
LOG_ENTITY_ICON(TAG, prefix, *(obj)); \
|
||||
if ((obj)->traits.get_assumed_state()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Assumed State: YES", prefix); \
|
||||
} \
|
||||
|
||||
@@ -150,27 +150,24 @@ void Nextion::dump_config() {
|
||||
#ifdef USE_NEXTION_CONFIG_SKIP_CONNECTION_HANDSHAKE
|
||||
ESP_LOGCONFIG(TAG, " Skip handshake: YES");
|
||||
#else // USE_NEXTION_CONFIG_SKIP_CONNECTION_HANDSHAKE
|
||||
ESP_LOGCONFIG(TAG,
|
||||
#ifdef USE_NEXTION_CONFIG_DUMP_DEVICE_INFO
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Device Model: %s\n"
|
||||
" FW Version: %s\n"
|
||||
" Serial Number: %s\n"
|
||||
" Flash Size: %s\n"
|
||||
" Max queue age: %u ms\n"
|
||||
" Startup override: %u ms\n",
|
||||
this->device_model_.c_str(), this->firmware_version_.c_str(), this->serial_number_.c_str(),
|
||||
this->flash_size_.c_str(), this->max_q_age_ms_, this->startup_override_ms_);
|
||||
#endif // USE_NEXTION_CONFIG_DUMP_DEVICE_INFO
|
||||
#ifdef USE_NEXTION_CONFIG_EXIT_REPARSE_ON_START
|
||||
" Exit reparse: YES\n"
|
||||
ESP_LOGCONFIG(TAG, " Exit reparse: YES\n");
|
||||
#endif // USE_NEXTION_CONFIG_EXIT_REPARSE_ON_START
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Wake On Touch: %s\n"
|
||||
" Touch Timeout: %" PRIu16,
|
||||
#ifdef USE_NEXTION_CONFIG_DUMP_DEVICE_INFO
|
||||
this->device_model_.c_str(), this->firmware_version_.c_str(), this->serial_number_.c_str(),
|
||||
this->flash_size_.c_str(), this->max_q_age_ms_,
|
||||
this->startup_override_ms_
|
||||
#endif // USE_NEXTION_CONFIG_DUMP_DEVICE_INFO
|
||||
YESNO(this->connection_state_.auto_wake_on_touch_),
|
||||
this->touch_sleep_timeout_);
|
||||
YESNO(this->connection_state_.auto_wake_on_touch_), this->touch_sleep_timeout_);
|
||||
#endif // USE_NEXTION_CONFIG_SKIP_CONNECTION_HANDSHAKE
|
||||
|
||||
#ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP
|
||||
|
||||
@@ -69,9 +69,21 @@ def set_core_data(config: ConfigType) -> ConfigType:
|
||||
|
||||
|
||||
def set_framework(config: ConfigType) -> ConfigType:
|
||||
version = cv.Version.parse(cv.version_number(config[CONF_FRAMEWORK][CONF_VERSION]))
|
||||
CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = version
|
||||
return config
|
||||
framework_ver = cv.Version.parse(
|
||||
cv.version_number(config[CONF_FRAMEWORK][CONF_VERSION])
|
||||
)
|
||||
CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = framework_ver
|
||||
if framework_ver < cv.Version(2, 9, 2):
|
||||
return cv.require_framework_version(
|
||||
nrf52_zephyr=cv.Version(2, 6, 1, "a"),
|
||||
)(config)
|
||||
if framework_ver < cv.Version(3, 2, 0):
|
||||
return cv.require_framework_version(
|
||||
nrf52_zephyr=cv.Version(2, 9, 2, "2"),
|
||||
)(config)
|
||||
return cv.require_framework_version(
|
||||
nrf52_zephyr=cv.Version(3, 2, 0, "1"),
|
||||
)(config)
|
||||
|
||||
|
||||
BOOTLOADERS = [
|
||||
@@ -140,7 +152,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_UICR_ERASE, default=False): cv.boolean,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_FRAMEWORK, default={CONF_VERSION: "2.6.1-7"}): cv.Schema(
|
||||
cv.Optional(CONF_FRAMEWORK, default={CONF_VERSION: "2.6.1-a"}): cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_VERSION): cv.string_strict,
|
||||
}
|
||||
@@ -181,13 +193,12 @@ async def to_code(config: ConfigType) -> None:
|
||||
cg.add_platformio_option(CONF_FRAMEWORK, CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK])
|
||||
cg.add_platformio_option(
|
||||
"platform",
|
||||
"https://github.com/tomaszduda23/platform-nordicnrf52/archive/refs/tags/v10.3.0-1.zip",
|
||||
"https://github.com/tomaszduda23/platform-nordicnrf52/archive/refs/tags/v10.3.0-5.zip",
|
||||
)
|
||||
cg.add_platformio_option(
|
||||
"platform_packages",
|
||||
[
|
||||
f"platformio/framework-zephyr@https://github.com/tomaszduda23/framework-sdk-nrf/archive/refs/tags/v{CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION]}.zip",
|
||||
"platformio/toolchain-gccarmnoneeabi@https://github.com/tomaszduda23/toolchain-sdk-ng/archive/refs/tags/v0.17.4-0.zip",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -14,18 +14,9 @@ void log_number(const char *tag, const char *prefix, const char *type, Number *o
|
||||
}
|
||||
|
||||
ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str());
|
||||
|
||||
if (!obj->get_icon_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
|
||||
}
|
||||
|
||||
if (!obj->traits.get_unit_of_measurement_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Unit of Measurement: '%s'", prefix, obj->traits.get_unit_of_measurement_ref().c_str());
|
||||
}
|
||||
|
||||
if (!obj->traits.get_device_class_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Device Class: '%s'", prefix, obj->traits.get_device_class_ref().c_str());
|
||||
}
|
||||
LOG_ENTITY_ICON(tag, prefix, *obj);
|
||||
LOG_ENTITY_UNIT_OF_MEASUREMENT(tag, prefix, obj->traits);
|
||||
LOG_ENTITY_DEVICE_CLASS(tag, prefix, obj->traits);
|
||||
}
|
||||
|
||||
void Number::publish_state(float state) {
|
||||
|
||||
@@ -41,12 +41,14 @@ class PrometheusHandler : public AsyncWebHandler, public Component {
|
||||
void add_label_name(EntityBase *obj, const std::string &value) { relabel_map_name_.insert({obj, value}); }
|
||||
|
||||
bool canHandle(AsyncWebServerRequest *request) const override {
|
||||
if (request->method() == HTTP_GET) {
|
||||
if (request->url() == "/metrics")
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (request->method() != HTTP_GET)
|
||||
return false;
|
||||
#ifdef USE_ESP32
|
||||
char url_buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||
return request->url_to(url_buf) == "/metrics";
|
||||
#else
|
||||
return request->url() == ESPHOME_F("/metrics");
|
||||
#endif
|
||||
}
|
||||
|
||||
void handleRequest(AsyncWebServerRequest *req) override;
|
||||
|
||||
@@ -12,9 +12,7 @@ namespace esphome::select {
|
||||
#define LOG_SELECT(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
if (!(obj)->get_icon_ref().empty()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
|
||||
} \
|
||||
LOG_ENTITY_ICON(TAG, prefix, *(obj)); \
|
||||
}
|
||||
|
||||
#define SUB_SELECT(name) \
|
||||
|
||||
@@ -22,13 +22,8 @@ void log_sensor(const char *tag, const char *prefix, const char *type, Sensor *o
|
||||
LOG_STR_ARG(state_class_to_string(obj->get_state_class())), prefix,
|
||||
obj->get_unit_of_measurement_ref().c_str(), prefix, obj->get_accuracy_decimals());
|
||||
|
||||
if (!obj->get_device_class_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Device Class: '%s'", prefix, obj->get_device_class_ref().c_str());
|
||||
}
|
||||
|
||||
if (!obj->get_icon_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
|
||||
}
|
||||
LOG_ENTITY_DEVICE_CLASS(tag, prefix, *obj);
|
||||
LOG_ENTITY_ICON(tag, prefix, *obj);
|
||||
|
||||
if (obj->get_force_update()) {
|
||||
ESP_LOGV(tag, "%s Force Update: YES", prefix);
|
||||
|
||||
@@ -96,18 +96,14 @@ void log_switch(const char *tag, const char *prefix, const char *type, Switch *o
|
||||
LOG_STR_ARG(onoff));
|
||||
|
||||
// Add optional fields separately
|
||||
if (!obj->get_icon_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
|
||||
}
|
||||
LOG_ENTITY_ICON(tag, prefix, *obj);
|
||||
if (obj->assumed_state()) {
|
||||
ESP_LOGCONFIG(tag, "%s Assumed State: YES", prefix);
|
||||
}
|
||||
if (obj->is_inverted()) {
|
||||
ESP_LOGCONFIG(tag, "%s Inverted: YES", prefix);
|
||||
}
|
||||
if (!obj->get_device_class_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Device Class: '%s'", prefix, obj->get_device_class_ref().c_str());
|
||||
}
|
||||
LOG_ENTITY_DEVICE_CLASS(tag, prefix, *obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,7 @@ namespace text {
|
||||
#define LOG_TEXT(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
if (!(obj)->get_icon_ref().empty()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
|
||||
} \
|
||||
LOG_ENTITY_ICON(TAG, prefix, *(obj)); \
|
||||
}
|
||||
|
||||
/** Base-class for all text inputs.
|
||||
|
||||
@@ -9,19 +9,18 @@ namespace text_sensor {
|
||||
static const char *const TAG = "text_sensor.filter";
|
||||
|
||||
// Filter
|
||||
void Filter::input(const std::string &value) {
|
||||
void Filter::input(std::string value) {
|
||||
ESP_LOGVV(TAG, "Filter(%p)::input(%s)", this, value.c_str());
|
||||
optional<std::string> out = this->new_value(value);
|
||||
if (out.has_value())
|
||||
this->output(*out);
|
||||
if (this->new_value(value))
|
||||
this->output(value);
|
||||
}
|
||||
void Filter::output(const std::string &value) {
|
||||
void Filter::output(std::string &value) {
|
||||
if (this->next_ == nullptr) {
|
||||
ESP_LOGVV(TAG, "Filter(%p)::output(%s) -> SENSOR", this, value.c_str());
|
||||
this->parent_->internal_send_state_to_frontend(value);
|
||||
} else {
|
||||
ESP_LOGVV(TAG, "Filter(%p)::output(%s) -> %p", this, value.c_str(), this->next_);
|
||||
this->next_->input(value);
|
||||
this->next_->input(std::move(value));
|
||||
}
|
||||
}
|
||||
void Filter::initialize(TextSensor *parent, Filter *next) {
|
||||
@@ -35,43 +34,48 @@ LambdaFilter::LambdaFilter(lambda_filter_t lambda_filter) : lambda_filter_(std::
|
||||
const lambda_filter_t &LambdaFilter::get_lambda_filter() const { return this->lambda_filter_; }
|
||||
void LambdaFilter::set_lambda_filter(const lambda_filter_t &lambda_filter) { this->lambda_filter_ = lambda_filter; }
|
||||
|
||||
optional<std::string> LambdaFilter::new_value(std::string value) {
|
||||
auto it = this->lambda_filter_(value);
|
||||
ESP_LOGVV(TAG, "LambdaFilter(%p)::new_value(%s) -> %s", this, value.c_str(), it.value_or("").c_str());
|
||||
return it;
|
||||
bool LambdaFilter::new_value(std::string &value) {
|
||||
auto result = this->lambda_filter_(value);
|
||||
if (result.has_value()) {
|
||||
ESP_LOGVV(TAG, "LambdaFilter(%p)::new_value(%s) -> %s (continue)", this, value.c_str(), result->c_str());
|
||||
value = std::move(*result);
|
||||
return true;
|
||||
}
|
||||
ESP_LOGVV(TAG, "LambdaFilter(%p)::new_value(%s) -> (stop)", this, value.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// ToUpperFilter
|
||||
optional<std::string> ToUpperFilter::new_value(std::string value) {
|
||||
bool ToUpperFilter::new_value(std::string &value) {
|
||||
for (char &c : value)
|
||||
c = ::toupper(c);
|
||||
return value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ToLowerFilter
|
||||
optional<std::string> ToLowerFilter::new_value(std::string value) {
|
||||
bool ToLowerFilter::new_value(std::string &value) {
|
||||
for (char &c : value)
|
||||
c = ::tolower(c);
|
||||
return value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Append
|
||||
optional<std::string> AppendFilter::new_value(std::string value) {
|
||||
bool AppendFilter::new_value(std::string &value) {
|
||||
value.append(this->suffix_);
|
||||
return value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Prepend
|
||||
optional<std::string> PrependFilter::new_value(std::string value) {
|
||||
bool PrependFilter::new_value(std::string &value) {
|
||||
value.insert(0, this->prefix_);
|
||||
return value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Substitute
|
||||
SubstituteFilter::SubstituteFilter(const std::initializer_list<Substitution> &substitutions)
|
||||
: substitutions_(substitutions) {}
|
||||
|
||||
optional<std::string> SubstituteFilter::new_value(std::string value) {
|
||||
bool SubstituteFilter::new_value(std::string &value) {
|
||||
for (const auto &sub : this->substitutions_) {
|
||||
// Compute lengths once per substitution (strlen is fast, called infrequently)
|
||||
const size_t from_len = strlen(sub.from);
|
||||
@@ -84,20 +88,20 @@ optional<std::string> SubstituteFilter::new_value(std::string value) {
|
||||
pos += to_len;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Map
|
||||
MapFilter::MapFilter(const std::initializer_list<Substitution> &mappings) : mappings_(mappings) {}
|
||||
|
||||
optional<std::string> MapFilter::new_value(std::string value) {
|
||||
bool MapFilter::new_value(std::string &value) {
|
||||
for (const auto &mapping : this->mappings_) {
|
||||
if (value == mapping.from) {
|
||||
value.assign(mapping.to);
|
||||
return value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return value; // Pass through if no match
|
||||
return true; // Pass through if no match
|
||||
}
|
||||
|
||||
} // namespace text_sensor
|
||||
|
||||
@@ -17,21 +17,20 @@ class Filter {
|
||||
public:
|
||||
/** This will be called every time the filter receives a new value.
|
||||
*
|
||||
* It can return an empty optional to indicate that the filter chain
|
||||
* should stop, otherwise the value in the filter will be passed down
|
||||
* the chain.
|
||||
* Modify the value in place. Return false to stop the filter chain
|
||||
* (value will not be published), or true to continue.
|
||||
*
|
||||
* @param value The new value.
|
||||
* @return An optional string, the new value that should be pushed out.
|
||||
* @param value The value to filter (modified in place).
|
||||
* @return True to continue the filter chain, false to stop.
|
||||
*/
|
||||
virtual optional<std::string> new_value(std::string value) = 0;
|
||||
virtual bool new_value(std::string &value) = 0;
|
||||
|
||||
/// Initialize this filter, please note this can be called more than once.
|
||||
virtual void initialize(TextSensor *parent, Filter *next);
|
||||
|
||||
void input(const std::string &value);
|
||||
void input(std::string value);
|
||||
|
||||
void output(const std::string &value);
|
||||
void output(std::string &value);
|
||||
|
||||
protected:
|
||||
friend TextSensor;
|
||||
@@ -45,15 +44,14 @@ using lambda_filter_t = std::function<optional<std::string>(std::string)>;
|
||||
/** This class allows for creation of simple template filters.
|
||||
*
|
||||
* The constructor accepts a lambda of the form std::string -> optional<std::string>.
|
||||
* It will be called with each new value in the filter chain and returns the modified
|
||||
* value that shall be passed down the filter chain. Returning an empty Optional
|
||||
* means that the value shall be discarded.
|
||||
* Return a modified string to continue the chain, or return {} to stop
|
||||
* (value will not be published).
|
||||
*/
|
||||
class LambdaFilter : public Filter {
|
||||
public:
|
||||
explicit LambdaFilter(lambda_filter_t lambda_filter);
|
||||
|
||||
optional<std::string> new_value(std::string value) override;
|
||||
bool new_value(std::string &value) override;
|
||||
|
||||
const lambda_filter_t &get_lambda_filter() const;
|
||||
void set_lambda_filter(const lambda_filter_t &lambda_filter);
|
||||
@@ -71,7 +69,14 @@ class StatelessLambdaFilter : public Filter {
|
||||
public:
|
||||
explicit StatelessLambdaFilter(optional<std::string> (*lambda_filter)(std::string)) : lambda_filter_(lambda_filter) {}
|
||||
|
||||
optional<std::string> new_value(std::string value) override { return this->lambda_filter_(value); }
|
||||
bool new_value(std::string &value) override {
|
||||
auto result = this->lambda_filter_(value);
|
||||
if (result.has_value()) {
|
||||
value = std::move(*result);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
optional<std::string> (*lambda_filter_)(std::string);
|
||||
@@ -80,20 +85,20 @@ class StatelessLambdaFilter : public Filter {
|
||||
/// A simple filter that converts all text to uppercase
|
||||
class ToUpperFilter : public Filter {
|
||||
public:
|
||||
optional<std::string> new_value(std::string value) override;
|
||||
bool new_value(std::string &value) override;
|
||||
};
|
||||
|
||||
/// A simple filter that converts all text to lowercase
|
||||
class ToLowerFilter : public Filter {
|
||||
public:
|
||||
optional<std::string> new_value(std::string value) override;
|
||||
bool new_value(std::string &value) override;
|
||||
};
|
||||
|
||||
/// A simple filter that adds a string to the end of another string
|
||||
class AppendFilter : public Filter {
|
||||
public:
|
||||
explicit AppendFilter(const char *suffix) : suffix_(suffix) {}
|
||||
optional<std::string> new_value(std::string value) override;
|
||||
bool new_value(std::string &value) override;
|
||||
|
||||
protected:
|
||||
const char *suffix_;
|
||||
@@ -103,7 +108,7 @@ class AppendFilter : public Filter {
|
||||
class PrependFilter : public Filter {
|
||||
public:
|
||||
explicit PrependFilter(const char *prefix) : prefix_(prefix) {}
|
||||
optional<std::string> new_value(std::string value) override;
|
||||
bool new_value(std::string &value) override;
|
||||
|
||||
protected:
|
||||
const char *prefix_;
|
||||
@@ -118,7 +123,7 @@ struct Substitution {
|
||||
class SubstituteFilter : public Filter {
|
||||
public:
|
||||
explicit SubstituteFilter(const std::initializer_list<Substitution> &substitutions);
|
||||
optional<std::string> new_value(std::string value) override;
|
||||
bool new_value(std::string &value) override;
|
||||
|
||||
protected:
|
||||
FixedVector<Substitution> substitutions_;
|
||||
@@ -151,7 +156,7 @@ class SubstituteFilter : public Filter {
|
||||
class MapFilter : public Filter {
|
||||
public:
|
||||
explicit MapFilter(const std::initializer_list<Substitution> &mappings);
|
||||
optional<std::string> new_value(std::string value) override;
|
||||
bool new_value(std::string &value) override;
|
||||
|
||||
protected:
|
||||
FixedVector<Substitution> mappings_;
|
||||
|
||||
@@ -15,14 +15,8 @@ void log_text_sensor(const char *tag, const char *prefix, const char *type, Text
|
||||
}
|
||||
|
||||
ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str());
|
||||
|
||||
if (!obj->get_device_class_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Device Class: '%s'", prefix, obj->get_device_class_ref().c_str());
|
||||
}
|
||||
|
||||
if (!obj->get_icon_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
|
||||
}
|
||||
LOG_ENTITY_DEVICE_CLASS(tag, prefix, *obj);
|
||||
LOG_ENTITY_ICON(tag, prefix, *obj);
|
||||
}
|
||||
|
||||
void TextSensor::publish_state(const std::string &state) { this->publish_state(state.data(), state.size()); }
|
||||
|
||||
@@ -20,9 +20,7 @@ const extern float VALVE_CLOSED;
|
||||
if (traits_.get_is_assumed_state()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Assumed State: YES", prefix); \
|
||||
} \
|
||||
if (!(obj)->get_device_class_ref().empty()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, (obj)->get_device_class_ref().c_str()); \
|
||||
} \
|
||||
LOG_ENTITY_DEVICE_CLASS(TAG, prefix, *(obj)); \
|
||||
}
|
||||
|
||||
class Valve;
|
||||
|
||||
@@ -31,6 +31,7 @@ from esphome.const import (
|
||||
PLATFORM_ESP32,
|
||||
PLATFORM_ESP8266,
|
||||
PLATFORM_LN882X,
|
||||
PLATFORM_RP2040,
|
||||
PLATFORM_RTL87XX,
|
||||
)
|
||||
from esphome.core import CORE, CoroPriority, coroutine_with_priority
|
||||
@@ -213,6 +214,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
PLATFORM_ESP8266,
|
||||
PLATFORM_BK72XX,
|
||||
PLATFORM_LN882X,
|
||||
PLATFORM_RP2040,
|
||||
PLATFORM_RTL87XX,
|
||||
]
|
||||
),
|
||||
|
||||
@@ -32,8 +32,15 @@ class OTARequestHandler : public AsyncWebHandler {
|
||||
void handleUpload(AsyncWebServerRequest *request, const PlatformString &filename, size_t index, uint8_t *data,
|
||||
size_t len, bool final) override;
|
||||
bool canHandle(AsyncWebServerRequest *request) const override {
|
||||
// Check if this is an OTA update request
|
||||
bool is_ota_request = request->url() == "/update" && request->method() == HTTP_POST;
|
||||
if (request->method() != HTTP_POST)
|
||||
return false;
|
||||
// Check if this is an OTA update request
|
||||
#ifdef USE_ESP32
|
||||
char url_buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||
bool is_ota_request = request->url_to(url_buf) == "/update";
|
||||
#else
|
||||
bool is_ota_request = request->url() == ESPHOME_F("/update");
|
||||
#endif
|
||||
|
||||
#if defined(USE_WEBSERVER_OTA_DISABLED) && defined(USE_CAPTIVE_PORTAL)
|
||||
// IMPORTANT: USE_WEBSERVER_OTA_DISABLED only disables OTA for the web_server component
|
||||
|
||||
@@ -2187,7 +2187,12 @@ std::string WebServer::update_json_(update::UpdateEntity *obj, JsonDetail start_
|
||||
#endif
|
||||
|
||||
bool WebServer::canHandle(AsyncWebServerRequest *request) const {
|
||||
#ifdef USE_ESP32
|
||||
char url_buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||
StringRef url = request->url_to(url_buf);
|
||||
#else
|
||||
const auto &url = request->url();
|
||||
#endif
|
||||
const auto method = request->method();
|
||||
|
||||
// Static URL checks - use ESPHOME_F to keep strings in flash on ESP8266
|
||||
@@ -2323,30 +2328,35 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) const {
|
||||
return false;
|
||||
}
|
||||
void WebServer::handleRequest(AsyncWebServerRequest *request) {
|
||||
#ifdef USE_ESP32
|
||||
char url_buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||
StringRef url = request->url_to(url_buf);
|
||||
#else
|
||||
const auto &url = request->url();
|
||||
#endif
|
||||
|
||||
// Handle static routes first
|
||||
if (url == "/") {
|
||||
if (url == ESPHOME_F("/")) {
|
||||
this->handle_index_request(request);
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined(USE_ESP32) && defined(USE_ARDUINO)
|
||||
if (url == "/events") {
|
||||
if (url == ESPHOME_F("/events")) {
|
||||
this->events_.add_new_client(this, request);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_WEBSERVER_CSS_INCLUDE
|
||||
if (url == "/0.css") {
|
||||
if (url == ESPHOME_F("/0.css")) {
|
||||
this->handle_css_request(request);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_WEBSERVER_JS_INCLUDE
|
||||
if (url == "/0.js") {
|
||||
if (url == ESPHOME_F("/0.js")) {
|
||||
this->handle_js_request(request);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -47,5 +47,10 @@ async def to_code(config):
|
||||
cg.add_library("ESP8266WiFi", None)
|
||||
if CORE.is_libretiny:
|
||||
CORE.add_platformio_option("lib_ignore", ["ESPAsyncTCP", "RPAsyncTCP"])
|
||||
if CORE.is_rp2040:
|
||||
# Ignore bundled AsyncTCP libraries - we use RPAsyncTCP from async_tcp component
|
||||
CORE.add_platformio_option(
|
||||
"lib_ignore", ["ESPAsyncTCP", "AsyncTCP", "AsyncTCP_RP2040W"]
|
||||
)
|
||||
# https://github.com/ESP32Async/ESPAsyncWebServer/blob/main/library.json
|
||||
cg.add_library("ESP32Async/ESPAsyncWebServer", "3.9.5")
|
||||
|
||||
@@ -246,21 +246,16 @@ optional<std::string> AsyncWebServerRequest::get_header(const char *name) const
|
||||
return request_get_header(*this, name);
|
||||
}
|
||||
|
||||
std::string AsyncWebServerRequest::url() const {
|
||||
auto *query_start = strchr(this->req_->uri, '?');
|
||||
std::string result;
|
||||
if (query_start == nullptr) {
|
||||
result = this->req_->uri;
|
||||
} else {
|
||||
result = std::string(this->req_->uri, query_start - this->req_->uri);
|
||||
}
|
||||
StringRef AsyncWebServerRequest::url_to(std::span<char, URL_BUF_SIZE> buffer) const {
|
||||
const char *uri = this->req_->uri;
|
||||
const char *query_start = strchr(uri, '?');
|
||||
size_t uri_len = query_start ? static_cast<size_t>(query_start - uri) : strlen(uri);
|
||||
size_t copy_len = std::min(uri_len, URL_BUF_SIZE - 1);
|
||||
memcpy(buffer.data(), uri, copy_len);
|
||||
buffer[copy_len] = '\0';
|
||||
// Decode URL-encoded characters in-place (e.g., %20 -> space)
|
||||
// This matches AsyncWebServer behavior on Arduino
|
||||
if (!result.empty()) {
|
||||
size_t new_len = url_decode(&result[0]);
|
||||
result.resize(new_len);
|
||||
}
|
||||
return result;
|
||||
size_t decoded_len = url_decode(buffer.data());
|
||||
return StringRef(buffer.data(), decoded_len);
|
||||
}
|
||||
|
||||
std::string AsyncWebServerRequest::host() const { return this->get_header("Host").value(); }
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/string_ref.h"
|
||||
#include <esp_http_server.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -110,7 +112,15 @@ class AsyncWebServerRequest {
|
||||
~AsyncWebServerRequest();
|
||||
|
||||
http_method method() const { return static_cast<http_method>(this->req_->method); }
|
||||
std::string url() const;
|
||||
static constexpr size_t URL_BUF_SIZE = CONFIG_HTTPD_MAX_URI_LEN + 1; ///< Buffer size for url_to()
|
||||
/// Write URL (without query string) to buffer, returns StringRef pointing to buffer.
|
||||
/// URL is decoded (e.g., %20 -> space).
|
||||
StringRef url_to(std::span<char, URL_BUF_SIZE> buffer) const;
|
||||
/// Get URL as std::string. Prefer url_to() to avoid heap allocation.
|
||||
std::string url() const {
|
||||
char buffer[URL_BUF_SIZE];
|
||||
return std::string(this->url_to(buffer));
|
||||
}
|
||||
std::string host() const;
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
size_t contentLength() const { return this->req_->content_len; }
|
||||
@@ -306,7 +316,10 @@ class AsyncEventSource : public AsyncWebHandler {
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
bool canHandle(AsyncWebServerRequest *request) const override {
|
||||
return request->method() == HTTP_GET && request->url() == this->url_;
|
||||
if (request->method() != HTTP_GET)
|
||||
return false;
|
||||
char url_buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||
return request->url_to(url_buf) == this->url_;
|
||||
}
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
void handleRequest(AsyncWebServerRequest *request) override;
|
||||
|
||||
@@ -152,4 +152,22 @@ void EntityBase_UnitOfMeasurement::set_unit_of_measurement(const char *unit_of_m
|
||||
this->unit_of_measurement_ = unit_of_measurement;
|
||||
}
|
||||
|
||||
void log_entity_icon(const char *tag, const char *prefix, const EntityBase &obj) {
|
||||
if (!obj.get_icon_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj.get_icon_ref().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void log_entity_device_class(const char *tag, const char *prefix, const EntityBase_DeviceClass &obj) {
|
||||
if (!obj.get_device_class_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Device Class: '%s'", prefix, obj.get_device_class_ref().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void log_entity_unit_of_measurement(const char *tag, const char *prefix, const EntityBase_UnitOfMeasurement &obj) {
|
||||
if (!obj.get_unit_of_measurement_ref().empty()) {
|
||||
ESP_LOGCONFIG(tag, "%s Unit of Measurement: '%s'", prefix, obj.get_unit_of_measurement_ref().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
@@ -230,6 +230,16 @@ class EntityBase_UnitOfMeasurement { // NOLINT(readability-identifier-naming)
|
||||
const char *unit_of_measurement_{nullptr}; ///< Unit of measurement override
|
||||
};
|
||||
|
||||
/// Log entity icon if set (for use in dump_config)
|
||||
#define LOG_ENTITY_ICON(tag, prefix, obj) log_entity_icon(tag, prefix, obj)
|
||||
void log_entity_icon(const char *tag, const char *prefix, const EntityBase &obj);
|
||||
/// Log entity device class if set (for use in dump_config)
|
||||
#define LOG_ENTITY_DEVICE_CLASS(tag, prefix, obj) log_entity_device_class(tag, prefix, obj)
|
||||
void log_entity_device_class(const char *tag, const char *prefix, const EntityBase_DeviceClass &obj);
|
||||
/// Log entity unit of measurement if set (for use in dump_config)
|
||||
#define LOG_ENTITY_UNIT_OF_MEASUREMENT(tag, prefix, obj) log_entity_unit_of_measurement(tag, prefix, obj)
|
||||
void log_entity_unit_of_measurement(const char *tag, const char *prefix, const EntityBase_UnitOfMeasurement &obj);
|
||||
|
||||
/**
|
||||
* An entity that has a state.
|
||||
* @tparam T The type of the state
|
||||
|
||||
@@ -200,6 +200,7 @@ platform_packages =
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
${common:arduino.lib_deps}
|
||||
ayushsharma82/RPAsyncTCP@1.3.2 ; async_tcp
|
||||
bblanchon/ArduinoJson@7.4.2 ; json
|
||||
ESP32Async/ESPAsyncWebServer@3.9.5 ; web_server_base
|
||||
build_flags =
|
||||
@@ -229,11 +230,10 @@ build_src_flags = -include Arduino.h
|
||||
; This is the common settings for the nRF52 using Zephyr.
|
||||
[common:nrf52-zephyr]
|
||||
extends = common
|
||||
platform = https://github.com/tomaszduda23/platform-nordicnrf52/archive/refs/tags/v10.3.0-1.zip
|
||||
platform = https://github.com/tomaszduda23/platform-nordicnrf52/archive/refs/tags/v10.3.0-5.zip
|
||||
framework = zephyr
|
||||
platform_packages =
|
||||
platformio/framework-zephyr @ https://github.com/tomaszduda23/framework-sdk-nrf/archive/refs/tags/v2.6.1-7.zip
|
||||
platformio/toolchain-gccarmnoneeabi@https://github.com/tomaszduda23/toolchain-sdk-ng/archive/refs/tags/v0.17.4-0.zip
|
||||
platformio/framework-zephyr @ https://github.com/tomaszduda23/framework-sdk-nrf/archive/refs/tags/v2.6.1-a.zip
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
-DUSE_ZEPHYR
|
||||
|
||||
@@ -7,6 +7,7 @@ esp32:
|
||||
enable_lwip_mdns_queries: true
|
||||
enable_lwip_bridge_interface: true
|
||||
disable_libc_locks_in_iram: false # Test explicit opt-out of RAM optimization
|
||||
use_full_certificate_bundle: false # Test CMN bundle (default)
|
||||
|
||||
wifi:
|
||||
ssid: MySSID
|
||||
|
||||
@@ -273,12 +273,9 @@ text_sensor:
|
||||
display:
|
||||
- platform: nextion
|
||||
id: main_lcd
|
||||
update_interval: 5s
|
||||
command_spacing: 5ms
|
||||
max_commands_per_loop: 20
|
||||
max_queue_size: 50
|
||||
startup_override_ms: 10000ms # Wait 10s for display ready
|
||||
max_queue_age: 5000ms # Remove queue items after 5s
|
||||
update_interval: 5s
|
||||
on_sleep:
|
||||
then:
|
||||
lambda: 'ESP_LOGD("display","Display went to sleep");'
|
||||
@@ -294,3 +291,8 @@ display:
|
||||
on_buffer_overflow:
|
||||
then:
|
||||
logger.log: "Nextion reported a buffer overflow!"
|
||||
|
||||
command_spacing: 5ms
|
||||
dump_device_info: true
|
||||
max_queue_age: 5000ms # Remove queue items after 5s
|
||||
startup_override_ms: 10000ms # Wait 10s for display ready
|
||||
|
||||
@@ -20,4 +20,4 @@ nrf52:
|
||||
voltage: 2.1V
|
||||
uicr_erase: true
|
||||
framework:
|
||||
version: "2.6.1-7"
|
||||
version: "2.6.1-a"
|
||||
|
||||
1
tests/components/web_server/test.rp2040-ard.yaml
Normal file
1
tests/components/web_server/test.rp2040-ard.yaml
Normal file
@@ -0,0 +1 @@
|
||||
<<: !include common_v2.yaml
|
||||
Reference in New Issue
Block a user