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": "Подключение к Reticulum",
"description": "Home Assistant запустит экземпляр Reticulum и подключится к вашему стеку Reticulum по TCP (на соседней машине должен быть настроен TCPServerInterface).",
"description": "Home Assistant запустит экземпляр Reticulum и подключится к вашему стеку по TCP. Первая LXMF-identity создаётся автоматически; остальные можно добавить позже на странице интеграции.",
"data": {
"target_host": "Хост",
"target_port": "Порт",
"display_name": "Отображаемое имя",
"interface_name": "Название интерфейса"
"interface_name": "Название интерфейса",
"display_name": "Имя первой identity"
},
"data_description": {
"target_host": "Имя хоста или IP-адрес машины с TCP-сервером Reticulum.",
"target_port": "TCP-порт TCPServerInterface Reticulum (по умолчанию 4242).",
"display_name": "Имя, анонсируемое другим узлам Reticulum для этого Home Assistant.",
"interface_name": "Метка соединения в конфигурации Reticulum."
"interface_name": "Метка соединения в конфигурации Reticulum.",
"display_name": "Имя первой LXMF-identity, анонсируемое узлам."
}
}
},
@@ -23,39 +23,81 @@
},
"abort": {
"already_configured": "Reticulum уже настроен.",
"single_instance_allowed": "Допускается только один экземпляр Reticulum."
"single_instance_allowed": "Допускается только один стек Reticulum. Добавляйте новые identity к существующему."
}
},
"options": {
"step": {
"init": {
"title": "Параметры Reticulum",
"title": "Параметры стека Reticulum",
"data": {
"enable_assist": "Направлять входящие сообщения в Assist",
"assist_agent": "Агент Assist (id сущности/агента, пусто = по умолчанию)",
"assist_language": "Язык Assist (пусто = язык системы)",
"allow_all_senders": "Отвечать любому отправителю",
"allowed_identities": "Разрешённые адреса отправителей",
"default_recipient": "Адрес получателя по умолчанию (для сущности notify)",
"greeting": "Автоответ (когда Assist выключен)",
"delivery_method": "Способ доставки по умолчанию",
"announce_interval": "Интервал анонсов",
"propagation_node": "Адрес узла ретрансляции (propagation node)",
"sync_interval": "Интервал синхронизации с узлом ретрансляции",
"loglevel": "Уровень логирования Reticulum (0-7)"
},
"data_description": {
"enable_assist": "Если включено, входящие сообщения LXMF обрабатываются агентом Assist, а ответ отправляется обратно через Reticulum.",
"allowed_identities": "По одному адресу в строке (или через запятую). Используется только если «Отвечать любому отправителю» выключено.",
"default_recipient": "16-байтовый hex-адрес LXMF, на который отправляет сущность notify.reticulum.",
"greeting": "Отправляется автоматически в ответ на входящие сообщения только когда «Направлять входящие сообщения в Assist» выключено. Оставьте пустым, чтобы отключить.",
"announce_interval": "Как часто (в секундах) анонсировать наш адрес. 0 отключает периодические анонсы.",
"propagation_node": "Необязательный узел ретрансляции LXMF для доставки по принципу store-and-forward.",
"sync_interval": "Как часто (в секундах) забирать сообщения из очереди узла ретрансляции. 0 отключает."
}
}
}
},
"config_subentries": {
"identity": {
"initiate_flow": {
"user": "Добавить identity",
"reconfigure": "Изменить identity"
},
"entry_type": "LXMF identity",
"step": {
"user": {
"title": "Добавить LXMF identity",
"data": {
"display_name": "Имя (анонсируется узлам)",
"enable_assist": "Направлять входящие сообщения в Assist",
"assist_agent": "Агент Assist",
"assist_language": "Язык Assist",
"allow_all_senders": "Отвечать любому отправителю",
"allowed_identities": "Разрешённые адреса отправителей",
"default_recipient": "Адрес получателя по умолчанию",
"greeting": "Автоответ (когда Assist выключен)",
"delivery_method": "Способ доставки по умолчанию",
"announce_interval": "Интервал анонсов",
"propagation_node": "Адрес узла ретрансляции",
"sync_interval": "Интервал синхронизации с узлом ретрансляции"
},
"data_description": {
"display_name": "Имя контакта, анонсируемое другим узлам Reticulum. Также используется как имя identity в Home Assistant.",
"enable_assist": "Если включено, входящие сообщения LXMF обрабатываются агентом Assist, а ответ отправляется обратно.",
"allowed_identities": "По одному адресу в строке (или через запятую). Используется только если «Отвечать любому отправителю» выключено.",
"greeting": "Отправляется автоматически в ответ на входящие сообщения только когда «Направлять входящие сообщения в Assist» выключено. Оставьте пустым, чтобы отключить.",
"default_recipient": "16-байтовый hex-адрес LXMF, на который отправляет сущность notify этой identity.",
"announce_interval": "Как часто (в секундах) анонсировать эту identity. 0 отключает периодические анонсы.",
"propagation_node": "Необязательный узел ретрансляции LXMF (store-and-forward).",
"sync_interval": "Как часто (в секундах) забирать сообщения из очереди узла ретрансляции. 0 отключает."
}
},
"reconfigure": {
"title": "Изменить LXMF identity",
"data": {
"display_name": "Имя (анонсируется узлам)",
"enable_assist": "Направлять входящие сообщения в Assist",
"assist_agent": "Агент Assist",
"assist_language": "Язык Assist",
"allow_all_senders": "Отвечать любому отправителю",
"allowed_identities": "Разрешённые адреса отправителей",
"default_recipient": "Адрес получателя по умолчанию",
"greeting": "Автоответ (когда Assist выключен)",
"delivery_method": "Способ доставки по умолчанию",
"announce_interval": "Интервал анонсов",
"propagation_node": "Адрес узла ретрансляции",
"sync_interval": "Интервал синхронизации с узлом ретрансляции"
},
"data_description": {
"display_name": "Имя контакта, анонсируемое другим узлам Reticulum. Изменение применится к будущим анонсам.",
"greeting": "Отправляется автоматически в ответ на входящие сообщения только когда «Направлять входящие сообщения в Assist» выключено. Оставьте пустым, чтобы отключить."
}
}
},
"abort": {
"reconfigure_successful": "Identity обновлена."
}
}
},
"entity": {
"sensor": {
"lxmf_address": { "name": "Адрес LXMF" },
@@ -77,7 +119,8 @@
},
"button": {
"announce": { "name": "Анонсировать" },
"sync": { "name": "Синхронизировать узел ретрансляции" }
"sync": { "name": "Синхронизировать узел ретрансляции" },
"regenerate": { "name": "Перегенерировать identity" }
},
"notify": {
"message": { "name": "Отправить сообщение" }
@@ -109,17 +152,12 @@
"name": "Получатель",
"description": "16-байтовый hex-хэш адреса LXMF получателя."
},
"content": {
"name": "Текст",
"description": "Тело сообщения."
},
"title": {
"name": "Заголовок",
"description": "Необязательный заголовок/тема сообщения."
},
"method": {
"name": "Способ",
"description": "Используемый способ доставки."
"content": { "name": "Текст", "description": "Тело сообщения." },
"title": { "name": "Заголовок", "description": "Необязательный заголовок/тема сообщения." },
"method": { "name": "Способ", "description": "Используемый способ доставки." },
"identity": {
"name": "Identity",
"description": "От какой identity отправлять (имя или адрес LXMF). По умолчанию — первая identity."
},
"fields": {
"name": "Поля",
@@ -129,7 +167,13 @@
},
"announce": {
"name": "Анонсировать",
"description": "Анонсировать адрес LXMF этого Home Assistant в сети."
"description": "Анонсировать адрес LXMF identity в сети.",
"fields": {
"identity": {
"name": "Identity",
"description": "Какую identity анонсировать. По умолчанию — первая."
}
}
},
"request_path": {
"name": "Запросить маршрут",
@@ -138,26 +182,38 @@
"destination": {
"name": "Получатель",
"description": "Хэш адреса, до которого нужно найти маршрут."
},
"identity": {
"name": "Identity",
"description": "От какой identity действовать. По умолчанию — первая."
}
}
},
"set_propagation_node": {
"name": "Задать узел ретрансляции",
"description": "Задать исходящий узел ретрансляции LXMF.",
"description": "Задать исходящий узел ретрансляции LXMF для identity.",
"fields": {
"destination": {
"name": "Получатель",
"description": "Хэш адреса узла ретрансляции."
},
"identity": {
"name": "Identity",
"description": "Какую identity настроить. По умолчанию — первая."
}
}
},
"sync_propagation": {
"name": "Синхронизировать узел ретрансляции",
"description": "Забрать сообщения из очереди настроенного узла ретрансляции.",
"description": "Забрать сообщения из очереди узла ретрансляции identity.",
"fields": {
"max_messages": {
"name": "Макс. сообщений",
"description": "Максимальное число сообщений для получения."
},
"identity": {
"name": "Identity",
"description": "Какую identity синхронизировать. По умолчанию — первая."
}
}
}