Releases: DAB-LABS/HAIR
HAIR v0.4.0
HAIR v0.4.0
Added
- Pick a known device when creating a remote. The Create Remote dialog on the Clipper tab gains a Type dropdown: leave it on Blank remote for the usual remote you fill by pasting, or choose a manufacturer and model under "From code library" to materialize a remote pre-filled with one signal per button, each named for its function. The list is whatever device codes your installed Home Assistant infrared library carries. It is a shortcut for the supported devices, not a universal lookup.
- Protocol-decoded matching for NEC-family remotes. When HAIR can read a captured signal as NEC, it records the decoded identity alongside the raw timings. Pressing an already-assigned button is now recognized reliably even when the receiver path jitters the timings, so it no longer leaks back into the Sniffer as an unknown signal.
- Encode-from-decoded transmit. For commands HAIR decoded as NEC, Test and automations send clean, library-encoded timings instead of replaying the captured ones. A per-command AUTO / RAW toggle lets you fall back to the captured timings for the rare device that wants them.
Changed
- Transmit uses canonical NEC timings by default for decodable commands, with the per-command opt-out above. Commands HAIR cannot decode transmit exactly as before.
- The Sniffer empty state now tells "no IR receiver is set up" apart from "no signals yet".
- The Assign and Trigger dialogs show a signal's name when you have given it one, instead of the raw diamond pattern.
- Diagnostics now report the installed infrared library version and a count of decoded commands by protocol.
- The Clipper now has a persistent "Delete remote" button on every remote, so a remote can be removed in one step instead of deleting each signal first. The confirmation names the remote and how many signals it holds.
Fixed
- Replaying a captured NEC signal failed against some destinations that expect clean timings (for example a NAD C320BEE bridged setup), because the captured Pronto carried receiver-side timing distortion. Transmitting the re-encoded canonical timings fixes it. Reported by @frafall (GH #14).
- The code-library picker and diagnostics no longer do file-system work on the event loop, clearing the blocking-call warnings Home Assistant logged.
- Panel components now register defensively, so a re-evaluated frontend bundle no longer throws a "name has already been used" error in the browser console.
Removed
- The Broadlink capture provider. Its learn-mode output was never a sendable IR code, so capturing through it could not work. Broadlink transmit is unaffected.
v0.3.4
Bug-fix release.
Fixed
- Distinct IR codes that share an S/L fingerprint are now kept as separate signals. Some protocols (the Panasonic and Kaseikyo family, the TCL family, and a handful of similar consumer remotes) have a "long" pulse that sits just below HAIR's S/L threshold, so genuinely different buttons produced the same S/L pattern. The Clipper's duplicate guard then refused the second paste as "already on this remote", and on the Sniffer the two signals collapsed into one. HAIR now adds a byte-level tiebreaker so signals that share a pattern but carry different timing are stored, named, tested, reordered, and assigned independently. Only an identical code is still treated as a duplicate. Reported by @SNMetamorph (GH #13 follow-up) and @akikun21 (GH #16).
- Empty Actions popover on Other-type device cards. The Actions button now hides on devices whose platform (remote) does not expose mappable feature actions.
Full changelog: https://github.com/DAB-LABS/HAIR/blob/main/CHANGELOG.md
0.3.3 - Race condition Hot Fix
Fixed
Updating a device while its entity was still being registered with Home Assistant could raise "Attribute hass is None for " and roll back the change. The race fired most often when promoting a remote with several commands (each command-add fires a device update before the entity registration coroutine has finished). Affects every HAIR entity platform (media_player, climate, fan, light, switch, cover, remote, button). Each entity's update path now defers state writes until registration completes; the initial state captured at construction time is correct and is written when HA finishes adding the entity.
v0.3.2
See CHANGELOG.md for full detail. Highlights: drag-to-reorder for device cards, Sniffer and Clipper remotes, and the signals within a remote; a duplicate-signal guard with automatic cleanup on the Clipper; and the Add Remote / Add Signal button rename for consistency with the Devices tab.
HAIR v0.3.1 - Copy Pronto + Create button
HAIR v0.3.1 is a small follow-up to v0.3.0.
Added
- A copy control on every signal row, in both the Sniffer and the Clipper. Click it to open a small popover showing the signal's raw Pronto code in a selectable box, with a Copy button. Copy works over plain http through a clipboard fallback, and the code is always selectable so you can copy it by hand if needed.
Changed
- The Clipper's "Create" button moved to the top-right of the tab bar, matching the Devices tab's "Add Device" button (kept in the Clipper's copper accent). Show Dismissed stays in the Clipper header.
Full detail in CHANGELOG.md.
HAIR v0.3.0 - Clipper + Alias + Polish
HAIR v0.3.0 introduces the Clipper tab and signal aliases.
Added
- HAIR Clipper tab: build virtual remotes by pasting Pronto hex codes, for when you have a code from a converter, a datasheet, or an ESPHome log but no live signal to sniff. Each code is validated live (carrier frequency, burst pair count, an S/L diamond preview, and specific error messages), and a pasted signal behaves exactly like a sniffed one: Test, Trigger, Assign, or Promote.
- Signal aliases: name any signal by clicking its S/L diamond pattern, in both the Sniffer and Clipper. An alias is a label on the signal, not a command name, so the same signal can still become differently-named commands on different devices.
- "+ Sniffed Signal" and "+ Clipped Signal" add-command buttons on each HAIR device card, jumping to the Sniffer or Clipper to capture or paste a command.
- The Sniffer signal rows now show each signal's captured carrier frequency.
- An empty clipped remote can be deleted directly from the Clipper tab.
Changed
- Assigning a signal now keeps it. The signal is copied into the device and left in place, so one signal can be assigned to several devices or as several commands. Only Delete, Dismiss, and Clear All remove a signal.
- Clipped remotes are never auto-evicted; anything you build in the Clipper stays until you delete it.
- The HAIR Device badge now matches the Promote badge in size and uses uppercase, and Promote uses a more vivid teal so it reads distinctly from the green.
- Each tab's cards carry their own accent: Sniffer remotes lead with the blue radio icon and a blue card stroke, Clipper remotes with the copper paperclip and a muted copper stroke. Card titles are a single line, and the remote name edits inline on hover.
Fixed
- The row hover highlight no longer escapes a card's rounded corners.
Full detail in CHANGELOG.md.
HAIR 0.2.1 -- Sniffer dismiss fix
Fixes a bug where the Sniffer would silently drop signals from remotes after a specific dismiss + assign / delete sequence.
Affected users auto-recover on the next HA restart after upgrading thanks to a self-heal pass at load time -- no manual file editing required.
See the CHANGELOG for the full list of changes.
Reported by @KimmoJ (#9) and confirmed by @roblamoreaux.
HAIR 0.2.0 - Welcome RX + Polish
HAIR 0.2.0 ships alongside HA 2026.6 with end-to-end IR through HA's native infrared platform, plus a stack of UX wins from the launch-thread feedback.
What's new
- Native receiver support (HA 2026.6+). HAIR subscribes to
InfraredReceiverEntityinstances viainfrared.async_subscribe_receiver(). Hardware-agnostic. Legacy ESPHome event-bus bridge still works automatically on HA 2026.4-2026.5. - IR triggers. Captured signals become native HA
evententities firinghair_ir_command_received. Any automation can listen. As far as we know, HAIR is the only HA integration turning received IR into automation triggers as of HA 2026.6. - NATIVE / BRIDGE badges on receiver and proxy cards so the receive-path migration state is visible at a glance.
- Device duplicate clones a device with all its commands, action mappings, and emitter assignments in one click.
- Card-level corner actions: duplicate top-right, delete bottom-right, no need to open the detail view.
- Sniffer Test emitter picker replaces the silent "first emitter on first device" fallback. Pick which emitter(s) to send through, broadcast to all at once. The picker remembers your selection for the session.
- Show Dismissed activity glow quietly pulses blue when previously hidden remotes are still firing, plus a persistent dot indicator until you click through. Tooltip reworded to "Restore previously hidden remotes".
- Mobile nav button at the top of the panel on viewports under 768 px so phone users can return to the HA sidebar without the edge-swipe gesture.
- Drag-to-reorder commands inside a device.
- Curated ESPHome configs in a new
esphome/folder: XIAO Smart IR Mate (community contribution credited to Didgeridrew), Athom RF IR Remote, generic ESP32s. Two tiers per device: minimal and full. - Trigger card trash icon styled to match the device card trash icon.
- Trigger panel auto-refreshes when triggers are created or deleted from a command row.
- Command and Sniffer signal rows now blend with the page background instead of standing out as highlighted strips.
Migration: ESPHome YAML for native RX
If you're on HA 2026.6+ and want the native receiver path, add the infrared platform entry to your ESPHome YAML for both TX and RX. The new esphome/ folder has canonical examples for the Athom RF IR Remote, XIAO Smart IR Mate, and generic ESP32 boards.
If you keep the legacy on_pronto: bridge in place, nothing changes for you. The panel will show a RX-BRIDGE badge instead of RX-NATIVE so you can see the difference at a glance.
Fixes
- Blocking-call warning during integration startup is fixed. HA's loop detector now stays quiet.
- Various small UI polish: optimistic emitter-change rendering, reorder revert handling, receiver entity filtering out of emitter pickers.
Upgrading
HACS will offer the update once this release publishes. If you installed HAIR manually, pull main and reload the integration.
A grace request
The native RX API is brand new in HA itself. HAIR's adapter is brand new on our side. It is new all the way around. If you hit issues, please open a GitHub issue and include your infrared platform integration (ESPHome, Tuya Local, Broadlink, SMLIGHT), your HA version, and any relevant log lines. Patience appreciated while we shake out edge cases on both sides.
Full changelog: CHANGELOG.md
Forum announcement: link will land in the v0.1 launch thread as a follow-up.
Walk-ins welcome.
v0.1.2
Fixed - 2026-05-17
- Add "Add Device" button to the tab bar, visible in all states including the zero-device onboarding flow. Previously there was no way to add a device when hardware was detected but no HAIR devices existed yet.
- Fix missing Name field in the Add Device dialog on HA 2026.5+ (
ha-textfieldcomponent no longer renders). Replaced with a native input element. - Always show the HAIR Devices section header even when no devices exist, with an empty-state hint message.
- Remove redundant floating action button from bottom-right corner.
v0.1.1
Fixed - 2026-05-16
- Fix TX failure on HA 2026.5+ ("Timing object cannot be interpreted as an integer"). The upstream
infrared-protocolslibrary removed theTimingdataclass in v2.0.0, changingget_raw_timings()fromlist[Timing]tolist[int]with signed microseconds. HAIR'sProntoCommandandRawTimingsCommandadapters now return flat signed integers, compatible with both HA 2026.4 and 2026.5+. - Add error logging to the send command WebSocket handler. Previously, TX errors were returned to the frontend but not logged in HA logs, making diagnosis difficult.