mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 02:02:51 +00:00
[toshiba] Move the lookup tables to PROGMEM (#20636)
This commit is contained in:
@@ -3,8 +3,6 @@
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome::toshiba {
|
||||
|
||||
struct RacPt1411hwruFanSpeed {
|
||||
@@ -69,8 +67,8 @@ const uint8_t RAC_PT1411HWRU_CS_FOOTER_COOL = 0x72;
|
||||
const uint8_t RAC_PT1411HWRU_CS_FOOTER_HEAT = 0x7E;
|
||||
// RAC-PT1411HWRU Swing
|
||||
const uint8_t RAC_PT1411HWRU_SWING_HEADER = 0xB9;
|
||||
const std::vector<uint8_t> RAC_PT1411HWRU_SWING_VERTICAL{0xB9, 0x46, 0xF5, 0x0A, 0x04, 0xFB};
|
||||
const std::vector<uint8_t> RAC_PT1411HWRU_SWING_OFF{0xB9, 0x46, 0xF5, 0x0A, 0x05, 0xFA};
|
||||
static constexpr uint8_t RAC_PT1411HWRU_SWING_VERTICAL[] PROGMEM = {0xB9, 0x46, 0xF5, 0x0A, 0x04, 0xFB};
|
||||
static constexpr uint8_t RAC_PT1411HWRU_SWING_OFF[] PROGMEM = {0xB9, 0x46, 0xF5, 0x0A, 0x05, 0xFA};
|
||||
// RAC-PT1411HWRU Fan speeds
|
||||
const uint8_t RAC_PT1411HWRU_FAN_OFF = 0x7B;
|
||||
constexpr RacPt1411hwruFanSpeed RAC_PT1411HWRU_FAN_AUTO{0xBF, 0x66};
|
||||
@@ -92,12 +90,12 @@ const uint8_t RAC_PT1411HWRU_TEMPERATURE_FAN_ONLY = 0x0E;
|
||||
// Hence these look-up tables. In addition, the upper nibble is used here for additional
|
||||
// "negative" and "fractional value" flags as required for some temperatures.
|
||||
// RAC-PT1411HWRU °C Temperatures (short codes)
|
||||
const std::vector<uint8_t> RAC_PT1411HWRU_TEMPERATURE_C{0x10, 0x00, 0x01, 0x03, 0x02, 0x06, 0x07, 0x05,
|
||||
0x04, 0x0C, 0x0D, 0x09, 0x08, 0x0A, 0x0B};
|
||||
static constexpr uint8_t RAC_PT1411HWRU_TEMPERATURE_C[] PROGMEM = {0x10, 0x00, 0x01, 0x03, 0x02, 0x06, 0x07, 0x05,
|
||||
0x04, 0x0C, 0x0D, 0x09, 0x08, 0x0A, 0x0B};
|
||||
// RAC-PT1411HWRU °F Temperatures (short codes)
|
||||
const std::vector<uint8_t> RAC_PT1411HWRU_TEMPERATURE_F{0x10, 0x30, 0x00, 0x20, 0x01, 0x21, 0x03, 0x23, 0x02,
|
||||
0x22, 0x06, 0x26, 0x07, 0x05, 0x25, 0x04, 0x24, 0x0C,
|
||||
0x2C, 0x0D, 0x2D, 0x09, 0x08, 0x28, 0x0A, 0x2A, 0x0B};
|
||||
static constexpr uint8_t RAC_PT1411HWRU_TEMPERATURE_F[] PROGMEM = {
|
||||
0x10, 0x30, 0x00, 0x20, 0x01, 0x21, 0x03, 0x23, 0x02, 0x22, 0x06, 0x26, 0x07, 0x05,
|
||||
0x25, 0x04, 0x24, 0x0C, 0x2C, 0x0D, 0x2D, 0x09, 0x08, 0x28, 0x0A, 0x2A, 0x0B};
|
||||
|
||||
// RAS-2819T protocol constants
|
||||
const uint16_t RAS_2819T_HEADER1 = 0xC23D;
|
||||
@@ -213,7 +211,7 @@ static constexpr uint8_t SEIYA_SWING_HORIZONTAL = 0x09;
|
||||
static constexpr uint8_t SEIYA_SWING_NEUTRAL = 0x17; // no swing change in this frame
|
||||
|
||||
// RAS-2819T temperature codes for 18-30°C
|
||||
static const uint8_t RAS_2819T_TEMP_CODES[] = {
|
||||
static constexpr uint8_t RAS_2819T_TEMP_CODES[] PROGMEM = {
|
||||
0x10, // 18°C
|
||||
0x30, // 19°C
|
||||
0x20, // 20°C
|
||||
@@ -328,7 +326,7 @@ static uint8_t get_ras_2819t_temp_code(float temperature) {
|
||||
return 0x40; // Default to 24°C
|
||||
}
|
||||
|
||||
return RAS_2819T_TEMP_CODES[temp_index];
|
||||
return progmem_read_byte(&RAS_2819T_TEMP_CODES[temp_index]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,7 +337,7 @@ static float decode_ras_2819t_temperature(uint8_t temp_code) {
|
||||
|
||||
// Find the code in the temperature array
|
||||
for (size_t temp_index = 0; temp_index < sizeof(RAS_2819T_TEMP_CODES); temp_index++) {
|
||||
if (RAS_2819T_TEMP_CODES[temp_index] == base_temp_code) {
|
||||
if (progmem_read_byte(&RAS_2819T_TEMP_CODES[temp_index]) == base_temp_code) {
|
||||
return static_cast<float>(temp_index + 18); // 18°C is the minimum
|
||||
}
|
||||
}
|
||||
@@ -680,10 +678,10 @@ void ToshibaClimate::transmit_rac_pt1411hwru_() {
|
||||
index = static_cast<uint8_t>(roundf(temp_adjd));
|
||||
|
||||
if (this->model_ == MODEL_RAC_PT1411HWRU_F) {
|
||||
code = RAC_PT1411HWRU_TEMPERATURE_F[index];
|
||||
code = progmem_read_byte(&RAC_PT1411HWRU_TEMPERATURE_F[index]);
|
||||
message[9] |= RAC_PT1411HWRU_FLAG_FAH;
|
||||
} else {
|
||||
code = RAC_PT1411HWRU_TEMPERATURE_C[index];
|
||||
code = progmem_read_byte(&RAC_PT1411HWRU_TEMPERATURE_C[index]);
|
||||
}
|
||||
if ((this->mode == climate::CLIMATE_MODE_FAN_ONLY) || (this->mode == climate::CLIMATE_MODE_OFF)) {
|
||||
code = RAC_PT1411HWRU_TEMPERATURE_FAN_ONLY;
|
||||
@@ -752,15 +750,11 @@ void ToshibaClimate::transmit_rac_pt1411hwru_() {
|
||||
// Swing Mode
|
||||
data->reset();
|
||||
data->space(TOSHIBA_PACKET_SPACE);
|
||||
switch (this->swing_mode) {
|
||||
case climate::CLIMATE_SWING_VERTICAL:
|
||||
this->encode_(data, &RAC_PT1411HWRU_SWING_VERTICAL[0], RAC_PT1411HWRU_MESSAGE_LENGTH, 1);
|
||||
break;
|
||||
|
||||
case climate::CLIMATE_SWING_OFF:
|
||||
default:
|
||||
this->encode_(data, &RAC_PT1411HWRU_SWING_OFF[0], RAC_PT1411HWRU_MESSAGE_LENGTH, 1);
|
||||
}
|
||||
const uint8_t *swing_frame =
|
||||
this->swing_mode == climate::CLIMATE_SWING_VERTICAL ? RAC_PT1411HWRU_SWING_VERTICAL : RAC_PT1411HWRU_SWING_OFF;
|
||||
uint8_t swing[RAC_PT1411HWRU_MESSAGE_LENGTH];
|
||||
progmem_memcpy(swing, swing_frame, sizeof(swing));
|
||||
this->encode_(data, swing, sizeof(swing), 1);
|
||||
|
||||
data->space(TOSHIBA_PACKET_SPACE);
|
||||
transmit.perform();
|
||||
@@ -1300,14 +1294,14 @@ bool ToshibaClimate::on_receive(remote_base::RemoteReceiveData data) {
|
||||
temperature_code =
|
||||
(message[4] >> 4) | (message[14] & RAC_PT1411HWRU_FLAG_FRAC) | (message[15] & RAC_PT1411HWRU_FLAG_NEG);
|
||||
if (message[15] & RAC_PT1411HWRU_FLAG_FAH) {
|
||||
for (size_t i = 0; i < RAC_PT1411HWRU_TEMPERATURE_F.size(); i++) {
|
||||
if (RAC_PT1411HWRU_TEMPERATURE_F[i] == temperature_code) {
|
||||
for (size_t i = 0; i < sizeof(RAC_PT1411HWRU_TEMPERATURE_F); i++) {
|
||||
if (progmem_read_byte(&RAC_PT1411HWRU_TEMPERATURE_F[i]) == temperature_code) {
|
||||
this->target_temperature = static_cast<float>((i + TOSHIBA_RAC_PT1411HWRU_TEMP_F_MIN - 32) * 5) / 9;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < RAC_PT1411HWRU_TEMPERATURE_C.size(); i++) {
|
||||
if (RAC_PT1411HWRU_TEMPERATURE_C[i] == temperature_code) {
|
||||
for (size_t i = 0; i < sizeof(RAC_PT1411HWRU_TEMPERATURE_C); i++) {
|
||||
if (progmem_read_byte(&RAC_PT1411HWRU_TEMPERATURE_C[i]) == temperature_code) {
|
||||
this->target_temperature = i + TOSHIBA_RAC_PT1411HWRU_TEMP_C_MIN;
|
||||
}
|
||||
}
|
||||
@@ -1333,7 +1327,7 @@ bool ToshibaClimate::on_receive(remote_base::RemoteReceiveData data) {
|
||||
break;
|
||||
// Swing mode
|
||||
case RAC_PT1411HWRU_SWING_HEADER:
|
||||
if (message[4] == RAC_PT1411HWRU_SWING_VERTICAL[4]) {
|
||||
if (message[4] == progmem_read_byte(&RAC_PT1411HWRU_SWING_VERTICAL[4])) {
|
||||
this->swing_mode = climate::CLIMATE_SWING_VERTICAL;
|
||||
} else {
|
||||
this->swing_mode = climate::CLIMATE_SWING_OFF;
|
||||
|
||||
@@ -130,6 +130,61 @@ TEST(ToshibaGeneric, WaveformIsUnchangedByTheSharedPath) {
|
||||
expect_frame(f.last_frame(), waveform({0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x30, 0xC3, 0x00, 0xF2}, GENERIC), 9);
|
||||
}
|
||||
|
||||
// The RAC-PT1411HWRU sends its main message, then a separate swing packet
|
||||
// wrapped in packet spaces; both use the generic timings.
|
||||
static void expect_swing_packet(const remote_base::RawTimings &actual, const std::vector<uint8_t> &bytes) {
|
||||
ASSERT_GE(actual.size(), 2u);
|
||||
EXPECT_EQ(actual.front(), -10500);
|
||||
EXPECT_EQ(actual.back(), -10500);
|
||||
const remote_base::RawTimings frame(actual.begin() + 1, actual.end() - 1);
|
||||
expect_frame(frame, waveform(bytes, GENERIC), 6);
|
||||
}
|
||||
|
||||
TEST(ToshibaRacPt1411hwru, SendsTheSwingFrameFromFlash) {
|
||||
Fixture f(MODEL_RAC_PT1411HWRU_C);
|
||||
|
||||
f.command(climate::CLIMATE_MODE_COOL, 24, climate::CLIMATE_FAN_AUTO, climate::CLIMATE_SWING_VERTICAL);
|
||||
expect_swing_packet(f.last_frame(), {0xB9, 0x46, 0xF5, 0x0A, 0x04, 0xFB});
|
||||
|
||||
f.command(climate::CLIMATE_MODE_COOL, 24, climate::CLIMATE_FAN_AUTO, climate::CLIMATE_SWING_OFF);
|
||||
expect_swing_packet(f.last_frame(), {0xB9, 0x46, 0xF5, 0x0A, 0x05, 0xFA});
|
||||
}
|
||||
|
||||
// The temperature tables are read on the way out and searched on the way back
|
||||
// in, so what one fixture sends must decode to the same state in another.
|
||||
TEST(ToshibaRacPt1411hwru, TemperatureCodesRoundTrip) {
|
||||
for (const Model model : {MODEL_RAC_PT1411HWRU_C, MODEL_RAC_PT1411HWRU_F}) {
|
||||
for (int temperature = 16; temperature <= 30; temperature++) {
|
||||
SCOPED_TRACE(::testing::Message() << "model " << model << " temperature " << temperature);
|
||||
Fixture tx(model);
|
||||
tx.command(climate::CLIMATE_MODE_COOL, temperature, climate::CLIMATE_FAN_AUTO);
|
||||
// The main message is sent before the swing packet
|
||||
const auto &main_frame = tx.transmitter.frames[tx.transmitter.frames.size() - 2];
|
||||
|
||||
Fixture rx(model);
|
||||
remote_base::RemoteReceiveData data(main_frame, 25, remote_base::TOLERANCE_MODE_PERCENTAGE);
|
||||
ASSERT_TRUE(static_cast<remote_base::RemoteReceiverListener &>(rx.climate).on_receive(data));
|
||||
EXPECT_EQ(rx.climate.mode, climate::CLIMATE_MODE_COOL);
|
||||
EXPECT_NEAR(rx.climate.target_temperature, temperature, 0.3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The RAS-2819T table is read for the code on the way out and searched on the way back in.
|
||||
TEST(ToshibaRas2819t, TemperatureCodesRoundTrip) {
|
||||
for (int temperature = 18; temperature <= 30; temperature++) {
|
||||
SCOPED_TRACE(::testing::Message() << "temperature " << temperature);
|
||||
Fixture tx(MODEL_RAS_2819T);
|
||||
tx.command(climate::CLIMATE_MODE_COOL, temperature, climate::CLIMATE_FAN_AUTO);
|
||||
|
||||
Fixture rx(MODEL_RAS_2819T);
|
||||
remote_base::RemoteReceiveData data(tx.last_frame(), 25, remote_base::TOLERANCE_MODE_PERCENTAGE);
|
||||
ASSERT_TRUE(static_cast<remote_base::RemoteReceiverListener &>(rx.climate).on_receive(data));
|
||||
EXPECT_EQ(rx.climate.mode, climate::CLIMATE_MODE_COOL);
|
||||
EXPECT_FLOAT_EQ(rx.climate.target_temperature, temperature);
|
||||
}
|
||||
}
|
||||
|
||||
static bool receive(ToshibaClimate &climate, const std::vector<uint8_t> &bytes, const Timings &t) {
|
||||
const remote_base::RawTimings raw = waveform(bytes, t);
|
||||
remote_base::RemoteReceiveData data(raw, 25, remote_base::TOLERANCE_MODE_PERCENTAGE);
|
||||
|
||||
Reference in New Issue
Block a user