Skip to content

Releases: markusg1234/ESPHome-espidf_ble_keyboard

v1.8.0 ESPHome BLE Keyboard

Choose a tag to compare

@markusg1234 markusg1234 released this 12 Aug 14:13

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#remote and 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 new remote_style text 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

Choose a tag to compare

@markusg1234 markusg1234 released this 07 Aug 12:05

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 new hold_buttons sensor. max_key_hold_ms guards against
    a release that never arrives.
  • The Media Remote card now follows the per-host hold-to-repeat settings, via a new
    repeat_buttons text 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 zoom option 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,
    so zoom: 0.55 brings 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; use zoom to 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
    Save mid-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

Choose a tag to compare

@markusg1234 markusg1234 released this 27 Jul 11:14

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/repeat and /repeat_set endpoints.

    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 the data-repeat markup 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

Choose a tag to compare

@markusg1234 markusg1234 released this 25 Jul 10:17

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 same host_slots,
    host_names and active_host_entity options.

  • 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_host sensor 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 with consumer:0x30 but only woken
    with Wake-on-LAN. They work as press_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_buttons option 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: false turns 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_wol
    

    Set that as remote_power in 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 an alternate: branch can be a whole macro. Names must now be unique
    and cannot contain |, since that would split the reference.

  • show_mac option on all three cards to show or hide the active host's MAC address.

  • host_url option 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
    a text_sensor.* entity, but Home Assistant has no such domain — ESPHome text sensors
    become sensor.* — so the lookup always failed and the line stayed blank. The cards now
    take the address from the device's configuration_url in Home Assistant's device
    registry (or host_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 sent Access-Control-Allow-Origin twice. ESPHome's
    web_server already 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
    inserts macro:<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 any restart, safe_mode or factory_reset button in
    your config appears on /ble_keyboard alongside the keyboard's own. Add them to
    hide_buttons, mark them internal: true, or set expose_buttons: false if 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

Choose a tag to compare

@markusg1234 markusg1234 released this 25 Jul 06:44

Added

  • YAML buttons as presets — your espidf_ble_keyboard buttons 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

Choose a tag to compare

@markusg1234 markusg1234 released this 23 Jul 08:56

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_buttons text 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_sensor platform, 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

Choose a tag to compare

@markusg1234 markusg1234 released this 17 Jul 15:04

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
    manual api: services: definitions of the same names — keeping both registers
    duplicate service names.
  • Immune to the ESPHome 2026.5+ StringRef link 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 0x680x73) are no longer silently dropped by the host. These
are ideal "phantom" macro keys on Windows (VK_F13VK_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

Choose a tag to compare

@markusg1234 markusg1234 released this 17 Jul 11:46

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), plus mouse_abs_save / mouse_abs_restore
  • mouse_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 YAML screen_width/screen_height and multi-monitors regions

Web Position Finder

  • New card on the web control page: aim on a live desktop map to move the cursor, copy ready-made mouse_goto values 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.bat for 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, and mouse_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_release REST 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.0 in external_components (or track main)
  • HA card users: copy the updated docs/mouse-card.js into config/www/ and add the mouse_hold/mouse_release services (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 🎉

Choose a tag to compare

@markusg1234 markusg1234 released this 17 Jul 11:49

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_connections modes)
  • Typing & shortcuts — string typing with us / uk / de / be layouts (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.