https://github.com/tostmann/headlessccu
HomeMatic CCU stack without WebUI / ReGaHss — bmcond + rfd + HMIPServer.jar packaged as Home Assistant add-on and plain Docker image.
https://github.com/tostmann/headlessccu
bmcond ccu docker home-assistant home-assistant-addon homematic homematic-ip raspberrymatic
Last synced: 14 days ago
JSON representation
HomeMatic CCU stack without WebUI / ReGaHss — bmcond + rfd + HMIPServer.jar packaged as Home Assistant add-on and plain Docker image.
- Host: GitHub
- URL: https://github.com/tostmann/headlessccu
- Owner: tostmann
- License: other
- Created: 2026-05-12T18:22:40.000Z (about 2 months ago)
- Default Branch: master
- Last Pushed: 2026-06-07T16:57:38.000Z (28 days ago)
- Last Synced: 2026-06-07T18:27:06.997Z (28 days ago)
- Topics: bmcond, ccu, docker, home-assistant, home-assistant-addon, homematic, homematic-ip, raspberrymatic
- Language: Python
- Size: 153 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# headlessCCU
HomeMatic CCU **without the WebUI / ReGaHss**. Bundles
[bmcond](https://github.com/tostmann/bmcond) + eQ-3's `rfd` +
`HMIPServer.jar` + a JSON-RPC stub for `aiohomematic` in a single
container.
This repository follows the Home Assistant **Add-On Repository**
layout: `repository.yaml` at the root, and the actual add-on under
`headlessccu/`. Both the HA-Supervisor "Add Repository" UI and a
plain `docker compose` from the subdirectory work out of the box.
Two distribution paths from the same image:
- **Home Assistant Add-On** (HA Supervisor / HAOS) — install via the
Add-On store, configure via UI, [`homematicip_local`](https://github.com/SukramJ/homematicip_local)
connects to it locally.
- **Plain Docker / docker-compose** — on any host with Docker and an
HmIP-RFUSB stick plugged in. Speaks XML-RPC on `:2001` (BidCoS) and
`:2010` (HmIP) plus JSON-RPC on `:8765`, so any consumer (Home
Assistant `homematicip_local`, ioBroker, Homegear, NodeRED, custom
scripts) just connects.
## Why not the regular CCU?
The eQ-3 CCU stack pulls in ReGaHss (Tcl logic engine), HMServer.jar,
WebUI, eshlight, and a few hundred MB of Tcl/web assets — none of which
are needed when Home Assistant is your automation engine. headlessCCU
strips the stack down to just the parts that actually move RF frames:
```
┌─────────────────────────────────────────────────────────────┐
│ Home Assistant (or any XML-RPC consumer) │
└──┬──────────────────────────────────────────────────────────┘
│ XML-RPC :2001 (BidCoS), :2010 (HmIP), JSON-RPC :80 / :8765
┌──▼──────────────────────────────────────────────────────────┐
│ headlessCCU container │
│ ┌────────────┐ ┌────────────┐ ┌─────────────────────┐ │
│ │ rfd │ │ HMIPServer │ │ rega_session_mock │ │
│ │ (BidCoS) │ │ (HmIP) │ │ (aiohomematic stub) │ │
│ └─────┬──────┘ └──────┬─────┘ └─────────────────────┘ │
│ /dev/mmd_bidcos /dev/mmd_hmip ↑ JSON-RPC :8765 │
│ ▲ ▲ (Session.login etc.) │
│ └─────────┬────────┘ │
│ multimacd │
│ (eq-3 Mac-Layer: DUTY, CSMA, AES, demux) │
│ │ │
│ /dev/raw-uart (PTY) │
│ │ │
│ bmcond │
│ (userspace transport — libusb / UDP / TCP / UART) │
└────────────┬───────────────────────────────────────────────┘
│ libusb-direct /dev/bus/usb
┌─────▼─────┐
│ HmIP-RFUSB │
└────────────┘
```
`bmcond` claims `/dev/bus/usb`, detaches whatever kernel driver had
bound the stick, and exposes the radio's wire bytes as a PTY symlink.
`multimacd` opens that PTY as its `Coprocessor Device Path` and
handles all Mac-Layer concerns (DUTY-cycle, CSMA, AES, retransmits,
LLMAC ↔ APP translation, BidCoS / HmIP demuxing). No
`/dev/ttyUSB0`, no udev rule, no `cp210x` module blacklist needed for
the default path. An HA-side `rega_session_mock` answers the
JSON-RPC calls `aiohomematic` issues during setup — no ReGaHss
running on the container side.
## Quick install — Home Assistant Add-On (HAOS)
This is the recommended path on HAOS / Home Assistant Supervisor.
**Step 1 — Add this repository to the Add-On store.**
1. Settings → Add-ons → Add-on Store
2. Click the three-dots menu (top right) → **Repositories**
3. Paste `https://github.com/tostmann/headlessCCU` → **Add**, then close
**Step 2 — Install the add-on.**
1. The repository panel now appears at the bottom of the Add-on Store.
Click **headlessCCU**.
2. Click **Install**. HA Supervisor builds the image locally; this
takes ~5 minutes on a Raspberry Pi 5 because eQ-3 binaries are
fetched at build time from `apt.debmatic.de` (no eQ-3 closed-source
blobs are vendored into this repository).
3. Once installed, plug in your **eQ-3 HmIP-RFUSB** stick if it isn't
already (USB-ID `1b1f:c020`).
**Step 3 — Defaults work out of the box.**
The default `hmid: "auto"` makes the add-on roll a random 3-byte
gateway address on first start and persist it. Default transport
`usb=1b1f:c020` opens the HmIP-RFUSB via libusb directly. No
configuration is required for a single-stick setup.
If you have more than one CCU-like instance in the same LAN, or you
want to migrate pairings from an existing eQ-3 / debmatic install, set
the `hmid` option to a fixed 6-hex value.
**Step 4 — Start the add-on.**
1. Toggle **Start on boot** and **Watchdog** on.
2. Press **Start**.
3. Open **Log**. You should see a banner with the firmware bundle
version, an `eQ-3 HmIP-RFUSB` backend coming up via libusb, and
`── BusMatic-HASS up ──` after ~30 s.
4. Open **headlessCCU** in the HA sidebar (Ingress panel) — the bmcond
web UI shows the source inventory and slot mapping.
**Step 5 — Connect Home Assistant.**
Install the `homematicip_local` custom integration (e.g. via HACS).
Then **Settings → Devices & Services → Add Integration → HomematicIP
Local**:
| Field | Value |
| --- | --- |
| Instance name | `headlessccu` (or whatever) |
| Host | `172.30.32.1` (the HA Supervisor bridge gateway) |
| Username / Password | anything — the mock accepts any credentials |
| `custom_port_config` | leave off — defaults work |
The integration auto-detects both `BidCos-RF` and `HmIP-RF` interfaces.
Confirm the device list (initially empty) and finish setup.
**Step 6 — Pair your first device.**
In Home Assistant, **Settings → Devices & Services → HomematicIP Local
→ … (kebab) → Reload** to make the integration register interfaces.
To put the gateway into pair mode:
```bash
# in any host with access to the HA host:
curl -X POST http://172.30.32.1:2001/ \
-d 'setInstallMode160'
curl -X POST http://172.30.32.1:2010/ \
-d 'setInstallMode160'
```
Press the pair button on your HM-Classic or HmIP device. Once the
device announces itself, it appears as a new entity in HA within a few
seconds.
## Quick install — Plain Docker / docker-compose
```bash
git clone https://github.com/tostmann/headlessCCU
cd headlessCCU/headlessccu # add-on lives in a subdir (HA-repo layout)
./build.sh # builds headlessccu:dev image (~5 min)
docker compose up -d
```
`docker-compose.yml` sets `network_mode: host` (required so XML-RPC
callbacks from `rfd` reach Home Assistant) and passes
`/dev/bus/usb` through to the container. See the file for the full
port and environment-variable layout.
`build.sh` pulls the matching [bmcond](https://github.com/tostmann/bmcond)
version (default `2026.5.1`, override via `BMCOND_VERSION=main ./build.sh`)
and the pinned eq-3 bundle (`DEBMATIC_VERSION=3.85.7-123` by default;
override via `DEBMATIC_VERSION=latest ./build.sh`) at Docker-build time —
no local source-staging required.
Verify with the included smoke test (in this repo's parent project):
```bash
curl http://localhost:9126/api/effective | jq .running
```
should print a `version` and a non-zero `uptime_s`.
## Configuration options
| Option | Default | Description |
| --- | --- | --- |
| `hmid` | `auto` | `auto` = random 3-byte hex on first start, persisted to `/data/etc-config/ids`. Or a fixed 6-hex string |
| `serial` | `BMC0000001` | 10-char gateway serial reported to clients |
| `firmware` | `2.8.6` | Firmware version reported to clients |
| `bidcos_radio` | `usb=1b1f:c020` | Transport for the BidCoS plane |
| `hmip_radio` | `usb=1b1f:c020` | Transport for the HmIP plane. Empty or `none` = HmIP disabled |
| `loglevel` | `3` | `rfd` loglevel (0–5) |
| `log_level_mock` | `INFO` | `rega_session_mock` Python logging level |
Transport-string formats: `usb=VID:PID` (libusb-direct),
`rfusb=/dev/ttyXXX` (kernel-driver UART), `host:port` (TCP, e.g.
CULFW32 or HM-LGW2), `udp=host:port` (HB-RF-ETH / RFNetHM).
For HA Supervisor: configurable via the Add-On UI. Plain Docker:
environment variables in `docker-compose.yml`.
## BidCoS-only setup (HmIP disabled)
Set `hmip_radio` to empty or `none`. Effects:
- `bmcond` runs without an HmIP PTY (no `/tmp/mmd_hmip`).
- `HMIPServer.jar` is not started; port 2010 returns no service.
- `confgen` writes `InterfacesList.xml` without the `HmIP-RF` slot, so
`aiohomematic` only registers the BidCoS interface.
Useful for HM-Classic-only deployments — e.g. when the only RF source
is a CULFW32 acting as a BidCoS gateway over `_hmuartlgw._tcp:2327`.
## Legacy: cp210x-via-kernel path
If you want to keep the old kernel-driver path (e.g. coexisting with
another tool that owns `/dev/ttyUSB0`), set
`bidcos_radio: "rfusb=/dev/ttyUSB0"` in the options and apply this
one-time host setup:
```bash
# /etc/modprobe.d/blacklist-eq3.conf
blacklist hb_rf_usb_2
blacklist hb_rf_usb
blacklist generic_raw_uart
# /etc/modules-load.d/cp210x.conf
cp210x
# /etc/udev/rules.d/70-hmip-rfusb-cp210x.rules
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="1b1f", ATTRS{idProduct}=="c020", \
RUN+="/sbin/modprobe cp210x", \
RUN+="/bin/sh -c 'echo 1b1f c020 > /sys/bus/usb-serial/drivers/cp210x/new_id'"
```
Re-plug the stick after udev reload — `ls -l /dev/ttyUSB0` should now
appear. The container then receives it via
`--device /dev/ttyUSB0:/dev/ttyUSB0`.
## License
GPL-2.0-or-later — see [LICENSE](LICENSE).
> The Docker image *built* by this repo bundles eQ-3 closed-source
> binaries fetched from `apt.debmatic.de`. Do **not redistribute the
> built image publicly** — each user builds locally from upstream
> debmatic, which is what Alexander Reinert's packaging
> ([alexreinert/debmatic](https://github.com/alexreinert/debmatic)) is
> designed for.
## Project context
Part of the BusMatic effort by Dirk Tostmann
([@tostmann](https://github.com/tostmann)). `bmcond`
([github.com/tostmann/bmcond](https://github.com/tostmann/bmcond))
provides the userspace radio transport layer; this repo wraps it
together with eQ-3's `multimacd`, `rfd` and `HMIPServer.jar` into a
single container for HA / Docker consumption.