mirror of
https://github.com/esphome/esphome.git
synced 2026-09-28 23:40:25 +00:00
[remote_base] Add AEG Hob2Hood Infrared Protocol (#4687)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
co-authored by
pre-commit-ci-lite[bot]
J. Nick Koston
parent
bfe1f7bd17
commit
cfb7d8089e
@@ -0,0 +1,14 @@
|
||||
from esphome.types import ConfigType
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
|
||||
def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
from esphome.components.remote_base import request_protocol
|
||||
|
||||
async def to_code_testing(config: ConfigType) -> None:
|
||||
# Protocol sources are compiled only behind their define; keep the ones under test.
|
||||
request_protocol("hob2hood")
|
||||
|
||||
manifest.to_code = to_code_testing
|
||||
# AUTO_LOAD is not resolved by the unit test build.
|
||||
manifest.dependencies = manifest.dependencies + ["binary_sensor"]
|
||||
@@ -0,0 +1,83 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "esphome/components/remote_base/hob2hood_protocol.h"
|
||||
|
||||
namespace esphome::remote_base::testing {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::array<Hob2HoodCommand, 7> ALL_COMMANDS = {
|
||||
HOB2HOOD_COMMAND_LIGHT_OFF, HOB2HOOD_COMMAND_LIGHT_ON, HOB2HOOD_COMMAND_FAN_OFF, HOB2HOOD_COMMAND_FAN_LOW,
|
||||
HOB2HOOD_COMMAND_FAN_MEDIUM, HOB2HOOD_COMMAND_FAN_HIGH, HOB2HOOD_COMMAND_FAN_MAX,
|
||||
};
|
||||
|
||||
RawTimings encode(Hob2HoodCommand command) {
|
||||
RemoteTransmitData data;
|
||||
Hob2HoodProtocol().encode(&data, Hob2HoodData{command});
|
||||
return data.get_data();
|
||||
}
|
||||
|
||||
optional<Hob2HoodData> decode(const RawTimings &timings, uint32_t tolerance = 25,
|
||||
ToleranceMode mode = TOLERANCE_MODE_PERCENTAGE) {
|
||||
return Hob2HoodProtocol().decode(RemoteReceiveData(timings, tolerance, mode));
|
||||
}
|
||||
|
||||
void expect_decodes_to(const RawTimings &timings, Hob2HoodCommand command, uint32_t tolerance = 25,
|
||||
ToleranceMode mode = TOLERANCE_MODE_PERCENTAGE) {
|
||||
auto decoded = decode(timings, tolerance, mode);
|
||||
ASSERT_TRUE(decoded.has_value()) << "command 0x" << std::hex << int(command);
|
||||
// clang-tidy's unchecked-optional-access models neither gtest's ASSERT_TRUE nor value() as a check
|
||||
if (decoded.has_value()) {
|
||||
EXPECT_EQ(decoded->command, command);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// light_on is 0xd2: the bits 0 11010010 11010011 11010100 form 17 runs. A run of n zero bits is a mark of
|
||||
// n * 700 + 300 us; a run of n one bits is a space of n * 700 - 200 us.
|
||||
TEST(Hob2HoodProtocolTest, EncodesTheDocumentedTimings) {
|
||||
const RawTimings expected = {1000, -1200, 1000, -500, 1700, -500, 1000, -1200, 1000,
|
||||
-500, 1700, -2600, 1000, -500, 1000, -500, 1700};
|
||||
EXPECT_EQ(encode(HOB2HOOD_COMMAND_LIGHT_ON), expected);
|
||||
}
|
||||
|
||||
TEST(Hob2HoodProtocolTest, LongestFrameFitsTheReservedLength) {
|
||||
for (auto command : ALL_COMMANDS) {
|
||||
EXPECT_LE(encode(command).size(), 18u) << "command 0x" << std::hex << int(command);
|
||||
}
|
||||
EXPECT_EQ(encode(HOB2HOOD_COMMAND_LIGHT_OFF).size(), 18u);
|
||||
}
|
||||
|
||||
TEST(Hob2HoodProtocolTest, RoundTripsEveryCommand) {
|
||||
for (auto command : ALL_COMMANDS) {
|
||||
expect_decodes_to(encode(command), command);
|
||||
}
|
||||
}
|
||||
|
||||
// A receiver never captures the trailing space, so a frame that ends in one must still decode without it.
|
||||
TEST(Hob2HoodProtocolTest, DecodesWithoutTheTrailingSpace) {
|
||||
for (auto command : ALL_COMMANDS) {
|
||||
auto timings = encode(command);
|
||||
if (timings.back() < 0)
|
||||
timings.pop_back();
|
||||
expect_decodes_to(timings, command);
|
||||
}
|
||||
}
|
||||
|
||||
// Real receivers shorten marks and lengthen spaces by a couple of hundred microseconds, which is why the
|
||||
// documentation recommends a 350us tolerance.
|
||||
TEST(Hob2HoodProtocolTest, DecodesSkewedTimingsWithinTheRecommendedTolerance) {
|
||||
auto timings = encode(HOB2HOOD_COMMAND_FAN_HIGH);
|
||||
for (auto &t : timings) {
|
||||
t += t > 0 ? -240 : -230;
|
||||
}
|
||||
expect_decodes_to(timings, HOB2HOOD_COMMAND_FAN_HIGH, 350, TOLERANCE_MODE_TIME);
|
||||
}
|
||||
|
||||
TEST(Hob2HoodProtocolTest, RejectsAForeignFrame) {
|
||||
const RawTimings nec_like = {9000, -4500, 560, -560, 560, -1690, 560, -560, 560};
|
||||
EXPECT_FALSE(decode(nec_like).has_value());
|
||||
EXPECT_FALSE(decode({}).has_value());
|
||||
}
|
||||
|
||||
} // namespace esphome::remote_base::testing
|
||||
@@ -172,3 +172,8 @@ on_toto:
|
||||
- logger.log:
|
||||
format: "on_toto: %u %u %u"
|
||||
args: ["x.rc_code_1", "x.rc_code_2", "x.command"]
|
||||
on_hob2hood:
|
||||
then:
|
||||
- logger.log:
|
||||
format: "on_hob2hood: %u"
|
||||
args: ["x.command"]
|
||||
|
||||
@@ -15,3 +15,7 @@ binary_sensor:
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100BCBD
|
||||
- platform: remote_receiver
|
||||
name: Hob2Hood Light On
|
||||
hob2hood:
|
||||
command: light_on
|
||||
|
||||
@@ -278,3 +278,8 @@ button:
|
||||
- remote_transmitter.digital_write:
|
||||
transmitter_id: xmitr
|
||||
value: !lambda return id(remote_transmitter_test_number).state > 127;
|
||||
- platform: template
|
||||
name: Hob2Hood
|
||||
on_press:
|
||||
- remote_transmitter.transmit_hob2hood:
|
||||
command: light_on
|
||||
|
||||
Reference in New Issue
Block a user