Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

28 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

C100X Dashboard

Changelog: c100x_dashboard/CHANGELOG.md

C100X Dashboard

The integration ships its own icon in custom_components/c100x_dashboard/brand/ (Home Assistant 2026.3+).

Design custom screens for a BTicino Classe 100X video intercom and push them to its display from Home Assistant โ€” with live sensor values. Compose screens by dragging elements onto an 800ร—480 canvas in a web editor; the intercom shows the active screen and refreshes the values every second.

๐Ÿ‡ฎ๐Ÿ‡น Leggi in italiano

Editor screenshot

About this project โ€” authorship. Roughly 99% of this project was written by Claude (Anthropic's AI), working from the goals, testing, and on-device feedback provided by the repository owner. The owner directed the design, ran everything against real hardware, and validated each step; the code, the QML, the add-on and the integration were produced by Claude.

What's in here

  • Add-on (c100x_dashboard/) โ€” a Home Assistant add-on that is both the editor (web UI) and the server the intercom polls. It reads entity values from HA, renders Jinja2 templates, and serves the active screen, images and icons over HTTP.
  • Intercom side (c100x_dashboard/citofono/) โ€” SchedaPage.qml, the renderer that runs on the intercom, plus the patch scripts. Can be installed automatically from the add-on via SSH.
  • Integration (custom_components/c100x_dashboard/) โ€” an optional Home Assistant integration that adds services (show, hide, set_active) so you can trigger screens by name from automations.

How it works

Editor (add-on) โ”€โ”€saveโ”€โ”€> screen layouts (JSON)
                                โ”‚
HA automation / Node-RED โ”€showโ”€> add-on โ”€โ”€GET /activeโ”€โ”€> intercom (polls ~1s)
                                  โ”‚                          โ”‚
                                  โ””โ”€ reads HA entity values โ”€โ”˜ values refresh live

The intercom polls http://<add-on>:8099/active every second. When you "show" a screen, the intercom wakes and displays it; values update on screen while it stays up. You can hide it on command (handy for "show during a blackout, hide when power is back").

Requirements

  • A BTicino Classe 100X with SSH access and the community controller (fquinto/bticinoClasse300x / slyoldfox/c300x-controller).
  • Home Assistant with the Supervisor (Home Assistant OS or Supervised), needed to run add-ons.
  • The intercom and HA on the same LAN; the intercom must be able to reach HA over HTTP.
  • Node.js present on the intercom (it ships with the controller setup) for the QML patch step.

Install the add-on

As a local add-on (simplest):

  1. Copy the c100x_dashboard/ folder into your Home Assistant /addons/ directory (via the Samba, SSH & Web Terminal or Studio Code Server add-ons).
  2. Settings โ†’ Add-ons โ†’ Store โ†’ โ‹ฎ โ†’ Check for updates. It appears under Local add-ons.
  3. Open it โ†’ Install (the first build also downloads the MDI icon set), then Start.
  4. The editor shows up in the HA sidebar (Ingress). It's also at http://IP_HA:8099/.

As an add-on repository (one click for others): push this repo to GitHub, then in HA add the repo URL under Store โ†’ โ‹ฎ โ†’ Repositories. The add-on installs from there.

To ship changes, bump version: in config.yaml: Home Assistant then offers an Update for the add-on (Settings โ†’ Add-ons โ†’ Store โ†’ โ‹ฎ โ†’ Check for updates). The add-on's โ‹ฎ โ†’ Rebuild is only needed to force a fresh build without a version change.

Use the editor

Elements โ€” add from the palette: text, sensor value, entity icon, template, image, icon, shapes, line, arrow.

  • Sensor value: search the entity (autocomplete) and get a live preview. Optionally show a specific attribute instead of the state, append the unit of measurement automatically, and format dates/times (e.g. DD/MM/YYYY, HH:mm).
  • Entity icon: icon and colour follow the entity state. You can force a specific icon while keeping the state-driven colour, or drive the colour from a conditional template.
  • Template: write Jinja2 with basic markdown (bold, italic, headings, lists, line breaks), rendered like a Lovelace markdown card. A second template can set the colour conditionally (a direct colour, or true/false โ†’ two configurable colours).

Intercom buttons โ€” click a key on the on-screen intercom to bind a Home Assistant action to it. The front keys (1โ€“4, โ˜…, lock, eye), the wheel (up/down/OK) and both handsets are supported. Each button can show an on-screen message (which may contain Jinja2 for dynamic text) and optionally light up on press. Action data may also contain Jinja2 templates.

Editing โ€” drag to move, bottom-right handle to resize, top handle to rotate. Extras:

  • Arrow keys move by 1px (Shift = 10px), PgUp/PgDn change stacking order, Del removes.
  • Select several elements (Shift-click or rubber-band) to align them; group with Ctrl+G, ungroup with Ctrl+Shift+G.
  • Zoom with the wheel, pan with the middle mouse button, double middle-click to reset.

Screens โ€” name the layout and Save; press Show now (with a duration) to display it on the intercom. From the home screen you can export all screens to a backup file and import them back โ€” handy so you don't lose your work if you reinstall the add-on.

Install on the intercom

Press Intercom in the editor, enter the intercom's SSH host/user/password and the add-on URL as the intercom sees it (e.g. http://192.168.1.10:8099), then Install / update. This uploads SchedaPage.qml, patches main.qml (with a backup), patches MainPage.qml โ€” the native default menu โ€” to enable wheel navigation there too (a single added property, backed up first), uploads the live-view component and the ptrace-inject button-injection tool (see below), replaces the c300x-controller bundle on the intercom with a build that adds start/stop support for both (original bundle backed up first, its :8080 page also got a small visual refresh and is now fully in English), and reboots. A checkbox lets you store the SSH password in the add-on or be asked each time.

Prefer manual install? See c100x_dashboard/citofono/README.md.

Live screen view & remote control

Press Live in the editor for a real, interactive mirror of the intercom's screen: the add-on proxies a WebSocket connection through to a small VNC server on the intercom, and noVNC (a mature, vendored library) handles the actual protocol in the browser โ€” this replaced an earlier, simpler approach (the add-on polling a still image) that turned out to be too heavy for the intercom's weak CPU and could lock up its VNC server under load.

While it's open you also get a button panel (1-7, wheel up/down/OK, answer/hang up/mute) that really presses the intercom's own buttons at the system level: a small tool (ptrace-inject) attaches to the intercom's graphics process and injects the press directly into its system calls, indistinguishable from a physical press as far as the firmware is concerned. Unlike an approach based on calling QML functions, this works everywhere โ€” inside screens created with this add-on, and in the intercom's native default menu too.

This needs the custom controller bundle mentioned above (it's what starts/stops both the VNC server and the injector on the intercom), so both are part of the standard SSH install now, not optional.

A small backlight indicator (screen on/off) is always visible both in the live view and in the editor's top bar, reflecting the intercom's real state.

A note on risk. System-level injection via ptrace is inherently more invasive than a plain QML function call โ€” during development it caused one intercom reboot (not reproduced since, after a fix: it now delivers one input event at a time, matching how the real device driver behaves). For this reason the injector is only started while the Live view is open, and stopped a few seconds after you close it or lose connection โ€” it is not meant to run as a permanent background service.

Install the integration (optional)

The integration is separate from the add-on and is not installed automatically โ€” the add-on can't write into HA's custom_components/. You only need it if you want the convenient show / hide / set_active services in your automations, or the sensor/light entities below; without it you can still drive the add-on over REST (see below).

  1. Copy custom_components/c100x_dashboard/ into your HA config/custom_components/ (or add this repo to HACS as a custom integration).
  2. Restart Home Assistant.
  3. Settings โ†’ Devices & Services โ†’ Add integration โ†’ C100X Dashboard, and enter the add-on URL (e.g. http://192.168.1.10:8099).

See custom_components/c100x_dashboard/CHANGELOG.md for the integration's own version history (independent of the add-on's).

Entities exposed by the integration

Besides the show/hide/set_active services, the integration creates a few entities under the same device:

  • Intercom renderer (update.*) โ€” tracks whether the QML patch on the intercom matches the one shipped by this add-on version.
  • Pagina attiva (sensor.*) โ€” which screen is actually showing on the physical display right now (idle when the screen is free: home, closed via the side wheel, turned off by the intercom's native standby, or interrupted by a real call). Polled every 2s against a value the add-on already keeps in memory โ€” pushed live by the patched QML and cross-checked against the physical backlight read from sysfs, so it doesn't stay stuck on a screen name once the display is truly off โ€” so this has no extra impact on the intercom itself.
  • Citofono occupato (binary_sensor.*) โ€” on while the intercom's camera is in use, for any reason: a real doorbell press, the WebRTC bundle, the BTicino app locally, or the BTicino app over LTE. Detected at the OpenWebNet bus level, not the network level, so it covers all of the above with a single mechanism. Requires MQTT โ€” see below.
  • Ponte MQTT citofono online (binary_sensor.*) โ€” whether the MQTT bridge below is reachable.
  • Retroilluminazione display (light.*) โ€” the intercom display's backlight. Reflects the real state (read every ~2s) and can be turned on/off directly from Home Assistant.

MQTT-based occupancy detection (optional)

"Citofono occupato" needs two things you set up yourself, both optional:

  1. Home Assistant's own MQTT integration, configured against the same broker the intercom can reach.
  2. TcpDump2Mqtt installed and running on the intercom (/etc/tcpdump2mqtt), publishing raw OpenWebNet traffic to Bticino/tx and its own online/offline status to Bticino/LastWillT.

If either piece is missing, both entities degrade gracefully instead of breaking the integration:

  • No MQTT integration configured in HA โ†’ both entities stay unavailable, with a one-time warning in the HA log.
  • MQTT configured but the bridge never publishes โ†’ citofono_occupato defaults to off (assumes free) and ponte_mqtt_citofono_online stays unknown until the bridge's retained Last Will message arrives.

Known gotcha on the intercom side: TcpDump2Mqtt's own startup script checks for a default gateway only once; on a slow Wi-Fi reconnect after a reboot it can give up before wlan0 gets an IP, and nothing restarts it afterwards. If binary_sensor.ponte_mqtt_citofono_online stays off after a reboot, SSH in and run /etc/tcpdump2mqtt/TcpDump2Mqtt.sh again โ€” or patch the gateway check into a retry loop (see c100x_dashboard/citofono/README.md).

Trigger screens from Home Assistant

With the integration. Once installed (see above), you get these actions:

# Show a named screen, keep it until hidden
action: c100x_dashboard.show
data:
  name: consumi
  duration: 0

# Hide whatever is on screen
action: c100x_dashboard.hide

# Just set the active screen (without showing)
action: c100x_dashboard.set_active
data:
  name: consumi

Without the integration (REST). The add-on is a small REST server, so two calls work from Node-RED (http request nodes) or HA rest_command:

rest_command:
  citofono_mostra:
    url: "http://192.168.1.10:8099/api/show"
    method: POST
    content_type: "application/json"
    payload: '{"name":"{{ name }}","duration":{{ duration | default(0) }}}'
  citofono_nascondi:
    url: "http://192.168.1.10:8099/api/hide"
    method: POST

Main endpoints

Method Endpoint Purpose
GET / editor (Ingress)
GET/PUT/DELETE /api/layouts[/:name] list / save / delete layouts
GET /api/layout-live/:name layout with values resolved to the current state (thumbnails)
GET/POST /api/export ยท /api/import back up / restore all screens
POST /api/template-preview render a Jinja2 template for the editor preview
POST /api/active set the active layout
POST /api/show show now ({name?, duration?})
POST /api/hide hide
GET/POST /api/scheda-state what's actually on screen right now ({name} or {state:"idle"}), reported live by the patched QML
GET /api/entities ยท /api/icons ยท /api/entity-icons autocomplete sources
GET /icon/:name ยท /image/:name ยท /ha-image/:name icons / images for editor + intercom
POST /api/citofono/install upload + patch + reboot via SSH
POST /api/live/start ยท /api/live/stop start/stop the live view (VNC + button injector) on the intercom
WS /api/live/ws WebSocketโ†”TCP proxy to the intercom's VNC server, consumed by noVNC
POST /api/live/button press/release a real intercom button ({button, phase}) โ€” proxied to the controller's ptrace-inject endpoint
GET/POST /api/backlight-state current backlight state, reported live by the patched QML
GET/POST /api/backlight-command request the intercom to turn the backlight on/off
GET /active for the intercom: active layout with resolved values

Notes & limits

  • Port 8099 is exposed on the LAN without auth (the intercom must reach it). Fine on a home LAN.
  • The intercom's display has a limited colour gamut: flat graphics, icons and shapes look great; photographic images may shift in colour.
  • Only MDI icons are supported (HA's built-in set); custom icon packs aren't served to the intercom.
  • Template elements support basic markdown (bold, italic, headings, lists, line breaks): the intercom renders an HTML subset (Qt 5 RichText), so very complex markdown may not render exactly.
  • The SSH password, if saved, is stored in the add-on's /data in clear text and never returned to the browser.
  • The live view uses real CPU on the intercom (VNC server + button injector): fine for occasional use, but not meant to be left running continuously โ€” see the risk note above about ptrace.

Credits

This project stands on the shoulders of prior reverse-engineering work by the BTicino intercom community:

  • slyoldfox/c300x-controller โ€” the on-device controller this project relies on (Node runtime, HTTP endpoints, Home Assistant bridge).
  • slyoldfox/c300x-dashboard โ€” the inspiration: a controller-fed QML dashboard for the C300X (Qt 4.8.7 / QtQuick 1.x). Since it states "Bticino c100x devices are untested" and targets a different Qt/QtQuick generation, the renderer here was written from scratch for the C100X (Qt5 / QtQuick 2.x).
  • fquinto/bticinoClasse300x โ€” the modified firmware that makes root/SSH access possible.
  • novnc/noVNC โ€” the VNC client library (vendored) that powers the live screen view in the browser.
  • Roboto (Apache License 2.0) โ€” the bundled UI font, shared by the editor and the intercom renderer.

License

MIT โ€” see LICENSE.

About

Compose live Home Assistant dashboards on a BTicino Classe 100X video intercom display

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages