irbt-cli (0.2.2)

Published 2026-10-29 23:40:53 +00:00 by selu in selu/ir-bt-bridge

Installation

[registries.forgejo]
index = "sparse+" # Sparse index
# index = "" # Git

[net]
git-fetch-with-cli = true
cargo add irbt-cli@0.2.2 --registry forgejo

About this package

Command-line tool for configuring and controlling an ir-bt-bridge over USB

ir-bt-bridge

Turns any IR remote into a Bluetooth (BLE HID) remote for Google TV, using an ESP32-S3. Mappings are configured over USB with the irbt CLI. See SPEC.md for hardware, wiring and design.

Docs: https://selu.pages.selu.dev/ir-bt-bridge/, a user guide plus the API docs of the irbt and irbt-proto crates.

The repo holds two separate Cargo builds:

Path What Toolchain
/ (proto/, host/) wire protocol, irbt library and CLI stable Rust
firmware/ ESP32-S3 firmware (ESP-IDF, xtensa-esp32s3-espidf) esp (via firmware/rust-toolchain.toml)

Dev environment setup

  1. Install Rust with rustup (stable is enough for the host tools).
  2. Install the ESP tooling and the esp toolchain:
    cargo install espup espflash ldproxy
    espup install          # installs the `esp` toolchain and writes ~/export-esp.sh
    
  3. In every shell where you build firmware:
    . ~/export-esp.sh
    
    Make sure RUSTUP_TOOLCHAIN is not set. It overrides rust-toolchain.toml, and the firmware then fails to build with "can't find crate for core". Use cargo +esp … if you can't unset it.

ESP-IDF itself needs no manual install: the first firmware build downloads it into firmware/.embuild/. That first build takes several minutes, as does the first build after changing sdkconfig.defaults.

Updating the ESP tooling

Each part of the tooling updates separately:

  • CLI tools (espup, espflash, ldproxy): cargo install rebuilds only the ones that have a newer version.
    cargo install espup espflash ldproxy --locked
    
  • esp Rust toolchain (Xtensa rustc/LLVM):
    espup update
    . ~/export-esp.sh      # the script is rewritten; source it again in open shells
    
  • ESP-IDF: pinned by ESP_IDF_VERSION in firmware/.cargo/config.toml. Pick a version that your esp-idf-sys supports and change it there, then rebuild from scratch. The next build downloads the new IDF, which takes several minutes.
    cd firmware
    cargo clean
    rm -rf .embuild        # optional; otherwise the old IDF stays next to the new one
    cargo build
    
  • esp-idf-* crates: firmware/Cargo.toml patches esp-idf-hal and esp-idf-svc to their git repos (esp-idf-sys lives in the esp-idf-hal repo and comes with it). To pull their latest commits, run this in firmware/:
    cargo update -p esp-idf-hal -p esp-idf-svc
    
    For a new minor version (e.g. esp-idf-svc 0.53), also change the version in Cargo.toml and bump esp32-nimble to match it (see the comment there).

After updating, build and flash a release build to check that it still works.

Build

Host tools, from the repo root:

cargo build
cargo test --workspace
cargo install --path host/irbt-cli   # puts `irbt` on your PATH

Firmware:

cd firmware
cargo build            # debug
cargo build --release  # release (size-optimized)

Lint and format checks (same as CI, in either directory):

cargo fmt --all -- --check
cargo clippy --all-targets --all-features --workspace -- -D warnings

Flash the device

  1. Connect the board's USB-C port. If flashing fails to connect, hold BOOT while plugging it in to force download mode.
  2. Flash:
    cd firmware
    cargo run --release    # builds, then `espflash flash --monitor`
    
    or flash an existing build without the monitor:
    espflash flash target/xtensa-esp32s3-espidf/release/ir-bt-bridge
    
  3. The device's USB output is framed binary, so espflash monitor shows garbage. Exit it (Ctrl+C) and use irbt instead:
    irbt status
    irbt monitor --logs
    

