Files
ha-reticulum/README.md
claude b40c527515 Add Reticulum/LXMF integration for Home Assistant
Custom integration connecting Home Assistant to a Reticulum network over a
TCPClientInterface and exchanging LXMF messages, with an Assist conversation
bridge, notify entity, sensors (incl. interface telemetry), buttons, services,
bus events and device triggers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 18:08:12 +03:00

8.0 KiB
Raw Blame History

Reticulum for Home Assistant

A Home Assistant custom integration that connects Home Assistant to a Reticulum network over TCP and exchanges LXMF messages with users.

The headline feature: a user can chat with the Home Assistant Assist agent over Reticulum. Any LXMF client (Sideband, MeshChat, Nomad Network) can send a message to Home Assistant's address; the text is routed through the Assist conversation pipeline and the answer is sent straight back — over LoRa, packet radio, I2P, TCP, or anything else Reticulum runs on.

It also exposes a notify entity, a rich service API, sensors, and bus events so LXMF messaging can drive and be driven by automations.


How it fits together

┌────────────────────────┐        TCP         ┌─────────────────────────┐
│ Home Assistant (k8s)    │  TCPClientInterface│  Neighbouring machine    │
│                         │ ─────────────────► │  Reticulum instance      │
│  reticulum integration  │                    │  (TCPServerInterface)    │
│  • runs its own RNS     │ ◄───────────────── │  + any other interfaces  │
│  • LXMF delivery dest.  │                    │  (LoRa / RNode / I2P …)  │
│  • Assist bridge        │                    └─────────────────────────┘
└────────────────────────┘

Home Assistant runs a standalone, non-shared Reticulum instance inside its own process and reaches the wider network through the single TCPClientInterface pointing at the neighbouring stack. No shared-instance socket is used, which is what you want inside a container/pod.


Requirements

  • Home Assistant 2024.11 or newer.

  • A reachable Reticulum instance on another machine with a TCPServerInterface enabled. Example ~/.reticulum/config on that machine:

    [interfaces]
      [[TCP Server Interface]]
        type = TCPServerInterface
        enabled = yes
        listen_ip = 0.0.0.0
        listen_port = 4242
    

    In Kubernetes, expose that port to the HA pod (Service / NodePort / host networking as appropriate). Do not enable kiss_framing on either side.

The integration declares its Python dependencies (rns, lxmf) in manifest.json; Home Assistant installs them automatically on first setup.


Installation

HACS (custom repository)

  1. HACS → ⋮ → Custom repositories.
  2. Add this repository URL, category Integration.
  3. Install Reticulum, then restart Home Assistant.

Manual

Copy custom_components/reticulum into your Home Assistant config/custom_components/ directory and restart.


Configuration

Settings → Devices & Services → Add Integration → Reticulum.

Field Meaning
Target host Host/IP of the neighbouring Reticulum TCP server
Target port Its listen_port (default 4242)
Display name Name announced to other peers (e.g. Home Assistant)
Interface name Label for the connection in the generated RNS config

On first start the integration generates a stable identity and announces it. Find your LXMF address on the LXMF address sensor, or in the log:

Reticulum ready. LXMF address: a1b2c3… (Home Assistant)

Add that address as a contact in Sideband/MeshChat and send a message — Assist will answer.

Options (⚙ → Configure)

  • Route incoming messages to Assist turn the chat bridge on/off.
  • Assist agent / language pick a specific conversation agent, or leave blank for the default pipeline.
  • Reply to any sender / Allowed sender addresses restrict who Assist will answer.
  • Default recipient address used by the notify.reticulum entity.
  • Default delivery method direct, opportunistic, or propagated.
  • Announce interval periodic re-announce (seconds; 0 disables).
  • Propagation node + sync interval optional store-and-forward node so messages queue while HA is offline.
  • Reticulum log level 07.

Entities

Entity Description
sensor.reticulum_lxmf_address This HA's LXMF address (share this with users)
sensor.reticulum_messages_received / _sent / _failed Counters
sensor.reticulum_known_peers Count + peers attribute (address, name, hops)
sensor.reticulum_last_message Last inbound text + source/title attributes
sensor.reticulum_last_message_time Timestamp of last inbound message
sensor.reticulum_received / _transmitted Interface RX/TX byte counters
sensor.reticulum_bitrate Interface bitrate
sensor.reticulum_rssi / _snr / _link_quality Physical-link telemetry (disabled by default)
binary_sensor.reticulum_connected Whether the TCP interface is online
button.reticulum_announce Announce now
button.reticulum_sync_propagation_node Pull queued messages now
notify.reticulum_message Send a message to the default recipient

The telemetry sensors read from the outbound interface. RX/TX bytes and bitrate work for the TCP link. RSSI, SNR and link quality only carry data when the underlying interface is a physical one (RNode/LoRa) — they stay unavailable on a plain TCP link, so they are disabled by default. Enable them from the device page if you run a physical interface.


Services

reticulum.send_message

Send to any destination. Returns the message hash.

action: reticulum.send_message
data:
  destination: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
  content: "The garage door is still open."
  title: "Home Assistant"
  method: direct        # direct | opportunistic | propagated

Other services: reticulum.announce, reticulum.request_path, reticulum.set_propagation_node, reticulum.sync_propagation.


Events

  • reticulum_message_received{content, title, source, destination, timestamp, signature_validated, fields}
  • reticulum_message_delivered{message_hash, destination}
  • reticulum_message_failed{message_hash, destination}
  • reticulum_announce_received{destination, display_name, stamp_cost, hops}

Example automation — forward every inbound message to a mobile push

alias: Reticulum → phone
trigger:
  - platform: event
    event_type: reticulum_message_received
action:
  - action: notify.mobile_app_phone
    data:
      title: "Reticulum: {{ trigger.event.data.source[:8] }}"
      message: "{{ trigger.event.data.content }}"

Device triggers (automation UI)

Instead of raw event triggers you can pick these from the automation editor under the Reticulum device ("When… → Reticulum → …"):

  • Message received
  • Message delivered
  • Message delivery failed
  • Announce received (peer heard)

Each wraps the matching bus event, so trigger.event.data carries the same payload described above.

Example automation — alert over Reticulum when a door opens

alias: Door alert over Reticulum
trigger:
  - platform: state
    entity_id: binary_sensor.front_door
    to: "on"
action:
  - action: reticulum.send_message
    data:
      destination: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
      content: "Front door opened at {{ now().strftime('%H:%M') }}"

Notes & limitations

  • Reticulum uses a single process-wide instance. Only one Reticulum config entry is allowed, and because RNS/LXMF cannot be cleanly torn down inside a running process, changing the host/port or fully restarting the stack requires restarting Home Assistant. Option changes that don't touch the stack apply on reload.
  • The identity is stored in config/reticulum/identity — back it up to keep the same address.
  • Assist replies use the standard conversation pipeline, so whichever agent you select (built-in intents, a local LLM, a cloud LLM, …) is what answers.

License

MIT