1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-13 15:23:49 +01:00

Merge remote-tracking branch 'upstream/dev' into bound_tx_buf

This commit is contained in:
J. Nick Koston
2025-10-03 18:38:20 -05:00
28 changed files with 236 additions and 99 deletions

View File

@@ -466,7 +466,7 @@ jobs:
with: with:
python-version: ${{ env.DEFAULT_PYTHON }} python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }} cache-key: ${{ needs.common.outputs.cache-key }}
- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 - uses: esphome/action@43cd1109c09c544d97196f7730ee5b2e0cc6d81e # v3.0.1 fork with pinned actions/cache
env: env:
SKIP: pylint,clang-tidy-hash SKIP: pylint,clang-tidy-hash
- uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0 - uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0

View File

@@ -58,7 +58,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 uses: github/codeql-action/init@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }} build-mode: ${{ matrix.build-mode }}
@@ -86,6 +86,6 @@ jobs:
exit 1 exit 1
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 uses: github/codeql-action/analyze@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6
with: with:
category: "/language:${{matrix.language}}" category: "/language:${{matrix.language}}"

View File

@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Stale - name: Stale
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0 uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
with: with:
debug-only: ${{ github.ref != 'refs/heads/dev' }} # Dry-run when not run on dev branch debug-only: ${{ github.ref != 'refs/heads/dev' }} # Dry-run when not run on dev branch
remove-stale-when-updated: true remove-stale-when-updated: true

View File

@@ -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.13.2 rev: v0.13.3
hooks: hooks:
# Run the linter. # Run the linter.
- id: ruff - id: ruff

View File

