mirror of
https://github.com/esphome/esphome.git
synced 2026-01-19 17:46:23 -07:00
Compare commits
8 Commits
statsd_sta
...
mapping_de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
befe5d3bd2 | ||
|
|
bdabbdaaea | ||
|
|
90989aa7cd | ||
|
|
72ebee5267 | ||
|
|
648a40de7b | ||
|
|
52ac9e1861 | ||
|
|
c5e4a60884 | ||
|
|
a680884138 |
@@ -11,7 +11,7 @@ ci:
|
|||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
# Ruff version.
|
# Ruff version.
|
||||||
rev: v0.14.11
|
rev: v0.14.13
|
||||||
hooks:
|
hooks:
|
||||||
# Run the linter.
|
# Run the linter.
|
||||||
- id: ruff
|
- id: ruff
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
#include <cinttypes>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -43,8 +44,17 @@ template<typename K, typename V> class Mapping {
|
|||||||
esph_log_e(TAG, "Key '%p' not found in mapping", key);
|
esph_log_e(TAG, "Key '%p' not found in mapping", key);
|
||||||
} else if constexpr (std::is_same_v<K, std::string>) {
|
} else if constexpr (std::is_same_v<K, std::string>) {
|
||||||
esph_log_e(TAG, "Key '%s' not found in mapping", key.c_str());
|
esph_log_e(TAG, "Key '%s' not found in mapping", key.c_str());
|
||||||
|
} else if constexpr (std::is_integral_v<K>) {
|
||||||
|
char buf[24]; // enough for 64-bit integer
|
||||||
|
if constexpr (std::is_unsigned_v<K>) {
|
||||||
|
buf_append_printf(buf, sizeof(buf), 0, "%" PRIu64, static_cast<uint64_t>(key));
|
||||||
|
} else {
|
||||||
|
buf_append_printf(buf, sizeof(buf), 0, "%" PRId64, static_cast<int64_t>(key));
|
||||||
|
}
|
||||||
|
esph_log_e(TAG, "Key '%s' not found in mapping", buf);
|
||||||
} else {
|
} else {
|
||||||
esph_log_e(TAG, "Key '%s' not found in mapping", to_string(key).c_str());
|
// All supported key types are handled above - this should never be reached
|
||||||
|
static_assert(sizeof(K) == 0, "Unsupported key type for Mapping error logging");
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,8 +85,8 @@ optional<AEHAData> AEHAProtocol::decode(RemoteReceiveData src) {
|
|||||||
std::string AEHAProtocol::format_data_(const std::vector<uint8_t> &data) {
|
std::string AEHAProtocol::format_data_(const std::vector<uint8_t> &data) {
|
||||||
std::string out;
|
std::string out;
|
||||||
for (uint8_t byte : data) {
|
for (uint8_t byte : data) {
|
||||||
char buf[6];
|
char buf[8]; // "0x%02X," = 5 chars + null + margin
|
||||||
sprintf(buf, "0x%02X,", byte);
|
snprintf(buf, sizeof(buf), "0x%02X,", byte);
|
||||||
out += buf;
|
out += buf;
|
||||||
}
|
}
|
||||||
out.pop_back();
|
out.pop_back();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "raw_protocol.h"
|
#include "raw_protocol.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
@@ -8,36 +9,30 @@ static const char *const TAG = "remote.raw";
|
|||||||
|
|
||||||
bool RawDumper::dump(RemoteReceiveData src) {
|
bool RawDumper::dump(RemoteReceiveData src) {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
uint32_t buffer_offset = 0;
|
size_t pos = buf_append_printf(buffer, sizeof(buffer), 0, "Received Raw: ");
|
||||||
buffer_offset += sprintf(buffer, "Received Raw: ");
|
|
||||||
|
|
||||||
for (int32_t i = 0; i < src.size() - 1; i++) {
|
for (int32_t i = 0; i < src.size() - 1; i++) {
|
||||||
const int32_t value = src[i];
|
const int32_t value = src[i];
|
||||||
const uint32_t remaining_length = sizeof(buffer) - buffer_offset;
|
size_t prev_pos = pos;
|
||||||
int written;
|
|
||||||
|
|
||||||
if (i + 1 < src.size() - 1) {
|
if (i + 1 < src.size() - 1) {
|
||||||
written = snprintf(buffer + buffer_offset, remaining_length, "%" PRId32 ", ", value);
|
pos = buf_append_printf(buffer, sizeof(buffer), pos, "%" PRId32 ", ", value);
|
||||||
} else {
|
} else {
|
||||||
written = snprintf(buffer + buffer_offset, remaining_length, "%" PRId32, value);
|
pos = buf_append_printf(buffer, sizeof(buffer), pos, "%" PRId32, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (written < 0 || written >= int(remaining_length)) {
|
if (pos >= sizeof(buffer) - 1) {
|
||||||
// write failed, flush...
|
// buffer full, flush and continue
|
||||||
buffer[buffer_offset] = '\0';
|
buffer[prev_pos] = '\0';
|
||||||
ESP_LOGI(TAG, "%s", buffer);
|
ESP_LOGI(TAG, "%s", buffer);
|
||||||
buffer_offset = 0;
|
|
||||||
written = sprintf(buffer, " ");
|
|
||||||
if (i + 1 < src.size() - 1) {
|
if (i + 1 < src.size() - 1) {
|
||||||
written += sprintf(buffer + written, "%" PRId32 ", ", value);
|
pos = buf_append_printf(buffer, sizeof(buffer), 0, " %" PRId32 ", ", value);
|
||||||
} else {
|
} else {
|
||||||
written += sprintf(buffer + written, "%" PRId32, value);
|
pos = buf_append_printf(buffer, sizeof(buffer), 0, " %" PRId32, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_offset += written;
|
|
||||||
}
|
}
|
||||||
if (buffer_offset != 0) {
|
if (pos != 0) {
|
||||||
ESP_LOGI(TAG, "%s", buffer);
|
ESP_LOGI(TAG, "%s", buffer);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "remote_base.h"
|
#include "remote_base.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
@@ -169,36 +170,31 @@ void RemoteTransmitterBase::send_(uint32_t send_times, uint32_t send_wait) {
|
|||||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||||
const auto &vec = this->temp_.get_data();
|
const auto &vec = this->temp_.get_data();
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
uint32_t buffer_offset = 0;
|
size_t pos = buf_append_printf(buffer, sizeof(buffer), 0,
|
||||||
buffer_offset += sprintf(buffer, "Sending times=%" PRIu32 " wait=%" PRIu32 "ms: ", send_times, send_wait);
|
"Sending times=%" PRIu32 " wait=%" PRIu32 "ms: ", send_times, send_wait);
|
||||||
|
|
||||||
for (size_t i = 0; i < vec.size(); i++) {
|
for (size_t i = 0; i < vec.size(); i++) {
|
||||||
const int32_t value = vec[i];
|
const int32_t value = vec[i];
|
||||||
const uint32_t remaining_length = sizeof(buffer) - buffer_offset;
|
size_t prev_pos = pos;
|
||||||
int written;
|
|
||||||
|
|
||||||
if (i + 1 < vec.size()) {
|
if (i + 1 < vec.size()) {
|
||||||
written = snprintf(buffer + buffer_offset, remaining_length, "%" PRId32 ", ", value);
|
pos = buf_append_printf(buffer, sizeof(buffer), pos, "%" PRId32 ", ", value);
|
||||||
} else {
|
} else {
|
||||||
written = snprintf(buffer + buffer_offset, remaining_length, "%" PRId32, value);
|
pos = buf_append_printf(buffer, sizeof(buffer), pos, "%" PRId32, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (written < 0 || written >= int(remaining_length)) {
|
if (pos >= sizeof(buffer) - 1) {
|
||||||
// write failed, flush...
|
// buffer full, flush and continue
|
||||||
buffer[buffer_offset] = '\0';
|
buffer[prev_pos] = '\0';
|
||||||
ESP_LOGVV(TAG, "%s", buffer);
|
ESP_LOGVV(TAG, "%s", buffer);
|
||||||
buffer_offset = 0;
|
|
||||||
written = sprintf(buffer, " ");
|
|
||||||
if (i + 1 < vec.size()) {
|
if (i + 1 < vec.size()) {
|
||||||
written += sprintf(buffer + written, "%" PRId32 ", ", value);
|
pos = buf_append_printf(buffer, sizeof(buffer), 0, " %" PRId32 ", ", value);
|
||||||
} else {
|
} else {
|
||||||
written += sprintf(buffer + written, "%" PRId32, value);
|
pos = buf_append_printf(buffer, sizeof(buffer), 0, " %" PRId32, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_offset += written;
|
|
||||||
}
|
}
|
||||||
if (buffer_offset != 0) {
|
if (pos != 0) {
|
||||||
ESP_LOGVV(TAG, "%s", buffer);
|
ESP_LOGVV(TAG, "%s", buffer);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -8,17 +8,20 @@ from esphome.const import (
|
|||||||
CONF_ICON,
|
CONF_ICON,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
CONF_INDEX,
|
CONF_INDEX,
|
||||||
|
CONF_LAMBDA,
|
||||||
CONF_MODE,
|
CONF_MODE,
|
||||||
CONF_MQTT_ID,
|
CONF_MQTT_ID,
|
||||||
CONF_ON_VALUE,
|
CONF_ON_VALUE,
|
||||||
CONF_OPERATION,
|
CONF_OPERATION,
|
||||||
CONF_OPTION,
|
CONF_OPTION,
|
||||||
|
CONF_OPTIONS,
|
||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
CONF_WEB_SERVER,
|
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.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"]
|
CODEOWNERS = ["@esphome/core"]
|
||||||
IS_PLATFORM_COMPONENT = True
|
IS_PLATFORM_COMPONENT = True
|
||||||
@@ -38,6 +41,9 @@ SelectSetAction = select_ns.class_("SelectSetAction", automation.Action)
|
|||||||
SelectSetIndexAction = select_ns.class_("SelectSetIndexAction", automation.Action)
|
SelectSetIndexAction = select_ns.class_("SelectSetIndexAction", automation.Action)
|
||||||
SelectOperationAction = select_ns.class_("SelectOperationAction", automation.Action)
|
SelectOperationAction = select_ns.class_("SelectOperationAction", automation.Action)
|
||||||
|
|
||||||
|
# Conditions
|
||||||
|
SelectIsCondition = select_ns.class_("SelectIsCondition", automation.Condition)
|
||||||
|
|
||||||
# Enums
|
# Enums
|
||||||
SelectOperation = select_ns.enum("SelectOperation")
|
SelectOperation = select_ns.enum("SelectOperation")
|
||||||
SELECT_OPERATION_OPTIONS = {
|
SELECT_OPERATION_OPTIONS = {
|
||||||
@@ -165,6 +171,41 @@ async def select_set_index_to_code(config, action_id, template_arg, args):
|
|||||||
return var
|
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(
|
@automation.register_action(
|
||||||
"select.operation",
|
"select.operation",
|
||||||
SelectOperationAction,
|
SelectOperationAction,
|
||||||
|
|||||||
@@ -66,4 +66,34 @@ template<typename... Ts> class SelectOperationAction : public Action<Ts...> {
|
|||||||
Select *select_;
|
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
|
} // namespace esphome::select
|
||||||
|
|||||||
@@ -114,22 +114,14 @@ void StatsdComponent::update() {
|
|||||||
// This implies you can't explicitly set a gauge to a negative number without first setting it to zero.
|
// This implies you can't explicitly set a gauge to a negative number without first setting it to zero.
|
||||||
if (val < 0) {
|
if (val < 0) {
|
||||||
if (this->prefix_) {
|
if (this->prefix_) {
|
||||||
out.append(this->prefix_);
|
out.append(str_sprintf("%s.", this->prefix_));
|
||||||
out.append(".");
|
|
||||||
}
|
}
|
||||||
out.append(s.name);
|
out.append(str_sprintf("%s:0|g\n", s.name));
|
||||||
out.append(":0|g\n");
|
|
||||||
}
|
}
|
||||||
if (this->prefix_) {
|
if (this->prefix_) {
|
||||||
out.append(this->prefix_);
|
out.append(str_sprintf("%s.", this->prefix_));
|
||||||
out.append(".");
|
|
||||||
}
|
}
|
||||||
out.append(s.name);
|
out.append(str_sprintf("%s:%f|g\n", s.name, val));
|
||||||
// Buffer for ":" + value + "|g\n".
|
|
||||||
// %f with -DBL_MAX can produce up to 321 chars, plus ":" and "|g\n" (4) + null = 326
|
|
||||||
char val_buf[330];
|
|
||||||
buf_append_printf(val_buf, sizeof(val_buf), 0, ":%f|g\n", val);
|
|
||||||
out.append(val_buf);
|
|
||||||
|
|
||||||
if (out.length() > SEND_THRESHOLD) {
|
if (out.length() > SEND_THRESHOLD) {
|
||||||
this->send_(&out);
|
this->send_(&out);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
pylint==4.0.4
|
pylint==4.0.4
|
||||||
flake8==7.3.0 # also change in .pre-commit-config.yaml when updating
|
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
|
pyupgrade==3.21.2 # also change in .pre-commit-config.yaml when updating
|
||||||
pre-commit
|
pre-commit
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,17 @@ binary_sensor:
|
|||||||
// Garage Door is closed.
|
// Garage Door is closed.
|
||||||
return false;
|
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
|
- platform: template
|
||||||
id: other_binary_sensor
|
id: other_binary_sensor
|
||||||
name: "Garage Door Closed"
|
name: "Garage Door Closed"
|
||||||
@@ -320,6 +331,7 @@ valve:
|
|||||||
|
|
||||||
text:
|
text:
|
||||||
- platform: template
|
- platform: template
|
||||||
|
id: template_text
|
||||||
name: "Template text"
|
name: "Template text"
|
||||||
optimistic: true
|
optimistic: true
|
||||||
min_length: 0
|
min_length: 0
|
||||||
|
|||||||
Reference in New Issue
Block a user