mirror of
https://github.com/esphome/esphome.git
synced 2025-11-03 08:31:47 +00:00
Compare commits
38 Commits
2025.2.0b1
...
2025.2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c13174c318 | ||
|
|
8fa157581e | ||
|
|
7114d6bdd1 | ||
|
|
eca0c21966 | ||
|
|
20c9c410af | ||
|
|
79af437f48 | ||
|
|
6e27003787 | ||
|
|
7c9726859f | ||
|
|
ba79e2d7b1 | ||
|
|
ae65f76dfe | ||
|
|
4d380214df | ||
|
|
c5ebf7683e | ||
|
|
a973adda67 | ||
|
|
d9b419eaf5 | ||
|
|
2bc9782ce7 | ||
|
|
6583e17810 | ||
|
|
64c8bcef2e | ||
|
|
f9da8dbfb8 | ||
|
|
26d25464da | ||
|
|
78b55e22ee | ||
|
|
9ee5227fe0 | ||
|
|
e89603fe3b | ||
|
|
c0804d665d | ||
|
|
a67b85eabf | ||
|
|
6e45a7c9af | ||
|
|
e17582544e | ||
|
|
daa7960031 | ||
|
|
6999cc0581 | ||
|
|
92ad6286aa | ||
|
|
1111aa167f | ||
|
|
897873496a | ||
|
|
b0f6dd7d9c | ||
|
|
be5639faf1 | ||
|
|
e9a537784e | ||
|
|
35d303809e | ||
|
|
4740f12ce8 | ||
|
|
c8e7e275a4 | ||
|
|
077ee5b714 |
@@ -35,7 +35,7 @@ RUN \
|
||||
iputils-ping=3:20221126-1+deb12u1 \
|
||||
git=1:2.39.5-0+deb12u1 \
|
||||
curl=7.88.1-10+deb12u8 \
|
||||
openssh-client=1:9.2p1-2+deb12u3 \
|
||||
openssh-client=1:9.2p1-2+deb12u4 \
|
||||
python3-cffi=1.15.1-5 \
|
||||
libcairo2=1.16.0-7 \
|
||||
libmagic1=1:5.44-3 \
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from aioesphomeapi import APIClient
|
||||
from aioesphomeapi.api_pb2 import SubscribeLogsResponse
|
||||
from aioesphomeapi.log_runner import async_run
|
||||
|
||||
from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__
|
||||
@@ -14,6 +13,12 @@ from esphome.core import CORE
|
||||
|
||||
from . import CONF_ENCRYPTION
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from aioesphomeapi.api_pb2 import (
|
||||
SubscribeLogsResponse, # pylint: disable=no-name-in-module
|
||||
)
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#include "cse7766.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <cinttypes>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace esphome {
|
||||
namespace cse7766 {
|
||||
@@ -72,12 +69,8 @@ bool CSE7766Component::check_byte_() {
|
||||
void CSE7766Component::parse_data_() {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Raw data:" << std::hex << std::uppercase << std::setfill('0');
|
||||
for (uint8_t i = 0; i < 23; i++) {
|
||||
ss << ' ' << std::setw(2) << static_cast<unsigned>(this->raw_data_[i]);
|
||||
}
|
||||
ESP_LOGVV(TAG, "%s", ss.str().c_str());
|
||||
std::string s = format_hex_pretty(this->raw_data_, sizeof(this->raw_data_));
|
||||
ESP_LOGVV(TAG, "Raw data: %s", s.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -211,21 +204,20 @@ void CSE7766Component::parse_data_() {
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Parsed:";
|
||||
std::string buf = "Parsed:";
|
||||
if (have_voltage) {
|
||||
ss << " V=" << voltage << "V";
|
||||
buf += str_sprintf(" V=%fV", voltage);
|
||||
}
|
||||
if (have_current) {
|
||||
ss << " I=" << current * 1000.0f << "mA (~" << calculated_current * 1000.0f << "mA)";
|
||||
buf += str_sprintf(" I=%fmA (~%fmA)", current * 1000.0f, calculated_current * 1000.0f);
|
||||
}
|
||||
if (have_power) {
|
||||
ss << " P=" << power << "W";
|
||||
buf += str_sprintf(" P=%fW", power);
|
||||
}
|
||||
if (energy != 0.0f) {
|
||||
ss << " E=" << energy << "kWh (" << cf_pulses << ")";
|
||||
buf += str_sprintf(" E=%fkWh (%u)", energy, cf_pulses);
|
||||
}
|
||||
ESP_LOGVV(TAG, "%s", ss.str().c_str());
|
||||
ESP_LOGVV(TAG, "%s", buf.c_str());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ void DHT::dump_config() {
|
||||
} else {
|
||||
ESP_LOGCONFIG(TAG, " Model: DHT22 (or equivalent)");
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Internal Pull-up: %s", ONOFF(this->pin_->get_flags() & gpio::FLAG_PULLUP));
|
||||
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
|
||||
@@ -101,7 +102,7 @@ bool HOT IRAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool r
|
||||
} else {
|
||||
delayMicroseconds(800);
|
||||
}
|
||||
this->pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||
this->pin_->pin_mode(this->pin_->get_flags());
|
||||
|
||||
{
|
||||
InterruptLock lock;
|
||||
|
||||
@@ -34,7 +34,7 @@ DHT = dht_ns.class_("DHT", cg.PollingComponent)
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(DHT),
|
||||
cv.Required(CONF_PIN): pins.internal_gpio_input_pin_schema,
|
||||
cv.Required(CONF_PIN): pins.internal_gpio_input_pullup_pin_schema,
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_CELSIUS,
|
||||
accuracy_decimals=1,
|
||||
|
||||
@@ -815,8 +815,20 @@ void Display::test_card() {
|
||||
|
||||
DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {}
|
||||
void DisplayPage::show() { this->parent_->show_page(this); }
|
||||
void DisplayPage::show_next() { this->next_->show(); }
|
||||
void DisplayPage::show_prev() { this->prev_->show(); }
|
||||
void DisplayPage::show_next() {
|
||||
if (this->next_ == nullptr) {
|
||||
ESP_LOGE(TAG, "no next page");
|
||||
return;
|
||||
}
|
||||
this->next_->show();
|
||||
}
|
||||
void DisplayPage::show_prev() {
|
||||
if (this->prev_ == nullptr) {
|
||||
ESP_LOGE(TAG, "no previous page");
|
||||
return;
|
||||
}
|
||||
this->prev_->show();
|
||||
}
|
||||
void DisplayPage::set_parent(Display *parent) { this->parent_ = parent; }
|
||||
void DisplayPage::set_prev(DisplayPage *prev) { this->prev_ = prev; }
|
||||
void DisplayPage::set_next(DisplayPage *next) { this->next_ = next; }
|
||||
|
||||
@@ -123,12 +123,49 @@ void BLEClientBase::connect() {
|
||||
esp_err_t BLEClientBase::pair() { return esp_ble_set_encryption(this->remote_bda_, ESP_BLE_SEC_ENCRYPT); }
|
||||
|
||||
void BLEClientBase::disconnect() {
|
||||
if (this->state_ == espbt::ClientState::IDLE || this->state_ == espbt::ClientState::DISCONNECTING)
|
||||
if (this->state_ == espbt::ClientState::IDLE) {
|
||||
ESP_LOGI(TAG, "[%d] [%s] Disconnect requested, but already idle.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return;
|
||||
ESP_LOGI(TAG, "[%d] [%s] Disconnecting.", this->connection_index_, this->address_str_.c_str());
|
||||
}
|
||||
if (this->state_ == espbt::ClientState::DISCONNECTING) {
|
||||
ESP_LOGI(TAG, "[%d] [%s] Disconnect requested, but already disconnecting.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return;
|
||||
}
|
||||
if (this->state_ == espbt::ClientState::CONNECTING || this->conn_id_ == UNSET_CONN_ID) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Disconnecting before connected, disconnect scheduled.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
this->want_disconnect_ = true;
|
||||
return;
|
||||
}
|
||||
this->unconditional_disconnect();
|
||||
}
|
||||
|
||||
void BLEClientBase::unconditional_disconnect() {
|
||||
// Disconnect without checking the state.
|
||||
ESP_LOGI(TAG, "[%d] [%s] Disconnecting (conn_id: %d).", this->connection_index_, this->address_str_.c_str(),
|
||||
this->conn_id_);
|
||||
if (this->state_ == espbt::ClientState::DISCONNECTING) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] Tried to disconnect while already disconnecting.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return;
|
||||
}
|
||||
if (this->conn_id_ == UNSET_CONN_ID) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] No connection ID set, cannot disconnect.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return;
|
||||
}
|
||||
auto err = esp_ble_gattc_close(this->gattc_if_, this->conn_id_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_close error, err=%d", this->connection_index_, this->address_str_.c_str(),
|
||||
//
|
||||
// This is a fatal error, but we can't do anything about it
|
||||
// and it likely means the BLE stack is in a bad state.
|
||||
//
|
||||
// In the future we might consider App.reboot() here since
|
||||
// the BLE stack is in an indeterminate state.
|
||||
//
|
||||
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_close error, err=%d", this->connection_index_, this->address_str_.c_str(),
|
||||
err);
|
||||
}
|
||||
|
||||
@@ -184,12 +221,38 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
this->log_event_("ESP_GATTC_OPEN_EVT");
|
||||
this->conn_id_ = param->open.conn_id;
|
||||
this->service_count_ = 0;
|
||||
if (this->state_ != espbt::ClientState::CONNECTING) {
|
||||
// This should not happen but lets log it in case it does
|
||||
// because it means we have a bad assumption about how the
|
||||
// ESP BT stack works.
|
||||
if (this->state_ == espbt::ClientState::CONNECTED) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] Got ESP_GATTC_OPEN_EVT while already connected, status=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), param->open.status);
|
||||
} else if (this->state_ == espbt::ClientState::ESTABLISHED) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] Got ESP_GATTC_OPEN_EVT while already established, status=%d",
|
||||
this->connection_index_, this->address_str_.c_str(), param->open.status);
|
||||
} else if (this->state_ == espbt::ClientState::DISCONNECTING) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] Got ESP_GATTC_OPEN_EVT while disconnecting, status=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), param->open.status);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "[%d] [%s] Got ESP_GATTC_OPEN_EVT while not in connecting state, status=%d",
|
||||
this->connection_index_, this->address_str_.c_str(), param->open.status);
|
||||
}
|
||||
}
|
||||
if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection failed, status=%d", this->connection_index_, this->address_str_.c_str(),
|
||||
param->open.status);
|
||||
this->set_state(espbt::ClientState::IDLE);
|
||||
break;
|
||||
}
|
||||
if (this->want_disconnect_) {
|
||||
// Disconnect was requested after connecting started,
|
||||
// but before the connection was established. Now that we have
|
||||
// this->conn_id_ set, we can disconnect it.
|
||||
this->unconditional_disconnect();
|
||||
this->conn_id_ = UNSET_CONN_ID;
|
||||
break;
|
||||
}
|
||||
auto ret = esp_ble_gattc_send_mtu_req(this->gattc_if_, param->open.conn_id);
|
||||
if (ret) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_send_mtu_req failed, status=%x", this->connection_index_,
|
||||
@@ -241,6 +304,7 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
this->log_event_("ESP_GATTC_CLOSE_EVT");
|
||||
this->release_services();
|
||||
this->set_state(espbt::ClientState::IDLE);
|
||||
this->conn_id_ = UNSET_CONN_ID;
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_SEARCH_RES_EVT: {
|
||||
|
||||
@@ -21,6 +21,8 @@ namespace esp32_ble_client {
|
||||
|
||||
namespace espbt = esphome::esp32_ble_tracker;
|
||||
|
||||
static const int UNSET_CONN_ID = 0xFFFF;
|
||||
|
||||
class BLEClientBase : public espbt::ESPBTClient, public Component {
|
||||
public:
|
||||
void setup() override;
|
||||
@@ -37,6 +39,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
|
||||
void connect() override;
|
||||
esp_err_t pair();
|
||||
void disconnect() override;
|
||||
void unconditional_disconnect();
|
||||
void release_services();
|
||||
|
||||
bool connected() { return this->state_ == espbt::ClientState::ESTABLISHED; }
|
||||
@@ -94,7 +97,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
|
||||
int gattc_if_;
|
||||
esp_bd_addr_t remote_bda_;
|
||||
esp_ble_addr_type_t remote_addr_type_{BLE_ADDR_TYPE_PUBLIC};
|
||||
uint16_t conn_id_{0xFFFF};
|
||||
uint16_t conn_id_{UNSET_CONN_ID};
|
||||
uint64_t address_{0};
|
||||
bool auto_connect_{false};
|
||||
std::string address_str_{};
|
||||
|
||||
@@ -238,6 +238,12 @@ async def to_code(config):
|
||||
else:
|
||||
add_idf_sdkconfig_option("CONFIG_BTU_TASK_STACK_SIZE", 8192)
|
||||
add_idf_sdkconfig_option("CONFIG_BT_ACL_CONNECTIONS", 9)
|
||||
# CONFIG_BT_GATTC_NOTIF_REG_MAX controls the number of
|
||||
# max notifications in 5.x, setting CONFIG_BT_ACL_CONNECTIONS
|
||||
# is enough in 4.x
|
||||
# https://github.com/esphome/issues/issues/6808
|
||||
if CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version(5, 0, 0):
|
||||
add_idf_sdkconfig_option("CONFIG_BT_GATTC_NOTIF_REG_MAX", 9)
|
||||
|
||||
cg.add_define("USE_OTA_STATE_CALLBACK") # To be notified when an OTA update starts
|
||||
cg.add_define("USE_ESP32_BLE_CLIENT")
|
||||
|
||||
@@ -173,12 +173,22 @@ class ESPBTClient : public ESPBTDeviceListener {
|
||||
virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) = 0;
|
||||
virtual void connect() = 0;
|
||||
virtual void disconnect() = 0;
|
||||
virtual void set_state(ClientState st) { this->state_ = st; }
|
||||
virtual void set_state(ClientState st) {
|
||||
this->state_ = st;
|
||||
if (st == ClientState::IDLE) {
|
||||
this->want_disconnect_ = false;
|
||||
}
|
||||
}
|
||||
ClientState state() const { return state_; }
|
||||
int app_id;
|
||||
|
||||
protected:
|
||||
ClientState state_{ClientState::INIT};
|
||||
// want_disconnect_ is set to true when a disconnect is requested
|
||||
// while the client is connecting. This is used to disconnect the
|
||||
// client as soon as we get the connection id (conn_id_) from the
|
||||
// ESP_GATTC_OPEN_EVT event.
|
||||
bool want_disconnect_{false};
|
||||
};
|
||||
|
||||
class ESP32BLETracker : public Component,
|
||||
|
||||
@@ -7,13 +7,16 @@
|
||||
#ifdef USE_ARDUINO
|
||||
#include <esp32-hal-dac.h>
|
||||
#endif
|
||||
#ifdef USE_ESP_IDF
|
||||
#include <driver/dac.h>
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace esp32_dac {
|
||||
|
||||
#ifdef USE_ESP32_VARIANT_ESP32S2
|
||||
static constexpr uint8_t DAC0_PIN = 17;
|
||||
#else
|
||||
static constexpr uint8_t DAC0_PIN = 25;
|
||||
#endif
|
||||
|
||||
static const char *const TAG = "esp32_dac";
|
||||
|
||||
void ESP32DAC::setup() {
|
||||
@@ -22,8 +25,15 @@ void ESP32DAC::setup() {
|
||||
this->turn_off();
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
auto channel = pin_->get_pin() == 25 ? DAC_CHANNEL_1 : DAC_CHANNEL_2;
|
||||
dac_output_enable(channel);
|
||||
const dac_channel_t channel = this->pin_->get_pin() == DAC0_PIN ? DAC_CHAN_0 : DAC_CHAN_1;
|
||||
const dac_oneshot_config_t oneshot_cfg{channel};
|
||||
dac_oneshot_new_channel(&oneshot_cfg, &this->dac_handle_);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ESP32DAC::on_safe_shutdown() {
|
||||
#ifdef USE_ESP_IDF
|
||||
dac_oneshot_del_channel(this->dac_handle_);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -40,8 +50,7 @@ void ESP32DAC::write_state(float state) {
|
||||
state = state * 255;
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
auto channel = pin_->get_pin() == 25 ? DAC_CHANNEL_1 : DAC_CHANNEL_2;
|
||||
dac_output_voltage(channel, (uint8_t) state);
|
||||
dac_oneshot_output_voltage(this->dac_handle_, state);
|
||||
#endif
|
||||
#ifdef USE_ARDUINO
|
||||
dacWrite(this->pin_->get_pin(), state);
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#include <driver/dac_oneshot.h>
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace esp32_dac {
|
||||
|
||||
@@ -16,6 +20,7 @@ class ESP32DAC : public output::FloatOutput, public Component {
|
||||
|
||||
/// Initialize pin
|
||||
void setup() override;
|
||||
void on_safe_shutdown() override;
|
||||
void dump_config() override;
|
||||
/// HARDWARE setup_priority
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||
@@ -24,6 +29,9 @@ class ESP32DAC : public output::FloatOutput, public Component {
|
||||
void write_state(float state) override;
|
||||
|
||||
InternalGPIOPin *pin_;
|
||||
#ifdef USE_ESP_IDF
|
||||
dac_oneshot_handle_t dac_handle_;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace esp32_dac
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.components import output
|
||||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.esp32 import get_esp32_variant
|
||||
from esphome.components.esp32.const import VARIANT_ESP32, VARIANT_ESP32S2
|
||||
from esphome.const import CONF_ID, CONF_NUMBER, CONF_PIN
|
||||
|
||||
DEPENDENCIES = ["esp32"]
|
||||
|
||||
DAC_PINS = {
|
||||
VARIANT_ESP32: (25, 26),
|
||||
VARIANT_ESP32S2: (17, 18),
|
||||
}
|
||||
|
||||
|
||||
def valid_dac_pin(value):
|
||||
num = value[CONF_NUMBER]
|
||||
cv.one_of(25, 26)(num)
|
||||
variant = get_esp32_variant()
|
||||
try:
|
||||
valid_pins = DAC_PINS[variant]
|
||||
except KeyError as ex:
|
||||
raise cv.Invalid(f"DAC is not supported on {variant}") from ex
|
||||
given_pin = value[CONF_NUMBER]
|
||||
cv.one_of(*valid_pins)(given_pin)
|
||||
return value
|
||||
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ void ESP32TouchComponent::setup() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5 && defined(USE_ESP32_VARIANT_ESP32)
|
||||
touch_pad_set_measurement_clock_cycles(this->meas_cycle_);
|
||||
touch_pad_set_measurement_interval(this->sleep_cycle_);
|
||||
#else
|
||||
|
||||
@@ -5,8 +5,8 @@ import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
import esphome_glyphsets as glyphsets
|
||||
import freetype
|
||||
import glyphsets
|
||||
import requests
|
||||
|
||||
from esphome import core, external_files
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <iostream> // std::cout, std::fixed
|
||||
#include <iomanip>
|
||||
namespace esphome {
|
||||
namespace graph {
|
||||
|
||||
@@ -231,9 +228,8 @@ void GraphLegend::init(Graph *g) {
|
||||
ESP_LOGI(TAGL, " %s %d %d", txtstr.c_str(), fw, fh);
|
||||
|
||||
if (this->values_ != VALUE_POSITION_TYPE_NONE) {
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << std::setprecision(trace->sensor_->get_accuracy_decimals()) << trace->sensor_->get_state();
|
||||
std::string valstr = ss.str();
|
||||
std::string valstr =
|
||||
value_accuracy_to_string(trace->sensor_->get_state(), trace->sensor_->get_accuracy_decimals());
|
||||
if (this->units_) {
|
||||
valstr += trace->sensor_->get_unit_of_measurement();
|
||||
}
|
||||
@@ -368,9 +364,8 @@ void Graph::draw_legend(display::Display *buff, uint16_t x_offset, uint16_t y_of
|
||||
if (legend_->values_ != VALUE_POSITION_TYPE_NONE) {
|
||||
int xv = x + legend_->xv_;
|
||||
int yv = y + legend_->yv_;
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << std::setprecision(trace->sensor_->get_accuracy_decimals()) << trace->sensor_->get_state();
|
||||
std::string valstr = ss.str();
|
||||
std::string valstr =
|
||||
value_accuracy_to_string(trace->sensor_->get_state(), trace->sensor_->get_accuracy_decimals());
|
||||
if (legend_->units_) {
|
||||
valstr += trace->sensor_->get_unit_of_measurement();
|
||||
}
|
||||
|
||||
@@ -247,8 +247,8 @@ async def to_code(config):
|
||||
)
|
||||
cg.add(log.pre_setup())
|
||||
|
||||
for tag, level in config[CONF_LOGS].items():
|
||||
cg.add(log.set_log_level(tag, LOG_LEVELS[level]))
|
||||
for tag, log_level in config[CONF_LOGS].items():
|
||||
cg.add(log.set_log_level(tag, LOG_LEVELS[log_level]))
|
||||
|
||||
cg.add_define("USE_LOGGER")
|
||||
this_severity = LOG_LEVEL_SEVERITY.index(level)
|
||||
|
||||
@@ -102,9 +102,6 @@ void Logger::log_vprintf_(int level, const char *tag, int line, const __FlashStr
|
||||
#endif
|
||||
|
||||
int HOT Logger::level_for(const char *tag) {
|
||||
// Uses std::vector<> for low memory footprint, though the vector
|
||||
// could be sorted to minimize lookup times. This feature isn't used that
|
||||
// much anyway so it doesn't matter too much.
|
||||
if (this->log_levels_.count(tag) != 0)
|
||||
return this->log_levels_[tag];
|
||||
return this->current_level_;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
|
||||
#include "modbus_textsensor.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace esphome {
|
||||
namespace modbus_controller {
|
||||
@@ -12,20 +10,17 @@ static const char *const TAG = "modbus_controller.text_sensor";
|
||||
void ModbusTextSensor::dump_config() { LOG_TEXT_SENSOR("", "Modbus Controller Text Sensor", this); }
|
||||
|
||||
void ModbusTextSensor::parse_and_publish(const std::vector<uint8_t> &data) {
|
||||
std::ostringstream output;
|
||||
std::string output_str{};
|
||||
uint8_t items_left = this->response_bytes;
|
||||
uint8_t index = this->offset;
|
||||
char buffer[5];
|
||||
while ((items_left > 0) && index < data.size()) {
|
||||
uint8_t b = data[index];
|
||||
switch (this->encode_) {
|
||||
case RawEncoding::HEXBYTES:
|
||||
sprintf(buffer, "%02x", b);
|
||||
output << buffer;
|
||||
output_str += str_snprintf("%02x", 2, b);
|
||||
break;
|
||||
case RawEncoding::COMMA:
|
||||
sprintf(buffer, index != this->offset ? ",%d" : "%d", b);
|
||||
output << buffer;
|
||||
output_str += str_sprintf(index != this->offset ? ",%d" : "%d", b);
|
||||
break;
|
||||
case RawEncoding::ANSI:
|
||||
if (b < 0x20)
|
||||
@@ -33,25 +28,24 @@ void ModbusTextSensor::parse_and_publish(const std::vector<uint8_t> &data) {
|
||||
// FALLTHROUGH
|
||||
// Anything else no encoding
|
||||
default:
|
||||
output << (char) b;
|
||||
output_str += (char) b;
|
||||
break;
|
||||
}
|
||||
items_left--;
|
||||
index++;
|
||||
}
|
||||
|
||||
auto result = output.str();
|
||||
// Is there a lambda registered
|
||||
// call it with the pre converted value and the raw data array
|
||||
if (this->transform_func_.has_value()) {
|
||||
// the lambda can parse the response itself
|
||||
auto val = (*this->transform_func_)(this, result, data);
|
||||
auto val = (*this->transform_func_)(this, output_str, data);
|
||||
if (val.has_value()) {
|
||||
ESP_LOGV(TAG, "Value overwritten by lambda");
|
||||
result = val.value();
|
||||
output_str = val.value();
|
||||
}
|
||||
}
|
||||
this->publish_state(result);
|
||||
this->publish_state(output_str);
|
||||
}
|
||||
|
||||
} // namespace modbus_controller
|
||||
|
||||
@@ -9,10 +9,10 @@ namespace online_image {
|
||||
static const char *const TAG = "online_image.decoder";
|
||||
|
||||
bool ImageDecoder::set_size(int width, int height) {
|
||||
bool resized = this->image_->resize_(width, height);
|
||||
bool success = this->image_->resize_(width, height) > 0;
|
||||
this->x_scale_ = static_cast<double>(this->image_->buffer_width_) / width;
|
||||
this->y_scale_ = static_cast<double>(this->image_->buffer_height_) / height;
|
||||
return resized;
|
||||
return success;
|
||||
}
|
||||
|
||||
void ImageDecoder::draw(int x, int y, int w, int h, const Color &color) {
|
||||
@@ -51,8 +51,9 @@ size_t DownloadBuffer::read(size_t len) {
|
||||
}
|
||||
|
||||
size_t DownloadBuffer::resize(size_t size) {
|
||||
if (this->size_ == size) {
|
||||
return size;
|
||||
if (this->size_ >= size) {
|
||||
// Avoid useless reallocations; if the buffer is big enough, don't reallocate.
|
||||
return this->size_;
|
||||
}
|
||||
this->allocator_.deallocate(this->buffer_, this->size_);
|
||||
this->buffer_ = this->allocator_.allocate(size);
|
||||
@@ -61,6 +62,8 @@ size_t DownloadBuffer::resize(size_t size) {
|
||||
this->size_ = size;
|
||||
return size;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "allocation of %zu bytes failed. Biggest block in heap: %zu Bytes", size,
|
||||
this->allocator_.get_max_free_block_size());
|
||||
this->size_ = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ int HOT JpegDecoder::decode(uint8_t *buffer, size_t size) {
|
||||
}
|
||||
|
||||
if (!this->jpeg_.openRAM(buffer, size, draw_callback)) {
|
||||
ESP_LOGE(TAG, "Could not open image for decoding.");
|
||||
ESP_LOGE(TAG, "Could not open image for decoding: %d", this->jpeg_.getLastError());
|
||||
return DECODE_ERROR_INVALID_TYPE;
|
||||
}
|
||||
auto jpeg_type = this->jpeg_.getJPEGType();
|
||||
@@ -73,7 +73,9 @@ int HOT JpegDecoder::decode(uint8_t *buffer, size_t size) {
|
||||
|
||||
this->jpeg_.setUserPointer(this);
|
||||
this->jpeg_.setPixelType(RGB8888);
|
||||
this->set_size(this->jpeg_.getWidth(), this->jpeg_.getHeight());
|
||||
if (!this->set_size(this->jpeg_.getWidth(), this->jpeg_.getHeight())) {
|
||||
return DECODE_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (!this->jpeg_.decode(0, 0, 0)) {
|
||||
ESP_LOGE(TAG, "Error while decoding.");
|
||||
this->jpeg_.close();
|
||||
|
||||
@@ -64,33 +64,34 @@ void OnlineImage::release() {
|
||||
}
|
||||
}
|
||||
|
||||
bool OnlineImage::resize_(int width_in, int height_in) {
|
||||
size_t OnlineImage::resize_(int width_in, int height_in) {
|
||||
int width = this->fixed_width_;
|
||||
int height = this->fixed_height_;
|
||||
if (this->auto_resize_()) {
|
||||
if (this->is_auto_resize_()) {
|
||||
width = width_in;
|
||||
height = height_in;
|
||||
if (this->width_ != width && this->height_ != height) {
|
||||
this->release();
|
||||
}
|
||||
}
|
||||
if (this->buffer_) {
|
||||
return false;
|
||||
}
|
||||
size_t new_size = this->get_buffer_size_(width, height);
|
||||
if (this->buffer_) {
|
||||
// Buffer already allocated => no need to resize
|
||||
return new_size;
|
||||
}
|
||||
ESP_LOGD(TAG, "Allocating new buffer of %zu bytes", new_size);
|
||||
this->buffer_ = this->allocator_.allocate(new_size);
|
||||
if (this->buffer_ == nullptr) {
|
||||
ESP_LOGE(TAG, "allocation of %zu bytes failed. Biggest block in heap: %zu Bytes", new_size,
|
||||
this->allocator_.get_max_free_block_size());
|
||||
this->end_connection_();
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
this->buffer_width_ = width;
|
||||
this->buffer_height_ = height;
|
||||
this->width_ = width;
|
||||
ESP_LOGV(TAG, "New size: (%d, %d)", width, height);
|
||||
return true;
|
||||
return new_size;
|
||||
}
|
||||
|
||||
void OnlineImage::update() {
|
||||
|
||||
@@ -99,9 +99,22 @@ class OnlineImage : public PollingComponent,
|
||||
|
||||
int get_position_(int x, int y) const { return (x + y * this->buffer_width_) * this->get_bpp() / 8; }
|
||||
|
||||
ESPHOME_ALWAYS_INLINE bool auto_resize_() const { return this->fixed_width_ == 0 || this->fixed_height_ == 0; }
|
||||
ESPHOME_ALWAYS_INLINE bool is_auto_resize_() const { return this->fixed_width_ == 0 || this->fixed_height_ == 0; }
|
||||
|
||||
bool resize_(int width, int height);
|
||||
/**
|
||||
* @brief Resize the image buffer to the requested dimensions.
|
||||
*
|
||||
* The buffer will be allocated if not existing.
|
||||
* If the dimensions have been fixed in the yaml config, the buffer will be created
|
||||
* with those dimensions and not resized, even on request.
|
||||
* Otherwise, the old buffer will be deallocated and a new buffer with the requested
|
||||
* allocated
|
||||
*
|
||||
* @param width
|
||||
* @param height
|
||||
* @return 0 if no memory could be allocated, the size of the new buffer otherwise.
|
||||
*/
|
||||
size_t resize_(int width, int height);
|
||||
|
||||
/**
|
||||
* @brief Draw a pixel into the buffer.
|
||||
|
||||
@@ -36,7 +36,7 @@ template<typename... Ts> class TotoAction : public RemoteTransmitterActionBase<T
|
||||
data.rc_code_2 = this->rc_code_2_.value(x...);
|
||||
data.command = this->command_.value(x...);
|
||||
this->set_send_times(this->send_times_.value_or(x..., 3));
|
||||
this->set_send_wait(this->send_wait_.value_or(x..., 32000));
|
||||
this->set_send_wait(this->send_wait_.value_or(x..., 36000));
|
||||
TotoProtocol().encode(dst, data);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,7 +75,7 @@ CONFIG_SCHEMA = (
|
||||
cv.Optional(CONF_UPDATE_INTERVAL, default="60s"): cv.All(
|
||||
cv.positive_time_period_seconds,
|
||||
cv.Range(
|
||||
min=core.TimePeriod(seconds=1), max=core.TimePeriod(seconds=1800)
|
||||
min=core.TimePeriod(seconds=2), max=core.TimePeriod(seconds=1800)
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
"""Constants used by esphome."""
|
||||
|
||||
__version__ = "2025.2.0b1"
|
||||
__version__ = "2025.2.1"
|
||||
|
||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||
|
||||
@@ -582,7 +582,7 @@ class EsphomeCore:
|
||||
|
||||
@property
|
||||
def config_dir(self):
|
||||
return os.path.dirname(os.path.abspath(self.config_path))
|
||||
return os.path.abspath(os.path.dirname(self.config_path))
|
||||
|
||||
@property
|
||||
def data_dir(self):
|
||||
|
||||
@@ -217,6 +217,8 @@ def preload_core_config(config, result) -> str:
|
||||
target_platforms = []
|
||||
|
||||
for domain, _ in config.items():
|
||||
if domain.startswith("."):
|
||||
continue
|
||||
if _is_target_platform(domain):
|
||||
target_platforms += [domain]
|
||||
|
||||
|
||||
@@ -853,7 +853,7 @@ class InfoRequestHandler(BaseHandler):
|
||||
dashboard = DASHBOARD
|
||||
entry = dashboard.entries.get(yaml_path)
|
||||
|
||||
if not entry:
|
||||
if not entry or entry.storage is None:
|
||||
self.set_status(404)
|
||||
return
|
||||
|
||||
|
||||
@@ -13,11 +13,11 @@ platformio==6.1.16 # When updating platformio, also update Dockerfile
|
||||
esptool==4.7.0
|
||||
click==8.1.7
|
||||
esphome-dashboard==20250212.0
|
||||
aioesphomeapi==24.6.2
|
||||
zeroconf==0.143.0
|
||||
aioesphomeapi==29.1.1
|
||||
zeroconf==0.145.1
|
||||
puremagic==1.27
|
||||
ruamel.yaml==0.18.6 # dashboard_import
|
||||
glyphsets==1.0.0
|
||||
esphome-glyphsets==0.1.0
|
||||
pillow==10.4.0
|
||||
freetype-py==2.5.1
|
||||
|
||||
|
||||
15
tests/components/esp32_touch/common-variants.yaml
Normal file
15
tests/components/esp32_touch/common-variants.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
esp32_touch:
|
||||
setup_mode: false
|
||||
sleep_duration: 27ms
|
||||
measurement_duration: 8ms
|
||||
low_voltage_reference: 0.5V
|
||||
high_voltage_reference: 2.7V
|
||||
voltage_attenuation: 1.5V
|
||||
|
||||
binary_sensor:
|
||||
- platform: esp32_touch
|
||||
name: ESP32 Touch Pad
|
||||
pin: ${pin}
|
||||
threshold: 1000
|
||||
on_press:
|
||||
- logger.log: "I'm touched!"
|
||||
@@ -10,7 +10,7 @@ esp32_touch:
|
||||
binary_sensor:
|
||||
- platform: esp32_touch
|
||||
name: ESP32 Touch Pad
|
||||
pin: 27
|
||||
pin: ${pin}
|
||||
threshold: 1000
|
||||
on_press:
|
||||
- logger.log: "I'm touched!"
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
substitutions:
|
||||
pin: GPIO27
|
||||
|
||||
<<: !include common.yaml
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
substitutions:
|
||||
pin: GPIO27
|
||||
|
||||
<<: !include common.yaml
|
||||
|
||||
4
tests/components/esp32_touch/test.esp32-s2-ard.yaml
Normal file
4
tests/components/esp32_touch/test.esp32-s2-ard.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
substitutions:
|
||||
pin: GPIO12
|
||||
|
||||
<<: !include common-variants.yaml
|
||||
4
tests/components/esp32_touch/test.esp32-s2-idf.yaml
Normal file
4
tests/components/esp32_touch/test.esp32-s2-idf.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
substitutions:
|
||||
pin: GPIO12
|
||||
|
||||
<<: !include common-variants.yaml
|
||||
4
tests/components/esp32_touch/test.esp32-s3-ard.yaml
Normal file
4
tests/components/esp32_touch/test.esp32-s3-ard.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
substitutions:
|
||||
pin: GPIO12
|
||||
|
||||
<<: !include common-variants.yaml
|
||||
4
tests/components/esp32_touch/test.esp32-s3-idf.yaml
Normal file
4
tests/components/esp32_touch/test.esp32-s3-idf.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
substitutions:
|
||||
pin: GPIO12
|
||||
|
||||
<<: !include common-variants.yaml
|
||||
Reference in New Issue
Block a user