1
0
mirror of https://github.com/esphome/esphome.git synced 2026-02-08 16:51:52 +00:00

Merge branch 'cse7766_stack_debug' into integration

This commit is contained in:
J. Nick Koston
2026-01-16 11:51:16 -10:00
6 changed files with 93 additions and 36 deletions

View File

@@ -11,7 +11,7 @@ ci:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.14.11
rev: v0.14.13
hooks:
# Run the linter.
- id: ruff

View File

@@ -2,7 +2,6 @@
#include "esphome/core/application.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include <cstdarg>
namespace esphome {
namespace cse7766 {
@@ -10,32 +9,6 @@ namespace cse7766 {
static const char *const TAG = "cse7766";
static constexpr size_t CSE7766_RAW_DATA_SIZE = 24;
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
/// @brief Safely append formatted string to buffer.
/// @param buf Destination buffer (must be non-null)
/// @param size Total buffer size in bytes
/// @param pos Current write position (0 to size-1 for valid positions, size means full)
/// @param fmt printf-style format string
/// @return New write position: pos + chars_written, capped at size when buffer is full.
/// Returns size (not size-1) when full because vsnprintf already wrote the null
/// terminator at buf[size-1]. Returning size signals "no room for more content".
/// On encoding error, returns pos unchanged (no write occurred).
__attribute__((format(printf, 4, 5))) static size_t buf_append(char *buf, size_t size, size_t pos, const char *fmt,
...) {
if (pos >= size) {
return size;
}
va_list args;
va_start(args, fmt);
int written = vsnprintf(buf + pos, size - pos, fmt, args);
va_end(args);
if (written < 0) {
return pos; // encoding error
}
return std::min(pos + static_cast<size_t>(written), size);
}
#endif
void CSE7766Component::loop() {
const uint32_t now = App.get_loop_component_start_time();
if (now - this->last_transmission_ >= 500) {
@@ -237,18 +210,19 @@ void CSE7766Component::parse_data_() {
// Buffer: 7 + 15 + 33 + 15 + 25 = 95 chars max + null, rounded to 128 for safety margin.
// Float sizes with %.4f can be up to 11 chars for large values (e.g., 999999.9999).
char buf[128];
size_t pos = buf_append(buf, sizeof(buf), 0, "Parsed:");
size_t pos = buf_append_printf(buf, sizeof(buf), 0, "Parsed:");
if (have_voltage) {
pos = buf_append(buf, sizeof(buf), pos, " V=%.4fV", voltage);
pos = buf_append_printf(buf, sizeof(buf), pos, " V=%.4fV", voltage);
}
if (have_current) {
pos = buf_append(buf, sizeof(buf), pos, " I=%.4fmA (~%.4fmA)", current * 1000.0f, calculated_current * 1000.0f);
pos = buf_append_printf(buf, sizeof(buf), pos, " I=%.4fmA (~%.4fmA)", current * 1000.0f,
calculated_current * 1000.0f);
}
if (have_power) {
pos = buf_append(buf, sizeof(buf), pos, " P=%.4fW", power);
pos = buf_append_printf(buf, sizeof(buf), pos, " P=%.4fW", power);
}
if (energy != 0.0f) {
buf_append(buf, sizeof(buf), pos, " E=%.4fkWh (%u)", energy, cf_pulses);
buf_append_printf(buf, sizeof(buf), pos, " E=%.4fkWh (%u)", energy, cf_pulses);
}
ESP_LOGVV(TAG, "%s", buf);
}

View File

@@ -8,17 +8,20 @@ from esphome.const import (
CONF_ICON,
CONF_ID,
CONF_INDEX,
CONF_LAMBDA,
CONF_MODE,
CONF_MQTT_ID,
CONF_ON_VALUE,
CONF_OPERATION,
CONF_OPTION,
CONF_OPTIONS,
CONF_TRIGGER_ID,
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, setup_entity
from esphome.cpp_generator import MockObjClass
from esphome.cpp_generator import MockObjClass, TemplateArguments
from esphome.cpp_types import global_ns
CODEOWNERS = ["@esphome/core"]
IS_PLATFORM_COMPONENT = True
@@ -38,6 +41,9 @@ SelectSetAction = select_ns.class_("SelectSetAction", automation.Action)
SelectSetIndexAction = select_ns.class_("SelectSetIndexAction", automation.Action)
SelectOperationAction = select_ns.class_("SelectOperationAction", automation.Action)
# Conditions
SelectIsCondition = select_ns.class_("SelectIsCondition", automation.Condition)
# Enums
SelectOperation = select_ns.enum("SelectOperation")
SELECT_OPERATION_OPTIONS = {
@@ -165,6 +171,41 @@ async def select_set_index_to_code(config, action_id, template_arg, args):
return var
@automation.register_condition(
"select.is",
SelectIsCondition,
OPERATION_BASE_SCHEMA.extend(
{
cv.Optional(CONF_OPTIONS): cv.All(
cv.ensure_list(cv.string_strict), cv.Length(min=1)
),
cv.Optional(CONF_LAMBDA): cv.returning_lambda,
}
).add_extra(cv.has_exactly_one_key(CONF_OPTIONS, CONF_LAMBDA)),
)
async def select_is_to_code(config, condition_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
if options := config.get(CONF_OPTIONS):
# List of constant options
# Create a constexpr and pass that with a template length
arr_id = ID(
f"{condition_id}_data",
is_declaration=True,
type=global_ns.namespace("constexpr char * const"),
)
arg = cg.static_const_array(arr_id, cg.ArrayInitializer(*options))
template_arg = TemplateArguments(len(options), *template_arg)
else:
# Lambda
arg = await cg.process_lambda(
config[CONF_LAMBDA],
[(global_ns.namespace("StringRef &").operator("const"), "current")] + args,
return_type=cg.bool_,
)
template_arg = TemplateArguments(0, *template_arg)
return cg.new_Pvariable(condition_id, template_arg, paren, arg)
@automation.register_action(
"select.operation",
SelectOperationAction,

View File

@@ -66,4 +66,34 @@ template<typename... Ts> class SelectOperationAction : public Action<Ts...> {
Select *select_;
};
template<size_t N, typename... Ts> class SelectIsCondition : public Condition<Ts...> {
public:
SelectIsCondition(Select *parent, const char *const *option_list) : parent_(parent), option_list_(option_list) {}
bool check(const Ts &...x) override {
auto current = this->parent_->current_option();
for (size_t i = 0; i != N; i++) {
if (current == this->option_list_[i]) {
return true;
}
}
return false;
}
protected:
Select *parent_;
const char *const *option_list_;
};
template<typename... Ts> class SelectIsCondition<0, Ts...> : public Condition<Ts...> {
public:
SelectIsCondition(Select *parent, std::function<bool(const StringRef &, const Ts &...)> &&f)
: parent_(parent), f_(f) {}
bool check(const Ts &...x) override { return this->f_(this->parent_->current_option(), x...); }
protected:
Select *parent_;
std::function<bool(const StringRef &, const Ts &...)> f_;
};
} // namespace esphome::select

View File

@@ -1,6 +1,6 @@
pylint==4.0.4
flake8==7.3.0 # also change in .pre-commit-config.yaml when updating
ruff==0.14.12 # also change in .pre-commit-config.yaml when updating
ruff==0.14.13 # also change in .pre-commit-config.yaml when updating
pyupgrade==3.21.2 # also change in .pre-commit-config.yaml when updating
pre-commit

View File

@@ -53,6 +53,17 @@ binary_sensor:
// Garage Door is closed.
return false;
}
- platform: template
id: select_binary_sensor
name: Select is one or two
condition:
any:
- select.is:
id: template_select
options: [one, two]
- select.is:
id: template_select
lambda: return current == id(template_text).state;
- platform: template
id: other_binary_sensor
name: "Garage Door Closed"
@@ -320,6 +331,7 @@ valve:
text:
- platform: template
id: template_text
name: "Template text"
optimistic: true
min_length: 0