From 5fdda2f710ce7c5be07b42c8b023b625c8536316 Mon Sep 17 00:00:00 2001 From: Henrik Hoppania <49588855+JayyyXp@users.noreply.github.com> Date: Fri, 14 Aug 2026 14:52:41 +0800 Subject: [PATCH] Hitachi: Add RF07T4 remote to supported devices The RF07T4 remote uses the existing HITACHI_AC344 protocol and byte layout, so no code changes are needed. This just documents it as a known-working model, plus adds a unit test built from a real capture. Tested under real conditions: the remote was decoded from scratch against a Hitachi A/C, and the resulting byte map matched this library's HITACHI_AC344 layout exactly (button byte 11, temp byte 13, fan/mode byte 25, power byte 27, SwingH byte 35, including the same 0x92 0x6D preamble as the existing AC344 reference state). Frames built from that map have been driving the A/C reliably for several days -- power, mode, temp, fan and both swing axes. To be precise about what that does and doesn't prove: the decode side is verified against this library directly, by the new test. The send side was verified only in the sense that the byte layout is right -- those frames were transmitted from a Raspberry Pi via ir-ctl, reusing the remote's own captured pulse timings, not this library's nominal ones. So I can say the state encoding is correct, but I have not yet put sendHitachiAc344()'s timings (3300/1700 header, 400us marks, 1250/500 spaces) in front of the unit. Happy to test that and report back if it matters for acceptance. The new test decodes a genuine off-air capture: Power on, Cool, 24C, Fan auto. It needs setTolerance(40), because the capture came off a HX1838 demodulator through the Linux kernel's gpio-ir driver, which biases the mark/space boundary the opposite way to a typical TSOP capture -- marks read ~50us short and zero spaces ~90us long, while the bit periods themselves still line up. Same trick as the Mirage and Samsung tests. Two observations that don't affect this change, noted in case they're useful to someone later: this remote emits button code 0x41 for its dedicated "operation switch" (mode) key, which isn't among the kHitachiAc424Button* constants; and its Swing(V) key always transmits byte 37 bit 5 as 0, with the A/C toggling its own swing state on receipt, rather than the remote carrying the state. --- src/ir_Hitachi.h | 1 + test/ir_Hitachi_test.cpp | 84 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/src/ir_Hitachi.h b/src/ir_Hitachi.h index 413ab75e8..ca5d8fea1 100644 --- a/src/ir_Hitachi.h +++ b/src/ir_Hitachi.h @@ -21,6 +21,7 @@ // Brand: Hitachi, Model: R-LT0541-HTA/Y.K.1.1-1 V2.3 remote (HITACHI_AC1) // Brand: Hitachi, Model: RAS-22NK A/C (HITACHI_AC344) // Brand: Hitachi, Model: RF11T1 remote (HITACHI_AC344) +// Brand: Hitachi, Model: RF07T4 remote (HITACHI_AC344) // Brand: Hitachi, Model: RAR-2P2 remote (HITACHI_AC264) // Brand: Hitachi, Model: RAK-25NH5 A/C (HITACHI_AC264) // Brand: Hitachi, Model: RAR-3U3 remote (HITACHI_AC296) diff --git a/test/ir_Hitachi_test.cpp b/test/ir_Hitachi_test.cpp index 51664688a..18411cf4e 100644 --- a/test/ir_Hitachi_test.cpp +++ b/test/ir_Hitachi_test.cpp @@ -1919,6 +1919,90 @@ TEST(TestDecodeHitachiAc344, RealExample) { EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits); } +// Decode a 'real' HitachiAc344 message from a Hitachi RF07T4 remote. +TEST(TestDecodeHitachiAc344, RealExampleRF07T4) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + irrecv.setTolerance(40); // Bump tolerance to match the receiver's bias. + + // On, Cool, 24C, Fan Auto + uint8_t expected[kHitachiAc344StateLength] = { + 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xCC, 0x33, 0x92, 0x6D, 0x13, + 0xEC, 0x60, 0x9F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x53, 0xAC, 0xF1, 0x0E, 0x02, 0xFD, 0x12, 0xED, 0x80, 0x7F, 0x01, + 0xFE, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF}; + + // Ref: https://github.com/crankyoldgit/IRremoteESP8266/pull/2286 + const uint16_t rawData[691] = { + 3211, 1789, 325, 1302, 382, 564, 353, 565, 352, 591, 326, 565, 351, 590, + 326, 565, 352, 593, 349, 565, 351, 565, 352, 565, 351, 592, 325, 1335, + 350, 566, 350, 591, 325, 589, 353, 563, 353, 591, 326, 591, 326, 566, + 351, 564, 353, 565, 352, 590, 326, 616, 325, 563, 353, 565, 351, 590, + 326, 566, 350, 590, 325, 591, 326, 1359, 326, 616, 324, 1359, 326, 1360, + 326, 1334, 349, 1359, 326, 1359, 325, 1361, 324, 592, 325, 1384, 325, + 1290, 394, 1360, 324, 1359, 326, 1360, 325, 1358, 326, 1359, 325, 1332, + 352, 1384, 325, 592, 325, 568, 349, 591, 325, 565, 352, 590, 325, 592, + 325, 591, 325, 616, 326, 591, 326, 591, 325, 1359, 325, 1359, 325, 565, + 352, 590, 326, 1358, 326, 1385, 325, 1359, 325, 1359, 326, 564, 352, + 590, 325, 1360, 324, 1360, 325, 591, 325, 616, 326, 590, 326, 1360, 325, + 591, 325, 590, 326, 1359, 325, 591, 325, 564, 352, 1360, 350, 1359, 325, + 592, 325, 1359, 325, 1360, 325, 590, 326, 1359, 325, 1359, 325, 615, + 326, 1359, 325, 1333, 352, 563, 353, 591, 325, 1359, 326, 591, 326, 590, + 325, 589, 352, 564, 352, 590, 326, 1360, 324, 1359, 325, 590, 326, 1358, + 325, 1360, 325, 1384, 325, 590, 326, 566, 351, 591, 325, 591, 325, 563, + 354, 1333, 352, 1359, 324, 616, 326, 1331, 354, 1359, 325, 1359, 326, + 1359, 326, 1334, 350, 590, 326, 591, 325, 1384, 325, 566, 351, 591, 326, + 591, 325, 564, 354, 590, 325, 565, 352, 592, 324, 591, 350, 1360, 325, + 1360, 324, 1359, 325, 1330, 355, 1359, 325, 1360, 325, 1360, 324, 1384, + 325, 590, 327, 591, 325, 566, 351, 565, 352, 591, 326, 564, 352, 592, + 325, 616, 325, 1360, 324, 1361, 323, 1360, 325, 1359, 325, 1359, 326, + 1358, 326, 1359, 325, 1384, 325, 566, 350, 591, 325, 590, 326, 592, 325, + 591, 327, 590, 325, 566, 351, 616, 325, 1335, 350, 1359, 325, 1360, 325, + 1359, 326, 1359, 325, 1361, 324, 1359, 325, 1359, 351, 591, 325, 590, + 326, 592, 325, 591, 325, 591, 325, 591, 325, 591, 326, 616, 325, 1359, + 325, 1360, 324, 1359, 326, 1360, 325, 1360, 324, 1359, 325, 1360, 325, + 1385, 324, 591, 325, 592, 325, 591, 325, 591, 325, 591, 325, 591, 326, + 591, 326, 616, 325, 1360, 325, 1336, 349, 1358, 325, 1359, 325, 1360, + 325, 1359, 325, 1359, 325, 1384, 326, 1359, 325, 1360, 350, 566, 377, + 540, 325, 1360, 376, 540, 325, 1358, 377, 541, 401, 540, 325, 565, 402, + 1308, 350, 1334, 377, 539, 376, 1310, 349, 565, 351, 1360, 350, 1335, + 350, 566, 351, 566, 350, 566, 350, 1335, 376, 1309, 350, 1335, 350, + 1359, 351, 566, 350, 1335, 350, 1334, 351, 1340, 370, 540, 377, 540, + 376, 540, 350, 592, 351, 565, 351, 1333, 351, 566, 350, 566, 351, 565, + 350, 567, 349, 566, 351, 590, 352, 1333, 351, 566, 350, 1334, 350, 1334, + 351, 1334, 350, 1335, 350, 1333, 352, 1359, 349, 566, 350, 1333, 351, + 565, 351, 566, 351, 1334, 350, 565, 351, 566, 351, 590, 352, 1335, 349, + 566, 350, 1333, 351, 1334, 351, 566, 351, 1333, 352, 1333, 351, 1358, + 351, 566, 350, 567, 351, 565, 351, 566, 351, 565, 351, 565, 352, 565, + 351, 1332, 378, 1333, 351, 1334, 351, 1335, 349, 1334, 350, 1333, 351, + 1333, 352, 1333, 351, 590, 352, 1334, 350, 566, 351, 565, 351, 566, 351, + 565, 352, 565, 351, 541, 376, 591, 350, 565, 352, 1333, 351, 1334, 351, + 1334, 351, 1333, 351, 1334, 351, 1333, 351, 1361, 351, 566, 351, 565, + 351, 565, 351, 565, 351, 565, 351, 564, 352, 565, 351, 594, 351, 1334, + 351, 1334, 351, 1333, 351, 1334, 350, 1309, 376, 1334, 350, 1307, 377, + 1361, 351, 540, 377, 565, 352, 538, 378, 540, 377, 564, 352, 564, 352, + 540, 377, 593, 351, 1333, 351, 1333, 351, 1334, 351, 1333, 352, 1333, + 352, 1332, 351, 1333, 351, 1362, 351, 538, 378, 539, 378, 539, 378, 565, + 350, 539, 378, 540, 377, 565, 351, 593, 351, 1333, 351, 1308, 377, 1333, + 351, 1334, 351, 1307, 378, 1309, 375, 1309, 376, 1345, 377}; + + irsend.reset(); + irsend.sendRaw(rawData, 691, kHitachiAcFreq); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(HITACHI_AC344, irsend.capture.decode_type); + ASSERT_EQ(kHitachiAc344Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits); + + IRHitachiAc344 ac(kGpioUnused); + ac.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: On, Mode: 3 (Cool), Temp: 24C, Fan: 5 (Auto), " + "Button: 19 (Power/Mode), Swing(V): Off, Swing(H): 1 (Right Max)", + ac.toString()); +} + // Decode a synthetic HitachiAc344 message. TEST(TestDecodeHitachiAc344, SyntheticExample) { IRsendTest irsend(kGpioUnused);