Skip to content

Hitachi: Add RF07T4 remote to supported devices - #2286

Merged
NiKiZe merged 1 commit into
crankyoldgit:masterfrom
JayyyXp:hitachi-rf07t4
Aug 14, 2026
Merged

Hitachi: Add RF07T4 remote to supported devices#2286
NiKiZe merged 1 commit into
crankyoldgit:masterfrom
JayyyXp:hitachi-rf07t4

Conversation

@JayyyXp

@JayyyXp JayyyXp commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

The RF07T4 is another remote from the same family as the already-supported
RF11T1. It uses the existing HITACHI_AC344 protocol and byte layout unchanged,
so this is a supported-device note plus a unit test — no library code changes.

How it was verified

I decoded this remote from scratch (before reading this library's
implementation) using a HX1838 demodulator on a Raspberry Pi, capturing raw
timings through the Linux kernel gpio-ir driver with ir-ctl -r, then diffing
frames that differed by a single button press. The byte map I ended up with
turned out to match HITACHI_AC344 exactly:

Field Byte Matches
Button 11 0x13 Power/Mode, 0x42 Fan, 0x43/0x44 Temp down/up, 0x81 SwingV, 0x8C SwingH
Temp 13 °C × 4
Fan / Mode 25 fan in the high nibble, mode in the low nibble, same values
Power 27 0xF1 / 0xE1
Swing(H) 35 bits 0-2, Auto / RightMax … LeftMax

…right down to the same 0x92 0x6D preamble bytes as the existing AC344
reference state in TestDecodeIRHitachiAc344.ExampleMessages.

Testing

  • Tested under real conditions: yes. Frames built from this map have been
    driving the A/C — power, mode, temp, fan and both swing axes — reliably for
    several days.
  • New unit test TestDecodeHitachiAc344.RealExampleRF07T4 decodes a genuine
    off-air capture (Power on, Cool, 24C, Fan auto) and asserts both the raw
    state and toString().
  • Full make run suite passes, cpplint clean.

Both directions are verified:

  • Decode — the new unit test, against this library directly.
  • Send — I rendered the same 43-byte state using this library's nominal
    timings (3300/1700 header, 400us marks, 1250/500 spaces, 38kHz) rather than a
    replay of the remote's captured ones, and transmitted that at the A/C. The
    unit acted on it: it was off, and it switched on to Cool 24C, which is exactly
    what the frame encodes. So sendHitachiAc344()'s timings are accepted by real
    hardware, not just the byte layout.

Recording that transmission back on a separate IR receiver decoded to the
expected bytes, and incidentally let me measure the receiver bias described
below instead of inferring it: fed known 400us marks and 500us zero-spaces, the
demodulator reported medians of 306us and 588us — marks short, spaces long, the
same direction as the capture the test uses, which is why it needs the wider
tolerance.

About the tolerance bump in the new test

The test calls irrecv.setTolerance(40). The capture came through the kernel
gpio-ir driver rather than a typical Arduino-side TSOP capture, and that path
biases the mark/space boundary the opposite way: marks read ~50us short
(~350us) and zero spaces ~90us long (~590us), while the total bit periods still
line up with the library's constants. ir_Mirage_test.cpp and
ir_Samsung_test.cpp do the same for their own awkward data. Happy to drop the
raw-capture test and keep just the supported-device line if you'd rather not
carry data that needs a wider tolerance.

I left SupportedProtocols.md alone, since it looks like it gets regenerated at
release time rather than per-PR.

Two side observations

Neither affects this change, but noting them in case they're useful to someone
later:

  • This remote sends button code 0x41 for its dedicated "operation switch"
    (mode) key, which isn't among the current kHitachiAc424Button* constants.
  • Its Swing(V) key always transmits byte 37 bit 5 as 0 — the A/C toggles its
    own vertical swing state on receipt, rather than the remote carrying the
    state. I haven't tested whether the unit honours that bit when it is set
    explicitly.

@JayyyXp

JayyyXp commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Heads up: the Unit_Tests failure here is unrelated to this PR.

It's TestIRac.LG2_AKB73757604 (IRac_test.cpp:1490, expecting rawlen 361 but
getting 301) — an LG test, in a different test binary from anything this PR
touches. The only file this PR changes outside test/ir_Hitachi_test.cpp is a
one-line comment in src/ir_Hitachi.h.

I chased it down rather than just asserting it was someone else's problem, and
it turns out to be a genuine latent bug: IRLgAc::updateSwingPrev() never copies
_swingh to _swingh_prev, so that value is both uninitialised and never
updated. UBSAN on clean master:

../src/ir_LG.cpp:280:24: runtime error: load of value 74, which is not a valid
value for type 'bool'

The sixth message that test expects is the Swing(H) message gated on that
uninitialised bool, so the test passes or fails on stack garbage. It was green on
the same runner image on 2026-08-02 and happened to land the other way here.

Fix plus a deterministic regression test: #2287. Once that's in, a re-run here
should go green. Happy to rebase this on top of it if that's easier for you.

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.
@JayyyXp

JayyyXp commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Following up on the one thing I'd left open — I've now tested the send
direction against the actual A/C, and it works.

Method: took the same 43-byte state from the test, re-rendered it with this
library's nominal timings rather than a replay of the remote's captured ones
(3300/1700 header, 400us bit marks, 1250/500 spaces, 38kHz carrier), and
transmitted it from a Raspberry Pi through a gpio-ir-tx emitter. The A/C was
off; it switched on to Cool 24C, which is precisely what that frame encodes.

So sendHitachiAc344() should drive an RF07T4-controlled unit as-is — it's not
only the byte layout that lines up.

I also recorded the transmission on a separate IR receiver as a sanity check.
It decoded to the expected bytes (01 10 00 40 BF FF 00 CC 33 92 6D 13 EC 60 9F …), and usefully, it let me measure the receiver bias rather than infer it:
given known 400us marks and 500us zero-spaces, the demodulator reported medians
of 306us and 588us. Marks short, spaces long — the same direction as the capture
the new test uses, which is what the setTolerance(40) is there for.

PR description updated accordingly. No code changes.

@NiKiZe

NiKiZe commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

To verify my brain, there is no identifier or special feature on this remote?

@NiKiZe
NiKiZe merged commit f508756 into crankyoldgit:master Aug 14, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants