Repository navigation
Built-in A/C library: 66 protocols generated on demand, including a reverse-engineered Dawlance - #7
Merged
Merged
Conversation
Teaching an air conditioner by hand means capturing every temperature separately, because these remotes do not send "temperature up" -- every button transmits the unit's entire state. Thirteen captures for one mode, and you still cannot use a combination you never pressed. IRremoteESP8266 already knows the frame layout and checksum of ~65 of these protocols through IRac. This exposes that: pick a brand, set mode, temperature and fan, and the device encodes the frame itself. A "save a temperature range" action creates the whole set in one action, which is the part that replaces an afternoon at the receiver. Storage A generated command holds the standard stdAc::state_t struct rather than timings -- ~40 bytes against ~1.2 KB -- and is replayed by handing the struct back to the library. So the checksum stays the library's rather than our reconstruction of one, and a library upgrade improves existing commands for free. This needs no change to the store: the struct rides in the existing payload, one byte per entry, flagged IR_FLAG_AC_STATE. Its size is recorded so a future layout change is reported rather than transmitted as nonsense. Backup carries the flag, or a restore would replay a state struct as if it were timings. Pulling the encoded bytes out instead would have meant a switch with a case per protocol; one struct covers all sixty-five. Everything else about them is ordinary: they appear under Remotes, work with schedules and MQTT, and survive backup and restore. Protocols the library does not know -- the Dawlance unit this was developed against among them -- are unaffected and still captured as raw timings. Costs 5.5 % of flash (68.2 -> 73.7 %), leaving 26 % headroom. Verified on hardware: 65 protocols listed, preview/send/save all work, a generated Gree command stores as 56 bytes and sends through the normal command path, out-of-range temperatures and unknown protocol names are rejected with useful messages. Verified in a browser: live preview follows every control, and the range action created four commands into the Air Conditioner group in one click. Co-Authored-By: Claude Opus 5 <[email protected]>
The library listed 65 protocols and Dawlance was not among them, because
IRremoteESP8266 does not know it -- its 72-bit frame over a 6.7/3.3 ms
header matches nothing there. Adding it as a preset pack of captured codes
worked, but only for the buttons that had been captured; the whole point of
the library is that a brand covers combinations nobody pressed.
So it is now encoded natively, from the 18 captures taken off the unit:
AA 11 <mode|power|turbo> <temp-16> 00 <flags> 00 00 <checksum>
byte 0,1 constant AA 11
byte 2 bits 0-2 mode, bit 3 power, bit 7 turbo
byte 3 temperature - 16
byte 5 bit 7 display light, bit 0 economy
byte 8 sum(bytes 0..7) XOR 0xAA
Earlier in this work I declined to ship a Dawlance generator because the
checksum was only half derived, and a wrong checksum produces commands that
fail silently. That objection is now settled: the XOR form was worked out
and checks against 18 of 18 captures, and the full encoder reproduces every
one of them byte for byte, on the device, over the API.
One field remains a guess and is marked as such in the source: every
capture was taken in cool, so only mode = 1 is confirmed. Heat, dry, fan and
auto follow the ordering these controllers usually use. If they do not work
on a given unit, capturing that button still gives a correct raw command.
Also fixes a default that leaked: the display bit is set in every Dawlance
capture, so light defaults on for that protocol -- but the first version
applied that to all 66, which would have switched displays on unasked. It
is now scoped to Dawlance alone.
Verified on hardware after OTA: DAWLANCE appears in the picker (66
protocols), and generated frames match the captures for all thirteen
temperatures plus power on, power off, eco, lamp off and turbo.
Co-Authored-By: Claude Opus 5 <[email protected]>
The first version was written before the built-in library existed and
describes a device with six commands and no code generation. Rewritten from
section 3 onward; the hardware and network sections are unchanged because
the hardware is.
What is new in it:
- a branch table, because there are now three and two are unmerged. This
file moves to feat/ac-library, which supersedes docs/handoff, so that
branch should be deleted rather than merged.
- a section on the built-in library: what it solves, why generating beats
storing a code database, and how a generated command is stored as a
state struct rather than timings.
- the full Dawlance protocol -- byte layout, timings, the checksum, and
the verification table showing 18/18 on the checksum and byte-identical
output against every capture. Written down so it survives this
conversation.
- the one field that is a guess (mode, only cool was ever captured) called
out both here and at the top of the task list.
- the task list reordered by value rather than by area, since the next
session should start with the unverified modes and the range
measurement.
Also records two things that bit us and would bite again: schedules have no
backup path, and the shell has now eaten an escape three separate ways --
including a single-quoted perl string that collapsed a comment block onto
one line, swallowed the statement after it, and still compiled.
Identifying values stay redacted; the file says how to read the real ones
back off the device.
Co-Authored-By: Claude Opus 5 <[email protected]>
The PR template asks the author to confirm docs and a changelog entry, and neither mentioned any of the work after the first library commit. - CHANGELOG: the Dawlance protocol with its byte layout and checksum, plus the preset-pack mechanism. States plainly which part is verified against hardware and which single field is inferred. - API.md: notes that the protocol list is the library's 65 plus DAWLANCE and why that one is local, and documents preset packs as static files installed through /api/import. - USAGE.md: a Library section placed *before* Learning, because for an air conditioner it is what someone should try first -- capturing thirteen temperature buttons is the thing this replaces. Also fixes a stray line break that split the ir-backup.sh entry mid-sentence. Co-Authored-By: Claude Opus 5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Air conditioners are the reason this device is annoying to set up. An A/C remote
never sends "temperature up" -- every button transmits the unit's entire
state, so teaching one by hand means capturing every temperature separately,
and you still cannot use a combination you never pressed. Thirteen captures for
one mode.
This adds a built-in library that generates the frames instead.
66 A/C protocols. The 65 IRremoteESP8266 supports through
IRac(Gree,Coolix, Midea, Daikin, Electra, Fujitsu, Haier, Hitachi, LG, Samsung, TCL,
Toshiba, Argo, Airton…) plus DAWLANCE, implemented here. Pick a brand, set
mode / temperature / fan, and the device encodes the frame with the correct
checksum. A "save a whole temperature range" action creates one command per
degree in a single click.
Dawlance, reverse engineered. Not supported upstream -- its 72-bit frame
over a 6.7/3.3 ms header matches nothing in IRremoteESP8266, which is why those
captures decode as
UNKNOWN. Derived from 18 captures off a real unit:Preset packs in
data/presets/, for remotes that cannot be generated atall. The browser fetches a pack and posts each command to
/api/import-- thesame path a restore takes -- so adding a device to the library needs no
firmware change, only a new file and a line in
index.json.tools/make-preset.shbuilds one from any backup.Why
Generating beats shipping a code database, and not marginally. A database keyed
by combination needs thousands of entries per brand; the encoders already know
the frame layout and checksum, so one brand covers everything including
combinations nobody captured.
Storage follows the same reasoning. A generated command holds the standard
stdAc::state_tstruct rather than timings -- 56 bytes against ~1.2 KB --and is replayed by handing the struct back to the encoder, so the checksum stays
the library's rather than a reconstruction of it, and a library upgrade improves
existing commands for free. This needed no change to the store: the struct
rides in the existing payload, one byte per entry, flagged
IR_FLAG_AC_STATE.Pulling the encoded bytes out instead would have meant a switch with a case per
protocol; one struct covers all sixty-six.
Cost: 5.6 % of flash (68.2 → 73.8 % on
esp32dev), leaving 26 % headroom.How it was tested
esp32dev73.8 %,esp32dev_oled75.8 %,esp32s335.0 %,esp32c375.6 %tx: 'Gree Cool 24' (generated GREE))API.md(endpoints, DAWLANCE, preset packs),USAGE.md(Library tab, placed before Learning)CHANGELOG.mdupdated under UnreleasedNotes for the reviewer
One field is a guess, and is labelled as one. Every Dawlance capture was
taken in cool, so only
mode = 1is measured. Heat, dry, fan and auto followthe ordering these controllers usually use.
src/ir_library.cppmarks itINFERRED, and NOT verifiedat the point of use, and the docs repeat it. If amode turns out wrong, capturing that button still yields a correct raw command.
I refused to ship this generator earlier in the work because the checksum
was only half derived, and a wrong checksum produces commands that fail
silently. That objection is settled — the XOR form checks against 18 of 18
captures and the encoder reproduces every one byte for byte, on the device, over
the API. Everything except the mode field is measured rather than assumed.
The
lightdefault is deliberately protocol-specific. Every Dawlancecapture carries the display bit set, so it has to default on for that protocol
or generated frames would differ from the remote. The first version applied that
to all 66, which would have switched other people's displays on unasked; it is
now scoped to Dawlance alone.
HANDOFF.mdmoves onto this branch and supersedes the copy ondocs/handoff. That branch should be deleted rather than merged.🤖 Generated with Claude Code