Avoid using wall time in case it jumps. (#3)

Instead, use std::chrono's steady_clock.
This commit is contained in:
jgruen
2025-01-07 00:40:27 -08:00
committed by GitHub
parent dab1b661ec
commit e21d0cee83
2 changed files with 25 additions and 28 deletions

View File

@@ -24,27 +24,17 @@ void EmporiaVueUtility::update() {
} }
void EmporiaVueUtility::loop() { void EmporiaVueUtility::loop() {
static const time_t delayed_start_time = static const steady_time_point delayed_start_time =
::time(nullptr) + INITIAL_STARTUP_DELAY; steady_clock::now() + INITIAL_STARTUP_DELAY;
static time_t next_expected_meter_request = 0; static steady_time_point next_expected_meter_request = min_steady_time_point;
static time_t next_meter_join = delayed_start_time + METER_REJOIN_INTERVAL; static steady_time_point next_meter_join = delayed_start_time + METER_REJOIN_INTERVAL;
static time_t next_version_request = 0; static steady_time_point next_version_request = min_steady_time_point;
static uint8_t startup_step = 0; static uint8_t startup_step = 0;
char msg_type = 0; char msg_type = 0;
size_t msg_len = 0; size_t msg_len = 0;
msg_len = read_msg(); msg_len = read_msg();
now = ::time(nullptr); now = steady_clock::now();
/* sanity checks! */
if (next_expected_meter_request >
now + (INITIAL_STARTUP_DELAY + METER_REJOIN_INTERVAL)) {
ESP_LOGD(TAG, "Time jumped back (%lld > %lld + %lld); resetting",
(long long)next_expected_meter_request, (long long)now,
(long long)(INITIAL_STARTUP_DELAY + METER_REJOIN_INTERVAL));
next_meter_join = 0;
next_expected_meter_request = now + update_interval_;
}
if (msg_len != 0) { if (msg_len != 0) {
msg_type = input_buffer.data[2]; msg_type = input_buffer.data[2];
@@ -52,7 +42,7 @@ void EmporiaVueUtility::loop() {
switch (msg_type) { switch (msg_type) {
case 'r': // Meter reading case 'r': // Meter reading
led_link(true); led_link(true);
if (now < last_meter_reading + int(update_interval_ / 4)) { if (now < (last_meter_reading + update_interval_ / 4)) {
// Sometimes a duplicate message is sent in quick succession. // Sometimes a duplicate message is sent in quick succession.
// Ignoring the duplicate. // Ignoring the duplicate.
ESP_LOGD(TAG, "Got extra message %lds after the previous message.", ESP_LOGD(TAG, "Got extra message %lds after the previous message.",
@@ -159,4 +149,4 @@ void EmporiaVueUtility::dump_config() {
LOG_UPDATE_INTERVAL(this); LOG_UPDATE_INTERVAL(this);
} }
} // namespace emporia_vue_utility } // namespace emporia_vue_utility
} // namespace esphome } // namespace esphome

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include <chrono>
#include "driver/gpio.h" #include "driver/gpio.h"
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
@@ -24,13 +26,13 @@
// How often to attempt to re-join the meter when it hasn't // How often to attempt to re-join the meter when it hasn't
// been returning readings // been returning readings
#define METER_REJOIN_INTERVAL 30 #define METER_REJOIN_INTERVAL std::chrono::seconds(30)
// How often to attempt to re-request the MGM firmware version. // How often to attempt to re-request the MGM firmware version.
#define MGM_FIRMWARE_REQUEST_INTERVAL 3 #define MGM_FIRMWARE_REQUEST_INTERVAL std::chrono::seconds(3)
// On first startup, how long before trying to start to talk to meter // On first startup, how long before trying to start to talk to meter
#define INITIAL_STARTUP_DELAY 10 #define INITIAL_STARTUP_DELAY std::chrono::seconds(10)
// Should this code manage the "wifi" and "link" LEDs? // Should this code manage the "wifi" and "link" LEDs?
// set to false if you want manually manage them elsewhere // set to false if you want manually manage them elsewhere
@@ -126,9 +128,14 @@ class EmporiaVueUtility : public PollingComponent, public uart::UARTDevice {
uint16_t pos = 0; uint16_t pos = 0;
uint16_t data_len; uint16_t data_len;
time_t last_meter_reading = 0; using steady_time_point = std::chrono::time_point<std::chrono::steady_clock>;
static constexpr steady_time_point min_steady_time_point =
steady_time_point::min();
using steady_clock = std::chrono::steady_clock;
steady_time_point last_meter_reading = min_steady_time_point;
bool last_reading_has_error; bool last_reading_has_error;
time_t now; steady_time_point now;
// The most recent meter divisor, meter reading payload V2 byte 47 // The most recent meter divisor, meter reading payload V2 byte 47
uint8_t meter_div = 0; uint8_t meter_div = 0;
@@ -139,7 +146,7 @@ class EmporiaVueUtility : public PollingComponent, public uart::UARTDevice {
void set_debug(bool enable) { debug_ = enable; } void set_debug(bool enable) { debug_ = enable; }
void set_update_interval(uint32_t update_interval) { void set_update_interval(uint32_t update_interval) {
PollingComponent::set_update_interval(update_interval); PollingComponent::set_update_interval(update_interval);
update_interval_ = update_interval / 1000; update_interval_ = std::chrono::milliseconds(update_interval);
} }
void set_power_sensor(sensor::Sensor *sensor) { power_sensor_ = sensor; } void set_power_sensor(sensor::Sensor *sensor) { power_sensor_ = sensor; }
void set_power_export_sensor(sensor::Sensor *sensor) { void set_power_export_sensor(sensor::Sensor *sensor) {
@@ -311,7 +318,7 @@ class EmporiaVueUtility : public PollingComponent, public uart::UARTDevice {
// Extra debugging of non-zero bytes, only on first packet or if // Extra debugging of non-zero bytes, only on first packet or if
// debug_ is true // debug_ is true
if ((debug_) || (last_meter_reading == 0)) { if ((debug_) || (last_meter_reading == min_steady_time_point)) {
ESP_LOGD(TAG, "Meter Divisor: %d", meter_div); ESP_LOGD(TAG, "Meter Divisor: %d", meter_div);
ESP_LOGD(TAG, "Meter Cost Unit: %d", cost_unit); ESP_LOGD(TAG, "Meter Cost Unit: %d", cost_unit);
ESP_LOGD(TAG, "Meter Flags: %02x %02x", mr2->maybe_flags[0], ESP_LOGD(TAG, "Meter Flags: %02x %02x", mr2->maybe_flags[0],
@@ -356,7 +363,7 @@ class EmporiaVueUtility : public PollingComponent, public uart::UARTDevice {
// Extra debugging of non-zero bytes, only on first packet or if // Extra debugging of non-zero bytes, only on first packet or if
// debug_ is true // debug_ is true
if ((debug_) || (last_meter_reading == 0)) { if ((debug_) || (last_meter_reading == min_steady_time_point)) {
ESP_LOGD(TAG, "Meter Cost Unit: %d", cost_unit); ESP_LOGD(TAG, "Meter Cost Unit: %d", cost_unit);
ESP_LOGD(TAG, "Meter Divisor: %d", meter_div); ESP_LOGD(TAG, "Meter Divisor: %d", meter_div);
ESP_LOGD(TAG, "Meter Energy Import Flags: %08x", mr7->import_wh); ESP_LOGD(TAG, "Meter Energy Import Flags: %08x", mr7->import_wh);
@@ -777,7 +784,7 @@ class EmporiaVueUtility : public PollingComponent, public uart::UARTDevice {
private: private:
bool debug_ = false; bool debug_ = false;
uint32_t update_interval_; steady_clock::duration update_interval_;
sensor::Sensor *power_sensor_{nullptr}; sensor::Sensor *power_sensor_{nullptr};
sensor::Sensor *power_export_sensor_{nullptr}; sensor::Sensor *power_export_sensor_{nullptr};
sensor::Sensor *power_import_sensor_{nullptr}; sensor::Sensor *power_import_sensor_{nullptr};
@@ -788,4 +795,4 @@ class EmporiaVueUtility : public PollingComponent, public uart::UARTDevice {
}; };
} // namespace emporia_vue_utility } // namespace emporia_vue_utility
} // namespace esphome } // namespace esphome