mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-08 01:46:35 +00:00
Add "add matter device" link to add integration dialog (#15365)
This commit is contained in:
parent
e47b59f826
commit
5b504bf9ce
@ -4,12 +4,15 @@ import { domainToName } from "../../data/integration";
|
|||||||
import { getIntegrationDescriptions } from "../../data/integrations";
|
import { getIntegrationDescriptions } from "../../data/integrations";
|
||||||
import { showConfigFlowDialog } from "../../dialogs/config-flow/show-dialog-config-flow";
|
import { showConfigFlowDialog } from "../../dialogs/config-flow/show-dialog-config-flow";
|
||||||
import { showConfirmationDialog } from "../../dialogs/generic/show-dialog-box";
|
import { showConfirmationDialog } from "../../dialogs/generic/show-dialog-box";
|
||||||
|
import { showMatterAddDeviceDialog } from "../../panels/config/integrations/integration-panels/matter/show-dialog-add-matter-device";
|
||||||
import { showZWaveJSAddNodeDialog } from "../../panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node";
|
import { showZWaveJSAddNodeDialog } from "../../panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import { documentationUrl } from "../../util/documentation-url";
|
import { documentationUrl } from "../../util/documentation-url";
|
||||||
import { isComponentLoaded } from "../config/is_component_loaded";
|
import { isComponentLoaded } from "../config/is_component_loaded";
|
||||||
import { navigate } from "../navigate";
|
import { navigate } from "../navigate";
|
||||||
|
|
||||||
|
export const PROTOCOL_INTEGRATIONS = ["zha", "zwave_js", "matter"] as const;
|
||||||
|
|
||||||
export const protocolIntegrationPicked = async (
|
export const protocolIntegrationPicked = async (
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -113,5 +116,42 @@ export const protocolIntegrationPicked = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
navigate("/config/zha/add");
|
navigate("/config/zha/add");
|
||||||
|
} else if (domain === "matter") {
|
||||||
|
const entries = await getConfigEntries(hass, {
|
||||||
|
domain,
|
||||||
|
});
|
||||||
|
if (!isComponentLoaded(hass, domain) || !entries.length) {
|
||||||
|
// If the component isn't loaded, ask them to load the integration first
|
||||||
|
showConfirmationDialog(element, {
|
||||||
|
title: hass.localize(
|
||||||
|
"ui.panel.config.integrations.config_flow.missing_zwave_zigbee_title",
|
||||||
|
{ integration: "Matter" }
|
||||||
|
),
|
||||||
|
text: hass.localize(
|
||||||
|
"ui.panel.config.integrations.config_flow.missing_matter",
|
||||||
|
{
|
||||||
|
brand: options?.brand || options?.domain || "Matter",
|
||||||
|
link: html`<a
|
||||||
|
href=${documentationUrl(hass, "/integrations/matter")}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>${hass.localize(
|
||||||
|
"ui.panel.config.integrations.config_flow.supported_hardware"
|
||||||
|
)}</a
|
||||||
|
>`,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
confirmText: hass.localize(
|
||||||
|
"ui.panel.config.integrations.config_flow.proceed"
|
||||||
|
),
|
||||||
|
confirm: () => {
|
||||||
|
showConfigFlowDialog(element, {
|
||||||
|
startFlowHandler: "matter",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showMatterAddDeviceDialog(element);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,53 @@
|
|||||||
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
|
import { navigate } from "../common/navigate";
|
||||||
import { HomeAssistant } from "../types";
|
import { HomeAssistant } from "../types";
|
||||||
|
import { subscribeDeviceRegistry } from "./device_registry";
|
||||||
|
|
||||||
|
export const canCommissionMatterExternal = (hass: HomeAssistant) =>
|
||||||
|
hass.auth.external?.config.canCommissionMatter;
|
||||||
|
|
||||||
|
export const startExternalCommissioning = (hass: HomeAssistant) =>
|
||||||
|
hass.auth.external!.fireMessage({
|
||||||
|
type: "matter/commission",
|
||||||
|
});
|
||||||
|
|
||||||
|
export const redirectOnNewMatterDevice = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
callback?: () => void
|
||||||
|
): UnsubscribeFunc => {
|
||||||
|
let curMatterDevices: Set<string> | undefined;
|
||||||
|
const unsubDeviceReg = subscribeDeviceRegistry(hass.connection, (entries) => {
|
||||||
|
if (!curMatterDevices) {
|
||||||
|
curMatterDevices = new Set(
|
||||||
|
Object.values(entries)
|
||||||
|
.filter((device) =>
|
||||||
|
device.identifiers.find((identifier) => identifier[0] === "matter")
|
||||||
|
)
|
||||||
|
.map((device) => device.id)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const newMatterDevices = Object.values(entries).filter(
|
||||||
|
(device) =>
|
||||||
|
device.identifiers.find((identifier) => identifier[0] === "matter") &&
|
||||||
|
!curMatterDevices!.has(device.id)
|
||||||
|
);
|
||||||
|
if (newMatterDevices.length) {
|
||||||
|
unsubDeviceReg();
|
||||||
|
curMatterDevices = undefined;
|
||||||
|
callback?.();
|
||||||
|
navigate(`/config/devices/device/${newMatterDevices[0].id}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
unsubDeviceReg();
|
||||||
|
curMatterDevices = undefined;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addMatterDevice = (hass: HomeAssistant) => {
|
||||||
|
startExternalCommissioning(hass);
|
||||||
|
};
|
||||||
|
|
||||||
export const commissionMatterDevice = (
|
export const commissionMatterDevice = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
@ -39,6 +39,7 @@ import { HomeAssistant, Route } from "../../../types";
|
|||||||
import { brandsUrl } from "../../../util/brands-url";
|
import { brandsUrl } from "../../../util/brands-url";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import "../integrations/ha-integration-overflow-menu";
|
import "../integrations/ha-integration-overflow-menu";
|
||||||
|
import { showMatterAddDeviceDialog } from "../integrations/integration-panels/matter/show-dialog-add-matter-device";
|
||||||
import { showZWaveJSAddNodeDialog } from "../integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node";
|
import { showZWaveJSAddNodeDialog } from "../integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node";
|
||||||
import { showAddIntegrationDialog } from "../integrations/show-add-integration-dialog";
|
import { showAddIntegrationDialog } from "../integrations/show-add-integration-dialog";
|
||||||
|
|
||||||
@ -543,6 +544,10 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
this._showZJSAddDeviceDialog(filteredConfigEntry);
|
this._showZJSAddDeviceDialog(filteredConfigEntry);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (filteredConfigEntry?.domain === "matter") {
|
||||||
|
showMatterAddDeviceDialog(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
showAddIntegrationDialog(this);
|
showAddIntegrationDialog(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,10 @@ import { styleMap } from "lit/directives/style-map";
|
|||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { protocolIntegrationPicked } from "../../../common/integrations/protocolIntegrationPicked";
|
import {
|
||||||
|
protocolIntegrationPicked,
|
||||||
|
PROTOCOL_INTEGRATIONS,
|
||||||
|
} from "../../../common/integrations/protocolIntegrationPicked";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { caseInsensitiveStringCompare } from "../../../common/string/compare";
|
import { caseInsensitiveStringCompare } from "../../../common/string/compare";
|
||||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||||
@ -136,10 +139,9 @@ class AddIntegrationDialog extends LitElement {
|
|||||||
localize: LocalizeFunc,
|
localize: LocalizeFunc,
|
||||||
filter?: string
|
filter?: string
|
||||||
): IntegrationListItem[] => {
|
): IntegrationListItem[] => {
|
||||||
const addDeviceRows: IntegrationListItem[] = (
|
const addDeviceRows: IntegrationListItem[] = PROTOCOL_INTEGRATIONS.filter(
|
||||||
["zha", "zwave_js"] as const
|
(domain) => components.includes(domain)
|
||||||
)
|
)
|
||||||
.filter((domain) => components.includes(domain))
|
|
||||||
.map((domain) => ({
|
.map((domain) => ({
|
||||||
name: localize(`ui.panel.config.integrations.add_${domain}_device`),
|
name: localize(`ui.panel.config.integrations.add_${domain}_device`),
|
||||||
domain,
|
domain,
|
||||||
@ -371,7 +373,7 @@ class AddIntegrationDialog extends LitElement {
|
|||||||
),
|
),
|
||||||
confirm: () => {
|
confirm: () => {
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
if (["zha", "zwave_js"].includes(integration.supported_by)) {
|
if (PROTOCOL_INTEGRATIONS.includes(integration.supported_by)) {
|
||||||
protocolIntegrationPicked(this, this.hass, integration.supported_by);
|
protocolIntegrationPicked(this, this.hass, integration.supported_by);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -519,7 +521,9 @@ class AddIntegrationDialog extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
["zha", "zwave_js"].includes(integration.domain) &&
|
(PROTOCOL_INTEGRATIONS as ReadonlyArray<string>).includes(
|
||||||
|
integration.domain
|
||||||
|
) &&
|
||||||
isComponentLoaded(this.hass, integration.domain)
|
isComponentLoaded(this.hass, integration.domain)
|
||||||
) {
|
) {
|
||||||
this._pickedBrand = integration.domain;
|
this._pickedBrand = integration.domain;
|
||||||
|
@ -3,7 +3,10 @@ import { css, html, LitElement } from "lit";
|
|||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { protocolIntegrationPicked } from "../../../common/integrations/protocolIntegrationPicked";
|
import {
|
||||||
|
protocolIntegrationPicked,
|
||||||
|
PROTOCOL_INTEGRATIONS,
|
||||||
|
} from "../../../common/integrations/protocolIntegrationPicked";
|
||||||
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
|
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { caseInsensitiveStringCompare } from "../../../common/string/compare";
|
import { caseInsensitiveStringCompare } from "../../../common/string/compare";
|
||||||
@ -77,38 +80,41 @@ class HaDomainIntegrations extends LitElement {
|
|||||||
: ""}`
|
: ""}`
|
||||||
: ""}
|
: ""}
|
||||||
${this.integration?.iot_standards
|
${this.integration?.iot_standards
|
||||||
? (
|
? this.integration.iot_standards
|
||||||
this.integration.iot_standards.filter(
|
.filter((standard) =>
|
||||||
(standard) => standard in standardToDomain
|
(PROTOCOL_INTEGRATIONS as ReadonlyArray<string>).includes(
|
||||||
) as (keyof typeof standardToDomain)[]
|
standardToDomain[standard] || standard
|
||||||
).map((standard) => {
|
)
|
||||||
const domain = standardToDomain[standard];
|
)
|
||||||
return html`<mwc-list-item
|
.map((standard) => {
|
||||||
graphic="medium"
|
const domain: (typeof PROTOCOL_INTEGRATIONS)[number] =
|
||||||
.domain=${domain}
|
standardToDomain[standard] || standard;
|
||||||
@request-selected=${this._standardPicked}
|
return html`<mwc-list-item
|
||||||
hasMeta
|
graphic="medium"
|
||||||
>
|
.domain=${domain}
|
||||||
<img
|
@request-selected=${this._standardPicked}
|
||||||
slot="graphic"
|
hasMeta
|
||||||
loading="lazy"
|
|
||||||
alt=""
|
|
||||||
src=${brandsUrl({
|
|
||||||
domain,
|
|
||||||
type: "icon",
|
|
||||||
useFallback: true,
|
|
||||||
darkOptimized: this.hass.themes?.darkMode,
|
|
||||||
})}
|
|
||||||
referrerpolicy="no-referrer"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
>${this.hass.localize(
|
|
||||||
`ui.panel.config.integrations.add_${domain}_device`
|
|
||||||
)}</span
|
|
||||||
>
|
>
|
||||||
<ha-icon-next slot="meta"></ha-icon-next>
|
<img
|
||||||
</mwc-list-item>`;
|
slot="graphic"
|
||||||
})
|
loading="lazy"
|
||||||
|
alt=""
|
||||||
|
src=${brandsUrl({
|
||||||
|
domain,
|
||||||
|
type: "icon",
|
||||||
|
useFallback: true,
|
||||||
|
darkOptimized: this.hass.themes?.darkMode,
|
||||||
|
})}
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
>${this.hass.localize(
|
||||||
|
`ui.panel.config.integrations.add_${domain}_device`
|
||||||
|
)}</span
|
||||||
|
>
|
||||||
|
<ha-icon-next slot="meta"></ha-icon-next>
|
||||||
|
</mwc-list-item>`;
|
||||||
|
})
|
||||||
: ""}
|
: ""}
|
||||||
${this.integration &&
|
${this.integration &&
|
||||||
"integrations" in this.integration &&
|
"integrations" in this.integration &&
|
||||||
@ -144,7 +150,7 @@ class HaDomainIntegrations extends LitElement {
|
|||||||
</ha-integration-list-item>`
|
</ha-integration-list-item>`
|
||||||
)
|
)
|
||||||
: ""}
|
: ""}
|
||||||
${this.domain === "zha" || this.domain === "zwave_js"
|
${(PROTOCOL_INTEGRATIONS as ReadonlyArray<string>).includes(this.domain)
|
||||||
? html`<mwc-list-item
|
? html`<mwc-list-item
|
||||||
graphic="medium"
|
graphic="medium"
|
||||||
.domain=${this.domain}
|
.domain=${this.domain}
|
||||||
@ -165,7 +171,9 @@ class HaDomainIntegrations extends LitElement {
|
|||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
>${this.hass.localize(
|
>${this.hass.localize(
|
||||||
`ui.panel.config.integrations.add_${this.domain}_device`
|
`ui.panel.config.integrations.add_${
|
||||||
|
this.domain as (typeof PROTOCOL_INTEGRATIONS)[number]
|
||||||
|
}_device`
|
||||||
)}</span
|
)}</span
|
||||||
>
|
>
|
||||||
<ha-icon-next slot="meta"></ha-icon-next>
|
<ha-icon-next slot="meta"></ha-icon-next>
|
||||||
|
@ -73,6 +73,7 @@ import { documentationUrl } from "../../../util/documentation-url";
|
|||||||
import { fileDownload } from "../../../util/file_download";
|
import { fileDownload } from "../../../util/file_download";
|
||||||
import type { ConfigEntryExtended } from "./ha-config-integrations";
|
import type { ConfigEntryExtended } from "./ha-config-integrations";
|
||||||
import "./ha-integration-header";
|
import "./ha-integration-header";
|
||||||
|
import { isDevVersion } from "../../../common/config/version";
|
||||||
|
|
||||||
const integrationsWithPanel = {
|
const integrationsWithPanel = {
|
||||||
matter: "/config/matter",
|
matter: "/config/matter",
|
||||||
@ -346,7 +347,9 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
? html`<mwc-button unelevated @click=${this._handleEnable}>
|
? html`<mwc-button unelevated @click=${this._handleEnable}>
|
||||||
${this.hass.localize("ui.common.enable")}
|
${this.hass.localize("ui.common.enable")}
|
||||||
</mwc-button>`
|
</mwc-button>`
|
||||||
: item.domain in integrationsWithPanel
|
: item.domain in integrationsWithPanel &&
|
||||||
|
(item.domain !== "matter" ||
|
||||||
|
isDevVersion(this.hass.config.version))
|
||||||
? html`<a
|
? html`<a
|
||||||
href=${`${integrationsWithPanel[item.domain]}?config_entry=${
|
href=${`${integrationsWithPanel[item.domain]}?config_entry=${
|
||||||
item.entry_id
|
item.entry_id
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
import "@material/mwc-button/mwc-button";
|
||||||
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
|
import { css, html, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
|
import "../../../../../components/ha-circular-progress";
|
||||||
|
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
||||||
|
import {
|
||||||
|
addMatterDevice,
|
||||||
|
canCommissionMatterExternal,
|
||||||
|
redirectOnNewMatterDevice,
|
||||||
|
} from "../../../../../data/matter";
|
||||||
|
import { haStyleDialog } from "../../../../../resources/styles";
|
||||||
|
import { HomeAssistant } from "../../../../../types";
|
||||||
|
|
||||||
|
@customElement("dialog-matter-add-device")
|
||||||
|
class DialogMatterAddDevice extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private _open = false;
|
||||||
|
|
||||||
|
private _unsub?: UnsubscribeFunc;
|
||||||
|
|
||||||
|
public showDialog(): void {
|
||||||
|
this._open = true;
|
||||||
|
if (!canCommissionMatterExternal(this.hass)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._unsub = redirectOnNewMatterDevice(this.hass, () =>
|
||||||
|
this.closeDialog()
|
||||||
|
);
|
||||||
|
addMatterDevice(this.hass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeDialog(): void {
|
||||||
|
this._open = false;
|
||||||
|
this._unsub?.();
|
||||||
|
this._unsub = undefined;
|
||||||
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._open) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-dialog
|
||||||
|
open
|
||||||
|
@closed=${this.closeDialog}
|
||||||
|
.heading=${createCloseHeading(this.hass, "Add Matter device")}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
${!canCommissionMatterExternal(this.hass)
|
||||||
|
? this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.config_flow.matter_mobile_app"
|
||||||
|
)
|
||||||
|
: html`<ha-circular-progress
|
||||||
|
size="large"
|
||||||
|
active
|
||||||
|
></ha-circular-progress>`}
|
||||||
|
</div>
|
||||||
|
<mwc-button slot="primaryAction" @click=${this.closeDialog}>
|
||||||
|
${this.hass.localize("ui.common.cancel")}
|
||||||
|
</mwc-button>
|
||||||
|
</ha-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [
|
||||||
|
haStyleDialog,
|
||||||
|
css`
|
||||||
|
div {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
ha-circular-progress {
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"dialog-matter-add-device": DialogMatterAddDevice;
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +1,23 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
|
import { css, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { isComponentLoaded } from "../../../../../common/config/is_component_loaded";
|
||||||
|
import "../../../../../components/ha-alert";
|
||||||
import "../../../../../components/ha-card";
|
import "../../../../../components/ha-card";
|
||||||
import {
|
import {
|
||||||
acceptSharedMatterDevice,
|
acceptSharedMatterDevice,
|
||||||
|
canCommissionMatterExternal,
|
||||||
commissionMatterDevice,
|
commissionMatterDevice,
|
||||||
matterSetThread,
|
matterSetThread,
|
||||||
matterSetWifi,
|
matterSetWifi,
|
||||||
|
redirectOnNewMatterDevice,
|
||||||
|
startExternalCommissioning,
|
||||||
} from "../../../../../data/matter";
|
} from "../../../../../data/matter";
|
||||||
|
import { showPromptDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
||||||
import "../../../../../layouts/hass-subpage";
|
import "../../../../../layouts/hass-subpage";
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
import "../../../../../components/ha-alert";
|
|
||||||
import { showPromptDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
|
||||||
import { navigate } from "../../../../../common/navigate";
|
|
||||||
import { isComponentLoaded } from "../../../../../common/config/is_component_loaded";
|
|
||||||
import { isDevVersion } from "../../../../../common/config/version";
|
|
||||||
|
|
||||||
@customElement("matter-config-panel")
|
@customElement("matter-config-panel")
|
||||||
export class MatterConfigPanel extends LitElement {
|
export class MatterConfigPanel extends LitElement {
|
||||||
@ -25,10 +27,11 @@ export class MatterConfigPanel extends LitElement {
|
|||||||
|
|
||||||
@state() private _error?: string;
|
@state() private _error?: string;
|
||||||
|
|
||||||
private _curMatterDevices?: Set<string>;
|
private _unsub?: UnsubscribeFunc;
|
||||||
|
|
||||||
private get _canCommissionMatter() {
|
disconnectedCallback() {
|
||||||
return this.hass.auth.external?.config.canCommissionMatter;
|
super.disconnectedCallback();
|
||||||
|
this._stopRedirect();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
@ -57,19 +60,17 @@ export class MatterConfigPanel extends LitElement {
|
|||||||
share code.
|
share code.
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
${this._canCommissionMatter
|
${canCommissionMatterExternal(this.hass)
|
||||||
? html`<mwc-button @click=${this._startMobileCommissioning}
|
? html`<mwc-button @click=${this._startMobileCommissioning}
|
||||||
>Commission device with mobile app</mwc-button
|
>Commission device with mobile app</mwc-button
|
||||||
>`
|
>`
|
||||||
: ""}
|
: ""}
|
||||||
${isDevVersion(this.hass.config.version)
|
<mwc-button @click=${this._commission}
|
||||||
? html`<mwc-button @click=${this._commission}
|
>Commission device</mwc-button
|
||||||
>Commission device</mwc-button
|
>
|
||||||
>
|
<mwc-button @click=${this._acceptSharedDevice}
|
||||||
<mwc-button @click=${this._acceptSharedDevice}
|
>Add shared device</mwc-button
|
||||||
>Add shared device</mwc-button
|
>
|
||||||
>`
|
|
||||||
: ""}
|
|
||||||
<mwc-button @click=${this._setWifi}
|
<mwc-button @click=${this._setWifi}
|
||||||
>Set WiFi Credentials</mwc-button
|
>Set WiFi Credentials</mwc-button
|
||||||
>
|
>
|
||||||
@ -83,33 +84,23 @@ export class MatterConfigPanel extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override updated(changedProps: PropertyValues) {
|
private _redirectOnNewMatterDevice() {
|
||||||
super.updated(changedProps);
|
if (this._unsub) {
|
||||||
|
|
||||||
if (!this._curMatterDevices || !changedProps.has("hass")) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this._unsub = redirectOnNewMatterDevice(this.hass, () => {
|
||||||
|
this._unsub = undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
private _stopRedirect() {
|
||||||
if (!oldHass || oldHass.devices === this.hass.devices) {
|
this._unsub?.();
|
||||||
return;
|
this._unsub = undefined;
|
||||||
}
|
|
||||||
|
|
||||||
const newMatterDevices = Object.values(this.hass.devices).filter(
|
|
||||||
(device) =>
|
|
||||||
device.identifiers.find((identifier) => identifier[0] === "matter") &&
|
|
||||||
!this._curMatterDevices!.has(device.id)
|
|
||||||
);
|
|
||||||
if (newMatterDevices.length) {
|
|
||||||
navigate(`/config/devices/device/${newMatterDevices[0].id}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _startMobileCommissioning() {
|
private _startMobileCommissioning() {
|
||||||
this._redirectOnNewDevice();
|
this._redirectOnNewMatterDevice();
|
||||||
this.hass.auth.external!.fireMessage({
|
startExternalCommissioning(this.hass);
|
||||||
type: "matter/commission",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _setWifi(): Promise<void> {
|
private async _setWifi(): Promise<void> {
|
||||||
@ -150,11 +141,12 @@ export class MatterConfigPanel extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._error = undefined;
|
this._error = undefined;
|
||||||
this._redirectOnNewDevice();
|
this._redirectOnNewMatterDevice();
|
||||||
try {
|
try {
|
||||||
await commissionMatterDevice(this.hass, code);
|
await commissionMatterDevice(this.hass, code);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = err.message;
|
this._error = err.message;
|
||||||
|
this._stopRedirect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,11 +161,12 @@ export class MatterConfigPanel extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._error = undefined;
|
this._error = undefined;
|
||||||
this._redirectOnNewDevice();
|
this._redirectOnNewMatterDevice();
|
||||||
try {
|
try {
|
||||||
await acceptSharedMatterDevice(this.hass, Number(code));
|
await acceptSharedMatterDevice(this.hass, Number(code));
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = err.message;
|
this._error = err.message;
|
||||||
|
this._stopRedirect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,19 +188,6 @@ export class MatterConfigPanel extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _redirectOnNewDevice() {
|
|
||||||
if (this._curMatterDevices) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._curMatterDevices = new Set(
|
|
||||||
Object.values(this.hass.devices)
|
|
||||||
.filter((device) =>
|
|
||||||
device.identifiers.find((identifier) => identifier[0] === "matter")
|
|
||||||
)
|
|
||||||
.map((device) => device.id)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = [
|
static styles = [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
|
|
||||||
|
export const loadAddDeviceDialog = () => import("./dialog-matter-add-device");
|
||||||
|
|
||||||
|
export const showMatterAddDeviceDialog = (element: HTMLElement): void => {
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "dialog-matter-add-device",
|
||||||
|
dialogImport: loadAddDeviceDialog,
|
||||||
|
dialogParams: {},
|
||||||
|
});
|
||||||
|
};
|
@ -2993,6 +2993,7 @@
|
|||||||
"search_brand": "Search for a brand name",
|
"search_brand": "Search for a brand name",
|
||||||
"add_zwave_js_device": "Add Z-Wave device",
|
"add_zwave_js_device": "Add Z-Wave device",
|
||||||
"add_zha_device": "Add Zigbee device",
|
"add_zha_device": "Add Zigbee device",
|
||||||
|
"add_matter_device": "Add Matter device",
|
||||||
"disable": {
|
"disable": {
|
||||||
"show_disabled": "Show disabled integrations",
|
"show_disabled": "Show disabled integrations",
|
||||||
"disabled_integrations": "{number} disabled",
|
"disabled_integrations": "{number} disabled",
|
||||||
@ -3106,8 +3107,10 @@
|
|||||||
"could_not_load": "Config flow could not be loaded",
|
"could_not_load": "Config flow could not be loaded",
|
||||||
"not_loaded": "The integration could not be loaded, try to restart Home Assistant.",
|
"not_loaded": "The integration could not be loaded, try to restart Home Assistant.",
|
||||||
"supported_brand_flow": "Support for {supported_brand} devices is provided by {flow_domain_name}. Do you want to continue?",
|
"supported_brand_flow": "Support for {supported_brand} devices is provided by {flow_domain_name}. Do you want to continue?",
|
||||||
"missing_zwave_zigbee": "To add a {brand} device, you first need {supported_hardware_link} and the {integration} integration set up. If you already have the hardware then you can proceed with the setup of {integration}.",
|
|
||||||
"missing_zwave_zigbee_title": "{integration} is not setup",
|
"missing_zwave_zigbee_title": "{integration} is not setup",
|
||||||
|
"missing_zwave_zigbee": "To add a {brand} device, you first need {supported_hardware_link} and the {integration} integration set up. If you already have the hardware then you can proceed with the setup of {integration}.",
|
||||||
|
"missing_matter": "To add a {brand} device, you first need the {integration} integration and {supported_hardware_link}. Do you want to proceed with the setup of {integration}?",
|
||||||
|
"matter_mobile_app": "You need to use the Home Assistant Companion app on your mobile phone to commission Matter devices.",
|
||||||
"supported_hardware": "supported hardware",
|
"supported_hardware": "supported hardware",
|
||||||
"proceed": "Proceed"
|
"proceed": "Proceed"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user