Files
esphome/tests/components/ufm01/ufm01_diagnostics_test.cpp
T
86192d89f4 [ufm01] Improve stale recovery, add diagnostics and clear flow action (#18899)
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-10-11 09:29:56 -10:00

174 lines
6.1 KiB
C++

#include "common.h"
namespace esphome::ufm01::testing {
TEST_F(UFM01Test, ActiveFramePublishesMeterIdOnce) {
this->attach_diagnostic_text_sensors();
auto frame = make_active_frame();
this->mock_uart_.enqueue(frame);
EXPECT_TRUE(this->ufm01_.process_active_stream());
EXPECT_TRUE(this->ufm01_.meter_id_published());
EXPECT_STREQ(this->meter_id_text_sensor_.state.c_str(), "2307140001");
this->mock_uart_.enqueue(frame);
EXPECT_TRUE(this->ufm01_.process_active_stream());
EXPECT_STREQ(this->meter_id_text_sensor_.state.c_str(), "2307140001");
}
#ifdef USE_SENSOR
TEST_F(UFM01Test, PassiveFrameWithIdUsesDocumentedMeasurementOffsets) {
this->attach_diagnostic_text_sensors();
this->attach_flow_and_temperature_sensors();
this->ufm01_.start_passive_read();
this->expect_written(READ_SENSOR_DATA_WITH_ID);
this->mock_uart_.enqueue(make_passive_with_id_frame());
EXPECT_EQ(this->ufm01_.continue_passive_read(), ReadResult::READ_RESULT_SUCCESS);
EXPECT_STREQ(this->meter_id_text_sensor_.state.c_str(), "2307140001");
EXPECT_NEAR(this->flow_sensor_.get_state(), 0.01234f, 0.000001f);
EXPECT_NEAR(this->temperature_sensor_.get_state(), 23.5f, 0.001f);
}
#endif
TEST_F(UFM01Test, InvalidPassiveFrameWithIdIsRejected) {
this->attach_diagnostic_text_sensors();
this->ufm01_.start_passive_read();
auto frame = make_passive_with_id_frame();
frame[37] ^= 0xFF;
this->mock_uart_.enqueue(frame);
EXPECT_EQ(this->ufm01_.continue_passive_read(), ReadResult::READ_RESULT_FAILURE);
EXPECT_FALSE(this->ufm01_.meter_id_published());
}
TEST_F(UFM01Test, SoftwareVersionResponseDecoded) {
this->attach_diagnostic_text_sensors();
this->ufm01_.start_software_version_read();
this->mock_uart_.enqueue(make_software_version_response());
EXPECT_EQ(this->ufm01_.continue_software_version_read(), ReadResult::READ_RESULT_SUCCESS);
EXPECT_TRUE(this->ufm01_.software_version_published());
EXPECT_STREQ(this->software_version_text_sensor_.state.c_str(), "23380315");
}
TEST_F(UFM01Test, SoftwareVersionReadSkipsLeftoverStreamBytes) {
this->attach_diagnostic_text_sensors();
this->ufm01_.start_software_version_read();
// Tail of an active frame that was still on the wire when the command was sent
auto frame = make_active_frame();
this->mock_uart_.enqueue(std::vector<uint8_t>(frame.begin() + 20, frame.end()));
this->mock_uart_.enqueue(make_software_version_response());
EXPECT_EQ(this->ufm01_.continue_software_version_read(), ReadResult::READ_RESULT_SUCCESS);
EXPECT_STREQ(this->software_version_text_sensor_.state.c_str(), "23380315");
}
TEST_F(UFM01Test, InvalidSoftwareVersionBcdFails) {
this->attach_diagnostic_text_sensors();
this->ufm01_.start_software_version_read();
auto response = make_software_version_response();
response[2] = 0xFA;
response[5] = checksum(response, 1, 5);
this->mock_uart_.enqueue(response);
EXPECT_EQ(this->ufm01_.continue_software_version_read(), ReadResult::READ_RESULT_FAILURE);
EXPECT_FALSE(this->ufm01_.software_version_published());
}
TEST_F(UFM01Test, SoftwareVersionReadTimeoutFails) {
this->attach_diagnostic_text_sensors();
this->ufm01_.start_software_version_read();
this->advance(1900);
EXPECT_EQ(this->ufm01_.continue_software_version_read(), ReadResult::READ_RESULT_PENDING);
this->advance(100);
EXPECT_EQ(this->ufm01_.continue_software_version_read(), ReadResult::READ_RESULT_FAILURE);
EXPECT_FALSE(this->ufm01_.software_version_published());
}
TEST_F(UFM01Test, StartupReadsSoftwareVersionBeforeActiveMode) {
this->attach_diagnostic_text_sensors();
this->ufm01_.begin_post_reset_wait();
this->advance(3000);
this->ufm01_.loop_startup();
EXPECT_EQ(this->ufm01_.startup_phase(), StartupPhase::SOFTWARE_VERSION_WAIT_REPLY);
this->expect_written(GET_SOFTWARE_VERSION);
this->mock_uart_.enqueue(make_software_version_response());
this->mock_uart_.written_data.clear();
this->ufm01_.loop_startup();
EXPECT_EQ(this->ufm01_.startup_phase(), StartupPhase::ACTIVE_WAIT_FRAME);
this->expect_written(ACTIVE_MODE);
EXPECT_TRUE(this->ufm01_.software_version_published());
EXPECT_STREQ(this->software_version_text_sensor_.state.c_str(), "23380315");
}
TEST_F(UFM01Test, AlreadyActiveStartupRequestsSoftwareVersion) {
this->attach_diagnostic_text_sensors();
this->mock_uart_.enqueue(make_active_frame());
this->ufm01_.init_wait_phase();
this->ufm01_.loop_startup();
EXPECT_EQ(this->ufm01_.operating_mode(), OperatingMode::ACTIVE_STREAM);
EXPECT_TRUE(this->ufm01_.meter_id_published());
EXPECT_TRUE(this->mock_uart_.written_data.empty());
this->ufm01_.loop_active_stream();
this->expect_written(GET_SOFTWARE_VERSION);
}
TEST_F(UFM01Test, ActiveStreamRetriesSoftwareVersionRead) {
this->attach_diagnostic_text_sensors();
this->ufm01_.set_operating_mode(OperatingMode::ACTIVE_STREAM);
this->ufm01_.set_last_software_version_attempt_ms(this->now_);
this->advance(29000);
this->ufm01_.loop_active_stream();
EXPECT_TRUE(this->mock_uart_.written_data.empty());
this->advance(2000);
this->ufm01_.loop_active_stream();
this->expect_written(GET_SOFTWARE_VERSION);
}
TEST_F(UFM01Test, ActiveStreamGivesUpSoftwareVersionAfterRepeatedFailures) {
this->attach_diagnostic_text_sensors();
this->ufm01_.set_operating_mode(OperatingMode::ACTIVE_STREAM);
for (int attempt = 0; attempt < 3; ++attempt) {
this->ufm01_.loop_active_stream();
this->expect_written(GET_SOFTWARE_VERSION);
this->mock_uart_.written_data.clear();
this->advance(2000);
this->ufm01_.loop_active_stream();
this->advance(30000);
}
this->ufm01_.loop_active_stream();
EXPECT_TRUE(this->mock_uart_.written_data.empty());
EXPECT_FALSE(this->ufm01_.software_version_published());
}
TEST_F(UFM01Test, InvalidMeterIdLeavesSensorUnknown) {
this->attach_diagnostic_text_sensors();
auto frame = make_active_frame();
frame[2] = 0xAB;
frame[30] = checksum(frame, 0, 30);
this->mock_uart_.enqueue(frame);
EXPECT_TRUE(this->ufm01_.process_active_stream());
EXPECT_FALSE(this->ufm01_.meter_id_published());
EXPECT_FALSE(this->meter_id_text_sensor_.has_state());
}
} // namespace esphome::ufm01::testing