Linux: your user needs access to the serial port. Join the dialout group (sudo usermod -aG dialout $USER, then log in again). WSL2: attach the board to WSL with usbipd-win (usbipd attach --wsl --busid <id>). Re-attach it after every replug or reset into download mode.

Releases

Prebuilt binaries are on the releases page:

File What
ir-bt-bridge-<tag>-esp32s3.elf firmware, for espflash
ir-bt-bridge-<tag>-esp32s3-merged.bin firmware as a single image for offset 0x0
irbt-<tag>-{x86_64,aarch64}-linux.tar.gz static irbt for Linux
irbt-<tag>-x86_64-windows.zip irbt.exe
SHA256SUMS checksums

On macOS, build irbt from source (see Build), or install it from the Cargo registry (below).

Crates

The host crates are published to the Cargo registry on code.selu.dev: irbt-proto (wire protocol), irbt (host library), irbt-cli (the irbt binary) and irbt-build-info (a build-script helper). Add the registry to ~/.cargo/config.toml or a project's .cargo/config.toml:

[registries.selu]
index = "sparse+https://code.selu.dev/api/packages/selu/cargo/"

then:

cargo install irbt-cli --registry selu
cargo add irbt --registry selu

To update a device, flash the ELF. This keeps the stored mappings and pairings:

espflash flash ir-bt-bridge-<tag>-esp32s3.elf

The merged image needs only esptool (or a browser-based flasher), but it erases the mappings and pairings because it overwrites NVS. Use it for new boards:

esptool.py --chip esp32s3 write_flash 0x0 ir-bt-bridge-<tag>-esp32s3-merged.bin

Cutting a release

.forgejo/workflows/release.yml builds and publishes a release when a v* tag is pushed. It fails if the tag doesn't match the crate versions. The workflows need a Forgejo runner; see docs/forgejo-runner.md to set one up.

  1. Bump version in Cargo.toml (in [workspace.package] and in the [workspace.dependencies] entries) and firmware/Cargo.toml, and run cargo update -w in the repo root and in firmware/ to update the lockfiles. Commit.
  2. Tag it. The tag message becomes the release notes. A tag with a - (v0.3.0-rc1) makes a prerelease.
    git tag -a v0.3.0
    git push origin master v0.3.0
    

The release also publishes the host crates to the Cargo registry. That needs the repo secret CARGO_REGISTRY_TOKEN: a token with write:package. To publish by hand instead, run cargo login --registry selu "Bearer <token>" once, then cargo publish --workspace --registry selu.

The docs workflow builds the docs site on every push. A v* tag also pushes it to the pages branch, which git-pages serves.

To rebuild the release of an existing tag, run the workflow by hand from the Actions tab and enter the tag.

Use

irbt learn home          # press a remote button to bind it to `home`
irbt list                # show mappings
irbt send-hid up         # send a key over BLE without IR
irbt keys                # all key names

Both the firmware and irbt carry the git commit they were built from, as 0.1.0 (c7f30e8 2026-10-27) with -dirty added for uncommitted changes. irbt status shows the firmware's commit, its rustc, ESP-IDF and crate versions. irbt -V shows the CLI's commit, and irbt --version adds its toolchain and dependency versions.

To pair with the TV, go to Settings → Remotes & Accessories → Add accessory → IR Bridge.

Status LED

The onboard RGB LED shows the Bluetooth state:

LED Meaning
Blue, blinking (2×/s) No Bluetooth host connected; advertising
Green, steady (dim) Connected and paired to a host
Purple flash A key was sent to the host

Keys pressed while the LED is blinking blue are dropped (no flash).

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Dependencies

ID Version
anyhow ^1
clap ^4
ctrlc ^3
irbt ^0.2.2
serde ^1
serde_json ^1
toml ^1.1
build-info ^0.2.2
Details
Cargo
2026-10-29 23:40:53 +00:00
0
Szabolcs Seláf <selu@selu.dev>
MIT OR Apache-2.0
14 KiB
Assets (1)
Versions (2) View all
0.3.0 2026-10-31
0.2.2 2026-10-29