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