npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

homebridge-xbloom

v1.1.3

Published

Brew your saved xBloom coffee recipes from HomeKit/Siri over Bluetooth LE.

Readme

homebridge-xbloom

npm license ko-fi

Brew your saved xBloom coffee recipes from HomeKit / Siri, over Bluetooth LE.

Each recipe you define becomes a HomeKit switch, so you can say "Hey Siri, turn on Ethiopia" or trigger a brew from any HomeKit automation (alarm, sunrise, presence, …). The plugin connects to the machine only when needed and frees it again afterwards, so your phone's xBloom app keeps working normally.

Unofficial. Not affiliated with, endorsed by, or supported by xBloom. It talks to the machine locally over Bluetooth (no cloud) using a clean-room understanding of its BLE protocol. Use at your own risk.


Features

  • 🎯 One switch per recipe — trigger by name with Siri, scenes, or automations.
  • Recipes defined in the config UI — dose, grind, ratio, and full pour profile (water / temperature / flow / pattern / pause per pour). No app or capture required.
  • 🔄 Connect-on-demand — no permanent Bluetooth connection; the machine stays free for your phone between brews (see Bluetooth & the single-device limit).
  • 📊 Live status — an xBloom Brewing sensor in Apple Home, plus fault reporting for no beans / tank empty / bad dose, and a log of grind → pour → complete with live ml.
  • 🛑 Optional Stop Brew switch and an optional manual Bluetooth hold/release switch.

Accessories it exposes

| Accessory | Type | Default | Purpose | |---|---|---|---| | (each recipe) | Switch | — | Turn on to brew that recipe (auto-resets) | | xBloom Brewing | Contact Sensor | on | Open while grinding/brewing; fault on errors | | Stop Brew | Switch | on | Aborts the current brew | | xBloom Bluetooth | Switch | off | Manual hold/release of the BLE link (override) |


Requirements

  • Homebridge v1.8+ or v2.x running on Node.js 22 or 24.
  • A Linux host with BlueZ (bluetoothd) and a working Bluetooth adapter (most Raspberry Pi / NUC / mini-PC setups). The plugin talks to BlueZ over D-Bus.
  • An xBloom machine (tested on the original/Studio-class, XBLOOM … BLE name).
  • The machine must be physically loaded (pod or grounds, cup, water) for a brew — Bluetooth only triggers the program; it can't load coffee.

macOS/Windows Homebridge hosts are not supported for the BLE link (BlueZ is Linux-only).


Installation

Option A — Homebridge UI (recommended)

  1. In the Homebridge UI, go to Plugins, search homebridge-xbloom, and install.
  2. Open the plugin settings and add your machine + recipes (see Configuration).
  3. Make sure the host can reach Bluetooth (see Linux / BlueZ setup).

Option B — Command line

sudo npm install -g homebridge-xbloom

Linux / BlueZ setup

The plugin uses node-ble, which speaks to the system Bluetooth daemon over D-Bus (it coexists with bluetoothd — no adapter takeover).

  1. Install and enable BlueZ:
    sudo apt install bluez
    sudo systemctl enable --now bluetooth
    bluetoothctl power on
  2. Permissions. If Homebridge runs as root, BlueZ's default policy already allows access. If it runs as a non-root user, grant that user access to org.bluez by creating /etc/dbus-1/system.d/node-ble.conf:
    <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
      "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
    <busconfig>
      <policy user="homebridge">
        <allow send_destination="org.bluez"/>
        <allow send_interface="org.bluez.Adapter1"/>
        <allow send_interface="org.bluez.Device1"/>
        <allow send_interface="org.bluez.GattService1"/>
        <allow send_interface="org.bluez.GattCharacteristic1"/>
        <allow send_interface="org.bluez.GattDescriptor1"/>
        <allow send_interface="org.freedesktop.DBus.ObjectManager"/>
        <allow send_interface="org.freedesktop.DBus.Properties"/>
      </policy>
    </busconfig>
    Replace homebridge with the actual user, then sudo systemctl reload dbus.

Docker Homebridge

Only needed if your Homebridge runs in Docker. Native installs (Raspberry Pi, etc.) need nothing here — the plugin uses the system Bluetooth automatically.

