Allow to transfer all Thread datasets with TLV (#22183)

* Allow to transfer all Thread datasets with TLV

This commit allows to transfer all Thread datasets with TLV. Since
PR #22022 the preferred dataset is transmitted when using Matter
external commissioning. This commit makes the Thread configuration
dialog to have feature parity.

* Drop preferred border agent id as additional metric for default router

We always have the extended address, so use this as primary and only
metric which router is the default. The preferred border agent id gets
updated best effort.

Also use isDefaultRouter consistently in the code.
This commit is contained in:
Stefan Agner 2024-10-02 15:06:06 +02:00 committed by GitHub
parent cdd29295e5
commit fe0fb2382a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 43 additions and 29 deletions

View File

@ -18,7 +18,7 @@ export interface ThreadDataSet {
channel: number | null; channel: number | null;
created: string; created: string;
dataset_id: string; dataset_id: string;
extended_pan_id: string | null; extended_pan_id: string;
network_name: string; network_name: string;
pan_id: string | null; pan_id: string | null;
preferred_border_agent_id: string | null; preferred_border_agent_id: string | null;

View File

@ -141,9 +141,10 @@ interface EMOutgoingMessageImprovScan extends EMMessage {
interface EMOutgoingMessageThreadStoreInPlatformKeychain extends EMMessage { interface EMOutgoingMessageThreadStoreInPlatformKeychain extends EMMessage {
type: "thread/store_in_platform_keychain"; type: "thread/store_in_platform_keychain";
payload: { payload: {
mac_extended_address: string; mac_extended_address: string | null;
border_agent_id: string; border_agent_id: string | null;
active_operational_dataset: string; active_operational_dataset: string;
extended_pan_id: string;
}; };
} }

View File

@ -37,6 +37,7 @@ import {
ThreadDataSet, ThreadDataSet,
ThreadRouter, ThreadRouter,
addThreadDataSet, addThreadDataSet,
getThreadDataSetTLV,
listThreadDataSets, listThreadDataSets,
removeThreadDataSet, removeThreadDataSet,
setPreferredBorderAgent, setPreferredBorderAgent,
@ -168,8 +169,7 @@ export class ThreadConfigPanel extends SubscribeMixin(LitElement) {
(otbr) => otbr.extended_pan_id === network.dataset!.extended_pan_id (otbr) => otbr.extended_pan_id === network.dataset!.extended_pan_id
)); ));
const canImportKeychain = const canImportKeychain =
this.hass.auth.external?.config.canTransferThreadCredentialsToKeychain && this.hass.auth.external?.config.canTransferThreadCredentialsToKeychain;
otbrForNetwork;
return html`<ha-card> return html`<ha-card>
<div class="card-header"> <div class="card-header">
@ -208,8 +208,12 @@ export class ThreadConfigPanel extends SubscribeMixin(LitElement) {
${network.routers.map((router) => { ${network.routers.map((router) => {
const otbr = const otbr =
this._otbrInfo && this._otbrInfo[router.extended_address]; this._otbrInfo && this._otbrInfo[router.extended_address];
const showOverflow = const showDefaultRouter = !!network.dataset;
("dataset" in network && router.border_agent_id) || otbr; const isDefaultRouter =
showDefaultRouter &&
router.extended_address ===
network.dataset!.preferred_extended_address;
const showOverflow = showDefaultRouter || otbr;
return html`<ha-list-item return html`<ha-list-item
class="router" class="router"
twoline twoline
@ -235,9 +239,7 @@ export class ThreadConfigPanel extends SubscribeMixin(LitElement) {
""} ""}
<span slot="secondary">${router.server}</span> <span slot="secondary">${router.server}</span>
${showOverflow ${showOverflow
? html`${network.dataset && ? html`${isDefaultRouter
router.extended_address ===
network.dataset.preferred_extended_address
? html`<ha-svg-icon ? html`<ha-svg-icon
.path=${mdiCellphoneKey} .path=${mdiCellphoneKey}
.title=${this.hass.localize( .title=${this.hass.localize(
@ -259,13 +261,9 @@ export class ThreadConfigPanel extends SubscribeMixin(LitElement) {
.path=${mdiDotsVertical} .path=${mdiDotsVertical}
slot="trigger" slot="trigger"
></ha-icon-button> ></ha-icon-button>
${network.dataset && router.border_agent_id ${showDefaultRouter
? html`<ha-list-item ? html`<ha-list-item .disabled=${isDefaultRouter}>
.disabled=${router.border_agent_id === ${isDefaultRouter
network.dataset.preferred_border_agent_id}
>
${router.border_agent_id ===
network.dataset.preferred_border_agent_id
? this.hass.localize( ? this.hass.localize(
"ui.panel.config.thread.default_router" "ui.panel.config.thread.default_router"
) )
@ -321,9 +319,13 @@ export class ThreadConfigPanel extends SubscribeMixin(LitElement) {
> >
</div>` </div>`
: ""} : ""}
${canImportKeychain ${canImportKeychain &&
network.dataset?.preferred &&
network.routers?.length
? html`<div class="card-actions"> ? html`<div class="card-actions">
<mwc-button .otbr=${otbrForNetwork} @click=${this._sendCredentials} <mwc-button
.networkDataset=${network.dataset}
@click=${this._sendCredentials}
>Send credentials to phone</mwc-button >Send credentials to phone</mwc-button
> >
</div>` </div>`
@ -331,17 +333,30 @@ export class ThreadConfigPanel extends SubscribeMixin(LitElement) {
</ha-card>`; </ha-card>`;
} }
private _sendCredentials(ev) { private async _sendCredentials(ev) {
const otbr = (ev.currentTarget as any).otbr as OTBRInfo; const dataset = (ev.currentTarget as any).networkDataset as ThreadDataSet;
if (!otbr) { if (!dataset) {
return;
}
if (
!dataset.preferred_extended_address &&
!dataset.preferred_border_agent_id
) {
showAlertDialog(this, {
title: "Error",
text: this.hass.localize("ui.panel.config.thread.no_preferred_router"),
});
return; return;
} }
this.hass.auth.external!.fireMessage({ this.hass.auth.external!.fireMessage({
type: "thread/store_in_platform_keychain", type: "thread/store_in_platform_keychain",
payload: { payload: {
mac_extended_address: otbr.extended_address, mac_extended_address: dataset.preferred_extended_address,
border_agent_id: otbr.border_agent_id, border_agent_id: dataset.preferred_border_agent_id,
active_operational_dataset: otbr.active_dataset_tlvs, active_operational_dataset: (
await getThreadDataSetTLV(this.hass, dataset.dataset_id)
).tlv,
extended_pan_id: dataset.extended_pan_id,
}, },
}); });
} }
@ -467,10 +482,7 @@ export class ThreadConfigPanel extends SubscribeMixin(LitElement) {
const network = (ev.currentTarget as any).network as ThreadNetwork; const network = (ev.currentTarget as any).network as ThreadNetwork;
const router = (ev.currentTarget as any).router as ThreadRouter; const router = (ev.currentTarget as any).router as ThreadRouter;
const otbr = (ev.currentTarget as any).otbr as OTBRInfo; const otbr = (ev.currentTarget as any).otbr as OTBRInfo;
const index = const index = Number(ev.detail.index);
network.dataset && router.border_agent_id
? Number(ev.detail.index)
: Number(ev.detail.index) + 1;
switch (index) { switch (index) {
case 0: case 0:
this._setPreferredBorderAgent(network.dataset!, router); this._setPreferredBorderAgent(network.dataset!, router);

View File

@ -4590,6 +4590,7 @@
"confirm_delete_dataset": "Delete {name} dataset?", "confirm_delete_dataset": "Delete {name} dataset?",
"confirm_delete_dataset_text": "This network will be removed from Home Assistant.", "confirm_delete_dataset_text": "This network will be removed from Home Assistant.",
"no_border_routers": "No border routers found", "no_border_routers": "No border routers found",
"no_preferred_router": "No preferred border router defined",
"border_routers": "{count} border {count, plural,\n one {router}\n other {routers}\n}", "border_routers": "{count} border {count, plural,\n one {router}\n other {routers}\n}",
"managed_by_home_assistant": "Managed by Home Assistant", "managed_by_home_assistant": "Managed by Home Assistant",
"operational_dataset": "Operational dataset", "operational_dataset": "Operational dataset",