mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 10:12:52 +00:00
Merge remote-tracking branch 'origin/shelly-dimmer-update-test' into shelly_dimmer-tables-progmem
This commit is contained in:
@@ -330,7 +330,9 @@ async def write_image(
|
||||
if byte_order is not None:
|
||||
# Check for valid type has already been done in validate_settings
|
||||
encoder.set_big_endian(byte_order == "BIG_ENDIAN")
|
||||
pixels = encoder.convert(image.resize((width, height)), path).getdata()
|
||||
pixels = encoder.convert(
|
||||
image.resize((width, height)), path
|
||||
).get_flattened_data()
|
||||
for row in range(height):
|
||||
for col in range(width):
|
||||
encoder.encode(pixels[row * width + col])
|
||||
|
||||
@@ -35,7 +35,7 @@ CONFIG_SCHEMA = cv.ensure_list(
|
||||
|
||||
|
||||
async def to_code(config: list[ConfigType]) -> None:
|
||||
cg.add_library("wjtje/qr-code-generator-library", "^1.7.0")
|
||||
cg.add_library("wjtje/qr-code-generator-library", "1.7.0")
|
||||
|
||||
for entry in config:
|
||||
var = cg.new_Pvariable(entry[CONF_ID])
|
||||
|
||||
@@ -115,7 +115,7 @@ class PNGFormat(Format):
|
||||
|
||||
def actions(self) -> None:
|
||||
cg.add_define("USE_RUNTIME_IMAGE_PNG")
|
||||
cg.add_library("pngle", "1.1.0")
|
||||
cg.add_library("kikuchan98/pngle", "1.1.0")
|
||||
|
||||
|
||||
class QOIFormat(Format):
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
|
||||
#include "esphome/components/logger/logger.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
namespace esphome::syslog {
|
||||
|
||||
// Map log levels to syslog severity using an array, indexed by ESPHome log level (1-7)
|
||||
constexpr int LOG_LEVEL_TO_SYSLOG_SEVERITY[] = {
|
||||
static constexpr uint8_t LOG_LEVEL_TO_SYSLOG_SEVERITY[] PROGMEM = {
|
||||
3, // NONE
|
||||
3, // ERROR
|
||||
4, // WARN
|
||||
@@ -35,7 +36,7 @@ void Syslog::log_(const int level, const char *tag, const char *message, size_t
|
||||
// Syslog PRI calculation: facility * 8 + severity
|
||||
int severity = 7;
|
||||
if ((unsigned) level <= 7) {
|
||||
severity = LOG_LEVEL_TO_SYSLOG_SEVERITY[level];
|
||||
severity = progmem_read_byte(&LOG_LEVEL_TO_SYSLOG_SEVERITY[level]);
|
||||
}
|
||||
int pri = this->facility_ * 8 + severity;
|
||||
|
||||
|
||||
@@ -240,12 +240,6 @@ def validate_thermostat(config: ConfigType) -> ConfigType:
|
||||
CONF_SUPPLEMENTAL_HEATING_ACTION,
|
||||
CONF_SUPPLEMENTAL_HEATING_DELTA,
|
||||
],
|
||||
CONF_MIN_COOLING_OFF_TIME: [
|
||||
CONF_COOL_ACTION,
|
||||
],
|
||||
CONF_MIN_COOLING_RUN_TIME: [
|
||||
CONF_COOL_ACTION,
|
||||
],
|
||||
CONF_MIN_FANNING_OFF_TIME: [
|
||||
CONF_FAN_ONLY_ACTION,
|
||||
],
|
||||
@@ -284,6 +278,17 @@ def validate_thermostat(config: ConfigType) -> ConfigType:
|
||||
f"{req_trigger} must be defined to use {config_trigger}"
|
||||
)
|
||||
|
||||
# Dry mode runs on the cooling timers, so a dehumidifier needs no cool_action.
|
||||
for timer in (CONF_MIN_COOLING_OFF_TIME, CONF_MIN_COOLING_RUN_TIME):
|
||||
if (
|
||||
timer in config
|
||||
and CONF_COOL_ACTION not in config
|
||||
and CONF_DRY_ACTION not in config
|
||||
):
|
||||
raise cv.Invalid(
|
||||
f"{CONF_COOL_ACTION} or {CONF_DRY_ACTION} must be defined to use {timer}"
|
||||
)
|
||||
|
||||
if CONF_FAN_ONLY_ACTION in config:
|
||||
# determine validation requirements based on fan_only_action_uses_fan_mode_timer setting
|
||||
if config[CONF_FAN_ONLY_ACTION_USES_FAN_MODE_TIMER] is True:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -21,6 +21,8 @@ dependencies:
|
||||
version: "1.8.2"
|
||||
espressif/esp-tflite-micro:
|
||||
version: 1.3.3~1
|
||||
espressif/esp-nn:
|
||||
version: 1.1.2
|
||||
espressif/esp32-camera:
|
||||
version: 2.1.7
|
||||
espressif/mdns:
|
||||
|
||||
+5
-5
@@ -46,9 +46,9 @@ lib_deps =
|
||||
${common.lib_deps_base}
|
||||
https://github.com/dudanov/MideaUART.git#eeea6c3e9b4474f067054592b435be1c4e466815 ; midea
|
||||
improv/Improv@1.2.7 ; improv_serial / improv_ble
|
||||
kikuchan98/pngle@1.1.0 ; online_image
|
||||
kikuchan98/pngle@1.1.0 ; runtime_image
|
||||
; Using the repository directly, otherwise ESP-IDF can't use the library
|
||||
https://github.com/bitbank2/JPEGDEC.git#1.8.4 ; online_image
|
||||
https://github.com/bitbank2/JPEGDEC.git#1.8.4 ; runtime_image
|
||||
; This dependency is used only in unit tests.
|
||||
; Must coincide with PLATFORMIO_GOOGLE_TEST_LIB in scripts/cpp_unit_test.py
|
||||
; See scripts/cpp_unit_test.py and tests/components/README.md
|
||||
@@ -82,7 +82,7 @@ lib_deps =
|
||||
esphome/noise-c@0.1.31 ; noise (api, ota)
|
||||
SPI ; spi (Arduino built-in)
|
||||
Wire ; i2c (Arduino built-int)
|
||||
heman/AsyncMqttClient-esphome@1.0.0 ; mqtt
|
||||
heman/AsyncMqttClient-esphome@2.0.0 ; mqtt
|
||||
freekode/TM1651@1.0.1 ; tm1651
|
||||
tonia/HeatpumpIR@1.0.42 ; heatpumpir
|
||||
build_flags =
|
||||
@@ -252,8 +252,8 @@ lib_deps =
|
||||
DNSServer ; captive_portal
|
||||
heman/AsyncMqttClient-esphome@2.0.0 ; mqtt
|
||||
improv/Improv@1.2.7 ; improv_serial
|
||||
kikuchan98/pngle@1.1.0 ; online_image
|
||||
https://github.com/bitbank2/JPEGDEC.git#1.8.4 ; online_image
|
||||
kikuchan98/pngle@1.1.0 ; runtime_image
|
||||
https://github.com/bitbank2/JPEGDEC.git#1.8.4 ; runtime_image
|
||||
build_flags =
|
||||
${common:arduino.build_flags}
|
||||
-DUSE_LIBRETINY
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
logger:
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
|
||||
sensor:
|
||||
- platform: template
|
||||
id: temp_sensor
|
||||
lambda: return 21.0;
|
||||
|
||||
climate:
|
||||
- platform: thermostat
|
||||
id: heater
|
||||
name: Heater
|
||||
sensor: temp_sensor
|
||||
min_idle_time: 30s
|
||||
min_heating_off_time: 300s
|
||||
min_heating_run_time: 300s
|
||||
min_cooling_off_time: 300s
|
||||
heat_action:
|
||||
- logger.log: heat
|
||||
idle_action:
|
||||
- logger.log: idle
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
logger:
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
|
||||
sensor:
|
||||
- platform: template
|
||||
id: temp_sensor
|
||||
lambda: return 21.0;
|
||||
|
||||
climate:
|
||||
- platform: thermostat
|
||||
id: dehumidifier
|
||||
name: Dehumidifier
|
||||
sensor: temp_sensor
|
||||
min_idle_time: 0s
|
||||
min_cooling_off_time: 0s
|
||||
min_cooling_run_time: 0s
|
||||
min_fanning_off_time: 0s
|
||||
min_fanning_run_time: 0s
|
||||
idle_action:
|
||||
- logger.log: idle
|
||||
fan_only_action:
|
||||
- logger.log: fan only
|
||||
dry_action:
|
||||
- logger.log: dry
|
||||
@@ -0,0 +1,36 @@
|
||||
"""Tests for the thermostat config validation."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.config import read_config
|
||||
from esphome.core import CORE
|
||||
|
||||
|
||||
def test_dry_only_config_is_valid(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""A dehumidifier has dry mode but no cool_action; dry mode uses the cooling timers."""
|
||||
main_cpp = generate_main(component_config_path("dry_only.yaml"))
|
||||
|
||||
assert "dehumidifier->set_cooling_minimum_off_time_in_sec(0);" in main_cpp
|
||||
assert "dehumidifier->set_cooling_minimum_run_time_in_sec(0);" in main_cpp
|
||||
assert "dehumidifier->set_supports_dry(true);" in main_cpp
|
||||
assert "dehumidifier->set_supports_cool(" not in main_cpp
|
||||
|
||||
|
||||
def test_cooling_timer_needs_cool_or_dry_action(
|
||||
component_config_path: Callable[[str], Path],
|
||||
capsys: pytest.CaptureFixture[str],
|
||||
) -> None:
|
||||
"""A cooling timer with neither cool_action nor dry_action is still rejected."""
|
||||
CORE.config_path = component_config_path("cooling_timer_without_action.yaml")
|
||||
assert read_config({}) is None
|
||||
captured = capsys.readouterr()
|
||||
assert (
|
||||
"cool_action or dry_action must be defined to use min_cooling_off_time"
|
||||
in captured.out
|
||||
)
|
||||
@@ -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