A Docker container can't see the host's Bluetooth by default, and the official homebridge/homebridge image (with ENABLE_AVAHI=1) runs its own internal D-Bus. Three one-time things are required:

  1. Mount the host's D-Bus socket into the container.
  2. Unconfine AppArmor for the container (otherwise the host's dbus-daemon blocks it).
  3. Set dbusAddress in the plugin config so it uses that host bus.

Steps 1 & 2 — edit your Homebridge docker-compose.yml:

services:
  homebridge:
    # …existing config…
    volumes:
      - ./volumes/homebridge:/homebridge
      - /run/dbus/system_bus_socket:/run/host-dbus/system_bus_socket:ro   # ← add this
    security_opt:
      - apparmor=unconfined   # ← add this (AppArmor blocks container→host D-Bus otherwise)

Then docker compose up -d to recreate the container.

Why apparmor=unconfined? On hosts with AppArmor (e.g. Ubuntu), the default Docker profile + dbus-daemon mediation block a container from talking to the host's system D-Bus (you'd see "An AppArmor policy prevents this sender…"). Unconfining lets the container reach Bluetooth. The Homebridge container already runs with host networking; if you'd rather keep confinement, write a custom AppArmor profile that allows dbus send.

Step 3 — set dbusAddress in the plugin config to that path:

unix:path=/run/host-dbus/system_bus_socket

That's it. The plugin points only its own Bluetooth connection at the host bus — your container's avahi / HomeKit advertising is left completely untouched (no container-wide environment variables). The image runs as root, so BlueZ's default permissions are enough.

Finding your device (address is optional)

You usually don't need the MAC address. Leave deviceAddress blank and the plugin auto-discovers your machine by its advertised name (default prefix XBLOOM ). xBloom machines advertise as XBLOOM <number>, so the default matches.

Set an explicit address only if you have more than one xBloom, or auto-discovery isn't finding it. To find it:

bluetoothctl --timeout 12 scan le | grep -i xbloom
# e.g. [NEW] Device AA:BB:CC:DD:EE:FF XBLOOM 123456

Other ways to find the MAC: the xBloom app (machine/Bluetooth info), or your router's DHCP/device list (look for the XBLOOM hostname).

Either way, the machine only advertises while awake and not connected to another device (disconnect the phone app first).


Configuration

Use the Homebridge UI settings, or add a platform block to config.json:

{
  "platforms": [
    {
      "platform": "XBloom",
      "name": "xBloom",
      "exposeBrewingSensor": true,
      "exposeStopSwitch": true,
      "exposeConnectionSwitch": false,
      "holdTimeoutSec": 300,
      "brewTimeoutSec": 300,
      "dryRun": false,
      "recipes": [
        {
          "name": "Morning Pour Over",
          "cupType": "xdripper",
          "doseGrams": 18,
          "grinderSize": 36,
          "rpm": 60,
          "ratio": 17,
          "pours": [
            { "volume": 55, "temperature": 93, "flowRate": 3.5, "pattern": 0, "pausing": 40 },
            { "volume": 95, "temperature": 93, "flowRate": 3.5, "pattern": 1, "pausing": 20 },
            { "volume": 85, "temperature": 92, "flowRate": 3.5, "pattern": 2, "pausing": 20 },
            { "volume": 71, "temperature": 92, "flowRate": 3.5, "pattern": 2, "pausing": 5 }
          ]
        }
      ]
    }
  ]
}

Platform options

| Option | Default | Description | |---|---|---| | deviceAddress | — | Machine BLE address. Optional — leave blank to auto-find by name. Set only for multiple machines. | | deviceName | XBLOOM | Name prefix used to auto-find the machine when no address is set. | | recipes | [] | Your recipes (see below). Each becomes a switch. | | dryRun | false | Log the frames that would be sent without touching Bluetooth. Great for first setup. | | exposeBrewingSensor | true | Expose the xBloom Brewing status sensor. | | exposeStopSwitch | true | Expose the Stop Brew switch. | | exposeConnectionSwitch | false | Expose the manual xBloom Bluetooth hold/release switch. | | holdTimeoutSec | 300 | When manually held on, auto-release after this many seconds (0 = until turned off). | | brewTimeoutSec | 300 | How long to watch a brew for completion before releasing the link. |

Recipe options

| Field | Notes | |---|---| | name | Switch name / Siri phrase. | | cupType | xdripper, xpod, or other (sets the cup weight bounds). | | doseGrams | Beans to grind, 5–40 g. | | grinderSize | Grind setting, 1–80. | | rpm | Grinder speed: 60/70/80/90/100/110/120. | | ratio | Brew ratio (1:N), 1:5–1:25 in 0.5 steps (e.g. 17 for 1:17). | | pours[] | Ordered pour stages. Volumes should sum to doseGrams × ratio (see note below). | | pours[].volume | Water for this pour, ml. | | pours[].temperature | °C (40–100). | | pours[].flowRate | e.g. 3.5. | | pours[].pattern | 0 = center, 1 = circular, 2 = spiral. | | pours[].pausing | Seconds to pause after this pour. | | pours[].vibBefore / vibAfter | Optional grounds vibration. | | cupMax / cupMin | Advanced: explicit cup weight bounds (g), overrides cupType. |

