{"id":50509725,"url":"https://github.com/dmatking/esp32-ble-kbd-host","last_synced_at":"2026-06-02T19:01:15.206Z","repository":{"id":352500760,"uuid":"1210953718","full_name":"dmatking/esp32-ble-kbd-host","owner":"dmatking","description":"BLE HID keyboard host for ESP-IDF (NimBLE) with reconnect, re-pair, and callback API","archived":false,"fork":false,"pushed_at":"2026-05-16T01:31:15.000Z","size":89,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-16T03:43:20.421Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dmatking.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-14T23:37:29.000Z","updated_at":"2026-05-16T01:31:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dmatking/esp32-ble-kbd-host","commit_stats":null,"previous_names":["dmatking/esp32-ble-kbd-host"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dmatking/esp32-ble-kbd-host","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmatking%2Fesp32-ble-kbd-host","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmatking%2Fesp32-ble-kbd-host/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmatking%2Fesp32-ble-kbd-host/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmatking%2Fesp32-ble-kbd-host/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dmatking","download_url":"https://codeload.github.com/dmatking/esp32-ble-kbd-host/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmatking%2Fesp32-ble-kbd-host/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33833277,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-02T02:00:07.132Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-02T19:01:13.633Z","updated_at":"2026-06-02T19:01:15.201Z","avatar_url":"https://github.com/dmatking.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# esp32-ble-kbd-host\n\nBLE HID keyboard host component for ESP-IDF (NimBLE stack).\n\nHandles pairing, reconnection, and key decoding with a clean callback API.\nNo display or GPIO coupling — works headless or with any UI layer.\n\n## Features\n\n- **Automatic reconnection** — reconnects to the last bonded keyboard without re-pairing\n- **Reliable re-pair** — `ble_kbd_host_start_pairing()` escapes from any state, including\n  the reconnect loop (fixes a common watchdog bug where BOOT hold was ignored mid-retry)\n- **Single persistent task** — one `kbd_main_task` state machine replaces the\n  scan-task → watchdog hand-off pattern that caused missed BOOT presses\n- **Callback API** — on_key, on_status, on_passkey, on_scan_updated; no queue returned,\n  no display pointer, no GPIO in the component\n- **Bundled modified esp_hid** — includes `esp_ble_hidh_dev_reconnect()` (lightweight\n  reconnect without full GATT rediscovery), passkey handler, enc-change handler,\n  device kept alive on disconnect\n- **ESP32-P4 support** — BLE via ESP32-C6 co-processor through `esp_hosted` / vHCI\n\n## Quick start\n\nIn your project's `main/idf_component.yml`:\n\n```yaml\ndependencies:\n  dmatking/esp32-ble-kbd-host: \"\u003e=1.0.0\"\n```\n\nFor local development, use a path dependency instead:\n\n```yaml\ndependencies:\n  esp32-ble-kbd-host:\n    path: /path/to/esp32-ble-kbd-host\n```\n\n```c\n#include \"esp_ble_kbd_host.h\"\n\nstatic QueueHandle_t s_key_queue;\n\nstatic void on_key(char ascii, void *ctx) {\n    if (ascii == '\\0') return;   // synthetic wakeup — discard\n    xQueueSend(s_key_queue, \u0026ascii, 0);\n}\n\nstatic void on_status(ble_kbd_state_t state,\n                      const char *line1, const char *line2, void *ctx) {\n    ESP_LOGI(\"kbd\", \"state %d: %s / %s\", state, line1, line2);\n}\n\nvoid app_main(void) {\n    s_key_queue = xQueueCreate(64, sizeof(char));\n\n    ble_kbd_host_config_t cfg = {\n        .callbacks = {\n            .on_key    = on_key,\n            .on_status = on_status,\n            .ctx       = NULL,\n        },\n    };\n    ESP_ERROR_CHECK(ble_kbd_host_init(\u0026cfg));\n\n    // Block until keyboard connects (optional)\n    ble_kbd_host_wait_connected();\n\n    char c;\n    while (1) {\n        if (xQueueReceive(s_key_queue, \u0026c, portMAX_DELAY)) {\n            printf(\"key: %c\\n\", c);\n        }\n    }\n}\n```\n\n## API\n\n```c\n// Initialise — starts the internal kbd_main_task\nesp_err_t ble_kbd_host_init(const ble_kbd_host_config_t *cfg);\n\n// Trigger re-pair from any state (safe to call from any task)\nvoid ble_kbd_host_start_pairing(void);\n\n// Select device by index during SCANNING state\nvoid ble_kbd_host_select_device(int index);\n\n// Query state\nbool            ble_kbd_host_is_connected(void);\nble_kbd_state_t ble_kbd_host_get_state(void);\n\n// Block until CONNECTED (useful in app_main before starting SSH etc.)\nvoid ble_kbd_host_wait_connected(void);\n```\n\n## Config (`menuconfig`)\n\n| Key | Default | Description |\n|-----|---------|-------------|\n| `BLE_KBD_HOST_TASK_STACK` | 8192 | kbd_main_task stack bytes |\n| `BLE_KBD_HOST_TASK_PRIORITY` | 2 | kbd_main_task priority |\n| `BLE_KBD_HOST_RECONNECT_INTERVAL_MS` | 3000 | Delay between reconnect attempts |\n| `BLE_KBD_HOST_SCAN_TIMEOUT_MS` | 20000 | BLE scan window before restart |\n\n## State machine\n\n```\nIDLE\n  └─ has bonds? ──yes──► RECONNECTING ─── reconnect succeeds ───► CONNECTED\n                │                 │                                    │\n                │                 └── CMD_START_PAIRING ──►            │\n                no                                        │        disconnect\n                │                                         ▼            │\n                └─────────────────────────────────► SCANNING           │\n                                                         │              │\n                                               device selected          │\n                                                         ▼              │\n                                                    CONNECTING          │\n                                                         │              │\n                                                    open succeeds       │\n                                                         └──────────────┘\n```\n\n`CMD_START_PAIRING` (from `ble_kbd_host_start_pairing()`) clears bonds and forces\na scan regardless of current state. This is what makes BOOT hold reliable from\nthe RECONNECTING state — the previous watchdog implementation polled BOOT only in\nthe scan loop, so holding BOOT while retrying a reconnect had no effect.\n\n## License\n\nApache-2.0. Bundled `esp_hid/` sources are from Espressif Systems\n(Unlicense / Apache-2.0); see file headers for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmatking%2Fesp32-ble-kbd-host","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdmatking%2Fesp32-ble-kbd-host","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmatking%2Fesp32-ble-kbd-host/lists"}