[mitsubishi_cn105] Defer status requests after responses (#18227)

This commit is contained in:
Boris Krivonog
2026-08-24 10:51:09 -05:00
committed by GitHub
parent 5ed20805ce
commit b11a34af5c
4 changed files with 88 additions and 21 deletions
@@ -15,11 +15,10 @@ struct MitsubishiCN105ClimateTestContext {
TEST(MitsubishiCN105ClimateTests, CelsiusTemperatureMappingAndTraitsMatchExpectedValues) {
MitsubishiCN105ClimateTestContext context;
const auto mapping = TemperatureMapping();
for (int temperature = 16; temperature <= 31; ++temperature) {
EXPECT_EQ(mapping.to_mitsubishi(temperature), temperature);
EXPECT_EQ(mapping.from_mitsubishi(temperature), temperature);
EXPECT_EQ(context.component.get_temperature_mapping().to_mitsubishi(temperature), temperature);
EXPECT_EQ(context.component.get_temperature_mapping().from_mitsubishi(temperature), temperature);
}
const auto traits = context.sut.traits();
@@ -32,8 +31,6 @@ TEST(MitsubishiCN105ClimateTests, CelsiusTemperatureMappingAndTraitsMatchExpecte
TEST(MitsubishiCN105ClimateTests, FahrenheitTemperatureMappingAndTraitsMatchExpectedValues) {
MitsubishiCN105ClimateTestContext context;
auto mapping = TemperatureMapping();
mapping.set_use_fahrenheit(true);
context.component.set_use_fahrenheit(true);
const std::array cases{
@@ -46,8 +43,8 @@ TEST(MitsubishiCN105ClimateTests, FahrenheitTemperatureMappingAndTraitsMatchExpe
};
for (const auto &[fahrenheit, mitsubishi_celsius] : cases) {
EXPECT_FLOAT_EQ(mapping.to_mitsubishi(fahrenheit), mitsubishi_celsius);
EXPECT_FLOAT_EQ(mapping.from_mitsubishi(mitsubishi_celsius), fahrenheit);
EXPECT_FLOAT_EQ(context.component.get_temperature_mapping().to_mitsubishi(fahrenheit), mitsubishi_celsius);
EXPECT_FLOAT_EQ(context.component.get_temperature_mapping().from_mitsubishi(mitsubishi_celsius), fahrenheit);
}
const auto traits = context.sut.traits();
EXPECT_EQ(traits.get_temperature_unit(), TemperatureUnit::FAHRENHEIT);
@@ -42,11 +42,17 @@ TEST(MitsubishiCN105Tests, ConnectAndUpdateStatus) {
// All bytes from UART should be consumed
EXPECT_TRUE(ctx.uart.rx.empty());
// After successful connect we request status, first settings (0x02)
// Defer the first settings request (0x02) until the next update.
EXPECT_EQ(ctx.sut.state_, TestableMitsubishiCN105::State::DEFERRED_STATUS_REQUEST);
EXPECT_TRUE(ctx.uart.tx.empty());
ctx.sut.set_current_time(201);
ASSERT_FALSE(ctx.sut.update());
EXPECT_EQ(ctx.sut.state_, TestableMitsubishiCN105::State::UPDATING_STATUS);
EXPECT_THAT(ctx.uart.tx, ::testing::ElementsAre(0xFC, 0x42, 0x01, 0x30, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7B));
EXPECT_EQ(ctx.sut.operation_start_ms_, 200);
EXPECT_EQ(ctx.sut.operation_start_ms_, 201);
// Clear TX bytes.
ctx.uart.tx.clear();
@@ -75,15 +81,24 @@ TEST(MitsubishiCN105Tests, ConnectAndUpdateStatus) {
EXPECT_EQ(ctx.sut.status().vane_mode, MitsubishiCN105::VaneMode::POSITION_4);
EXPECT_EQ(ctx.sut.status().wide_vane_mode, MitsubishiCN105::WideVaneMode::SWING);
// Now fetch telemetry (0x03)
// Defer the telemetry request (0x03) until the next update.
EXPECT_EQ(ctx.sut.state_, TestableMitsubishiCN105::State::DEFERRED_STATUS_REQUEST);
EXPECT_TRUE(ctx.uart.tx.empty());
ctx.sut.set_current_time(301);
ASSERT_FALSE(ctx.sut.update());
EXPECT_EQ(ctx.sut.state_, TestableMitsubishiCN105::State::UPDATING_STATUS);
EXPECT_THAT(ctx.uart.tx, ::testing::ElementsAre(0xFC, 0x42, 0x01, 0x30, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7A));
EXPECT_EQ(ctx.sut.operation_start_ms_, 300);
EXPECT_EQ(ctx.sut.operation_start_ms_, 301);
// Clear TX bytes.
ctx.uart.tx.clear();
// Queue a setting while waiting for telemetry.
ctx.sut.set_power(true);
// Telemetry response
ctx.uart.push_rx({0xFC, 0x62, 0x01, 0x30, 0x10, 0x03, 0x00, 0x00, 0x0B, 0x00, 0x00,
0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA5});
@@ -103,6 +118,13 @@ TEST(MitsubishiCN105Tests, ConnectAndUpdateStatus) {
EXPECT_TRUE(ctx.uart.tx.empty());
EXPECT_EQ(ctx.sut.state_, TestableMitsubishiCN105::State::WAITING_FOR_SCHEDULED_STATUS_UPDATE);
EXPECT_EQ(ctx.sut.operation_start_ms_, 400);
// Apply the pending setting on the next update, outside RX processing.
ctx.sut.set_current_time(401);
ASSERT_FALSE(ctx.sut.update());
EXPECT_EQ(ctx.sut.state_, TestableMitsubishiCN105::State::APPLYING_SETTINGS);
EXPECT_FALSE(ctx.uart.tx.empty());
EXPECT_EQ(ctx.sut.operation_start_ms_, 401);
}
TEST(MitsubishiCN105Tests, NoResponseTriggersReconnect) {
@@ -469,6 +491,36 @@ TEST(MitsubishiCN105Tests, WriteInterruptsWaitingForNextStatusUpdate) {
EXPECT_EQ(ctx.sut.status_update_wait_credit_ms_, 0);
}
TEST(MitsubishiCN105Tests, PendingSettingsTakePriorityOverDueTelemetry) {
MitsubishiCN105TestsContext ctx;
ctx.sut.status_.target_temperature = 24.0f;
ctx.sut.status_.room_temperature = 21.0f;
ASSERT_TRUE(ctx.sut.is_status_initialized());
ctx.sut.state_ = TestableMitsubishiCN105::State::STATUS_UPDATED;
ctx.sut.set_state(TestableMitsubishiCN105::State::SCHEDULE_NEXT_STATUS_UPDATE);
ctx.sut.set_current_time(1000);
ASSERT_FALSE(ctx.sut.update());
ASSERT_EQ(ctx.sut.state_, TestableMitsubishiCN105::State::UPDATING_STATUS);
ctx.uart.tx.clear();
ctx.sut.set_power(true);
ctx.uart.push_rx({0xFC, 0x62, 0x01, 0x30, 0x10, 0x02, 0x00, 0x00, 0x00, 0x08, 0x07,
0x00, 0x04, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C});
ctx.sut.set_current_time(1001);
ASSERT_TRUE(ctx.sut.update());
EXPECT_TRUE(ctx.uart.tx.empty());
EXPECT_EQ(ctx.sut.state_, TestableMitsubishiCN105::State::WAITING_FOR_SCHEDULED_STATUS_UPDATE);
ctx.sut.set_current_time(1002);
ASSERT_FALSE(ctx.sut.update());
EXPECT_EQ(ctx.sut.state_, TestableMitsubishiCN105::State::APPLYING_SETTINGS);
EXPECT_THAT(ctx.uart.tx, ::testing::ElementsAre(0xFC, 0x41, 0x01, 0x30, 0x10, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7B));
}
TEST(MitsubishiCN105Tests, SetAndClearRemoteRoomTemp) {
MitsubishiCN105TestsContext ctx;