mirror of
https://github.com/esphome/esphome.git
synced 2026-09-18 18:48:39 +00:00
Merge remote-tracking branch 'upstream/dev' into integration
This commit is contained in:
@@ -614,6 +614,7 @@ FILTER_SOURCE_FILES = filter_source_files_from_platform(
|
||||
PlatformFramework.RTL87XX_ARDUINO,
|
||||
PlatformFramework.LN882X_ARDUINO,
|
||||
},
|
||||
"task_log_buffer_zephyr.cpp": {PlatformFramework.NRF52_ZEPHYR},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -671,9 +671,10 @@ void LvglComponent::static_flush_cb(lv_display_t *disp_drv, const lv_area_t *are
|
||||
* @param e The event data
|
||||
* @param color_start The color to apply to the first tick
|
||||
* @param color_end The color to apply to the last tick
|
||||
* @param width
|
||||
*/
|
||||
void lv_scale_draw_event_cb(lv_event_t *e, uint16_t range_start, uint16_t range_end, lv_color_t color_start,
|
||||
lv_color_t color_end, bool local) {
|
||||
lv_color_t color_end, int width, bool local) {
|
||||
auto *scale = static_cast<lv_obj_t *>(lv_event_get_target(e));
|
||||
lv_draw_task_t *task = lv_event_get_draw_task(e);
|
||||
|
||||
@@ -691,6 +692,7 @@ void lv_scale_draw_event_cb(lv_event_t *e, uint16_t range_start, uint16_t range_
|
||||
range = 1;
|
||||
auto ratio = (tick * 255) / range;
|
||||
line_dsc->color = lv_color_mix(color_end, color_start, ratio);
|
||||
line_dsc->width += width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ extern std::string lv_event_code_name_for(lv_event_t *event);
|
||||
lv_obj_t *lv_container_create(lv_obj_t *parent);
|
||||
#ifdef USE_LVGL_SCALE
|
||||
void lv_scale_draw_event_cb(lv_event_t *e, uint16_t range_start, uint16_t range_end, lv_color_t color_start,
|
||||
lv_color_t color_end, bool local);
|
||||
lv_color_t color_end, int width, bool local);
|
||||
#endif
|
||||
#if LV_COLOR_DEPTH == 16
|
||||
static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_565;
|
||||
|
||||
@@ -177,7 +177,7 @@ INDICATOR_ARC_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_VALUE): lv_float,
|
||||
cv.Optional(CONF_START_VALUE): lv_float,
|
||||
cv.Optional(CONF_END_VALUE): lv_float,
|
||||
cv.Optional(CONF_OPA): opacity,
|
||||
cv.Optional(CONF_OPA, default=1.0): opacity,
|
||||
}
|
||||
).add_extra(cv.has_at_most_one_key(CONF_VALUE, CONF_START_VALUE))
|
||||
|
||||
@@ -247,7 +247,7 @@ SCALE_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_RANGE_FROM, default=0.0): lv_int,
|
||||
cv.Optional(CONF_RANGE_TO, default=100.0): lv_int,
|
||||
cv.Optional(CONF_ANGLE_RANGE, default=270): lv_angle_degrees,
|
||||
cv.Optional(CONF_ROTATION, default=0): lv_angle_degrees,
|
||||
cv.Optional(CONF_ROTATION): lv_angle_degrees,
|
||||
cv.Optional(CONF_INDICATORS): cv.ensure_list(INDICATOR_SCHEMA),
|
||||
cv.Optional(CONF_DRAW_TICKS_ON_TOP, default=True): bool,
|
||||
}
|
||||
@@ -329,7 +329,7 @@ class MeterType(WidgetType):
|
||||
)
|
||||
|
||||
def get_uses(self):
|
||||
return CONF_SCALE, CONF_LINE
|
||||
return CONF_SCALE, CONF_LINE, CONF_IMAGE
|
||||
|
||||
def validate(self, value):
|
||||
return cv.has_at_most_one_key(CONF_INDICATOR, CONF_PIVOT)(value)
|
||||
@@ -366,16 +366,17 @@ class MeterType(WidgetType):
|
||||
lv.scale_set_range(scale_var, range_from, range_to)
|
||||
|
||||
angle_range = await lv_angle_degrees.process(scale_conf[CONF_ANGLE_RANGE])
|
||||
rotation = await lv_angle_degrees.process(scale_conf[CONF_ROTATION])
|
||||
if (rotation := scale_conf.get(CONF_ROTATION)) is not None:
|
||||
rotation = await lv_angle_degrees.process(rotation)
|
||||
else:
|
||||
rotation = 90 + (360 - angle_range) // 2
|
||||
|
||||
# Set angle range
|
||||
lv.scale_set_angle_range(
|
||||
scale_var,
|
||||
angle_range,
|
||||
)
|
||||
|
||||
# Set rotation if specified
|
||||
if rotation:
|
||||
lv.scale_set_rotation(scale_var, rotation)
|
||||
lv.scale_set_rotation(scale_var, rotation)
|
||||
|
||||
# Handle indicators as sections
|
||||
for indicator in scale_conf.get(CONF_INDICATORS, ()):
|
||||
@@ -393,10 +394,9 @@ class MeterType(WidgetType):
|
||||
props = {
|
||||
"arc_width": v[CONF_WIDTH],
|
||||
"arc_color": v[CONF_COLOR],
|
||||
"arc_opa": v[CONF_OPA],
|
||||
"arc_rounded": v.get("arc_rounded", False),
|
||||
}
|
||||
if (opa := v.get(CONF_OPA)) is not None:
|
||||
props["arc_opa"] = opa
|
||||
if CONF_R_MOD in v:
|
||||
get_warnings().add(
|
||||
"The 'r_mod' indicator property is not supported in LVGL 9.x and will be ignored."
|
||||
@@ -424,6 +424,7 @@ class MeterType(WidgetType):
|
||||
end_value,
|
||||
color_start,
|
||||
color_end,
|
||||
v[CONF_WIDTH],
|
||||
local,
|
||||
)
|
||||
lv_obj.add_event_cb(
|
||||
|
||||
@@ -95,10 +95,6 @@ void PMSX003Component::loop() {
|
||||
// Just go ahead and read stuff
|
||||
break;
|
||||
}
|
||||
} else if (now - this->last_update_ < this->update_interval_) {
|
||||
// Otherwise just leave the sensor powered up and come back when we hit the update
|
||||
// time
|
||||
return;
|
||||
}
|
||||
|
||||
if (now - this->last_transmission_ >= 500) {
|
||||
@@ -114,10 +110,11 @@ void PMSX003Component::loop() {
|
||||
this->read_byte(&this->data_[this->data_index_]);
|
||||
auto check = this->check_byte_();
|
||||
if (!check.has_value()) {
|
||||
// finished
|
||||
this->parse_data_();
|
||||
if (this->update_interval_ > STABILISING_MS || now - this->last_update_ >= this->update_interval_) {
|
||||
this->parse_data_();
|
||||
this->last_update_ = now;
|
||||
}
|
||||
this->data_index_ = 0;
|
||||
this->last_update_ = now;
|
||||
} else if (!*check) {
|
||||
// wrong data
|
||||
this->data_index_ = 0;
|
||||
@@ -138,7 +135,7 @@ optional<bool> PMSX003Component::check_byte_() {
|
||||
return true;
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "Start character %u mismatch: 0x%02X != 0x%02X", index + 1, byte, START_CHARACTER_1);
|
||||
ESP_LOGW(TAG, "Start character %u mismatch: 0x%02X != 0x%02X", index + 1, byte, start_char);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "sht4x.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
@@ -6,11 +6,17 @@ namespace esphome::ultrasonic {
|
||||
|
||||
static const char *const TAG = "ultrasonic.sensor";
|
||||
|
||||
static constexpr uint32_t DEBOUNCE_US = 50; // Ignore edges within 50us of each other (noise filtering)
|
||||
static constexpr uint32_t START_DELAY_US = 100; // Ignore edges within 100us of trigger (filters bleed-through)
|
||||
static constexpr uint32_t START_TIMEOUT_US = 40000; // Maximum time to wait for echo pulse to start
|
||||
|
||||
void IRAM_ATTR UltrasonicSensorStore::gpio_intr(UltrasonicSensorStore *arg) {
|
||||
uint32_t now = micros();
|
||||
if (arg->echo_pin_isr.digital_read()) {
|
||||
// Ignore edges after measurement complete or too soon after trigger pulse
|
||||
if (arg->echo_end || (now - arg->measurement_start_us) <= START_DELAY_US) {
|
||||
return;
|
||||
}
|
||||
if (!arg->echo_start || (now - arg->echo_start_us) <= DEBOUNCE_US) {
|
||||
arg->echo_start_us = now;
|
||||
arg->echo_start = true;
|
||||
} else {
|
||||
@@ -21,15 +27,14 @@ void IRAM_ATTR UltrasonicSensorStore::gpio_intr(UltrasonicSensorStore *arg) {
|
||||
|
||||
void IRAM_ATTR UltrasonicSensorComponent::send_trigger_pulse_() {
|
||||
InterruptLock lock;
|
||||
this->store_.echo_start_us = 0;
|
||||
this->store_.echo_end_us = 0;
|
||||
this->store_.echo_start = false;
|
||||
this->store_.echo_end = false;
|
||||
this->store_.measurement_start_us = micros();
|
||||
this->trigger_pin_isr_.digital_write(true);
|
||||
delayMicroseconds(this->pulse_time_us_);
|
||||
this->trigger_pin_isr_.digital_write(false);
|
||||
this->measurement_pending_ = true;
|
||||
this->measurement_start_us_ = micros();
|
||||
this->measurement_start_us_ = this->store_.measurement_start_us;
|
||||
}
|
||||
|
||||
void UltrasonicSensorComponent::setup() {
|
||||
@@ -37,7 +42,6 @@ void UltrasonicSensorComponent::setup() {
|
||||
this->trigger_pin_->digital_write(false);
|
||||
this->trigger_pin_isr_ = this->trigger_pin_->to_isr();
|
||||
this->echo_pin_->setup();
|
||||
this->store_.echo_pin_isr = this->echo_pin_->to_isr();
|
||||
this->echo_pin_->attach_interrupt(UltrasonicSensorStore::gpio_intr, &this->store_, gpio::INTERRUPT_ANY_EDGE);
|
||||
}
|
||||
|
||||
@@ -77,17 +81,10 @@ void UltrasonicSensorComponent::loop() {
|
||||
}
|
||||
|
||||
if (this->store_.echo_end) {
|
||||
float result;
|
||||
if (this->store_.echo_start) {
|
||||
uint32_t pulse_duration = this->store_.echo_end_us - this->store_.echo_start_us;
|
||||
ESP_LOGV(TAG, "pulse start took %" PRIu32 "us, echo took %" PRIu32 "us",
|
||||
this->store_.echo_start_us - this->measurement_start_us_, pulse_duration);
|
||||
result = UltrasonicSensorComponent::us_to_m(pulse_duration);
|
||||
ESP_LOGD(TAG, "'%s' - Got distance: %.3f m", this->name_.c_str(), result);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - pulse end before pulse start, does the echo pin need to be inverted?", this->name_.c_str());
|
||||
result = NAN;
|
||||
}
|
||||
uint32_t pulse_duration = this->store_.echo_end_us - this->store_.echo_start_us;
|
||||
ESP_LOGV(TAG, "Echo took %" PRIu32 "us", pulse_duration);
|
||||
float result = UltrasonicSensorComponent::us_to_m(pulse_duration);
|
||||
ESP_LOGD(TAG, "'%s' - Got distance: %.3f m", this->name_.c_str(), result);
|
||||
this->publish_state(result);
|
||||
this->measurement_pending_ = false;
|
||||
return;
|
||||
|
||||
@@ -11,8 +11,7 @@ namespace esphome::ultrasonic {
|
||||
struct UltrasonicSensorStore {
|
||||
static void gpio_intr(UltrasonicSensorStore *arg);
|
||||
|
||||
ISRInternalGPIOPin echo_pin_isr;
|
||||
volatile uint32_t wait_start_us{0};
|
||||
volatile uint32_t measurement_start_us{0};
|
||||
volatile uint32_t echo_start_us{0};
|
||||
volatile uint32_t echo_end_us{0};
|
||||
volatile bool echo_start{false};
|
||||
|
||||
@@ -262,19 +262,6 @@ StringRef AsyncWebServerRequest::url_to(std::span<char, URL_BUF_SIZE> buffer) co
|
||||
return StringRef(buffer.data(), decoded_len);
|
||||
}
|
||||
|
||||
void AsyncWebServerRequest::send(AsyncWebServerResponse *response) {
|
||||
httpd_resp_send(*this, response->get_content_data(), response->get_content_size());
|
||||
}
|
||||
|
||||
void AsyncWebServerRequest::send(int code, const char *content_type, const char *content) {
|
||||
this->init_response_(nullptr, code, content_type);
|
||||
if (content) {
|
||||
httpd_resp_send(*this, content, HTTPD_RESP_USE_STRLEN);
|
||||
} else {
|
||||
httpd_resp_send(*this, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncWebServerRequest::redirect(const std::string &url) {
|
||||
httpd_resp_set_status(*this, "302 Found");
|
||||
httpd_resp_set_hdr(*this, "Location", url.c_str());
|
||||
|
||||
@@ -134,8 +134,17 @@ class AsyncWebServerRequest {
|
||||
|
||||
void redirect(const std::string &url);
|
||||
|
||||
void send(AsyncWebServerResponse *response);
|
||||
void send(int code, const char *content_type = nullptr, const char *content = nullptr);
|
||||
inline void ESPHOME_ALWAYS_INLINE send(AsyncWebServerResponse *response) {
|
||||
httpd_resp_send(*this, response->get_content_data(), response->get_content_size());
|
||||
}
|
||||
inline void ESPHOME_ALWAYS_INLINE send(int code, const char *content_type = nullptr, const char *content = nullptr) {
|
||||
this->init_response_(nullptr, code, content_type);
|
||||
if (content) {
|
||||
httpd_resp_send(*this, content, HTTPD_RESP_USE_STRLEN);
|
||||
} else {
|
||||
httpd_resp_send(*this, nullptr, 0);
|
||||
}
|
||||
}
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
AsyncWebServerResponse *beginResponse(int code, const char *content_type) {
|
||||
auto *res = new AsyncWebServerResponseEmpty(this); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
|
||||
@@ -26,7 +26,7 @@ void setup() {
|
||||
|
||||
// Log functions call global_logger->log_vprintf_() without a null check,
|
||||
// so we must set up a Logger before any test that triggers logging.
|
||||
static esphome::logger::Logger test_logger(0);
|
||||
static esphome::logger::Logger test_logger(0, 64);
|
||||
test_logger.set_log_level(ESPHOME_LOG_LEVEL);
|
||||
test_logger.pre_setup();
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ void original_setup() {
|
||||
void setup() {
|
||||
// Log functions call global_logger->log_vprintf_() without a null check,
|
||||
// so we must set up a Logger before any test that triggers logging.
|
||||
static esphome::logger::Logger test_logger(0);
|
||||
static esphome::logger::Logger test_logger(0, 64);
|
||||
test_logger.set_log_level(ESPHOME_LOG_LEVEL);
|
||||
test_logger.pre_setup();
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ esphome:
|
||||
|
||||
host:
|
||||
api:
|
||||
batch_delay: 0ms # Disable batching to receive all state updates
|
||||
logger:
|
||||
level: VERBOSE
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ esphome:
|
||||
|
||||
host:
|
||||
api:
|
||||
batch_delay: 0ms # Disable batching to receive all state updates
|
||||
logger:
|
||||
level: VERBOSE
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ esphome:
|
||||
|
||||
host:
|
||||
api:
|
||||
batch_delay: 0ms # Disable batching to receive all state updates
|
||||
logger:
|
||||
level: VERBOSE
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ esphome:
|
||||
|
||||
host:
|
||||
api:
|
||||
batch_delay: 0ms # Disable batching to receive all state updates
|
||||
logger:
|
||||
level: VERBOSE
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ esphome:
|
||||
|
||||
host:
|
||||
api:
|
||||
batch_delay: 0ms # Disable batching to receive all state updates
|
||||
logger:
|
||||
level: VERBOSE
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ esphome:
|
||||
|
||||
host:
|
||||
api:
|
||||
batch_delay: 0ms # Disable batching to receive all state updates
|
||||
logger:
|
||||
level: VERBOSE
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ esphome:
|
||||
|
||||
host:
|
||||
api:
|
||||
batch_delay: 0ms # Disable batching to receive all state updates
|
||||
logger:
|
||||
level: VERBOSE
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ esphome:
|
||||
|
||||
host:
|
||||
api:
|
||||
batch_delay: 0ms # Disable batching to receive all state updates
|
||||
logger:
|
||||
level: VERBOSE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user