Multiple identities via config subentries + regenerate + editable name
Refactor from one-entry-one-identity to a hub config entry (shared RNS stack) plus config subentries of type "identity", each an independent LXMF identity with its own LXMRouter, address, device and entities. This is required because LXMRouter allows only one delivery identity per instance. - ReticulumStack: owns the single process-wide RNS instance, peer discovery and interface telemetry (hub device). - IdentityManager: one per subentry, its own LXMRouter/identity/destination and delivery callback (identity device). Signal handlers suppressed and atexit handlers tamed for each router too. - Config subentry flow (add / reconfigure identity); a first identity is seeded on stack creation. Editable announce display name = subentry title. - Per-identity "Regenerate identity" button: new address + re-announce (clears the router's single delivery destination first). - Services and events gain an "identity" field to target/distinguish identities. - Per-identity assist bridge, greeting-when-assist-off, allow-list, notify, announce/sync buttons, message counters; hub-level connectivity/telemetry/peers. Verified against current HA config_entries/entity_platform/selector and RNS/LXMF sources. Docs and en/ru translations updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
129
README.md
129
README.md
@@ -75,69 +75,80 @@ directory and restart.
|
||||
|
||||
**Settings → Devices & Services → Add Integration → Reticulum.**
|
||||
|
||||
| Field | Meaning |
|
||||
You configure the shared **stack** once (the RNS connection), and a first LXMF
|
||||
**identity** is created automatically. Additional identities are added as
|
||||
**sub-entries** from the integration page.
|
||||
|
||||
| Stack 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 |
|
||||
| First identity name | Announce name of the first identity |
|
||||
|
||||
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:
|
||||
### Identities (sub-entries)
|
||||
|
||||
```
|
||||
Reticulum ready. LXMF address: a1b2c3… (Home Assistant)
|
||||
```
|
||||
Each identity is an independent LXMF address with its own settings, its own
|
||||
device, and its own entities. Add one via the integration's **⋮ → Add identity**
|
||||
(or reconfigure an existing one). Typical uses:
|
||||
|
||||
Add that address as a contact in Sideband/MeshChat and send a message — Assist
|
||||
will answer.
|
||||
- an **assistant** identity (Assist enabled) that users chat with;
|
||||
- a **receive-only** identity (Assist disabled) whose messages are handled by
|
||||
automations via the `reticulum_message_received` event.
|
||||
|
||||
### Options (⚙ → Configure)
|
||||
Per-identity settings:
|
||||
|
||||
- **Name** – contact name announced to peers (also the identity's HA name).
|
||||
Change it any time by reconfiguring the identity; future announces use it.
|
||||
- **Route incoming messages to Assist** – turn the chat bridge on/off.
|
||||
- **Assist agent / language** – pick the conversation agent from the dropdown.
|
||||
> **Want free-form chat?** The default *Home Assistant* agent only recognises
|
||||
> device-control commands and will answer anything else with "Sorry, I
|
||||
> couldn't understand that". To actually chat, install an LLM conversation
|
||||
> integration (OpenAI, Google Generative AI, Anthropic, Ollama, …), then
|
||||
> select that agent here.
|
||||
- **Reply to any sender** / **Allowed sender addresses** – restrict who Assist
|
||||
will answer.
|
||||
- **Default recipient** – address the `notify.reticulum_send_message` entity
|
||||
sends to (see Entities below).
|
||||
- **Greeting / auto-reply** – message sent automatically in reply to incoming
|
||||
messages **only when "Route incoming messages to Assist" is off** (so senders
|
||||
get an acknowledgement instead of silence). Blank = disabled.
|
||||
- **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** – `0`–`7`.
|
||||
> device-control commands. To chat, install an LLM conversation integration
|
||||
> (OpenAI, Google Generative AI, Anthropic, Ollama, …) and select it here.
|
||||
- **Reply to any sender** / **Allowed sender addresses** – restrict who is answered.
|
||||
- **Default recipient** – address this identity's notify entity sends to.
|
||||
- **Auto-reply (when Assist is off)** – message sent automatically in reply to
|
||||
incoming messages only when Assist routing is off. Blank = disabled.
|
||||
- **Default delivery method**, **announce interval**, **propagation node** +
|
||||
**sync interval**.
|
||||
|
||||
Stack-level options (**⚙ → Configure**): **Reticulum log level** (`0`–`7`).
|
||||
|
||||
Find each identity's **LXMF address** on its *LXMF address* sensor, or in the
|
||||
log (`Reticulum identity '…' ready: a1b2c3…`). Add it as a contact in
|
||||
Sideband/MeshChat and message it.
|
||||
|
||||
---
|
||||
|
||||
## Entities
|
||||
|
||||
**Hub (stack) device — `Reticulum`:**
|
||||
|
||||
| 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_send_message` | `notify` entity that sends an LXMF message to the **default recipient** set in options — use it in automations/scripts (`action: notify.send_message`) or the Developer Tools; for arbitrary addresses use the `reticulum.send_message` service |
|
||||
| `binary_sensor` Connected | Whether the TCP interface is online |
|
||||
| `sensor` Known peers | Count + `peers` attribute (address, name, hops) |
|
||||
| `sensor` Received / Transmitted | Interface RX/TX byte counters |
|
||||
| `sensor` Bitrate | Interface bitrate |
|
||||
| `sensor` RSSI / SNR / Link quality | Physical-link telemetry (disabled by default) |
|
||||
|
||||
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.
|
||||
**Per identity device (one per identity):**
|
||||
|
||||
| Entity | Description |
|
||||
|--------|-------------|
|
||||
| `sensor` LXMF address | This identity's address (share it with users) |
|
||||
| `sensor` Messages received / sent / failed | Counters |
|
||||
| `sensor` Last message | Last inbound text + source/title attributes |
|
||||
| `button` Announce | Announce this identity now |
|
||||
| `button` Sync propagation node | Pull queued messages now |
|
||||
| `button` Regenerate identity | Generate a brand-new address for this identity |
|
||||
| `notify` Send message | Sends an LXMF message from this identity to its **default recipient** (`action: notify.send_message`); for arbitrary addresses use the `reticulum.send_message` service |
|
||||
|
||||
RSSI, SNR and link quality only carry data on a physical interface (RNode/LoRa)
|
||||
— they stay unavailable on a plain TCP link, so they are disabled by default.
|
||||
|
||||
> **Regenerate identity** replaces this identity's address with a fresh one and
|
||||
> re-announces. The old address stops working — contacts must re-add the new one.
|
||||
|
||||
---
|
||||
|
||||
@@ -153,20 +164,26 @@ data:
|
||||
content: "The garage door is still open."
|
||||
title: "Home Assistant"
|
||||
method: direct # direct | opportunistic | propagated
|
||||
identity: "Home Assistant" # optional: which identity to send from (name or
|
||||
# LXMF address); defaults to the first identity
|
||||
```
|
||||
|
||||
Other services: `reticulum.announce`, `reticulum.request_path`,
|
||||
`reticulum.set_propagation_node`, `reticulum.sync_propagation`.
|
||||
`reticulum.set_propagation_node`, `reticulum.sync_propagation`. Each accepts an
|
||||
optional `identity` to pick which identity to act through.
|
||||
|
||||
---
|
||||
|
||||
## 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_message_received` — `{content, title, source, destination, timestamp, signature_validated, fields, identity, identity_name, local_address}`
|
||||
- `reticulum_message_delivered` — `{message_hash, destination, identity, identity_name, local_address}`
|
||||
- `reticulum_message_failed` — `{message_hash, destination, identity, identity_name, local_address}`
|
||||
- `reticulum_announce_received` — `{destination, display_name, stamp_cost, hops}`
|
||||
|
||||
`identity` is the subentry id and `identity_name` the identity's name, so
|
||||
automations can tell which identity received/sent a message.
|
||||
|
||||
### Example automation — forward every inbound message to a mobile push
|
||||
|
||||
```yaml
|
||||
@@ -213,15 +230,15 @@ action:
|
||||
|
||||
## 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, the running stack is reused across reloads. Changing the
|
||||
host/port (or recovering from a failed first start) therefore requires a
|
||||
**full Home Assistant restart**, not just an integration reload — a reload
|
||||
reuses the already-running stack. 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.
|
||||
- Reticulum uses a **single process-wide instance**, so only one Reticulum
|
||||
config entry (the stack) is allowed; add multiple **identities** as sub-entries
|
||||
under it. Because RNS/LXMF cannot be cleanly torn down inside a running
|
||||
process, the running stack and each identity's router are reused across
|
||||
reloads. Changing the host/port (or recovering from a failed first start)
|
||||
therefore requires a **full Home Assistant restart**, not just a reload.
|
||||
- Each identity is stored in `config/reticulum/identities/<subentry_id>/identity`
|
||||
— back it up to keep the same address. **Regenerating** an identity overwrites
|
||||
it with a new address.
|
||||
- RNS and LXMF are standalone-daemon-style libraries — both install
|
||||
SIGINT/SIGTERM handlers and `atexit` persistence in their constructors. To
|
||||
embed them cleanly the integration suppresses those signal handlers during
|
||||
|
||||
Reference in New Issue
Block a user