@@ -14,9 +14,11 @@ from typing import Protocol
import argcomplete import argcomplete
# Note: Do not import modules from esphome.components here, as this would
# cause them to be loaded before external components are processed, resulting
# in the built-in version being used instead of the external component one.
from esphome import const, writer, yaml_util from esphome import const, writer, yaml_util
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.mqtt import CONF_DISCOVER_IP
from esphome.config import iter_component_configs, read_config, strip_default_ids from esphome.config import iter_component_configs, read_config, strip_default_ids
from esphome.const import ( from esphome.const import (
ALLOWED_NAME_CHARS, ALLOWED_NAME_CHARS,
@@ -240,6 +242,8 @@ def has_ota() -> bool:
def has_mqtt_ip_lookup() -> bool: def has_mqtt_ip_lookup() -> bool:
"""Check if MQTT is available and IP lookup is supported.""" """Check if MQTT is available and IP lookup is supported."""
from esphome.components.mqtt import CONF_DISCOVER_IP
if CONF_MQTT not in CORE.config: if CONF_MQTT not in CORE.config:
return False return False
# Default Enabled # Default Enabled

View File

@@ -14,6 +14,7 @@ from esphome.const import (
CONF_EVENT, CONF_EVENT,
CONF_ID, CONF_ID,
CONF_KEY, CONF_KEY,
CONF_MAX_CONNECTIONS,
CONF_ON_CLIENT_CONNECTED, CONF_ON_CLIENT_CONNECTED,
CONF_ON_CLIENT_DISCONNECTED, CONF_ON_CLIENT_DISCONNECTED,
CONF_PASSWORD, CONF_PASSWORD,
@@ -60,7 +61,6 @@ CONF_CUSTOM_SERVICES = "custom_services"
CONF_HOMEASSISTANT_SERVICES = "homeassistant_services" CONF_HOMEASSISTANT_SERVICES = "homeassistant_services"
CONF_HOMEASSISTANT_STATES = "homeassistant_states" CONF_HOMEASSISTANT_STATES = "homeassistant_states"
CONF_LISTEN_BACKLOG = "listen_backlog" CONF_LISTEN_BACKLOG = "listen_backlog"
CONF_MAX_CONNECTIONS = "max_connections"
CONF_MAX_SEND_QUEUE = "max_send_queue" CONF_MAX_SEND_QUEUE = "max_send_queue"

View File

@@ -205,7 +205,8 @@ void APIConnection::loop() {
// Disconnect if not responded within 2.5*keepalive // Disconnect if not responded within 2.5*keepalive
if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) { if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) {
on_fatal_error(); on_fatal_error();
ESP_LOGW(TAG, "%s is unresponsive; disconnecting", this->get_client_combined_info().c_str()); ESP_LOGW(TAG, "%s (%s) is unresponsive; disconnecting", this->client_info_.name.c_str(),
this->client_info_.peername.c_str());
} }
} else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && !this->flags_.remove) { } else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && !this->flags_.remove) {
// Only send ping if we're not disconnecting // Only send ping if we're not disconnecting
@@ -255,7 +256,7 @@ bool APIConnection::send_disconnect_response(const DisconnectRequest &msg) {
// remote initiated disconnect_client // remote initiated disconnect_client
// don't close yet, we still need to send the disconnect response // don't close yet, we still need to send the disconnect response
// close will happen on next loop // close will happen on next loop
ESP_LOGD(TAG, "%s disconnected", this->get_client_combined_info().c_str()); ESP_LOGD(TAG, "%s (%s) disconnected", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
this->flags_.next_close = true; this->flags_.next_close = true;
DisconnectResponse resp; DisconnectResponse resp;
return this->send_message(resp, DisconnectResponse::MESSAGE_TYPE); return this->send_message(resp, DisconnectResponse::MESSAGE_TYPE);
@@ -1385,7 +1386,7 @@ void APIConnection::complete_authentication_() {
} }
this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::AUTHENTICATED); this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::AUTHENTICATED);
ESP_LOGD(TAG, "%s connected", this->get_client_combined_info().c_str()); ESP_LOGD(TAG, "%s (%s) connected", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER #ifdef USE_API_CLIENT_CONNECTED_TRIGGER
this->parent_->get_client_connected_trigger()->trigger(this->client_info_.name, this->client_info_.peername); this->parent_->get_client_connected_trigger()->trigger(this->client_info_.name, this->client_info_.peername);
#endif #endif
@@ -1609,12 +1610,12 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) {
#ifdef USE_API_PASSWORD #ifdef USE_API_PASSWORD
void APIConnection::on_unauthenticated_access() { void APIConnection::on_unauthenticated_access() {
this->on_fatal_error(); this->on_fatal_error();
ESP_LOGD(TAG, "%s access without authentication", this->get_client_combined_info().c_str()); ESP_LOGD(TAG, "%s (%s) no authentication", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
} }
#endif #endif
void APIConnection::on_no_setup_connection() { void APIConnection::on_no_setup_connection() {
this->on_fatal_error(); this->on_fatal_error();
ESP_LOGD(TAG, "%s access without full connection", this->get_client_combined_info().c_str()); ESP_LOGD(TAG, "%s (%s) no connection setup", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
} }
void APIConnection::on_fatal_error() { void APIConnection::on_fatal_error() {
this->helper_->close(); this->helper_->close();
@@ -1866,8 +1867,8 @@ void APIConnection::process_state_subscriptions_() {
#endif // USE_API_HOMEASSISTANT_STATES #endif // USE_API_HOMEASSISTANT_STATES
void APIConnection::log_warning_(const LogString *message, APIError err) { void APIConnection::log_warning_(const LogString *message, APIError err) {
ESP_LOGW(TAG, "%s: %s %s errno=%d", this->get_client_combined_info().c_str(), LOG_STR_ARG(message), ESP_LOGW(TAG, "%s (%s): %s %s errno=%d", this->client_info_.name.c_str(), this->client_info_.peername.c_str(),
LOG_STR_ARG(api_error_to_logstr(err)), errno); LOG_STR_ARG(message), LOG_STR_ARG(api_error_to_logstr(err)), errno);
} }
void APIConnection::log_socket_operation_failed_(APIError err) { void APIConnection::log_socket_operation_failed_(APIError err) {

View File

@@ -19,14 +19,6 @@ namespace esphome::api {
struct ClientInfo { struct ClientInfo {
std::string name; // Client name from Hello message std::string name; // Client name from Hello message
std::string peername; // IP:port from socket std::string peername; // IP:port from socket
std::string get_combined_info() const {
if (name == peername) {
// Before Hello message, both are the same
return name;
}
return name + " (" + peername + ")";
}
}; };
// Keepalive timeout in milliseconds // Keepalive timeout in milliseconds
@@ -278,7 +270,8 @@ class APIConnection final : public APIServerConnection {
bool try_to_clear_buffer(bool log_out_of_space); bool try_to_clear_buffer(bool log_out_of_space);
bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) override; bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) override;
std::string get_client_combined_info() const { return this->client_info_.get_combined_info(); } const std::string &get_name() const { return this->client_info_.name; }
const std::string &get_peername() const { return this->client_info_.peername; }
protected: protected:
// Helper function to handle authentication completion // Helper function to handle authentication completion

View File

@@ -13,7 +13,8 @@ namespace esphome::api {
static const char *const TAG = "api.frame_helper"; static const char *const TAG = "api.frame_helper";
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, this->client_info_->get_combined_info().c_str(), ##__VA_ARGS__) #define HELPER_LOG(msg, ...) \
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__)
#ifdef HELPER_LOG_PACKETS #ifdef HELPER_LOG_PACKETS
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str()) #define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str())

View File

@@ -24,7 +24,8 @@ static const char *const PROLOGUE_INIT = "NoiseAPIInit";
#endif #endif
static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit") static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit")
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, this->client_info_->get_combined_info().c_str(), ##__VA_ARGS__) #define HELPER_LOG(msg, ...) \
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__)
#ifdef HELPER_LOG_PACKETS #ifdef HELPER_LOG_PACKETS
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str()) #define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str())

View File

@@ -18,7 +18,8 @@ namespace esphome::api {
static const char *const TAG = "api.plaintext"; static const char *const TAG = "api.plaintext";
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, this->client_info_->get_combined_info().c_str(), ##__VA_ARGS__) #define HELPER_LOG(msg, ...) \
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__)
#ifdef HELPER_LOG_PACKETS #ifdef HELPER_LOG_PACKETS
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str()) #define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str())

View File

@@ -177,7 +177,8 @@ void APIServer::loop() {
// Network is down - disconnect all clients // Network is down - disconnect all clients
for (auto &client : this->clients_) { for (auto &client : this->clients_) {
client->on_fatal_error(); client->on_fatal_error();
ESP_LOGW(TAG, "%s: Network down; disconnect", client->get_client_combined_info().c_str()); ESP_LOGW(TAG, "%s (%s): Network down; disconnect", client->client_info_.name.c_str(),
client->client_info_.peername.c_str());
} }
// Continue to process and clean up the clients below // Continue to process and clean up the clients below
} }

View File

@@ -55,7 +55,7 @@ template<typename... Ts> class UserServiceBase : public UserServiceDescriptor {
protected: protected:
virtual void execute(Ts... x) = 0; virtual void execute(Ts... x) = 0;
template<int... S> void execute_(std::vector<ExecuteServiceArgument> args, seq<S...> type) { template<int... S> void execute_(const std::vector<ExecuteServiceArgument> &args, seq<S...> type) {
this->execute((get_execute_arg_value<Ts>(args[S]))...); this->execute((get_execute_arg_value<Ts>(args[S]))...);
} }

View File

@@ -24,6 +24,7 @@ from esphome.const import (
CONF_INTERVAL, CONF_INTERVAL,
CONF_MAC_ADDRESS, CONF_MAC_ADDRESS,
CONF_MANUFACTURER_ID, CONF_MANUFACTURER_ID,
CONF_MAX_CONNECTIONS,
CONF_ON_BLE_ADVERTISE, CONF_ON_BLE_ADVERTISE,
CONF_ON_BLE_MANUFACTURER_DATA_ADVERTISE, CONF_ON_BLE_MANUFACTURER_DATA_ADVERTISE,
CONF_ON_BLE_SERVICE_DATA_ADVERTISE, CONF_ON_BLE_SERVICE_DATA_ADVERTISE,
@@ -41,7 +42,6 @@ CODEOWNERS = ["@bdraco"]
KEY_ESP32_BLE_TRACKER = "esp32_ble_tracker" KEY_ESP32_BLE_TRACKER = "esp32_ble_tracker"
KEY_USED_CONNECTION_SLOTS = "used_connection_slots" KEY_USED_CONNECTION_SLOTS = "used_connection_slots"
CONF_MAX_CONNECTIONS = "max_connections"
CONF_ESP32_BLE_ID = "esp32_ble_id" CONF_ESP32_BLE_ID = "esp32_ble_id"
CONF_SCAN_PARAMETERS = "scan_parameters" CONF_SCAN_PARAMETERS = "scan_parameters"
CONF_WINDOW = "window" CONF_WINDOW = "window"

View File

@@ -67,8 +67,16 @@ static bool get_bitrate(canbus::CanSpeed bitrate, twai_timing_config_t *t_config
} }
bool ESP32Can::setup_internal() { bool ESP32Can::setup_internal() {
static int next_twai_ctrl_num = 0;
if (next_twai_ctrl_num >= SOC_TWAI_CONTROLLER_NUM) {
ESP_LOGW(TAG, "Maximum number of esp32_can components created already");
this->mark_failed();
return false;
}
twai_general_config_t g_config = twai_general_config_t g_config =
TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, TWAI_MODE_NORMAL); TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, TWAI_MODE_NORMAL);
g_config.controller_id = next_twai_ctrl_num++;
if (this->tx_queue_len_.has_value()) { if (this->tx_queue_len_.has_value()) {
g_config.tx_queue_len = this->tx_queue_len_.value(); g_config.tx_queue_len = this->tx_queue_len_.value();
} }
@@ -86,14 +94,14 @@ bool ESP32Can::setup_internal() {
} }
// Install TWAI driver // Install TWAI driver
if (twai_driver_install(&g_config, &t_config, &f_config) != ESP_OK) { if (twai_driver_install_v2(&g_config, &t_config, &f_config, &(this->twai_handle_)) != ESP_OK) {
// Failed to install driver // Failed to install driver
this->mark_failed(); this->mark_failed();
return false; return false;
} }
// Start TWAI driver // Start TWAI driver
if (twai_start() != ESP_OK) { if (twai_start_v2(this->twai_handle_) != ESP_OK) {
// Failed to start driver // Failed to start driver
this->mark_failed(); this->mark_failed();
return false; return false;
@@ -102,6 +110,11 @@ bool ESP32Can::setup_internal() {
} }
canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) { canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) {
if (this->twai_handle_ == nullptr) {
// not setup yet or setup failed
return canbus::ERROR_FAIL;
}
if (frame->can_data_length_code > canbus::CAN_MAX_DATA_LENGTH) { if (frame->can_data_length_code > canbus::CAN_MAX_DATA_LENGTH) {
return canbus::ERROR_FAILTX; return canbus::ERROR_FAILTX;
} }
@@ -124,7 +137,7 @@ canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) {
memcpy(message.data, frame->data, frame->can_data_length_code); memcpy(message.data, frame->data, frame->can_data_length_code);
} }
if (twai_transmit(&message, this->tx_enqueue_timeout_ticks_) == ESP_OK) { if (twai_transmit_v2(this->twai_handle_, &message, this->tx_enqueue_timeout_ticks_) == ESP_OK) {
return canbus::ERROR_OK; return canbus::ERROR_OK;
} else { } else {
return canbus::ERROR_ALLTXBUSY; return canbus::ERROR_ALLTXBUSY;
@@ -132,9 +145,14 @@ canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) {
} }
canbus::Error ESP32Can::read_message(struct canbus::CanFrame *frame) { canbus::Error ESP32Can::read_message(struct canbus::CanFrame *frame) {
if (this->twai_handle_ == nullptr) {
// not setup yet or setup failed
return canbus::ERROR_FAIL;
}
twai_message_t message; twai_message_t message;
if (twai_receive(&message, 0) != ESP_OK) { if (twai_receive_v2(this->twai_handle_, &message, 0) != ESP_OK) {
return canbus::ERROR_NOMSG; return canbus::ERROR_NOMSG;
} }

View File

@@ -5,6 +5,8 @@
#include "esphome/components/canbus/canbus.h" #include "esphome/components/canbus/canbus.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include <driver/twai.h>
namespace esphome { namespace esphome {
namespace esp32_can { namespace esp32_can {
@@ -29,6 +31,7 @@ class ESP32Can : public canbus::Canbus {
TickType_t tx_enqueue_timeout_ticks_{}; TickType_t tx_enqueue_timeout_ticks_{};
optional<uint32_t> tx_queue_len_{}; optional<uint32_t> tx_queue_len_{};
optional<uint32_t> rx_queue_len_{}; optional<uint32_t> rx_queue_len_{};
twai_handle_t twai_handle_{nullptr};
}; };
} // namespace esp32_can } // namespace esp32_can

View File

@@ -355,9 +355,18 @@ class Logger : public Component {
buffer[pos++] = '['; buffer[pos++] = '[';
copy_string(buffer, pos, tag); copy_string(buffer, pos, tag);
buffer[pos++] = ':'; buffer[pos++] = ':';
buffer[pos++] = '0' + (line / 100) % 10; // Format line number without modulo operations (passed by value, safe to mutate)
buffer[pos++] = '0' + (line / 10) % 10; if (line > 999) [[unlikely]] {
buffer[pos++] = '0' + line % 10; int thousands = line / 1000;
buffer[pos++] = '0' + thousands;
line -= thousands * 1000;
}
int hundreds = line / 100;
int remainder = line - hundreds * 100;
int tens = remainder / 10;
buffer[pos++] = '0' + hundreds;
buffer[pos++] = '0' + tens;
buffer[pos++] = '0' + (remainder - tens * 10);
buffer[pos++] = ']'; buffer[pos++] = ']';
#if defined(USE_ESP32) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR) #if defined(USE_ESP32) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)

View File

@@ -3,11 +3,10 @@
namespace esphome::logger { namespace esphome::logger {
void LoggerLevelSelect::publish_state(int level) { void LoggerLevelSelect::publish_state(int level) {
auto value = this->at(level); const auto &option = this->at(level_to_index(level));
if (!value) { if (!option)
return; return;
} Select::publish_state(option.value());
Select::publish_state(value.value());
} }
void LoggerLevelSelect::setup() { void LoggerLevelSelect::setup() {
@@ -16,10 +15,10 @@ void LoggerLevelSelect::setup() {
} }
void LoggerLevelSelect::control(const std::string &value) { void LoggerLevelSelect::control(const std::string &value) {
auto level = this->index_of(value); const auto index = this->index_of(value);
if (!level) if (!index)
return; return;
this->parent_->set_log_level(level.value()); this->parent_->set_log_level(index_to_level(index.value()));
} }
} // namespace esphome::logger } // namespace esphome::logger

View File

@@ -3,11 +3,18 @@
#include "esphome/components/select/select.h" #include "esphome/components/select/select.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/components/logger/logger.h" #include "esphome/components/logger/logger.h"
namespace esphome::logger { namespace esphome::logger {
class LoggerLevelSelect : public Component, public select::Select, public Parented<Logger> { class LoggerLevelSelect : public Component, public select::Select, public Parented<Logger> {
public: public:
void publish_state(int level); void publish_state(int level);
void setup() override; void setup() override;
void control(const std::string &value) override; void control(const std::string &value) override;
protected:
// Convert log level to option index (skip CONFIG at level 4)
static uint8_t level_to_index(uint8_t level) { return (level > ESPHOME_LOG_LEVEL_CONFIG) ? level - 1 : level; }
// Convert option index to log level (skip CONFIG at level 4)
static uint8_t index_to_level(uint8_t index) { return (index >= ESPHOME_LOG_LEVEL_CONFIG) ? index + 1 : index; }
}; };
} // namespace esphome::logger } // namespace esphome::logger

View File

@@ -13,45 +13,46 @@ static const char *const TAG = "mpr121";
void MPR121Component::setup() { void MPR121Component::setup() {
// soft reset device // soft reset device
this->write_byte(MPR121_SOFTRESET, 0x63); this->write_byte(MPR121_SOFTRESET, 0x63);
delay(100); // NOLINT this->set_timeout(100, [this]() {
if (!this->write_byte(MPR121_ECR, 0x0)) { if (!this->write_byte(MPR121_ECR, 0x0)) {
this->error_code_ = COMMUNICATION_FAILED; this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed(); this->mark_failed();
return; return;
} }
// set touch sensitivity for all 12 channels
for (auto *channel : this->channels_) {
channel->setup();
}
this->write_byte(MPR121_MHDR, 0x01);
this->write_byte(MPR121_NHDR, 0x01);
this->write_byte(MPR121_NCLR, 0x0E);
this->write_byte(MPR121_FDLR, 0x00);
// set touch sensitivity for all 12 channels this->write_byte(MPR121_MHDF, 0x01);
for (auto *channel : this->channels_) { this->write_byte(MPR121_NHDF, 0x05);
channel->setup(); this->write_byte(MPR121_NCLF, 0x01);
} this->write_byte(MPR121_FDLF, 0x00);
this->write_byte(MPR121_MHDR, 0x01);
this->write_byte(MPR121_NHDR, 0x01);
this->write_byte(MPR121_NCLR, 0x0E);
this->write_byte(MPR121_FDLR, 0x00);
this->write_byte(MPR121_MHDF, 0x01); this->write_byte(MPR121_NHDT, 0x00);
this->write_byte(MPR121_NHDF, 0x05); this->write_byte(MPR121_NCLT, 0x00);
this->write_byte(MPR121_NCLF, 0x01); this->write_byte(MPR121_FDLT, 0x00);
this->write_byte(MPR121_FDLF, 0x00);
this->write_byte(MPR121_NHDT, 0x00); this->write_byte(MPR121_DEBOUNCE, 0);
this->write_byte(MPR121_NCLT, 0x00); // default, 16uA charge current
this->write_byte(MPR121_FDLT, 0x00); this->write_byte(MPR121_CONFIG1, 0x10);
// 0.5uS encoding, 1ms period
this->write_byte(MPR121_CONFIG2, 0x20);
this->write_byte(MPR121_DEBOUNCE, 0); // Write the Electrode Configuration Register
// default, 16uA charge current // * Highest 2 bits is "Calibration Lock", which we set to a value corresponding to 5 bits.
this->write_byte(MPR121_CONFIG1, 0x10); // * The 2 bits below is "Proximity Enable" and are left at 0.
// 0.5uS encoding, 1ms period // * The 4 least significant bits control how many electrodes are enabled. Electrodes are enabled
this->write_byte(MPR121_CONFIG2, 0x20); // as a range, starting at 0 up to the highest channel index used.
this->write_byte(MPR121_ECR, 0x80 | (this->max_touch_channel_ + 1));
// Write the Electrode Configuration Register this->flush_gpio_();
// * Highest 2 bits is "Calibration Lock", which we set to a value corresponding to 5 bits. this->setup_complete_ = true;
// * The 2 bits below is "Proximity Enable" and are left at 0. });
// * The 4 least significant bits control how many electrodes are enabled. Electrodes are enabled
// as a range, starting at 0 up to the highest channel index used.
this->write_byte(MPR121_ECR, 0x80 | (this->max_touch_channel_ + 1));
this->flush_gpio_();
} }
void MPR121Component::set_touch_debounce(uint8_t debounce) { void MPR121Component::set_touch_debounce(uint8_t debounce) {
@@ -73,15 +74,15 @@ void MPR121Component::dump_config() {
case COMMUNICATION_FAILED: case COMMUNICATION_FAILED:
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
break; break;
case WRONG_CHIP_STATE:
ESP_LOGE(TAG, "MPR121 has wrong default value for CONFIG2?");
break;
case NONE: case NONE:
default: default:
break; break;
} }
} }
void MPR121Component::loop() { void MPR121Component::loop() {
if (!this->setup_complete_)
return;
uint16_t val = 0; uint16_t val = 0;
this->read_byte_16(MPR121_TOUCHSTATUS_L, &val); this->read_byte_16(MPR121_TOUCHSTATUS_L, &val);

View File

@@ -80,6 +80,7 @@ class MPR121Component : public Component, public i2c::I2CDevice {
void pin_mode(uint8_t ionum, gpio::Flags flags); void pin_mode(uint8_t ionum, gpio::Flags flags);
protected: protected:
bool setup_complete_{false};
std::vector<MPR121Channel *> channels_{}; std::vector<MPR121Channel *> channels_{};
uint8_t debounce_{0}; uint8_t debounce_{0};
uint8_t touch_threshold_{}; uint8_t touch_threshold_{};
@@ -88,7 +89,6 @@ class MPR121Component : public Component, public i2c::I2CDevice {
enum ErrorCode { enum ErrorCode {
NONE = 0, NONE = 0,
COMMUNICATION_FAILED, COMMUNICATION_FAILED,
WRONG_CHIP_STATE,
} error_code_{NONE}; } error_code_{NONE};
bool flush_gpio_(); bool flush_gpio_();

View File

@@ -374,7 +374,7 @@ void Rtttl::loop() {
this->last_note_ = millis(); this->last_note_ = millis();
} }
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
static const LogString *state_to_string(State state) { static const LogString *state_to_string(State state) {
switch (state) { switch (state) {
case STATE_STOPPED: case STATE_STOPPED:

View File

@@ -45,24 +45,26 @@ void SPS30Component::setup() {
} }
ESP_LOGV(TAG, " Serial number: %s", this->serial_number_); ESP_LOGV(TAG, " Serial number: %s", this->serial_number_);
bool result;
if (this->fan_interval_.has_value()) { if (this->fan_interval_.has_value()) {
// override default value // override default value
result = this->write_command(SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS, this->fan_interval_.value()); this->result_ =
this->write_command(SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS, this->fan_interval_.value());
} else { } else {
result = this->write_command(SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS); this->result_ = this->write_command(SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS);
}
if (result) {
delay(20);
uint16_t secs[2];
if (this->read_data(secs, 2)) {
this->fan_interval_ = secs[0] << 16 | secs[1];
}
} }
this->status_clear_warning(); this->set_timeout(20, [this]() {
this->skipped_data_read_cycles_ = 0; if (this->result_) {
this->start_continuous_measurement_(); uint16_t secs[2];
if (this->read_data(secs, 2)) {
this->fan_interval_ = secs[0] << 16 | secs[1];
}
}
this->status_clear_warning();
this->skipped_data_read_cycles_ = 0;
this->start_continuous_measurement_();
this->setup_complete_ = true;
});
}); });
} }
@@ -111,6 +113,8 @@ void SPS30Component::dump_config() {
} }
void SPS30Component::update() { void SPS30Component::update() {
if (!this->setup_complete_)
return;
/// Check if warning flag active (sensor reconnected?) /// Check if warning flag active (sensor reconnected?)
if (this->status_has_warning()) { if (this->status_has_warning()) {
ESP_LOGD(TAG, "Reconnecting"); ESP_LOGD(TAG, "Reconnecting");

View File

@@ -30,9 +30,12 @@ class SPS30Component : public PollingComponent, public sensirion_common::Sensiri
bool start_fan_cleaning(); bool start_fan_cleaning();
protected: protected:
bool result_{false};
bool setup_complete_{false};
uint16_t raw_firmware_version_; uint16_t raw_firmware_version_;
char serial_number_[17] = {0}; /// Terminating NULL character char serial_number_[17] = {0}; /// Terminating NULL character
uint8_t skipped_data_read_cycles_ = 0; uint8_t skipped_data_read_cycles_ = 0;
bool start_continuous_measurement_(); bool start_continuous_measurement_();
enum ErrorCode : uint8_t { enum ErrorCode : uint8_t {

View File

@@ -429,8 +429,9 @@ void VoiceAssistant::client_subscription(api::APIConnection *client, bool subscr
if (this->api_client_ != nullptr) { if (this->api_client_ != nullptr) {
ESP_LOGE(TAG, "Multiple API Clients attempting to connect to Voice Assistant"); ESP_LOGE(TAG, "Multiple API Clients attempting to connect to Voice Assistant");
ESP_LOGE(TAG, "Current client: %s", this->api_client_->get_client_combined_info().c_str()); ESP_LOGE(TAG, "Current client: %s (%s)", this->api_client_->get_name().c_str(),
ESP_LOGE(TAG, "New client: %s", client->get_client_combined_info().c_str()); this->api_client_->get_peername().c_str());
ESP_LOGE(TAG, "New client: %s (%s)", client->get_name().c_str(), client->get_peername().c_str());
return; return;
} }

View File

@@ -542,6 +542,7 @@ CONF_MANUAL_IP = "manual_ip"
CONF_MANUFACTURER_ID = "manufacturer_id" CONF_MANUFACTURER_ID = "manufacturer_id"
CONF_MASK_DISTURBER = "mask_disturber" CONF_MASK_DISTURBER = "mask_disturber"
CONF_MAX_BRIGHTNESS = "max_brightness" CONF_MAX_BRIGHTNESS = "max_brightness"
CONF_MAX_CONNECTIONS = "max_connections"
CONF_MAX_COOLING_RUN_TIME = "max_cooling_run_time" CONF_MAX_COOLING_RUN_TIME = "max_cooling_run_time"
CONF_MAX_CURRENT = "max_current" CONF_MAX_CURRENT = "max_current"
CONF_MAX_DURATION = "max_duration" CONF_MAX_DURATION = "max_duration"
@@ -1169,7 +1170,7 @@ UNIT_KILOMETER = "km"
UNIT_KILOMETER_PER_HOUR = "km/h" UNIT_KILOMETER_PER_HOUR = "km/h"
UNIT_KILOVOLT_AMPS = "kVA" UNIT_KILOVOLT_AMPS = "kVA"
UNIT_KILOVOLT_AMPS_HOURS = "kVAh" UNIT_KILOVOLT_AMPS_HOURS = "kVAh"
UNIT_KILOVOLT_AMPS_REACTIVE = "kVAR" UNIT_KILOVOLT_AMPS_REACTIVE = "kvar"
UNIT_KILOVOLT_AMPS_REACTIVE_HOURS = "kvarh" UNIT_KILOVOLT_AMPS_REACTIVE_HOURS = "kvarh"
UNIT_KILOWATT = "kW" UNIT_KILOWATT = "kW"
UNIT_KILOWATT_HOURS = "kWh" UNIT_KILOWATT_HOURS = "kWh"

View File

@@ -1,6 +1,6 @@
pylint==3.3.8 pylint==3.3.8
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.13.2 # also change in .pre-commit-config.yaml when updating ruff==0.13.3 # also change in .pre-commit-config.yaml when updating
pyupgrade==3.20.0 # also change in .pre-commit-config.yaml when updating pyupgrade==3.20.0 # also change in .pre-commit-config.yaml when updating
pre-commit pre-commit

View File

@@ -0,0 +1,89 @@
esphome:
on_boot:
then:
- canbus.send:
# Extended ID explicit
canbus_id: esp32_internal_can
use_extended_id: true
can_id: 0x100
data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
- canbus.send:
# Standard ID by default
canbus_id: esp32_internal_can
can_id: 0x100
data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
- canbus.send:
# Extended ID explicit
canbus_id: esp32_internal_can_2
use_extended_id: true
can_id: 0x100
data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
- canbus.send:
# Standard ID by default
canbus_id: esp32_internal_can_2
can_id: 0x100
data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
canbus:
- platform: esp32_can
id: esp32_internal_can
rx_pin: GPIO8
tx_pin: GPIO7
can_id: 4
bit_rate: 50kbps
on_frame:
- can_id: 500
then:
- lambda: |-
std::string b(x.begin(), x.end());
ESP_LOGD("canbus1", "canid 500 %s", b.c_str() );
- can_id: 0b00000000000000000000001000000
can_id_mask: 0b11111000000000011111111000000
use_extended_id: true
then:
- lambda: |-
auto pdo_id = can_id >> 14;
switch (pdo_id)
{
case 117:
ESP_LOGD("canbus1", "exhaust_fan_duty");
break;
case 118:
ESP_LOGD("canbus1", "supply_fan_duty");
break;
case 119:
ESP_LOGD("canbus1", "supply_fan_flow");
break;
// to be continued...
}
- platform: esp32_can
id: esp32_internal_can_2
rx_pin: GPIO10
tx_pin: GPIO9
can_id: 4
bit_rate: 50kbps
on_frame:
- can_id: 500
then:
- lambda: |-
std::string b(x.begin(), x.end());
ESP_LOGD("canbus2", "canid 500 %s", b.c_str() );
- can_id: 0b00000000000000000000001000000
can_id_mask: 0b11111000000000011111111000000
use_extended_id: true
then:
- lambda: |-
auto pdo_id = can_id >> 14;
switch (pdo_id)
{
case 117:
ESP_LOGD("canbus2", "exhaust_fan_duty");
break;
case 118:
ESP_LOGD("canbus2", "supply_fan_duty");
break;
case 119:
ESP_LOGD("canbus2", "supply_fan_flow");
break;
// to be continued...
}