Releases: markusg1234/ESPHome-espidf_ble_keyboard
Release list
v1.8.0 ESPHome BLE Keyboard
Added
-
A paired host's identity key can now be read from Host Actions. Phones broadcast a random
address that changes every few minutes, and this key is the only thing that can tie one of those
back to a known host — what presence detection needs. Take it to Home Assistant or a second ESP32,
which has to do the detecting, since that job and this component both want to own the Bluetooth
controller. Shown only when asked for, kept out of backups, and refused to other websites. -
The web remote can be popped out into a window of its own, so it stays in reach while you
scroll the page or work in another app, and pinned back where it was afterwards. The window holds
the remote and nothing else, sized to it and resized whenever a host switch brings a style of a
different shape. On a Chromium browser reaching the device over https it can be kept above your
other windows; elsewhere it opens as an ordinary one.
The same view can be opened directly at/ble_keyboard#remoteand bookmarked as a remote-only page. -
A remote style that draws its own body loses the card from behind it once popped out, so what
floats in the window is the shape, shadow and taper it defines rather than a slab inside a slab.
In the page it keeps its card like the sections around it, and a style that draws no body of its
own keeps one everywhere. -
The web remote can now look different on each host. Pick a style per host slot in the new
Remote Style panel and the remote re-skins as you switch machines — five shapes alongside the full
one, from a compact media strip to a full set-top remote with a number pad, colour keys and a
circular nav ring, in a dark and a light body. Styles are stored on the
device, so they follow the host rather than the browser. Export one, edit the JSON, and import it
back to build your own; six fit on the device. -
More remote buttons, and buttons can carry your own label. The remote gains Menu, Exit, Guide,
TV, Voice, Subtitles and a full number pad as real keys, plus sixteen spares that send nothing
until you give them a per-host override — for app-launcher keys and anything else with no standard
code worth guessing. A style can now write a button as["spare1","Netflix"]to put its own text on the key,
so an imported layout reads the way the remote it came from does. -
A remote style can now look like the remote, not just carry its keys. New circular navigation
ring and one-piece volume/channel rocker sections, per-button colour and size, inverted light keys,
and body shaping through gradients, the full border-radius grammar and an optional taper. Enough
for a style to read as the device it belongs to rather than a generic slab. -
The Home Assistant remote card draws the same styles as the web page. Pick one in the card
editor, or let it follow whatever style the device has for the active host so switching hosts
re-skins the card too — that needs the newremote_styletext sensor. A style you made yourself
can be pasted into the card, where it joins the style list under its own name. The card's layout
now comes from the firmware's own definitions rather than a second hand-kept copy. -
Remote keys can now fire Home Assistant actions — a new action prefix asks HA to run
one of its own actions over the native API, so a key remapped in Host Actions can drive
an IR blaster, a script, or a scene, from the HA remote card and the web remote alike.
Off by default behind a new YAML opt-in, and additionally gated by HA's own per-device
permission; Host Actions and Macros gain a ready-to-edit preset once enabled.
Fixed
- Sharing a device with another Bluetooth component now fails loudly instead of quietly. Adding
a tracker or proxy alongside the keyboard used to compile and boot with nothing in the log, then
starve whichever one lost the race for the radio. The keyboard now checks whether Bluetooth is
already running, says which component to move to another board, and stops rather than half-working. - The web page asks the device for a lot less, so it stops resetting connections. The position
finder polled several times a second whatever was on screen; it now stops when its section is
hidden and slows right down while the map is locked. Any page in the background stops polling
until it is looked at again, and the browser no longer asks for a favicon the device never had. A
page and a popped-out remote together now make fewer requests than the page alone used to. - Removing a button from the remote no longer moves the others. The remaining buttons closed the
gap, so hiding OK pulled the D-pad arrows out of position; a removed button now leaves its place
empty. A row or section with nothing left visible still collapses.
v1.7.0 ESPHome BLE Keyboard
Added
- A paste bar on the web keyboard and the keyboard card — in the web page's keyboard
header, and on its own line above the card's keys. Paste or type any text and send it as
one piece instead of tapping it out key by key; multi-line text keeps its line breaks. An
optional auto mode types text the moment it is pasted, and on HTTPS a clipboard button
sends the clipboard in one tap. The card can hide the bar via a new editor toggle. - Press and hold: a key now stays down on the host for as long as the button is held.
Every keypress used to arrive as a short tap however long the button was held, so
push-to-talk was impossible. Set it per physical key with the new hold and release
automation actions, or per remote button per host in the new Press and hold panel; the
Media Remote card needs the newhold_buttonssensor.max_key_hold_msguards against
a release that never arrives. - The Media Remote card now follows the per-host hold-to-repeat settings, via a new
repeat_buttonstext sensor. It previously repeated volume and channel only, at a fixed
speed, ignoring whatever Host Actions said — so a host set to repeat the D-pad did so on
the web remote but not the card. - A text sensor for the connected host's Bluetooth address, so an automation can act on
which machine is connected rather than just which slot is active. It reports the host's
stable identity where one was exchanged at pairing, so it keeps working on phones, whose
connection address rotates every few minutes. Hosts with a fixed address report that
address unchanged. The web remote's host buttons and the cards show the same address, so
a phone no longer appears under one address in the web UI and another in the sensor. Each
host slot remembers its identity the next time that host connects, so an existing pairing
starts showing the right address on its own — there is no need to pair it again. - A bonded host slot now belongs to its host until you forget it. A different device that
pairs while that slot is active is disconnected and its bond removed, instead of quietly
taking the slot over — which mattered most on Android, where pairing has no PIN and nothing
stopped the last device to pair from claiming the slot. Your own host is matched by identity,
so it is still let back in after its address rotates or you re-pair it. - A
zoomoption on all three cards, in the visual editor's Config tab (0.25–3, default
1). It scales the whole card — buttons, text and spacing together — so you can shrink one
to fit a smaller space or enlarge it for a wall tablet. The card's height follows the zoom,
sozoom: 0.55brings the full media remote down to about 8 rows, which is as short as
HA's height slider goes. Everything scales by the same factor in both directions, so the
buttons keep their shape at any zoom, and a zoomed-in card scrolls rather than squashing. - All three Lovelace cards support resizing in sections dashboards. They keep their
natural size by default, as before — but the Layout tab now offers sensible width and
height ranges (1–12 columns, 1–8 rows) instead of warning that the card can't be resized.
Cards keep their proportions at whatever size you pick and scroll if the card is smaller
than they are; usezoomto change how big the controls actually are. - The mouse and keyboard cards scroll as one piece when narrowed. Previously only the
title row kept its full width while the keys and the touchpad shrank to whatever was
visible, so scrolling sideways dragged a squashed keyboard out of view and clipped key
labels. Every part of the card now shares the same width and scrolls together, at full
size. To actually make a card smaller rather than scroll it, lower its zoom.
Fixed
- The hidden-buttons sensor was empty until the first host switch. It published before
the saved lists were read from flash and never again, so a card starting up was told the
host hid nothing. The new hold and repeat sensors publish on the same path.
Changed
- The media remote's buttons stay centred in a 460px column on wide cards, instead of
spreading out with the power button stranded at the far edge. Only visible in panel view
or a wide masonry column; sections cap at 500px, so they look unchanged. - Forget Host moved into the Host Actions card, on the same row as the host picker, and
it now forgets the slot the picker shows rather than always the active host — so a host
that isn't currently connected can be forgotten too. The host bar at the top is host buttons
only. Still two taps (Confirm?, disarming after three seconds or when you change slot).
This also puts it on single-slot devices, which never had it: the host bar hides itself
below two slots, while the Host Actions card is always shown. - Both editors' save buttons now read
Save— the Macros button was+ Add(becoming
Savemid-edit) and the Host Actions one was+ Set. The Macros label no longer changes
to signal add-versus-update; the populated Name and Action fields are the cue instead. - The Host Actions replacement box is a 3-line textarea, matching the Macros action box,
so a long chained action is readable without scrolling through a single-line field. Both
action boxes are also wider than the name box beside them, and the two preset dropdowns are
now a matched width. - The host bar fills the card width, five hosts per row, dividing the space evenly instead
of leaving a lopsided gap at the right; a short final row stays left-aligned under the one
above. The toolbar's section toggles likewise stretch to reach the right-hand edge.
v1.6.0 ESPHome BLE Keyboard
Added
-
Hold to repeat on the web remote, configurable per host — holding a button makes it
fire repeatedly, the way a real remote ramps the volume or scrolls a menu; a quick tap
still sends exactly one press. The D-pad, volume, channel, rewind and fast forward
repeat by default. A Hold to repeat panel in the Host Actions card sets which
buttons repeat, how long a button must be held first (100–2000 ms, default 400) and how
fast it repeats (50–2000 ms, default 180) — per host, since a TV wants a fast volume
ramp while a PC may want only the D-pad. Stored on the device rather than in the
browser, so the setting follows the host instead of the phone that set it, and included
in Backup & Restore. New/api/ble_keyboard/repeatand/repeat_setendpoints.The 50 ms floor on the repeat rate is deliberate: the device drops an identical press
arriving within 30 ms of the last one, so a faster repeat would silently lose events.
Fixed
- Holding a button on the web remote did nothing. The repeat had been dropped in an
earlier reinstatement of tap-fires-on-release, leaving thedata-repeatmarkup with no
code behind it while the README still advertised the feature. - README no longer credits the Home Assistant card's Mute button with hold-to-repeat;
that card repeats volume and channel only.
v1.5.0 ESPHome BLE Keyboard
Added
-
Host switcher on the mouse and remote cards — the prev/next host selector that
the keyboard card had is now in all three cards' headers, via the samehost_slots,
host_namesandactive_host_entityoptions. -
Cards stay in sync with each other — switching the host on one card updates the
other two, as do switches made from the web control page, a physical button, or a YAML
action. Works out of the box via the cards' 30-second device poll; adding the optional
active_hostsensor makes it instant. -
Other ESPHome buttons appear on the web control page — every non-internal
button:
in your config is listed automatically, so the page can reach things BLE can't. The
motivating case is power: a monitor can be slept withconsumer:0x30but only woken
with Wake-on-LAN. They work aspress_button:<object_id>actions too, so they can be
used in macros, per-host overrides, and the REST API. Keyed by object id rather than
position, so adding buttons never repoints a saved macro. -
hide_buttonsoption to keep destructive buttons (factory_reset,restart) off
the page, which has no authentication. Hidden buttons are also refused if their action
is typed by hand.expose_buttons: falseturns the listing off entirely. -
alternate:action — runs one branch per press instead of everything in sequence,
so a single button can toggle. Branches split on||, while a single|keeps meaning
"next step", so each branch can be a whole sequence — necessary for displays that need a
confirmation step to power off:alternate:consumer:0x30 | delay:1000 | ok || repeat:3:press_button:samsung_43_m70f_wolSet that as
remote_powerin Host Actions and the remote's power button sleeps the
monitor over BLE, then wakes it over Wake-on-LAN. Editable with no reflash, and its
preset wraps what's already in the box rather than appending.repeat:composes,
which Wake-on-LAN usually wants since magic packets are unacknowledged UDP. Note this is
assumed state — HID is one-way, so the device can't detect the monitor being switched
off by other means; the README shows a template-button recipe for when it must be real. -
macro:<name>action — run a stored web macro from any action string, so macros can
call each other and analternate:branch can be a whole macro. Names must now be unique
and cannot contain|, since that would split the reference. -
show_macoption on all three cards to show or hide the active host's MAC address. -
host_urloption on all three cards to point a card at the ESP32 explicitly when
auto-detection can't find it.
Fixed
- The keyboard card's MAC address never displayed. It looked for the device's URL in
atext_sensor.*entity, but Home Assistant has no such domain — ESPHome text sensors
becomesensor.*— so the lookup always failed and the line stayed blank. The cards now
take the address from the device'sconfiguration_urlin Home Assistant's device
registry (orhost_url), and the MAC is drawn to the left of the selector. - Host switching failed for devices with a
-in their name. The card built the
service name from the raw device name instead of the underscored slug. - The host poller leaked a timer per dashboard view switch and never stopped. It is
now cleared on disconnect, re-armed on reconnect, and runs every 30 s instead of 5 s —
the endpoint returns every slot at once, so a host switch repaints from cache. - The
/api/ble_keyboard/*endpoints sentAccess-Control-Allow-Origintwice. ESPHome's
web_serveralready adds one globally, and the component added a second, so browsers saw
*, *and refused the request — stricter than sending no CORS header at all. Any
cross-origin read of the API failed, which is why the cards could never fetch host MACs.
The component no longer sets the header and relies on ESPHome's. - HACS updates could leave stale cards in the browser. The HACS entry point imported
the three card files at fixed URLs, so an update re-fetched the entry point (HACS gives
it a new?hacstag=) while the browser could keep serving cached copies of the cards
themselves. The imports now carry the release version, so every release produces URLs
no cache has seen.
Changed
- Host Actions now reference a macro instead of copying it. Picking a macro from the
preset dropdown used to paste a snapshot of its text, so editing the macro afterwards
left the override running the old version with nothing showing they'd diverged. It now
insertsmacro:<name>, which follows the macro. Existing overrides keep their copied
text and work unchanged — re-pick the macro to convert one into a reference. Overrides
pointing at a macro that no longer exists are flagged with a ⚠ naming it, updated live
as macros are renamed or deleted. - Your existing buttons will now show on the web control page. Button listing is on by
default, so after this update anyrestart,safe_modeorfactory_resetbutton in
your config appears on/ble_keyboardalongside the keyboard's own. Add them to
hide_buttons, mark theminternal: true, or setexpose_buttons: falseif you'd
rather they didn't.
Notes
- Reflash required for the MAC display and the button listing. Both are firmware-side.
The host switcher itself works after a card update alone; the MAC address and the new
buttons only appear once the device is reflashed. - The MAC is read straight from the ESP32 over HTTP. If Home Assistant is served over
HTTPS the browser blocks that as mixed content and the MAC line hides itself; the
switcher still works.
v1.4.0 ESPHome BLE Keyboard
Added
- YAML buttons as presets — your
espidf_ble_keyboardbuttons now appear under a
Buttons group in the web UI's preset dropdowns (Macros and Host Actions). Build a
macro or per-host override by picking an existing button instead of retyping its action. - Macros as Host Action presets — saved macros appear under a Macros group in the
Host Actions preset dropdown, so a per-host override can reuse a macro's actions. (The
Macros editor's own dropdown intentionally does not list macros.)
Changed
- Internal refactor of the component for readability and maintainability (no behaviour change).
- Updated the Home Assistant remote card screenshot in the docs.
v1.3.0 ESPHome BLE Keyboard
ESPHome BLE Keyboard v1.3.0
A big release focused on the remote, per-host customisation, and much easier
Home Assistant installation.
Firmware + cards. Re-flash your device to get the component changes. The
Lovelace cards can now be installed and updated through HACS (see below).
🎬 Remote controls
- Record button (HID Record
0x00B2) added to the web server remote and the
Home Assistant remote card. - The web server remote gained colour keys (F1–F4) and app-launcher
shortcuts (Explorer, Browser, Email, Calculator, Search), matching what the
Home Assistant card already offered. - Every remote button is now a named action, which is what makes per-host
remapping and hiding (below) possible.
🎛️ Per-host action overrides
- Any named remote action can now be remapped per host slot, from YAML
(hosts: → actions:) or live in the web UI's new Host Actions card — no
re-flash needed to change one. - Every remote button is now a named action, so all of them are remappable
(D-pad, power, channel, colour keys, app launchers …). Up to 8 overrides per host. - Example: make Record drive Windows Game Bar on your PC while a TV keeps
native HID Record.
🙈 Remove remote buttons per host
- Untick the buttons a host doesn't need — they disappear from the remote for
that host only (the action still works from macros / YAML / HA). Up to 40 per host. - Optional
hidden_buttonstext sensor lets the Home Assistant card mirror
the same per-host hiding.
💾 Backup & Restore
- Download every runtime setting (macros, host actions, layout, mouse
calibration, hidden buttons, learned hosts, UI prefs) to a JSON file and
restore it later or onto another board — new buttons next to Host Actions.
📦 HACS support + visual card editors
- The repo is now HACS-installable (custom repository, category Dashboard)
— one download brings all three cards and keeps them updated. - All three cards now have a visual editor in the dashboard UI, so you no
longer need to hand-write YAML. YAML editing still works.
⚠️ Changed behaviour
- OK button now sends keyboard Enter (
0x28) instead of HID Menu Pick
(0x0041). Enter is accepted by far more hosts (fixes OK doing nothing on
some smart TVs/monitors while the arrows worked). Hosts that need Menu Pick
can restore it with a per-host override:ok → consumer:0x0041.
🖥️ Web UI improvements
- New Mouse and Cursor Position preset groups; added the missing plain
left/right/middle-click presets. - Host-bar layout fixes so a wrapped host button no longer stretches the row,
and hosts + Forget Host pack onto one line. - Tooltips with worked examples on the Host Actions inputs.
📖 Docs
- Documented per-host overrides, button removal, backup/restore, the
text_sensorplatform, HACS install, and a "Developing the cards" guide. - Fixed the Usage Example, which was missing the
web_server:block required by
web_control: true.
Install / upgrade the cards: HACS → ⋮ → Custom repositories → this repo,
category Dashboard. Migrating from a manual install? Remove the old
/local/*-card.js dashboard resources afterwards.
v1.2.0 — Auto-registered Home Assistant services + F13–F24 keys
Auto-registered Home Assistant services
New api_services: true option on espidf_ble_keyboard: — the component now registers
all documented Home Assistant services itself. No more pasting api: services: yaml
snippets, and all three HA cards (mouse, keyboard, media remote) work out of the box.
Registered services (as esphome.<device>_<service>): run_action, run_macro,
send_string, send_key, send_consumer, mouse_move, mouse_scroll, mouse_click,
mouse_hold, mouse_release, mouse_abs, switch_host, forget_host.
- Requires the
api:component;api: custom_services: true(needed by ESPHome
2025.11+) is enabled automatically — you don't have to add it. - Default is
false, so existing configs are unchanged. If you enable it, delete your
manualapi: services:definitions of the same names — keeping both registers
duplicate service names. - Immune to the ESPHome 2026.5+
StringReflink error that can hit yaml-defined
string-arg services after an ESPHome upgrade (the manual-yaml workaround is now
documented in the README). - See the new "Home Assistant Services" section in the README for the full table.
F13–F24 key support
The keyboard HID report descriptor's key-array maximum is raised from 0x65 to 0x73,
so F13–F24 (keycodes 0x68–0x73) are no longer silently dropped by the host. These
are ideal "phantom" macro keys on Windows (VK_F13–VK_F24) — recognized system-wide
but unused by default, so they never collide with app shortcuts.
⚠ Re-pairing required: hosts cache the HID descriptor per Bluetooth bond. After
updating, remove the device from the host's Bluetooth settings and pair again, or
F13–F24 stay ignored. Existing keys are unaffected (descriptor-only change).
Keycode tables for F13–F24 added to docs/keycodes.md / docs/keycodes.html.
v1.1.0 Mouse positioning & drag release
Absolute positioning & mouse_goto
mouse_abs— move the cursor to an exact position by percent, pixel (mouse_abs_px), or per-monitor (mouse_abs_mon), plusmouse_abs_save/mouse_abs_restoremouse_goto:<x>:<y>— jump to an exact Windows virtual-desktop pixel across all monitors (homes the absolute pointer, then steps relatively with phased X/Y movement to prevent drift)- Per-axis, per-host calibration (
mouse_goto_scale_x/_y) persisted to NVS, with YAMLscreen_width/screen_heightand multi-monitorsregions
Web Position Finder
- New card on the web control page: aim on a live desktop map to move the cursor, copy ready-made
mouse_gotovalues into buttons/macros - Live calibration with ±nudges, per-host save, reset to YAML defaults, and lock/Edit toggle so stray taps can't move the cursor
- Helper scripts
docs/cursorpos.bat/docs/cursor_saverestore.batfor reading the real Windows cursor position while calibrating
Click-and-hold / drag — thanks @repaxan (#16)
send_mouse_click_start()/send_mouse_click_release()with held buttons carried through move, scroll, andmouse_goto→ true drag-and-drop, including drag-to-location- New action strings:
left/right/middle_click_hold,mouse_hold:<mask>,mouse_release - Web UI & HA mouse card: long-press a mouse button to hold (tap again to release); new
mouse_hold/mouse_releaseREST endpoints and HA services - Report characteristic values now stay readable/in sync for hosts that read instead of subscribing
Web control fixes & improvements
- Touchpad now owns every touch — no more page scrolling stealing a drag mid-gesture
- Much lower cursor latency: coalesced single-in-flight move requests and instant device-side sends (direction reversals register immediately)
- Macro repeat action (
repeat:N:<action>), zoom level persisted in the browser, build version badge
Compatibility
- Builds warning-free on ESPHome 2026.7.0 (new ESP-IDF toolchain int32 format fixes)
Upgrade notes
- Fully backward compatible — new YAML options and services are optional
- Pin this release with
ref: v1.1.0inexternal_components(or trackmain) - HA card users: copy the updated
docs/mouse-card.jsintoconfig/www/and add themouse_hold/mouse_releaseservices (see README) for long-press drag - Hard-refresh the web page after flashing — the badge should read v1.1.0
v1.0.0 First stable release 🎉
The first tagged release of the ESP32 BLE HID Keyboard component for ESPHome (ESP-IDF / Bluedroid). Everything you need to turn an ESP32 into a fully native Bluetooth keyboard, mouse, and media remote.
Highlights
- Native BLE HID keyboard — pairs with Windows, Android, and iOS (HOGP-compliant, battery + device info services, optional 6-digit passkey with
legacy/secure_connectionsmodes) - Typing & shortcuts — string typing with
us/uk/de/belayouts (UTF-8 + dead keys), hex key combos, Ctrl-Alt-Del, sleep / hibernate / shutdown / power - Media & consumer control — volume, playback, mute, or any HID consumer code
- Basic mouse — left/middle/right click, relative movement, scroll wheel
- Multi-host switching — up to 10 bonded hosts with per-slot passkey and layout, fast directed-advertising reconnect
- Web control page — full keyboard, mouse touchpad, remote, and editable macros (persisted to NVS) from any browser, no Home Assistant required
- Home Assistant cards — keyboard, mouse, and remote Lovelace cards with matching services
- Sensors — host RSSI with proximity triggers, keyboard LED state (Num/Caps/Scroll)
Install
external_components:
- source:
type: git
url: https://github.com/markusg1234/ESPHome-espidf_ble_keyboard
ref: v1.0.0
path: components
components: [ espidf_ble_keyboard ]See the README for full configuration.