Dose & ratio are the source of truth. The total water = doseGrams × ratio (e.g. 18 g × 17 = 306 ml), and your pour volumes should add up to that. If they don't, the plugin logs a warning at startup — the machine will still pour exactly the volumes you entered, but the actual ratio in the cup won't match what you set. Adjust the pour volumes to sum to dose × ratio, or change the dose/ratio.

Tip: dial in your recipe in the official xBloom app first, then copy the numbers (dose, grind, ratio, and each pour's water/temp/flow/pause/pattern) into the config.


Usage

  • Siri: "Hey Siri, turn on Morning Pour Over."
  • Automations: trigger a brew from a HomeKit automation (alarm, time of day, a button…).
  • The recipe switch turns itself off automatically when the brew finishes.
  • The xBloom Brewing sensor shows Open while grinding/brewing and reports a fault if the machine reports no beans, tank empty, or bad dose.

Remember the machine must be loaded (pod/grounds + cup + water) — Bluetooth only starts the program.


Bluetooth & the single-device limit

The xBloom connects to only one device at a time. If your phone's app is connected, the plugin can't connect, and vice-versa. This plugin is designed around that:

  • Connect-on-demand (automatic). The plugin holds no permanent connection. It connects only when you start a brew, streams status until the brew completes, then disconnects — so the machine is free for your phone the rest of the time. You don't have to do anything.
  • Manual override (optional). Enable exposeConnectionSwitch to get an xBloom Bluetooth switch:
    • On → the plugin connects and holds the link (e.g. to reserve it).
    • Off → releases it immediately, handing the machine back to your phone (even mid-brew — the machine keeps brewing on its own once started).
    • A safety holdTimeoutSec auto-releases the link so a manual hold never occupies the machine indefinitely.

If you try to brew while your phone is connected, the brew will fail to connect — just close the app (or disconnect it) and try again.


Troubleshooting

"No device advertising a name starting with XBLOOM was found" Auto-discovery couldn't see the machine. Make sure it's awake and not connected to your phone (one device at a time). If you have multiple xBloom machines, set an explicit deviceAddress (find it with bluetoothctl --timeout 12 scan le | grep -i xbloom).

Device not found / connect times out

  • The machine only advertises while awake and not connected to your phone. Wake it and disconnect the app, then retry.
  • Confirm the adapter is on: bluetoothctl showPowered: yes (bluetoothctl power on).

operation timed out or le-connection-abort-by-local Transient BLE hiccups, common right after another connect/disconnect. The plugin retries; if it persists, toggle the adapter (bluetoothctl power off && bluetoothctl power on).

Permission denied / org.bluez access Homebridge is running as a non-root user without a D-Bus policy. Add the policy in Linux / BlueZ setup and sudo systemctl reload dbus.

Docker: org.bluez was not provided by any .service files The plugin reached the container's D-Bus, which has no Bluetooth. Mount the host D-Bus socket and set the dbusAddress config option — see Docker Homebridge. (Two one-time steps; no container-wide environment variables needed.)

Wrong Node version Homebridge v2 requires Node 22 or 24. Check with node -v.

I just want to test without brewing Set dryRun: true. The plugin logs the exact frames it would send and never touches Bluetooth.


How it works

xBloom exposes a serial-style BLE service (0000e0ff-…) with a write characteristic (FFE1) and a notify characteristic (FFE2). A brew is the same four-frame sequence the official app sends — set dose, set cup bounds, send the recipe, execute — and the machine streams status codes back (grind/pour/complete, plus live weight and dispensed-ml telemetry). This plugin re-implements that protocol natively in TypeScript and validates it against real captures.

Credit to the reverse-engineering work in PyBloom and xbloom-ai-brew.


Support

If this saved you a few taps before coffee, you can support development here:

ko-fi.com/aziz66

Bug reports and PRs welcome on GitHub.


Disclaimer

This is an unofficial, community project. It is not affiliated with or endorsed by xBloom. Brewing involves heat, water, and moving parts — only trigger a brew when the machine is properly loaded and attended. The author is not responsible for any damage, mess, or under-caffeination resulting from use.

License

MIT © Abdulaziz Alharbi