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:
claude
2026-07-22 20:29:05 +03:00
parent c3b98043f7
commit 027ff685b7
16 changed files with 1572 additions and 1069 deletions

View File

@@ -3,18 +3,18 @@
"step": {
"user": {
"title": "Connect to Reticulum",
"description": "Home Assistant will run a Reticulum instance and connect out to your Reticulum stack over TCP (the neighbouring machine must expose a TCPServerInterface).",
"description": "Home Assistant will run a Reticulum instance and connect out to your Reticulum stack over TCP. A first LXMF identity is created automatically; add more later from the integration page.",
"data": {
"target_host": "Target host",
"target_port": "Target port",
"display_name": "Display name",
"interface_name": "Interface name"
"interface_name": "Interface name",
"display_name": "First identity name"
},
"data_description": {
"target_host": "Hostname or IP of the machine running the Reticulum TCP server.",
"target_port": "TCP port of the Reticulum TCPServerInterface (default 4242).",
"display_name": "Name announced to other Reticulum peers for this Home Assistant.",
"interface_name": "Label used for this connection in the Reticulum config."
"interface_name": "Label used for this connection in the Reticulum config.",
"display_name": "Announce name of the first LXMF identity."
}
}
},
@@ -23,39 +23,81 @@
},
"abort": {
"already_configured": "Reticulum is already configured.",
"single_instance_allowed": "Only a single Reticulum instance is allowed."
"single_instance_allowed": "Only a single Reticulum stack is allowed. Add more identities to the existing one."
}
},
"options": {
"step": {
"init": {
"title": "Reticulum options",
"title": "Reticulum stack options",
"data": {
"enable_assist": "Route incoming messages to Assist",
"assist_agent": "Assist agent (entity id / agent id, blank = default)",
"assist_language": "Assist language (blank = system default)",
"allow_all_senders": "Reply to any sender",
"allowed_identities": "Allowed sender addresses",
"default_recipient": "Default recipient address (for the notify entity)",
"greeting": "Auto-reply message (when Assist is off)",
"delivery_method": "Default delivery method",
"announce_interval": "Announce interval",
"propagation_node": "Propagation node address",
"sync_interval": "Propagation sync interval",
"loglevel": "Reticulum log level (0-7)"
},
"data_description": {
"enable_assist": "When enabled, incoming LXMF messages are answered by the Assist conversation agent and the reply is sent back over Reticulum.",
"allowed_identities": "One address per line (or comma separated). Only used when 'Reply to any sender' is off.",
"default_recipient": "16-byte hex LXMF address that the notify.reticulum entity sends to.",
"greeting": "Sent as an automatic reply to incoming messages only when 'Route incoming messages to Assist' is turned off. Leave blank to disable.",
"announce_interval": "How often (seconds) to announce our address. 0 disables periodic announces.",
"propagation_node": "Optional LXMF propagation node for store-and-forward delivery.",
"sync_interval": "How often (seconds) to pull queued messages from the propagation node. 0 disables."
}
}
}
},
"config_subentries": {
"identity": {
"initiate_flow": {
"user": "Add identity",
"reconfigure": "Reconfigure identity"
},
"entry_type": "LXMF identity",
"step": {
"user": {
"title": "Add LXMF identity",
"data": {
"display_name": "Name (announced to peers)",
"enable_assist": "Route incoming messages to Assist",
"assist_agent": "Assist agent",
"assist_language": "Assist language",
"allow_all_senders": "Reply to any sender",
"allowed_identities": "Allowed sender addresses",
"default_recipient": "Default recipient address",
"greeting": "Auto-reply message (when Assist is off)",
"delivery_method": "Default delivery method",
"announce_interval": "Announce interval",
"propagation_node": "Propagation node address",
"sync_interval": "Propagation sync interval"
},
"data_description": {
"display_name": "Contact name announced to other Reticulum peers. Also used as the identity's name in Home Assistant.",
"enable_assist": "When enabled, incoming LXMF messages are answered by the Assist conversation agent and the reply is sent back.",
"allowed_identities": "One address per line (or comma separated). Only used when 'Reply to any sender' is off.",
"greeting": "Sent as an automatic reply to incoming messages only when 'Route incoming messages to Assist' is off. Leave blank to disable.",
"default_recipient": "16-byte hex LXMF address that this identity's notify entity sends to.",
"announce_interval": "How often (seconds) to announce this identity. 0 disables periodic announces.",
"propagation_node": "Optional LXMF propagation node for store-and-forward delivery.",
"sync_interval": "How often (seconds) to pull queued messages from the propagation node. 0 disables."
}
},
"reconfigure": {
"title": "Reconfigure LXMF identity",
"data": {
"display_name": "Name (announced to peers)",
"enable_assist": "Route incoming messages to Assist",
"assist_agent": "Assist agent",
"assist_language": "Assist language",
"allow_all_senders": "Reply to any sender",
"allowed_identities": "Allowed sender addresses",
"default_recipient": "Default recipient address",
"greeting": "Auto-reply message (when Assist is off)",
"delivery_method": "Default delivery method",
"announce_interval": "Announce interval",
"propagation_node": "Propagation node address",
"sync_interval": "Propagation sync interval"
},
"data_description": {
"display_name": "Contact name announced to other Reticulum peers. Changing it updates future announces.",
"greeting": "Sent as an automatic reply to incoming messages only when 'Route incoming messages to Assist' is off. Leave blank to disable."
}
}
},
"abort": {
"reconfigure_successful": "Identity updated."
}
}
},
"entity": {
"sensor": {
"lxmf_address": { "name": "LXMF address" },
@@ -77,7 +119,8 @@
},
"button": {
"announce": { "name": "Announce" },
"sync": { "name": "Sync propagation node" }
"sync": { "name": "Sync propagation node" },
"regenerate": { "name": "Regenerate identity" }
},
"notify": {
"message": { "name": "Send message" }
@@ -109,17 +152,12 @@
"name": "Destination",
"description": "16-byte hex LXMF destination hash of the recipient."
},
"content": {
"name": "Content",
"description": "The message body."
},
"title": {
"name": "Title",
"description": "Optional message title / subject."
},
"method": {
"name": "Method",
"description": "Delivery method to use."
"content": { "name": "Content", "description": "The message body." },
"title": { "name": "Title", "description": "Optional message title / subject." },
"method": { "name": "Method", "description": "Delivery method to use." },
"identity": {
"name": "Identity",
"description": "Which identity to send from (name or LXMF address). Defaults to the first identity."
},
"fields": {
"name": "Fields",
@@ -129,7 +167,13 @@
},
"announce": {
"name": "Announce",
"description": "Announce this Home Assistant's LXMF destination on the network."
"description": "Announce an identity's LXMF destination on the network.",
"fields": {
"identity": {
"name": "Identity",
"description": "Which identity to announce. Defaults to the first identity."
}
}
},
"request_path": {
"name": "Request path",
@@ -138,26 +182,38 @@
"destination": {
"name": "Destination",
"description": "Destination hash to resolve a path to."
},
"identity": {
"name": "Identity",
"description": "Which identity to act through. Defaults to the first identity."
}
}
},
"set_propagation_node": {
"name": "Set propagation node",
"description": "Set the outbound LXMF propagation node.",
"description": "Set the outbound LXMF propagation node for an identity.",
"fields": {
"destination": {
"name": "Destination",
"description": "Propagation node destination hash."
},
"identity": {
"name": "Identity",
"description": "Which identity to configure. Defaults to the first identity."
}
}
},
"sync_propagation": {
"name": "Sync propagation node",
"description": "Pull queued messages from the configured propagation node.",
"description": "Pull queued messages from an identity's propagation node.",
"fields": {
"max_messages": {
"name": "Max messages",
"description": "Maximum number of messages to retrieve."
},
"identity": {
"name": "Identity",
"description": "Which identity to sync. Defaults to the first identity."
}
}
}