mirror of
https://github.com/esphome/esphome.git
synced 2026-05-25 10:26:10 +08:00
[usb_uart][nextion][feedback][whirlpool][packet_transport][he60r][hc8][runtime_stats] Fix millis() wrapping bugs (#14474)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
@@ -437,10 +437,15 @@ void FeedbackCover::recompute_position_() {
|
||||
}
|
||||
|
||||
// check if we have an acceleration_wait_time, and remove from position computation
|
||||
if (now > (this->start_dir_time_ + this->acceleration_wait_time_)) {
|
||||
this->position +=
|
||||
dir * (now - std::max(this->start_dir_time_ + this->acceleration_wait_time_, this->last_recompute_time_)) /
|
||||
(action_dur - this->acceleration_wait_time_);
|
||||
if (now - this->start_dir_time_ > this->acceleration_wait_time_) {
|
||||
uint32_t accel_end_time = this->start_dir_time_ + this->acceleration_wait_time_;
|
||||
uint32_t effective_start;
|
||||
if (static_cast<int32_t>(accel_end_time - this->last_recompute_time_) >= 0) {
|
||||
effective_start = accel_end_time;
|
||||
} else {
|
||||
effective_start = this->last_recompute_time_;
|
||||
}
|
||||
this->position += dir * (now - effective_start) / (action_dur - this->acceleration_wait_time_);
|
||||
this->position = clamp(this->position, min_pos, max_pos);
|
||||
}
|
||||
this->last_recompute_time_ = now;
|
||||
|
||||
@@ -24,12 +24,16 @@ void HC8Component::setup() {
|
||||
}
|
||||
|
||||
void HC8Component::update() {
|
||||
uint32_t now_ms = App.get_loop_component_start_time();
|
||||
uint32_t warmup_ms = this->warmup_seconds_ * 1000;
|
||||
if (now_ms < warmup_ms) {
|
||||
ESP_LOGW(TAG, "HC8 warming up, %" PRIu32 " s left", (warmup_ms - now_ms) / 1000);
|
||||
this->status_set_warning();
|
||||
return;
|
||||
if (!this->warmup_complete_) {
|
||||
uint32_t now_ms = App.get_loop_component_start_time();
|
||||
uint32_t warmup_ms = this->warmup_seconds_ * 1000;
|
||||
if (now_ms < warmup_ms) {
|
||||
ESP_LOGW(TAG, "HC8 warming up, %" PRIu32 " s left", (warmup_ms - now_ms) / 1000);
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
this->warmup_complete_ = true;
|
||||
this->status_clear_warning();
|
||||
}
|
||||
|
||||
while (this->available())
|
||||
|
||||
@@ -23,6 +23,7 @@ class HC8Component : public PollingComponent, public uart::UARTDevice {
|
||||
protected:
|
||||
sensor::Sensor *co2_sensor_{nullptr};
|
||||
uint32_t warmup_seconds_{0};
|
||||
bool warmup_complete_{false};
|
||||
};
|
||||
|
||||
template<typename... Ts> class HC8CalibrateAction : public Action<Ts...>, public Parented<HC8Component> {
|
||||
|
||||
@@ -239,7 +239,7 @@ void HE60rCover::recompute_position_() {
|
||||
return;
|
||||
|
||||
const uint32_t now = millis();
|
||||
if (now > this->last_recompute_time_) {
|
||||
if (now != this->last_recompute_time_) {
|
||||
auto diff = (unsigned) (now - last_recompute_time_);
|
||||
float delta;
|
||||
switch (this->current_operation) {
|
||||
|
||||
@@ -337,7 +337,7 @@ void Nextion::loop() {
|
||||
this->started_ms_ = App.get_loop_component_start_time();
|
||||
|
||||
if (this->startup_override_ms_ > 0 &&
|
||||
this->started_ms_ + this->startup_override_ms_ < App.get_loop_component_start_time()) {
|
||||
App.get_loop_component_start_time() - this->started_ms_ > this->startup_override_ms_) {
|
||||
ESP_LOGV(TAG, "Manual ready set");
|
||||
this->connection_state_.nextion_reports_is_setup_ = true;
|
||||
}
|
||||
@@ -853,10 +853,10 @@ void Nextion::process_nextion_commands_() {
|
||||
const uint32_t ms = App.get_loop_component_start_time();
|
||||
|
||||
if (this->max_q_age_ms_ > 0 && !this->nextion_queue_.empty() &&
|
||||
this->nextion_queue_.front()->queue_time + this->max_q_age_ms_ < ms) {
|
||||
ms - this->nextion_queue_.front()->queue_time > this->max_q_age_ms_) {
|
||||
for (size_t i = 0; i < this->nextion_queue_.size(); i++) {
|
||||
NextionComponentBase *component = this->nextion_queue_[i]->component;
|
||||
if (this->nextion_queue_[i]->queue_time + this->max_q_age_ms_ < ms) {
|
||||
if (ms - this->nextion_queue_[i]->queue_time > this->max_q_age_ms_) {
|
||||
if (this->nextion_queue_[i]->queue_time == 0) {
|
||||
ESP_LOGD(TAG, "Remove old queue '%s':'%s' (t=0)", component->get_queue_type_string().c_str(),
|
||||
component->get_variable_name().c_str());
|
||||
|
||||
@@ -330,15 +330,16 @@ void PacketTransport::update() {
|
||||
if (!this->ping_pong_enable_) {
|
||||
return;
|
||||
}
|
||||
auto now = millis() / 1000;
|
||||
if (this->last_key_time_ + this->ping_pong_recyle_time_ < now) {
|
||||
uint32_t now = millis();
|
||||
uint32_t ping_request_age = now - this->last_key_time_;
|
||||
if (ping_request_age > this->ping_pong_recyle_time_ * 1000u) {
|
||||
this->resend_ping_key_ = this->ping_pong_enable_;
|
||||
ESP_LOGV(TAG, "Ping request, age %" PRIu32, now - this->last_key_time_);
|
||||
ESP_LOGV(TAG, "Ping request, age %" PRIu32, ping_request_age);
|
||||
this->last_key_time_ = now;
|
||||
}
|
||||
for (const auto &provider : this->providers_) {
|
||||
uint32_t key_response_age = now - provider.second.last_key_response_time;
|
||||
if (key_response_age > (this->ping_pong_recyle_time_ * 2u)) {
|
||||
if (key_response_age > (this->ping_pong_recyle_time_ * 2000u)) {
|
||||
#ifdef USE_STATUS_SENSOR
|
||||
if (provider.second.status_sensor != nullptr && provider.second.status_sensor->state) {
|
||||
ESP_LOGI(TAG, "Ping status for %s timeout at %" PRIu32 " with age %" PRIu32, provider.first.c_str(), now,
|
||||
@@ -496,7 +497,7 @@ void PacketTransport::process_(std::span<const uint8_t> data) {
|
||||
if (decoder.decode(PING_KEY, key) == DECODE_OK) {
|
||||
if (key == this->ping_key_) {
|
||||
ping_key_seen = true;
|
||||
provider.last_key_response_time = millis() / 1000;
|
||||
provider.last_key_response_time = millis();
|
||||
ESP_LOGV(TAG, "Found good ping key %X at timestamp %" PRIu32, (unsigned) key, provider.last_key_response_time);
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Unknown ping key %X", (unsigned) key);
|
||||
|
||||
@@ -9,21 +9,16 @@ namespace esphome {
|
||||
|
||||
namespace runtime_stats {
|
||||
|
||||
RuntimeStatsCollector::RuntimeStatsCollector() : log_interval_(60000), next_log_time_(0) {
|
||||
RuntimeStatsCollector::RuntimeStatsCollector() : log_interval_(60000), next_log_time_(60000) {
|
||||
global_runtime_stats = this;
|
||||
}
|
||||
|
||||
void RuntimeStatsCollector::record_component_time(Component *component, uint32_t duration_us, uint32_t current_time) {
|
||||
void RuntimeStatsCollector::record_component_time(Component *component, uint32_t duration_us) {
|
||||
if (component == nullptr)
|
||||
return;
|
||||
|
||||
// Record stats using component pointer as key
|
||||
this->component_stats_[component].record_time(duration_us);
|
||||
|
||||
if (this->next_log_time_ == 0) {
|
||||
this->next_log_time_ = current_time + this->log_interval_;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void RuntimeStatsCollector::log_stats_() {
|
||||
@@ -88,10 +83,7 @@ void RuntimeStatsCollector::log_stats_() {
|
||||
}
|
||||
|
||||
void RuntimeStatsCollector::process_pending_stats(uint32_t current_time) {
|
||||
if (this->next_log_time_ == 0)
|
||||
return;
|
||||
|
||||
if (current_time >= this->next_log_time_) {
|
||||
if ((int32_t) (current_time - this->next_log_time_) >= 0) {
|
||||
this->log_stats_();
|
||||
this->reset_stats_();
|
||||
this->next_log_time_ = current_time + this->log_interval_;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
@@ -80,10 +81,13 @@ class RuntimeStatsCollector {
|
||||
public:
|
||||
RuntimeStatsCollector();
|
||||
|
||||
void set_log_interval(uint32_t log_interval) { this->log_interval_ = log_interval; }
|
||||
void set_log_interval(uint32_t log_interval) {
|
||||
this->log_interval_ = log_interval;
|
||||
this->next_log_time_ = millis() + log_interval;
|
||||
}
|
||||
uint32_t get_log_interval() const { return this->log_interval_; }
|
||||
|
||||
void record_component_time(Component *component, uint32_t duration_us, uint32_t current_time);
|
||||
void record_component_time(Component *component, uint32_t duration_us);
|
||||
|
||||
// Process any pending stats printing (should be called after component loop)
|
||||
void process_pending_stats(uint32_t current_time);
|
||||
@@ -101,7 +105,7 @@ class RuntimeStatsCollector {
|
||||
// We use Component* as the key since each component is unique
|
||||
std::map<Component *, ComponentRuntimeStats> component_stats_;
|
||||
uint32_t log_interval_;
|
||||
uint32_t next_log_time_;
|
||||
uint32_t next_log_time_{0};
|
||||
};
|
||||
|
||||
} // namespace runtime_stats
|
||||
|
||||
@@ -171,8 +171,8 @@ void USBUartChannel::flush() {
|
||||
// Safe to call from the main loop only.
|
||||
// The 100 ms timeout guards against a device that stops responding mid-flush;
|
||||
// in that case the main loop is blocked for the full duration.
|
||||
uint32_t deadline = millis() + 100; // 100 ms safety timeout
|
||||
while ((!this->output_queue_.empty() || this->output_started_.load()) && millis() < deadline) {
|
||||
uint32_t start = millis(); // 100 ms safety timeout
|
||||
while ((!this->output_queue_.empty() || this->output_started_.load()) && millis() - start < 100) {
|
||||
// Kick start_output() in case data arrived but no transfer is in flight yet.
|
||||
this->parent_->start_output(this);
|
||||
yield();
|
||||
|
||||
@@ -48,7 +48,7 @@ class WhirlpoolClimate : public climate_ir::ClimateIR {
|
||||
/// Handle received IR Buffer
|
||||
bool on_receive(remote_base::RemoteReceiveData data) override;
|
||||
/// Set the time of the last transmission.
|
||||
int32_t last_transmit_time_{};
|
||||
uint32_t last_transmit_time_{};
|
||||
|
||||
bool send_swing_cmd_{false};
|
||||
Model model_;
|
||||
|
||||
@@ -534,7 +534,7 @@ uint32_t WarnIfComponentBlockingGuard::finish() {
|
||||
// 1ms granularity, so results were essentially random noise.
|
||||
if (global_runtime_stats != nullptr) {
|
||||
uint32_t duration_us = micros() - this->started_us_;
|
||||
global_runtime_stats->record_component_time(this->component_, duration_us, curr_time);
|
||||
global_runtime_stats->record_component_time(this->component_, duration_us);
|
||||
}
|
||||
#endif
|
||||
if (blocking_time > WARN_IF_BLOCKING_OVER_MS) {
|
||||
|
||||
Reference in New Issue
Block a user