mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 19:26:36 +00:00
Clean up ZHA configuration UI (#13610)
This commit is contained in:
parent
0848c096b9
commit
3083d5b04c
@ -309,7 +309,7 @@ export const fetchCommandsForCluster = (
|
|||||||
cluster_type: clusterType,
|
cluster_type: clusterType,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const fetchClustersForZhaNode = (
|
export const fetchClustersForZhaDevice = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
ieeeAddress: string
|
ieeeAddress: string
|
||||||
): Promise<Cluster[]> =>
|
): Promise<Cluster[]> =>
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
mdiCogRefresh,
|
mdiCogRefresh,
|
||||||
mdiDelete,
|
mdiDelete,
|
||||||
mdiDrawPen,
|
|
||||||
mdiFamilyTree,
|
mdiFamilyTree,
|
||||||
mdiFileTree,
|
|
||||||
mdiGroup,
|
mdiGroup,
|
||||||
mdiPlus,
|
mdiPlus,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
@ -12,9 +10,7 @@ import type { DeviceRegistryEntry } from "../../../../../../data/device_registry
|
|||||||
import { fetchZHADevice } from "../../../../../../data/zha";
|
import { fetchZHADevice } from "../../../../../../data/zha";
|
||||||
import { showConfirmationDialog } from "../../../../../../dialogs/generic/show-dialog-box";
|
import { showConfirmationDialog } from "../../../../../../dialogs/generic/show-dialog-box";
|
||||||
import type { HomeAssistant } from "../../../../../../types";
|
import type { HomeAssistant } from "../../../../../../types";
|
||||||
import { showZHAClusterDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-cluster";
|
import { showZHAManageZigbeeDeviceDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-manage-zigbee-device";
|
||||||
import { showZHADeviceChildrenDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-device-children";
|
|
||||||
import { showZHADeviceZigbeeInfoDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-device-zigbee-info";
|
|
||||||
import { showZHAReconfigureDeviceDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-reconfigure-device";
|
import { showZHAReconfigureDeviceDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-reconfigure-device";
|
||||||
import type { DeviceAction } from "../../../ha-config-device-page";
|
import type { DeviceAction } from "../../../ha-config-device-page";
|
||||||
|
|
||||||
@ -59,13 +55,6 @@ export const getZHADeviceActions = async (
|
|||||||
icon: mdiPlus,
|
icon: mdiPlus,
|
||||||
action: () => navigate(`/config/zha/add/${zhaDevice!.ieee}`),
|
action: () => navigate(`/config/zha/add/${zhaDevice!.ieee}`),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: hass.localize(
|
|
||||||
"ui.dialogs.zha_device_info.buttons.device_children"
|
|
||||||
),
|
|
||||||
icon: mdiFileTree,
|
|
||||||
action: () => showZHADeviceChildrenDialog(el, { device: zhaDevice! }),
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -73,16 +62,10 @@ export const getZHADeviceActions = async (
|
|||||||
actions.push(
|
actions.push(
|
||||||
...[
|
...[
|
||||||
{
|
{
|
||||||
label: hass.localize(
|
label: hass.localize("ui.dialogs.zha_device_info.buttons.manage"),
|
||||||
"ui.dialogs.zha_device_info.buttons.zigbee_information"
|
|
||||||
),
|
|
||||||
icon: mdiDrawPen,
|
|
||||||
action: () => showZHADeviceZigbeeInfoDialog(el, { device: zhaDevice }),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: hass.localize("ui.dialogs.zha_device_info.buttons.clusters"),
|
|
||||||
icon: mdiGroup,
|
icon: mdiGroup,
|
||||||
action: () => showZHAClusterDialog(el, { device: zhaDevice }),
|
action: () =>
|
||||||
|
showZHAManageZigbeeDeviceDialog(el, { device: zhaDevice }),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: hass.localize("ui.dialogs.zha_device_info.buttons.view_network"),
|
label: hass.localize("ui.dialogs.zha_device_info.buttons.view_network"),
|
||||||
|
@ -23,6 +23,7 @@ export class HaDeviceActionsZha extends LitElement {
|
|||||||
@state() private _zhaDevice?: ZHADevice;
|
@state() private _zhaDevice?: ZHADevice;
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues) {
|
protected updated(changedProperties: PropertyValues) {
|
||||||
|
super.updated(changedProperties);
|
||||||
if (changedProperties.has("device")) {
|
if (changedProperties.has("device")) {
|
||||||
const zigbeeConnection = this.device.connections.find(
|
const zigbeeConnection = this.device.connections.find(
|
||||||
(conn) => conn[0] === "zigbee"
|
(conn) => conn[0] === "zigbee"
|
||||||
|
@ -1,142 +0,0 @@
|
|||||||
import {
|
|
||||||
CSSResultGroup,
|
|
||||||
html,
|
|
||||||
LitElement,
|
|
||||||
PropertyValues,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import { HASSDomEvent } from "../../../../../common/dom/fire_event";
|
|
||||||
import "../../../../../components/ha-code-editor";
|
|
||||||
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
|
||||||
import {
|
|
||||||
Cluster,
|
|
||||||
fetchBindableDevices,
|
|
||||||
fetchGroups,
|
|
||||||
ZHADevice,
|
|
||||||
ZHAGroup,
|
|
||||||
} from "../../../../../data/zha";
|
|
||||||
import { haStyleDialog } from "../../../../../resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../../../types";
|
|
||||||
import { sortZHADevices, sortZHAGroups } from "./functions";
|
|
||||||
import { ZHADeviceZigbeeInfoDialogParams } from "./show-dialog-zha-device-zigbee-info";
|
|
||||||
import { ZHAClusterSelectedParams } from "./types";
|
|
||||||
import "./zha-cluster-attributes";
|
|
||||||
import "./zha-cluster-commands";
|
|
||||||
import "./zha-clusters";
|
|
||||||
import "./zha-device-binding";
|
|
||||||
import "./zha-group-binding";
|
|
||||||
|
|
||||||
@customElement("dialog-zha-cluster")
|
|
||||||
class DialogZHACluster extends LitElement {
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@state() private _device?: ZHADevice;
|
|
||||||
|
|
||||||
@state() private _selectedCluster?: Cluster;
|
|
||||||
|
|
||||||
@state() private _bindableDevices: ZHADevice[] = [];
|
|
||||||
|
|
||||||
@state() private _groups: ZHAGroup[] = [];
|
|
||||||
|
|
||||||
public async showDialog(
|
|
||||||
params: ZHADeviceZigbeeInfoDialogParams
|
|
||||||
): Promise<void> {
|
|
||||||
this._device = params.device;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
|
||||||
super.update(changedProperties);
|
|
||||||
if (changedProperties.has("_device")) {
|
|
||||||
this._fetchData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this._device) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<ha-dialog
|
|
||||||
open
|
|
||||||
hideActions
|
|
||||||
@closed=${this._close}
|
|
||||||
.heading=${createCloseHeading(
|
|
||||||
this.hass,
|
|
||||||
this.hass.localize("ui.panel.config.zha.clusters.header")
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<zha-clusters
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selectedDevice=${this._device}
|
|
||||||
@zha-cluster-selected=${this._onClusterSelected}
|
|
||||||
></zha-clusters>
|
|
||||||
${this._selectedCluster
|
|
||||||
? html`
|
|
||||||
<zha-cluster-attributes
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selectedNode=${this._device}
|
|
||||||
.selectedCluster=${this._selectedCluster}
|
|
||||||
></zha-cluster-attributes>
|
|
||||||
<zha-cluster-commands
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selectedNode=${this._device}
|
|
||||||
.selectedCluster=${this._selectedCluster}
|
|
||||||
></zha-cluster-commands>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._bindableDevices.length > 0
|
|
||||||
? html`
|
|
||||||
<zha-device-binding-control
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selectedDevice=${this._device}
|
|
||||||
.bindableDevices=${this._bindableDevices}
|
|
||||||
></zha-device-binding-control>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._device && this._groups.length > 0
|
|
||||||
? html`
|
|
||||||
<zha-group-binding-control
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selectedDevice=${this._device}
|
|
||||||
.groups=${this._groups}
|
|
||||||
></zha-group-binding-control>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</ha-dialog>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onClusterSelected(
|
|
||||||
selectedClusterEvent: HASSDomEvent<ZHAClusterSelectedParams>
|
|
||||||
): void {
|
|
||||||
this._selectedCluster = selectedClusterEvent.detail.cluster;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _close(): void {
|
|
||||||
this._device = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _fetchData(): Promise<void> {
|
|
||||||
if (this._device && this.hass) {
|
|
||||||
this._bindableDevices =
|
|
||||||
this._device && this._device.device_type !== "Coordinator"
|
|
||||||
? (await fetchBindableDevices(this.hass, this._device.ieee)).sort(
|
|
||||||
sortZHADevices
|
|
||||||
)
|
|
||||||
: [];
|
|
||||||
this._groups = (await fetchGroups(this.hass!)).sort(sortZHAGroups);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return haStyleDialog;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"dialog-zha-cluster": DialogZHACluster;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import "../../../../../components/ha-code-editor";
|
|
||||||
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
|
||||||
import { haStyleDialog } from "../../../../../resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../../../types";
|
|
||||||
import { ZHADeviceZigbeeInfoDialogParams } from "./show-dialog-zha-device-zigbee-info";
|
|
||||||
|
|
||||||
@customElement("dialog-zha-device-zigbee-info")
|
|
||||||
class DialogZHADeviceZigbeeInfo extends LitElement {
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@state() private _signature: any;
|
|
||||||
|
|
||||||
public async showDialog(
|
|
||||||
params: ZHADeviceZigbeeInfoDialogParams
|
|
||||||
): Promise<void> {
|
|
||||||
this._signature = JSON.stringify(
|
|
||||||
{
|
|
||||||
...params.device.signature,
|
|
||||||
manufacturer: params.device.manufacturer,
|
|
||||||
model: params.device.model,
|
|
||||||
class: params.device.quirk_class,
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this._signature) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<ha-dialog
|
|
||||||
open
|
|
||||||
hideActions
|
|
||||||
@closed=${this._close}
|
|
||||||
.heading=${createCloseHeading(
|
|
||||||
this.hass,
|
|
||||||
this.hass.localize(`ui.dialogs.zha_device_info.device_signature`)
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<ha-code-editor
|
|
||||||
mode="yaml"
|
|
||||||
readOnly
|
|
||||||
.value=${this._signature}
|
|
||||||
dir="ltr"
|
|
||||||
>
|
|
||||||
</ha-code-editor>
|
|
||||||
</ha-dialog>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _close(): void {
|
|
||||||
this._signature = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return haStyleDialog;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"dialog-zha-device-zigbee-info": DialogZHADeviceZigbeeInfo;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,291 @@
|
|||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
|
import { mdiClose } from "@mdi/js";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { cache } from "lit/directives/cache";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
|
import "../../../../../components/ha-code-editor";
|
||||||
|
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
||||||
|
import {
|
||||||
|
fetchBindableDevices,
|
||||||
|
fetchGroups,
|
||||||
|
ZHADevice,
|
||||||
|
ZHAGroup,
|
||||||
|
} from "../../../../../data/zha";
|
||||||
|
import { haStyleDialog } from "../../../../../resources/styles";
|
||||||
|
import { HomeAssistant } from "../../../../../types";
|
||||||
|
import { sortZHADevices, sortZHAGroups } from "./functions";
|
||||||
|
import "./zha-cluster-attributes";
|
||||||
|
import "./zha-cluster-commands";
|
||||||
|
import "./zha-manage-clusters";
|
||||||
|
import "./zha-device-binding";
|
||||||
|
import "./zha-group-binding";
|
||||||
|
import "./zha-device-children";
|
||||||
|
import "./zha-device-signature";
|
||||||
|
import {
|
||||||
|
Tab,
|
||||||
|
ZHAManageZigbeeDeviceDialogParams,
|
||||||
|
} from "./show-dialog-zha-manage-zigbee-device";
|
||||||
|
import "../../../../../components/ha-header-bar";
|
||||||
|
import "@material/mwc-tab-bar/mwc-tab-bar";
|
||||||
|
import "@material/mwc-tab/mwc-tab";
|
||||||
|
|
||||||
|
@customElement("dialog-zha-manage-zigbee-device")
|
||||||
|
class DialogZHAManageZigbeeDevice extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ type: Boolean, reflect: true }) public large = false;
|
||||||
|
|
||||||
|
@state() private _currTab: Tab = "clusters";
|
||||||
|
|
||||||
|
@state() private _device?: ZHADevice;
|
||||||
|
|
||||||
|
@state() private _bindableDevices: ZHADevice[] = [];
|
||||||
|
|
||||||
|
@state() private _groups: ZHAGroup[] = [];
|
||||||
|
|
||||||
|
public async showDialog(
|
||||||
|
params: ZHAManageZigbeeDeviceDialogParams
|
||||||
|
): Promise<void> {
|
||||||
|
this._device = params.device;
|
||||||
|
if (!this._device) {
|
||||||
|
this.closeDialog();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._currTab = params.tab || "clusters";
|
||||||
|
this.large = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeDialog() {
|
||||||
|
this._device = undefined;
|
||||||
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
this.addEventListener("close-dialog", () => this.closeDialog());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected willUpdate(changedProps: PropertyValues) {
|
||||||
|
super.willUpdate(changedProps);
|
||||||
|
if (!this._device) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (changedProps.has("_device")) {
|
||||||
|
const tabs = this._getTabs(this._device);
|
||||||
|
if (!tabs.includes(this._currTab)) {
|
||||||
|
this._currTab = tabs[0];
|
||||||
|
}
|
||||||
|
this._fetchData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._device) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabs = this._getTabs(this._device);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-dialog
|
||||||
|
open
|
||||||
|
hideActions
|
||||||
|
@closed=${this.closeDialog}
|
||||||
|
.heading=${createCloseHeading(
|
||||||
|
this.hass,
|
||||||
|
this.hass.localize("ui.dialogs.zha_manage_device.heading")
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div slot="heading" class="heading">
|
||||||
|
<ha-header-bar>
|
||||||
|
<ha-icon-button
|
||||||
|
slot="navigationIcon"
|
||||||
|
dialogAction="cancel"
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.dialogs.more_info_control.dismiss"
|
||||||
|
)}
|
||||||
|
.path=${mdiClose}
|
||||||
|
></ha-icon-button>
|
||||||
|
<div
|
||||||
|
slot="title"
|
||||||
|
class="main-title"
|
||||||
|
.title=${this.hass.localize(
|
||||||
|
"ui.dialogs.zha_manage_device.heading"
|
||||||
|
)}
|
||||||
|
@click=${this._enlarge}
|
||||||
|
>
|
||||||
|
${this.hass.localize("ui.dialogs.zha_manage_device.heading")}
|
||||||
|
</div>
|
||||||
|
</ha-header-bar>
|
||||||
|
<mwc-tab-bar
|
||||||
|
.activeIndex=${tabs.indexOf(this._currTab)}
|
||||||
|
@MDCTabBar:activated=${this._handleTabChanged}
|
||||||
|
>
|
||||||
|
${tabs.map(
|
||||||
|
(tab) => html`
|
||||||
|
<mwc-tab
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
`ui.dialogs.zha_manage_device.tabs.${tab}`
|
||||||
|
)}
|
||||||
|
></mwc-tab>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</mwc-tab-bar>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content" tabindex="-1" dialogInitialFocus>
|
||||||
|
${cache(
|
||||||
|
this._currTab === "clusters"
|
||||||
|
? html`
|
||||||
|
<zha-manage-clusters
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this._device}
|
||||||
|
></zha-manage-clusters>
|
||||||
|
`
|
||||||
|
: this._currTab === "bindings"
|
||||||
|
? html`
|
||||||
|
${this._bindableDevices.length > 0
|
||||||
|
? html`
|
||||||
|
<zha-device-binding-control
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this._device}
|
||||||
|
.bindableDevices=${this._bindableDevices}
|
||||||
|
></zha-device-binding-control>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this._device && this._groups.length > 0
|
||||||
|
? html`
|
||||||
|
<zha-group-binding-control
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this._device}
|
||||||
|
.groups=${this._groups}
|
||||||
|
></zha-group-binding-control>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
`
|
||||||
|
: this._currTab === "signature"
|
||||||
|
? html`
|
||||||
|
<zha-device-zigbee-info
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this._device}
|
||||||
|
></zha-device-zigbee-info>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<zha-device-children
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this._device}
|
||||||
|
></zha-device-children>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ha-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _fetchData(): Promise<void> {
|
||||||
|
if (this._device && this.hass) {
|
||||||
|
this._bindableDevices =
|
||||||
|
this._device && this._device.device_type !== "Coordinator"
|
||||||
|
? (await fetchBindableDevices(this.hass, this._device.ieee)).sort(
|
||||||
|
sortZHADevices
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
this._groups = (await fetchGroups(this.hass!)).sort(sortZHAGroups);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _enlarge() {
|
||||||
|
this.large = !this.large;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleTabChanged(ev: CustomEvent): void {
|
||||||
|
const newTab = this._getTabs(this._device)[ev.detail.index];
|
||||||
|
if (newTab === this._currTab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._currTab = newTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getTabs = memoizeOne((device: ZHADevice | undefined) => {
|
||||||
|
const tabs: Tab[] = ["clusters", "bindings", "signature"];
|
||||||
|
|
||||||
|
if (
|
||||||
|
device &&
|
||||||
|
(device.device_type === "Router" || device.device_type === "Coordinator")
|
||||||
|
) {
|
||||||
|
tabs.push("children");
|
||||||
|
}
|
||||||
|
|
||||||
|
return tabs;
|
||||||
|
});
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [
|
||||||
|
haStyleDialog,
|
||||||
|
css`
|
||||||
|
ha-dialog {
|
||||||
|
--dialog-surface-position: static;
|
||||||
|
--dialog-content-position: static;
|
||||||
|
--vertial-align-dialog: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-header-bar {
|
||||||
|
--mdc-theme-on-primary: var(--primary-text-color);
|
||||||
|
--mdc-theme-primary: var(--mdc-theme-surface);
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||||
|
ha-header-bar {
|
||||||
|
--mdc-theme-primary: var(--app-header-background-color);
|
||||||
|
--mdc-theme-on-primary: var(--app-header-text-color, white);
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
border-bottom: 1px solid
|
||||||
|
var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (min-width: 600px) and (min-height: 501px) {
|
||||||
|
ha-dialog {
|
||||||
|
--mdc-dialog-min-width: 560px;
|
||||||
|
--mdc-dialog-max-width: 560px;
|
||||||
|
--dialog-surface-margin-top: 40px;
|
||||||
|
--mdc-dialog-max-height: calc(100% - 72px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-title {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([large]) ha-dialog,
|
||||||
|
ha-dialog[data-domain="camera"] {
|
||||||
|
--mdc-dialog-min-width: 90vw;
|
||||||
|
--mdc-dialog-max-width: 90vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"dialog-zha-manage-zigbee-device": DialogZHAManageZigbeeDevice;
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ import {
|
|||||||
Cluster,
|
Cluster,
|
||||||
ClusterConfigurationEvent,
|
ClusterConfigurationEvent,
|
||||||
ClusterConfigurationStatus,
|
ClusterConfigurationStatus,
|
||||||
fetchClustersForZhaNode,
|
fetchClustersForZhaDevice,
|
||||||
reconfigureNode,
|
reconfigureNode,
|
||||||
ZHA_CHANNEL_CFG_DONE,
|
ZHA_CHANNEL_CFG_DONE,
|
||||||
ZHA_CHANNEL_MSG_BIND,
|
ZHA_CHANNEL_MSG_BIND,
|
||||||
@ -321,16 +321,16 @@ class DialogZHAReconfigureDevice extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._clusterConfigurationStatuses = new Map(
|
this._clusterConfigurationStatuses = new Map(
|
||||||
(await fetchClustersForZhaNode(this.hass, this._params.device.ieee)).map(
|
(
|
||||||
(cluster: Cluster) => [
|
await fetchClustersForZhaDevice(this.hass, this._params.device.ieee)
|
||||||
|
).map((cluster: Cluster) => [
|
||||||
cluster.id,
|
cluster.id,
|
||||||
{
|
{
|
||||||
cluster: cluster,
|
cluster: cluster,
|
||||||
bindSuccess: undefined,
|
bindSuccess: undefined,
|
||||||
attributes: new Map<number, AttributeConfigurationStatus>(),
|
attributes: new Map<number, AttributeConfigurationStatus>(),
|
||||||
},
|
},
|
||||||
]
|
])
|
||||||
)
|
|
||||||
);
|
);
|
||||||
this._subscribe(this._params);
|
this._subscribe(this._params);
|
||||||
this._status = "started";
|
this._status = "started";
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
|
||||||
import { ZHADevice } from "../../../../../data/zha";
|
|
||||||
|
|
||||||
export interface ZHAClusterDialogParams {
|
|
||||||
device: ZHADevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loadZHAClusterDialog = () => import("./dialog-zha-cluster");
|
|
||||||
|
|
||||||
export const showZHAClusterDialog = (
|
|
||||||
element: HTMLElement,
|
|
||||||
params: ZHAClusterDialogParams
|
|
||||||
): void => {
|
|
||||||
fireEvent(element, "show-dialog", {
|
|
||||||
dialogTag: "dialog-zha-cluster",
|
|
||||||
dialogImport: loadZHAClusterDialog,
|
|
||||||
dialogParams: params,
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,20 +0,0 @@
|
|||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
|
||||||
import { ZHADevice } from "../../../../../data/zha";
|
|
||||||
|
|
||||||
export interface ZHADeviceChildrenDialogParams {
|
|
||||||
device: ZHADevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loadZHADeviceChildrenDialog = () =>
|
|
||||||
import("./dialog-zha-device-children");
|
|
||||||
|
|
||||||
export const showZHADeviceChildrenDialog = (
|
|
||||||
element: HTMLElement,
|
|
||||||
zhaDeviceChildrenParams: ZHADeviceChildrenDialogParams
|
|
||||||
): void => {
|
|
||||||
fireEvent(element, "show-dialog", {
|
|
||||||
dialogTag: "dialog-zha-device-children",
|
|
||||||
dialogImport: loadZHADeviceChildrenDialog,
|
|
||||||
dialogParams: zhaDeviceChildrenParams,
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,20 +0,0 @@
|
|||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
|
||||||
import { ZHADevice } from "../../../../../data/zha";
|
|
||||||
|
|
||||||
export interface ZHADeviceZigbeeInfoDialogParams {
|
|
||||||
device: ZHADevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loadZHADeviceZigbeeInfoDialog = () =>
|
|
||||||
import("./dialog-zha-device-zigbee-info");
|
|
||||||
|
|
||||||
export const showZHADeviceZigbeeInfoDialog = (
|
|
||||||
element: HTMLElement,
|
|
||||||
zhaDeviceZigbeeInfoParams: ZHADeviceZigbeeInfoDialogParams
|
|
||||||
): void => {
|
|
||||||
fireEvent(element, "show-dialog", {
|
|
||||||
dialogTag: "dialog-zha-device-zigbee-info",
|
|
||||||
dialogImport: loadZHADeviceZigbeeInfoDialog,
|
|
||||||
dialogParams: zhaDeviceZigbeeInfoParams,
|
|
||||||
});
|
|
||||||
};
|
|
@ -0,0 +1,23 @@
|
|||||||
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
|
import { ZHADevice } from "../../../../../data/zha";
|
||||||
|
|
||||||
|
export type Tab = "clusters" | "bindings" | "signature" | "children";
|
||||||
|
|
||||||
|
export interface ZHAManageZigbeeDeviceDialogParams {
|
||||||
|
device: ZHADevice;
|
||||||
|
tab?: Tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loadZHAManageZigbeeDeviceDialog = () =>
|
||||||
|
import("./dialog-zha-manage-zigbee-device");
|
||||||
|
|
||||||
|
export const showZHAManageZigbeeDeviceDialog = (
|
||||||
|
element: HTMLElement,
|
||||||
|
params: ZHAManageZigbeeDeviceDialogParams
|
||||||
|
): void => {
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "dialog-zha-manage-zigbee-device",
|
||||||
|
dialogImport: loadZHAManageZigbeeDeviceDialog,
|
||||||
|
dialogParams: params,
|
||||||
|
});
|
||||||
|
};
|
@ -1,5 +1,5 @@
|
|||||||
import { HaSelect } from "../../../../../components/ha-select";
|
import { HaSelect } from "../../../../../components/ha-select";
|
||||||
import { Cluster, ZHADevice } from "../../../../../data/zha";
|
import { ZHADevice } from "../../../../../data/zha";
|
||||||
|
|
||||||
export interface ItemSelectedEvent {
|
export interface ItemSelectedEvent {
|
||||||
target?: HaSelect;
|
target?: HaSelect;
|
||||||
@ -41,10 +41,6 @@ export interface ZHADeviceSelectedParams {
|
|||||||
node: ZHADevice;
|
node: ZHADevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ZHAClusterSelectedParams {
|
|
||||||
cluster: Cluster;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NodeServiceData {
|
export interface NodeServiceData {
|
||||||
ieee_address: string;
|
ieee_address: string;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import "@material/mwc-button";
|
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiHelpCircle } from "@mdi/js";
|
|
||||||
import "@polymer/paper-input/paper-input";
|
import "@polymer/paper-input/paper-input";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
@ -10,13 +8,12 @@ import {
|
|||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
||||||
import "../../../../../components/buttons/ha-call-service-button";
|
import "../../../../../components/buttons/ha-call-service-button";
|
||||||
import "../../../../../components/ha-card";
|
import "../../../../../components/ha-card";
|
||||||
import "../../../../../components/ha-icon-button";
|
|
||||||
import "../../../../../components/ha-select";
|
import "../../../../../components/ha-select";
|
||||||
import "../../../../../components/ha-service-description";
|
import "../../../../../components/buttons/ha-progress-button";
|
||||||
import {
|
import {
|
||||||
Attribute,
|
Attribute,
|
||||||
Cluster,
|
Cluster,
|
||||||
@ -27,7 +24,7 @@ import {
|
|||||||
} from "../../../../../data/zha";
|
} from "../../../../../data/zha";
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
import "../../../ha-config-section";
|
import { forwardHaptic } from "../../../../../data/haptics";
|
||||||
import { formatAsPaddedHex } from "./functions";
|
import { formatAsPaddedHex } from "./functions";
|
||||||
import {
|
import {
|
||||||
ChangeEvent,
|
ChangeEvent,
|
||||||
@ -35,18 +32,15 @@ import {
|
|||||||
SetAttributeServiceData,
|
SetAttributeServiceData,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
|
@customElement("zha-cluster-attributes")
|
||||||
export class ZHAClusterAttributes extends LitElement {
|
export class ZHAClusterAttributes extends LitElement {
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property() public isWide?: boolean;
|
@property() public device?: ZHADevice;
|
||||||
|
|
||||||
@property() public showHelp = false;
|
|
||||||
|
|
||||||
@property() public selectedNode?: ZHADevice;
|
|
||||||
|
|
||||||
@property() public selectedCluster?: Cluster;
|
@property() public selectedCluster?: Cluster;
|
||||||
|
|
||||||
@state() private _attributes: Attribute[] = [];
|
@state() private _attributes: Attribute[] | undefined;
|
||||||
|
|
||||||
@state() private _selectedAttributeId?: number;
|
@state() private _selectedAttributeId?: number;
|
||||||
|
|
||||||
@ -54,42 +48,26 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
|
|
||||||
@state() private _manufacturerCodeOverride?: string | number;
|
@state() private _manufacturerCodeOverride?: string | number;
|
||||||
|
|
||||||
|
@state() private _readingAttribute = false;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private _setAttributeServiceData?: SetAttributeServiceData;
|
private _setAttributeServiceData?: SetAttributeServiceData;
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
if (changedProperties.has("selectedCluster")) {
|
if (changedProperties.has("selectedCluster")) {
|
||||||
this._attributes = [];
|
this._attributes = undefined;
|
||||||
this._selectedAttributeId = undefined;
|
this._selectedAttributeId = undefined;
|
||||||
this._attributeValue = "";
|
this._attributeValue = "";
|
||||||
this._fetchAttributesForCluster();
|
this._fetchAttributesForCluster();
|
||||||
}
|
}
|
||||||
super.update(changedProperties);
|
super.updated(changedProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
if (!this.device || !this.selectedCluster || !this._attributes) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
return html`
|
return html`
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<div class="header" slot="header">
|
|
||||||
<span>
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_attributes.header"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<ha-icon-button
|
|
||||||
class="toggle-help-icon"
|
|
||||||
@click=${this._onHelpTap}
|
|
||||||
.path=${mdiHelpCircle}
|
|
||||||
.label=${this.hass!.localize("ui.common.help")}
|
|
||||||
>
|
|
||||||
</ha-icon-button>
|
|
||||||
</div>
|
|
||||||
<span slot="introduction">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_attributes.introduction"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<ha-card class="content">
|
<ha-card class="content">
|
||||||
<div class="attribute-picker">
|
<div class="attribute-picker">
|
||||||
<ha-select
|
<ha-select
|
||||||
@ -106,26 +84,16 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
${this._attributes.map(
|
${this._attributes.map(
|
||||||
(entry) => html`
|
(entry) => html`
|
||||||
<mwc-list-item .value=${String(entry.id)}>
|
<mwc-list-item .value=${String(entry.id)}>
|
||||||
${entry.name + " (id: " + formatAsPaddedHex(entry.id) + ")"}
|
${`${entry.name} (id: ${formatAsPaddedHex(entry.id)})`}
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</ha-select>
|
</ha-select>
|
||||||
</div>
|
</div>
|
||||||
${this.showHelp
|
|
||||||
? html`
|
|
||||||
<div class="help-text">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_attributes.help_attribute_dropdown"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._selectedAttributeId !== undefined
|
${this._selectedAttributeId !== undefined
|
||||||
? this._renderAttributeInteractions()
|
? this._renderAttributeInteractions()
|
||||||
: ""}
|
: ""}
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</ha-config-section>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,20 +120,15 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
></paper-input>
|
></paper-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<mwc-button @click=${this._onGetZigbeeAttributeClick}>
|
<ha-progress-button
|
||||||
|
@click=${this._onGetZigbeeAttributeClick}
|
||||||
|
.progress=${this._readingAttribute}
|
||||||
|
.disabled=${this._readingAttribute}
|
||||||
|
>
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.config.zha.cluster_attributes.get_zigbee_attribute"
|
"ui.panel.config.zha.cluster_attributes.read_zigbee_attribute"
|
||||||
)}
|
)}
|
||||||
</mwc-button>
|
</ha-progress-button>
|
||||||
${this.showHelp
|
|
||||||
? html`
|
|
||||||
<div class="help-text2">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_attributes.help_get_zigbee_attribute"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<ha-call-service-button
|
<ha-call-service-button
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
domain="zha"
|
domain="zha"
|
||||||
@ -173,44 +136,37 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
.serviceData=${this._setAttributeServiceData}
|
.serviceData=${this._setAttributeServiceData}
|
||||||
>
|
>
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.config.zha.cluster_attributes.set_zigbee_attribute"
|
"ui.panel.config.zha.cluster_attributes.write_zigbee_attribute"
|
||||||
)}
|
)}
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
${this.showHelp
|
|
||||||
? html`
|
|
||||||
<ha-service-description
|
|
||||||
.hass=${this.hass}
|
|
||||||
domain="zha"
|
|
||||||
service="set_zigbee_cluster_attribute"
|
|
||||||
class="help-text2"
|
|
||||||
></ha-service-description>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchAttributesForCluster(): Promise<void> {
|
private async _fetchAttributesForCluster(): Promise<void> {
|
||||||
if (this.selectedNode && this.selectedCluster && this.hass) {
|
if (this.device && this.selectedCluster && this.hass) {
|
||||||
this._attributes = await fetchAttributesForCluster(
|
this._attributes = await fetchAttributesForCluster(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.selectedNode!.ieee,
|
this.device!.ieee,
|
||||||
this.selectedCluster!.endpoint_id,
|
this.selectedCluster!.endpoint_id,
|
||||||
this.selectedCluster!.id,
|
this.selectedCluster!.id,
|
||||||
this.selectedCluster!.type
|
this.selectedCluster!.type
|
||||||
);
|
);
|
||||||
this._attributes.sort((a, b) => a.name.localeCompare(b.name));
|
this._attributes.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
if (this._attributes.length > 0) {
|
||||||
|
this._selectedAttributeId = this._attributes[0].id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeReadAttributeServiceData():
|
private _computeReadAttributeServiceData():
|
||||||
| ReadAttributeServiceData
|
| ReadAttributeServiceData
|
||||||
| undefined {
|
| undefined {
|
||||||
if (!this.selectedCluster || !this.selectedNode) {
|
if (!this.selectedCluster || !this.device) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
ieee: this.selectedNode!.ieee,
|
ieee: this.device!.ieee,
|
||||||
endpoint_id: this.selectedCluster!.endpoint_id,
|
endpoint_id: this.selectedCluster!.endpoint_id,
|
||||||
cluster_id: this.selectedCluster!.id,
|
cluster_id: this.selectedCluster!.id,
|
||||||
cluster_type: this.selectedCluster!.type,
|
cluster_type: this.selectedCluster!.type,
|
||||||
@ -224,11 +180,11 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
private _computeSetAttributeServiceData():
|
private _computeSetAttributeServiceData():
|
||||||
| SetAttributeServiceData
|
| SetAttributeServiceData
|
||||||
| undefined {
|
| undefined {
|
||||||
if (!this.selectedCluster || !this.selectedNode) {
|
if (!this.selectedCluster || !this.device) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
ieee: this.selectedNode!.ieee,
|
ieee: this.device!.ieee,
|
||||||
endpoint_id: this.selectedCluster!.endpoint_id,
|
endpoint_id: this.selectedCluster!.endpoint_id,
|
||||||
cluster_id: this.selectedCluster!.id,
|
cluster_id: this.selectedCluster!.id,
|
||||||
cluster_type: this.selectedCluster!.type,
|
cluster_type: this.selectedCluster!.type,
|
||||||
@ -250,15 +206,22 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
this._setAttributeServiceData = this._computeSetAttributeServiceData();
|
this._setAttributeServiceData = this._computeSetAttributeServiceData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _onGetZigbeeAttributeClick(): Promise<void> {
|
private async _onGetZigbeeAttributeClick(ev: CustomEvent): Promise<void> {
|
||||||
|
const button = ev.currentTarget as any;
|
||||||
const data = this._computeReadAttributeServiceData();
|
const data = this._computeReadAttributeServiceData();
|
||||||
if (data && this.hass) {
|
if (data && this.hass) {
|
||||||
|
this._readingAttribute = true;
|
||||||
|
try {
|
||||||
this._attributeValue = await readAttributeValue(this.hass, data);
|
this._attributeValue = await readAttributeValue(this.hass, data);
|
||||||
|
forwardHaptic("success");
|
||||||
|
button.actionSuccess();
|
||||||
|
} catch (err: any) {
|
||||||
|
forwardHaptic("failure");
|
||||||
|
button.actionError();
|
||||||
|
} finally {
|
||||||
|
this._readingAttribute = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
|
||||||
this.showHelp = !this.showHelp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _selectedAttributeChanged(event: ItemSelectedEvent): void {
|
private _selectedAttributeChanged(event: ItemSelectedEvent): void {
|
||||||
@ -278,14 +241,6 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-card {
|
|
||||||
max-width: 680px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions.warning ha-call-service-button {
|
.card-actions.warning ha-call-service-button {
|
||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
}
|
}
|
||||||
@ -306,33 +261,6 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
.header {
|
.header {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-help-icon {
|
|
||||||
float: right;
|
|
||||||
top: -6px;
|
|
||||||
right: 0;
|
|
||||||
padding-right: 0px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-service-description {
|
|
||||||
display: block;
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.help-text {
|
|
||||||
color: grey;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
}
|
|
||||||
.help-text2 {
|
|
||||||
color: grey;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -343,5 +271,3 @@ declare global {
|
|||||||
"zha-cluster-attributes": ZHAClusterAttributes;
|
"zha-cluster-attributes": ZHAClusterAttributes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("zha-cluster-attributes", ZHAClusterAttributes);
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiHelpCircle } from "@mdi/js";
|
|
||||||
import "@polymer/paper-input/paper-input";
|
import "@polymer/paper-input/paper-input";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
@ -13,9 +12,7 @@ import { property, state } from "lit/decorators";
|
|||||||
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
||||||
import "../../../../../components/buttons/ha-call-service-button";
|
import "../../../../../components/buttons/ha-call-service-button";
|
||||||
import "../../../../../components/ha-card";
|
import "../../../../../components/ha-card";
|
||||||
import "../../../../../components/ha-icon-button";
|
|
||||||
import "../../../../../components/ha-select";
|
import "../../../../../components/ha-select";
|
||||||
import "../../../../../components/ha-service-description";
|
|
||||||
import {
|
import {
|
||||||
Cluster,
|
Cluster,
|
||||||
Command,
|
Command,
|
||||||
@ -24,7 +21,6 @@ import {
|
|||||||
} from "../../../../../data/zha";
|
} from "../../../../../data/zha";
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
import "../../../ha-config-section";
|
|
||||||
import { formatAsPaddedHex } from "./functions";
|
import { formatAsPaddedHex } from "./functions";
|
||||||
import { ChangeEvent, IssueCommandServiceData } from "./types";
|
import { ChangeEvent, IssueCommandServiceData } from "./types";
|
||||||
|
|
||||||
@ -33,13 +29,11 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
|
|
||||||
@property() public isWide?: boolean;
|
@property() public isWide?: boolean;
|
||||||
|
|
||||||
@property() public selectedNode?: ZHADevice;
|
@property() public device?: ZHADevice;
|
||||||
|
|
||||||
@property() public selectedCluster?: Cluster;
|
@property() public selectedCluster?: Cluster;
|
||||||
|
|
||||||
@state() private _showHelp = false;
|
@state() private _commands: Command[] | undefined;
|
||||||
|
|
||||||
@state() private _commands: Command[] = [];
|
|
||||||
|
|
||||||
@state() private _selectedCommandId?: number;
|
@state() private _selectedCommandId?: number;
|
||||||
|
|
||||||
@ -50,36 +44,18 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
if (changedProperties.has("selectedCluster")) {
|
if (changedProperties.has("selectedCluster")) {
|
||||||
this._commands = [];
|
this._commands = undefined;
|
||||||
this._selectedCommandId = undefined;
|
this._selectedCommandId = undefined;
|
||||||
this._fetchCommandsForCluster();
|
this._fetchCommandsForCluster();
|
||||||
}
|
}
|
||||||
super.update(changedProperties);
|
super.updated(changedProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
if (!this.device || !this.selectedCluster || !this._commands) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
return html`
|
return html`
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<div class="header" slot="header">
|
|
||||||
<span>
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_commands.header"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<ha-icon-button
|
|
||||||
class="toggle-help-icon"
|
|
||||||
@click=${this._onHelpTap}
|
|
||||||
.path=${mdiHelpCircle}
|
|
||||||
.label=${this.hass!.localize("ui.common.help")}
|
|
||||||
>
|
|
||||||
</ha-icon-button>
|
|
||||||
</div>
|
|
||||||
<span slot="introduction">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_commands.introduction"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<ha-card class="content">
|
<ha-card class="content">
|
||||||
<div class="command-picker">
|
<div class="command-picker">
|
||||||
<ha-select
|
<ha-select
|
||||||
@ -102,15 +78,6 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</ha-select>
|
</ha-select>
|
||||||
</div>
|
</div>
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="help-text">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_commands.help_command_dropdown"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._selectedCommandId !== undefined
|
${this._selectedCommandId !== undefined
|
||||||
? html`
|
? html`
|
||||||
<div class="input-text">
|
<div class="input-text">
|
||||||
@ -137,45 +104,37 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
"ui.panel.config.zha.cluster_commands.issue_zigbee_command"
|
"ui.panel.config.zha.cluster_commands.issue_zigbee_command"
|
||||||
)}
|
)}
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<ha-service-description
|
|
||||||
.hass=${this.hass}
|
|
||||||
domain="zha"
|
|
||||||
service="issue_zigbee_cluster_command"
|
|
||||||
class="help-text2"
|
|
||||||
></ha-service-description>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</ha-config-section>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchCommandsForCluster(): Promise<void> {
|
private async _fetchCommandsForCluster(): Promise<void> {
|
||||||
if (this.selectedNode && this.selectedCluster && this.hass) {
|
if (this.device && this.selectedCluster && this.hass) {
|
||||||
this._commands = await fetchCommandsForCluster(
|
this._commands = await fetchCommandsForCluster(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.selectedNode!.ieee,
|
this.device!.ieee,
|
||||||
this.selectedCluster!.endpoint_id,
|
this.selectedCluster!.endpoint_id,
|
||||||
this.selectedCluster!.id,
|
this.selectedCluster!.id,
|
||||||
this.selectedCluster!.type
|
this.selectedCluster!.type
|
||||||
);
|
);
|
||||||
this._commands.sort((a, b) => a.name.localeCompare(b.name));
|
this._commands.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
if (this._commands.length > 0) {
|
||||||
|
this._selectedCommandId = this._commands[0].id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeIssueClusterCommandServiceData():
|
private _computeIssueClusterCommandServiceData():
|
||||||
| IssueCommandServiceData
|
| IssueCommandServiceData
|
||||||
| undefined {
|
| undefined {
|
||||||
if (!this.selectedNode || !this.selectedCluster) {
|
if (!this.device || !this.selectedCluster || !this._commands) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
ieee: this.selectedNode!.ieee,
|
ieee: this.device!.ieee,
|
||||||
endpoint_id: this.selectedCluster!.endpoint_id,
|
endpoint_id: this.selectedCluster!.endpoint_id,
|
||||||
cluster_id: this.selectedCluster!.id,
|
cluster_id: this.selectedCluster!.id,
|
||||||
cluster_type: this.selectedCluster!.type,
|
cluster_type: this.selectedCluster!.type,
|
||||||
@ -192,10 +151,6 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
this._computeIssueClusterCommandServiceData();
|
this._computeIssueClusterCommandServiceData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
|
||||||
this._showHelp = !this._showHelp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _selectedCommandChanged(event): void {
|
private _selectedCommandChanged(event): void {
|
||||||
this._selectedCommandId = Number(event.target.value);
|
this._selectedCommandId = Number(event.target.value);
|
||||||
this._issueClusterCommandServiceData =
|
this._issueClusterCommandServiceData =
|
||||||
@ -213,14 +168,6 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-card {
|
|
||||||
max-width: 680px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions.warning ha-call-service-button {
|
.card-actions.warning ha-call-service-button {
|
||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
}
|
}
|
||||||
@ -238,18 +185,6 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.help-text {
|
|
||||||
color: grey;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-text2 {
|
|
||||||
color: grey;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
@ -261,15 +196,6 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
padding-right: 0px;
|
padding-right: 0px;
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-service-description {
|
|
||||||
display: block;
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ export class ZHAClustersDataTable extends LitElement {
|
|||||||
title: "ID",
|
title: "ID",
|
||||||
template: (id: number) => html` ${formatAsPaddedHex(id)} `,
|
template: (id: number) => html` ${formatAsPaddedHex(id)} `,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
width: "15%",
|
width: "25%",
|
||||||
},
|
},
|
||||||
endpoint_id: {
|
endpoint_id: {
|
||||||
title: "Endpoint ID",
|
title: "Endpoint ID",
|
||||||
|
@ -1,195 +0,0 @@
|
|||||||
import "@material/mwc-list/mwc-list-item";
|
|
||||||
import { mdiHelpCircle } from "@mdi/js";
|
|
||||||
import {
|
|
||||||
css,
|
|
||||||
CSSResultGroup,
|
|
||||||
html,
|
|
||||||
LitElement,
|
|
||||||
PropertyValues,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit";
|
|
||||||
import { property, state } from "lit/decorators";
|
|
||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
|
||||||
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
|
||||||
import "../../../../../components/buttons/ha-call-service-button";
|
|
||||||
import "../../../../../components/ha-card";
|
|
||||||
import "../../../../../components/ha-icon-button";
|
|
||||||
import "../../../../../components/ha-select";
|
|
||||||
import "../../../../../components/ha-service-description";
|
|
||||||
import {
|
|
||||||
Cluster,
|
|
||||||
fetchClustersForZhaNode,
|
|
||||||
ZHADevice,
|
|
||||||
} from "../../../../../data/zha";
|
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../../../types";
|
|
||||||
import "../../../ha-config-section";
|
|
||||||
import { computeClusterKey } from "./functions";
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
// for fire event
|
|
||||||
interface HASSDomEvents {
|
|
||||||
"zha-cluster-selected": {
|
|
||||||
cluster?: Cluster;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ZHAClusters extends LitElement {
|
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
|
||||||
|
|
||||||
@property() public isWide?: boolean;
|
|
||||||
|
|
||||||
@property() public selectedDevice?: ZHADevice;
|
|
||||||
|
|
||||||
@property() public showHelp = false;
|
|
||||||
|
|
||||||
@state() private _selectedClusterIndex = -1;
|
|
||||||
|
|
||||||
@state() private _clusters: Cluster[] = [];
|
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
|
||||||
if (changedProperties.has("selectedDevice")) {
|
|
||||||
this._clusters = [];
|
|
||||||
this._selectedClusterIndex = -1;
|
|
||||||
fireEvent(this, "zha-cluster-selected", {
|
|
||||||
cluster: undefined,
|
|
||||||
});
|
|
||||||
this._fetchClustersForZhaNode();
|
|
||||||
}
|
|
||||||
super.update(changedProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<div class="header" slot="header">
|
|
||||||
<ha-icon-button
|
|
||||||
class="toggle-help-icon"
|
|
||||||
@click=${this._onHelpTap}
|
|
||||||
.path=${mdiHelpCircle}
|
|
||||||
.label=${this.hass!.localize("ui.common.help")}
|
|
||||||
>
|
|
||||||
</ha-icon-button>
|
|
||||||
</div>
|
|
||||||
<span slot="introduction">
|
|
||||||
${this.hass!.localize("ui.panel.config.zha.clusters.introduction")}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<ha-card class="content">
|
|
||||||
<div class="node-picker">
|
|
||||||
<ha-select
|
|
||||||
.label=${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.common.clusters"
|
|
||||||
)}
|
|
||||||
class="menu"
|
|
||||||
.value=${String(this._selectedClusterIndex)}
|
|
||||||
@selected=${this._selectedClusterChanged}
|
|
||||||
@closed=${stopPropagation}
|
|
||||||
fixedMenuPosition
|
|
||||||
naturalMenuWidth
|
|
||||||
>
|
|
||||||
${this._clusters.map(
|
|
||||||
(entry, idx) => html`
|
|
||||||
<mwc-list-item .value=${String(idx)}
|
|
||||||
>${computeClusterKey(entry)}</mwc-list-item
|
|
||||||
>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-select>
|
|
||||||
</div>
|
|
||||||
${this.showHelp
|
|
||||||
? html`
|
|
||||||
<div class="help-text">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.clusters.help_cluster_dropdown"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</ha-card>
|
|
||||||
</ha-config-section>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _fetchClustersForZhaNode(): Promise<void> {
|
|
||||||
if (this.hass) {
|
|
||||||
this._clusters = await fetchClustersForZhaNode(
|
|
||||||
this.hass,
|
|
||||||
this.selectedDevice!.ieee
|
|
||||||
);
|
|
||||||
this._clusters.sort((a, b) => a.name.localeCompare(b.name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _selectedClusterChanged(event): void {
|
|
||||||
this._selectedClusterIndex = Number(event.target!.value);
|
|
||||||
fireEvent(this, "zha-cluster-selected", {
|
|
||||||
cluster: this._clusters[this._selectedClusterIndex],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
|
||||||
this.showHelp = !this.showHelp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return [
|
|
||||||
haStyle,
|
|
||||||
css`
|
|
||||||
ha-select {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
.menu {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-card {
|
|
||||||
max-width: 680px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.node-picker {
|
|
||||||
align-items: center;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-help-icon {
|
|
||||||
float: right;
|
|
||||||
top: -6px;
|
|
||||||
right: 0;
|
|
||||||
padding-right: 0px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-text {
|
|
||||||
color: grey;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"zha-cluster": ZHAClusters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("zha-clusters", ZHAClusters);
|
|
@ -1,6 +1,4 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiHelpCircle } from "@mdi/js";
|
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
@ -11,26 +9,19 @@ import {
|
|||||||
} from "lit";
|
} from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
||||||
import "../../../../../components/buttons/ha-call-service-button";
|
import "../../../../../components/buttons/ha-progress-button";
|
||||||
import "../../../../../components/ha-card";
|
import "../../../../../components/ha-card";
|
||||||
import "../../../../../components/ha-icon-button";
|
|
||||||
import "../../../../../components/ha-select";
|
import "../../../../../components/ha-select";
|
||||||
import "../../../../../components/ha-service-description";
|
|
||||||
import { bindDevices, unbindDevices, ZHADevice } from "../../../../../data/zha";
|
import { bindDevices, unbindDevices, ZHADevice } from "../../../../../data/zha";
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
import "../../../ha-config-section";
|
|
||||||
import { ItemSelectedEvent } from "./types";
|
import { ItemSelectedEvent } from "./types";
|
||||||
|
|
||||||
@customElement("zha-device-binding-control")
|
@customElement("zha-device-binding-control")
|
||||||
export class ZHADeviceBindingControl extends LitElement {
|
export class ZHADeviceBindingControl extends LitElement {
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property() public isWide?: boolean;
|
@property() public device?: ZHADevice;
|
||||||
|
|
||||||
@property() public selectedDevice?: ZHADevice;
|
|
||||||
|
|
||||||
@state() private _showHelp = false;
|
|
||||||
|
|
||||||
@state() private _bindTargetIndex = -1;
|
@state() private _bindTargetIndex = -1;
|
||||||
|
|
||||||
@ -38,32 +29,23 @@ export class ZHADeviceBindingControl extends LitElement {
|
|||||||
|
|
||||||
@state() private _deviceToBind?: ZHADevice;
|
@state() private _deviceToBind?: ZHADevice;
|
||||||
|
|
||||||
|
@state() private _bindingOperationInProgress = false;
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
if (changedProperties.has("selectedDevice")) {
|
if (changedProperties.has("device")) {
|
||||||
this._bindTargetIndex = -1;
|
this._bindTargetIndex = -1;
|
||||||
}
|
}
|
||||||
super.update(changedProperties);
|
super.updated(changedProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<div class="header" slot="header">
|
|
||||||
<span>Device Binding</span>
|
|
||||||
<ha-icon-button
|
|
||||||
class="toggle-help-icon"
|
|
||||||
@click=${this._onHelpTap}
|
|
||||||
.path=${mdiHelpCircle}
|
|
||||||
.label=${this.hass!.localize("ui.common.help")}
|
|
||||||
>
|
|
||||||
</ha-icon-button>
|
|
||||||
</div>
|
|
||||||
<span slot="introduction">Bind and unbind devices.</span>
|
|
||||||
|
|
||||||
<ha-card class="content">
|
<ha-card class="content">
|
||||||
<div class="command-picker">
|
<div class="command-picker">
|
||||||
<ha-select
|
<ha-select
|
||||||
label="Bindable Devices"
|
label=${this.hass!.localize(
|
||||||
|
"ui.panel.config.zha.device_binding.picker_label"
|
||||||
|
)}
|
||||||
class="menu"
|
class="menu"
|
||||||
.value=${String(this._bindTargetIndex)}
|
.value=${String(this._bindTargetIndex)}
|
||||||
@selected=${this._bindTargetIndexChanged}
|
@selected=${this._bindTargetIndexChanged}
|
||||||
@ -82,33 +64,23 @@ export class ZHADeviceBindingControl extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</ha-select>
|
</ha-select>
|
||||||
</div>
|
</div>
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="helpText">
|
|
||||||
Select a device to issue a bind command.
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<mwc-button
|
<ha-progress-button
|
||||||
@click=${this._onBindDevicesClick}
|
@click=${this._onBindDevicesClick}
|
||||||
.disabled=${!(this._deviceToBind && this.selectedDevice)}
|
.disabled=${!(this._deviceToBind && this.device) ||
|
||||||
>Bind</mwc-button
|
this._bindingOperationInProgress}
|
||||||
>
|
>
|
||||||
${this._showHelp
|
${this.hass!.localize("ui.panel.config.zha.device_binding.bind")}
|
||||||
? html` <div class="helpText">Bind devices.</div> `
|
</ha-progress-button>
|
||||||
: ""}
|
<ha-progress-button
|
||||||
<mwc-button
|
|
||||||
@click=${this._onUnbindDevicesClick}
|
@click=${this._onUnbindDevicesClick}
|
||||||
.disabled=${!(this._deviceToBind && this.selectedDevice)}
|
.disabled=${!(this._deviceToBind && this.device) ||
|
||||||
>Unbind</mwc-button
|
this._bindingOperationInProgress}
|
||||||
>
|
>
|
||||||
${this._showHelp
|
${this.hass!.localize("ui.panel.config.zha.device_binding.unbind")}
|
||||||
? html` <div class="helpText">Unbind devices.</div> `
|
</ha-progress-button>
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</ha-config-section>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,27 +92,41 @@ export class ZHADeviceBindingControl extends LitElement {
|
|||||||
: this.bindableDevices[this._bindTargetIndex];
|
: this.bindableDevices[this._bindTargetIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
private async _onBindDevicesClick(ev: CustomEvent): Promise<void> {
|
||||||
this._showHelp = !this._showHelp;
|
const button = ev.currentTarget as any;
|
||||||
|
if (this.hass && this._deviceToBind && this.device) {
|
||||||
|
this._bindingOperationInProgress = true;
|
||||||
|
button.progress = true;
|
||||||
|
try {
|
||||||
|
await bindDevices(this.hass, this.device.ieee, this._deviceToBind.ieee);
|
||||||
|
button.actionSuccess();
|
||||||
|
} catch (err: any) {
|
||||||
|
button.actionError();
|
||||||
|
} finally {
|
||||||
|
this._bindingOperationInProgress = false;
|
||||||
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _onBindDevicesClick(): Promise<void> {
|
|
||||||
if (this.hass && this._deviceToBind && this.selectedDevice) {
|
|
||||||
await bindDevices(
|
|
||||||
this.hass,
|
|
||||||
this.selectedDevice.ieee,
|
|
||||||
this._deviceToBind.ieee
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _onUnbindDevicesClick(): Promise<void> {
|
private async _onUnbindDevicesClick(ev: CustomEvent): Promise<void> {
|
||||||
if (this.hass && this._deviceToBind && this.selectedDevice) {
|
const button = ev.currentTarget as any;
|
||||||
|
if (this.hass && this._deviceToBind && this.device) {
|
||||||
|
this._bindingOperationInProgress = true;
|
||||||
|
button.progress = true;
|
||||||
|
try {
|
||||||
await unbindDevices(
|
await unbindDevices(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.selectedDevice.ieee,
|
this.device.ieee,
|
||||||
this._deviceToBind.ieee
|
this._deviceToBind.ieee
|
||||||
);
|
);
|
||||||
|
button.actionSuccess();
|
||||||
|
} catch (err: any) {
|
||||||
|
button.actionError();
|
||||||
|
} finally {
|
||||||
|
this._bindingOperationInProgress = false;
|
||||||
|
button.progress = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,18 +138,6 @@ export class ZHADeviceBindingControl extends LitElement {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-card {
|
|
||||||
max-width: 680px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions.warning ha-call-service-button {
|
|
||||||
color: var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.command-picker {
|
.command-picker {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
@ -171,33 +145,9 @@ export class ZHADeviceBindingControl extends LitElement {
|
|||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.helpText {
|
|
||||||
color: grey;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-help-icon {
|
|
||||||
float: right;
|
|
||||||
top: -6px;
|
|
||||||
right: 0;
|
|
||||||
padding-right: 0px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-service-description {
|
|
||||||
display: block;
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { computeRTLDirection } from "../../../../../common/util/compute_rtl";
|
import { computeRTLDirection } from "../../../../../common/util/compute_rtl";
|
||||||
import "../../../../../components/ha-code-editor";
|
import "../../../../../components/ha-code-editor";
|
||||||
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
|
||||||
import { haStyleDialog } from "../../../../../resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
import { ZHADeviceChildrenDialogParams } from "./show-dialog-zha-device-children";
|
|
||||||
import "../../../../../components/data-table/ha-data-table";
|
import "../../../../../components/data-table/ha-data-table";
|
||||||
import type {
|
import type {
|
||||||
DataTableColumnContainer,
|
DataTableColumnContainer,
|
||||||
@ -14,7 +11,6 @@ import type {
|
|||||||
} from "../../../../../components/data-table/ha-data-table";
|
} from "../../../../../components/data-table/ha-data-table";
|
||||||
import "../../../../../components/ha-circular-progress";
|
import "../../../../../components/ha-circular-progress";
|
||||||
import { fetchDevices, ZHADevice } from "../../../../../data/zha";
|
import { fetchDevices, ZHADevice } from "../../../../../data/zha";
|
||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
|
||||||
|
|
||||||
export interface DeviceRowData extends DataTableRowData {
|
export interface DeviceRowData extends DataTableRowData {
|
||||||
id: string;
|
id: string;
|
||||||
@ -22,14 +18,21 @@ export interface DeviceRowData extends DataTableRowData {
|
|||||||
lqi: number;
|
lqi: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("dialog-zha-device-children")
|
@customElement("zha-device-children")
|
||||||
class DialogZHADeviceChildren extends LitElement {
|
class ZHADeviceChildren extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@state() private _device: ZHADevice | undefined;
|
@property() public device: ZHADevice | undefined;
|
||||||
|
|
||||||
@state() private _devices: Map<string, ZHADevice> | undefined;
|
@state() private _devices: Map<string, ZHADevice> | undefined;
|
||||||
|
|
||||||
|
protected updated(changedProperties: PropertyValues) {
|
||||||
|
super.updated(changedProperties);
|
||||||
|
if (this.hass && changedProperties.has("device")) {
|
||||||
|
this._fetchData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _deviceChildren = memoizeOne(
|
private _deviceChildren = memoizeOne(
|
||||||
(
|
(
|
||||||
device: ZHADevice | undefined,
|
device: ZHADevice | undefined,
|
||||||
@ -69,31 +72,11 @@ class DialogZHADeviceChildren extends LitElement {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
public showDialog(params: ZHADeviceChildrenDialogParams): void {
|
|
||||||
this._device = params.device;
|
|
||||||
this._fetchData();
|
|
||||||
}
|
|
||||||
|
|
||||||
public closeDialog(): void {
|
|
||||||
this._device = undefined;
|
|
||||||
this._devices = undefined;
|
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this._device) {
|
if (!this.device) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
|
||||||
hideActions
|
|
||||||
open
|
|
||||||
@closed=${this.closeDialog}
|
|
||||||
.heading=${createCloseHeading(
|
|
||||||
this.hass,
|
|
||||||
this.hass.localize(`ui.dialogs.zha_device_info.device_children`)
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
${!this._devices
|
${!this._devices
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
alt="Loading"
|
alt="Loading"
|
||||||
@ -103,7 +86,7 @@ class DialogZHADeviceChildren extends LitElement {
|
|||||||
: html`<ha-data-table
|
: html`<ha-data-table
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.columns=${this._columns}
|
.columns=${this._columns}
|
||||||
.data=${this._deviceChildren(this._device, this._devices)}
|
.data=${this._deviceChildren(this.device, this._devices)}
|
||||||
auto-height
|
auto-height
|
||||||
.dir=${computeRTLDirection(this.hass)}
|
.dir=${computeRTLDirection(this.hass)}
|
||||||
.searchLabel=${this.hass.localize(
|
.searchLabel=${this.hass.localize(
|
||||||
@ -113,26 +96,21 @@ class DialogZHADeviceChildren extends LitElement {
|
|||||||
"ui.components.data-table.no-data"
|
"ui.components.data-table.no-data"
|
||||||
)}
|
)}
|
||||||
></ha-data-table>`}
|
></ha-data-table>`}
|
||||||
</ha-dialog>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchData(): Promise<void> {
|
private async _fetchData(): Promise<void> {
|
||||||
if (this._device && this.hass) {
|
if (this.device && this.hass) {
|
||||||
const devices = await fetchDevices(this.hass!);
|
const devices = await fetchDevices(this.hass!);
|
||||||
this._devices = new Map(
|
this._devices = new Map(
|
||||||
devices.map((device: ZHADevice) => [device.ieee, device])
|
devices.map((device: ZHADevice) => [device.ieee, device])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return haStyleDialog;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"dialog-zha-device-children": DialogZHADeviceChildren;
|
"zha-device-children": ZHADeviceChildren;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import "../../../../../components/ha-code-editor";
|
||||||
|
import { ZHADevice } from "../../../../../data/zha";
|
||||||
|
import { HomeAssistant } from "../../../../../types";
|
||||||
|
|
||||||
|
@customElement("zha-device-zigbee-info")
|
||||||
|
class ZHADeviceZigbeeInfo extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public device: ZHADevice | undefined;
|
||||||
|
|
||||||
|
@state() private _signature: any;
|
||||||
|
|
||||||
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
|
if (changedProperties.has("device") && this.hass && this.device) {
|
||||||
|
this._signature = JSON.stringify(
|
||||||
|
{
|
||||||
|
...this.device.signature,
|
||||||
|
manufacturer: this.device.manufacturer,
|
||||||
|
model: this.device.model,
|
||||||
|
class: this.device.quirk_class,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
super.updated(changedProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._signature) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-code-editor mode="yaml" readOnly .value=${this._signature} dir="ltr">
|
||||||
|
</ha-code-editor>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"zha-device-zigbee-info": ZHADeviceZigbeeInfo;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,3 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
|
||||||
import { mdiHelpCircle } from "@mdi/js";
|
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
@ -11,37 +9,29 @@ import {
|
|||||||
import { customElement, property, state, query } from "lit/decorators";
|
import { customElement, property, state, query } from "lit/decorators";
|
||||||
import type { HASSDomEvent } from "../../../../../common/dom/fire_event";
|
import type { HASSDomEvent } from "../../../../../common/dom/fire_event";
|
||||||
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
||||||
import "../../../../../components/buttons/ha-call-service-button";
|
import "../../../../../components/buttons/ha-progress-button";
|
||||||
import { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table";
|
import { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table";
|
||||||
import "../../../../../components/ha-card";
|
import "../../../../../components/ha-card";
|
||||||
import "../../../../../components/ha-icon-button";
|
|
||||||
import "../../../../../components/ha-service-description";
|
|
||||||
import {
|
import {
|
||||||
bindDeviceToGroup,
|
bindDeviceToGroup,
|
||||||
Cluster,
|
Cluster,
|
||||||
fetchClustersForZhaNode,
|
fetchClustersForZhaDevice,
|
||||||
unbindDeviceFromGroup,
|
unbindDeviceFromGroup,
|
||||||
ZHADevice,
|
ZHADevice,
|
||||||
ZHAGroup,
|
ZHAGroup,
|
||||||
} from "../../../../../data/zha";
|
} from "../../../../../data/zha";
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../../../types";
|
import type { HomeAssistant } from "../../../../../types";
|
||||||
import "../../../ha-config-section";
|
|
||||||
import { ItemSelectedEvent } from "./types";
|
import { ItemSelectedEvent } from "./types";
|
||||||
import "./zha-clusters-data-table";
|
import "./zha-clusters-data-table";
|
||||||
import type { ZHAClustersDataTable } from "./zha-clusters-data-table";
|
import type { ZHAClustersDataTable } from "./zha-clusters-data-table";
|
||||||
|
import "@material/mwc-list/mwc-list-item";
|
||||||
|
|
||||||
@customElement("zha-group-binding-control")
|
@customElement("zha-group-binding-control")
|
||||||
export class ZHAGroupBindingControl extends LitElement {
|
export class ZHAGroupBindingControl extends LitElement {
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property() public isWide?: boolean;
|
@property() public device?: ZHADevice;
|
||||||
|
|
||||||
@property() public narrow?: boolean;
|
|
||||||
|
|
||||||
@property() public selectedDevice?: ZHADevice;
|
|
||||||
|
|
||||||
@state() private _showHelp = false;
|
|
||||||
|
|
||||||
@state() private _bindTargetIndex = -1;
|
@state() private _bindTargetIndex = -1;
|
||||||
|
|
||||||
@ -51,6 +41,8 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
|
|
||||||
@state() private _clusters: Cluster[] = [];
|
@state() private _clusters: Cluster[] = [];
|
||||||
|
|
||||||
|
@state() private _bindingOperationInProgress = false;
|
||||||
|
|
||||||
private _groupToBind?: ZHAGroup;
|
private _groupToBind?: ZHAGroup;
|
||||||
|
|
||||||
private _clustersToBind?: Cluster[];
|
private _clustersToBind?: Cluster[];
|
||||||
@ -59,38 +51,17 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
private _zhaClustersDataTable!: ZHAClustersDataTable;
|
private _zhaClustersDataTable!: ZHAClustersDataTable;
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
if (changedProperties.has("selectedDevice")) {
|
if (changedProperties.has("device")) {
|
||||||
this._bindTargetIndex = -1;
|
this._bindTargetIndex = -1;
|
||||||
this._selectedClusters = [];
|
this._selectedClusters = [];
|
||||||
this._clustersToBind = [];
|
this._clustersToBind = [];
|
||||||
this._fetchClustersForZhaNode();
|
this._fetchClustersForZhaNode();
|
||||||
}
|
}
|
||||||
super.update(changedProperties);
|
super.updated(changedProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<div class="sectionHeader" slot="header">
|
|
||||||
<span
|
|
||||||
>${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.group_binding.header"
|
|
||||||
)}</span
|
|
||||||
>
|
|
||||||
<ha-icon-button
|
|
||||||
class="toggle-help-icon"
|
|
||||||
@click=${this._onHelpTap}
|
|
||||||
.path=${mdiHelpCircle}
|
|
||||||
.label=${this.hass!.localize("ui.common.help")}
|
|
||||||
>
|
|
||||||
</ha-icon-button>
|
|
||||||
</div>
|
|
||||||
<span slot="introduction"
|
|
||||||
>${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.group_binding.introduction"
|
|
||||||
)}</span
|
|
||||||
>
|
|
||||||
|
|
||||||
<ha-card class="content">
|
<ha-card class="content">
|
||||||
<div class="command-picker">
|
<div class="command-picker">
|
||||||
<ha-select
|
<ha-select
|
||||||
@ -112,66 +83,32 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</ha-select>
|
</ha-select>
|
||||||
</div>
|
</div>
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="helpText">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.group_binding.group_picker_help"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<div class="command-picker">
|
<div class="command-picker">
|
||||||
<zha-clusters-data-table
|
<zha-clusters-data-table
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.narrow=${this.narrow}
|
|
||||||
.clusters=${this._clusters}
|
.clusters=${this._clusters}
|
||||||
@selection-changed=${this._handleClusterSelectionChanged}
|
@selection-changed=${this._handleClusterSelectionChanged}
|
||||||
class="menu"
|
class="menu"
|
||||||
></zha-clusters-data-table>
|
></zha-clusters-data-table>
|
||||||
</div>
|
</div>
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="helpText">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.group_binding.cluster_selection_help"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<mwc-button
|
<ha-progress-button
|
||||||
@click=${this._onBindGroupClick}
|
@click=${this._onBindGroupClick}
|
||||||
.disabled=${!this._canBind}
|
.disabled=${!this._canBind || this._bindingOperationInProgress}
|
||||||
>${this.hass!.localize(
|
>
|
||||||
|
${this.hass!.localize(
|
||||||
"ui.panel.config.zha.group_binding.bind_button_label"
|
"ui.panel.config.zha.group_binding.bind_button_label"
|
||||||
)}</mwc-button
|
|
||||||
>
|
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="helpText">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.group_binding.bind_button_help"
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</ha-progress-button>
|
||||||
`
|
|
||||||
: ""}
|
<ha-progress-button
|
||||||
<mwc-button
|
|
||||||
@click=${this._onUnbindGroupClick}
|
@click=${this._onUnbindGroupClick}
|
||||||
.disabled=${!this._canBind}
|
.disabled=${!this._canBind || this._bindingOperationInProgress}
|
||||||
>${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.group_binding.unbind_button_label"
|
|
||||||
)}</mwc-button
|
|
||||||
>
|
>
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="helpText">
|
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.config.zha.group_binding.unbind_button_help"
|
"ui.panel.config.zha.group_binding.unbind_button_label"
|
||||||
)}
|
)}
|
||||||
</div>
|
</ha-progress-button>
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
@ -186,31 +123,49 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
: this.groups[this._bindTargetIndex];
|
: this.groups[this._bindTargetIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
private async _onBindGroupClick(ev: CustomEvent): Promise<void> {
|
||||||
this._showHelp = !this._showHelp;
|
const button = ev.currentTarget as any;
|
||||||
}
|
|
||||||
|
|
||||||
private async _onBindGroupClick(): Promise<void> {
|
|
||||||
if (this.hass && this._canBind) {
|
if (this.hass && this._canBind) {
|
||||||
|
this._bindingOperationInProgress = true;
|
||||||
|
button.progress = true;
|
||||||
|
try {
|
||||||
await bindDeviceToGroup(
|
await bindDeviceToGroup(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.selectedDevice!.ieee,
|
this.device!.ieee,
|
||||||
this._groupToBind!.group_id,
|
this._groupToBind!.group_id,
|
||||||
this._clustersToBind!
|
this._clustersToBind!
|
||||||
);
|
);
|
||||||
this._zhaClustersDataTable.clearSelection();
|
this._zhaClustersDataTable.clearSelection();
|
||||||
|
button.actionSuccess();
|
||||||
|
} catch (err: any) {
|
||||||
|
button.actionError();
|
||||||
|
} finally {
|
||||||
|
this._bindingOperationInProgress = false;
|
||||||
|
button.progress = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _onUnbindGroupClick(): Promise<void> {
|
private async _onUnbindGroupClick(ev: CustomEvent): Promise<void> {
|
||||||
|
const button = ev.currentTarget as any;
|
||||||
if (this.hass && this._canBind) {
|
if (this.hass && this._canBind) {
|
||||||
|
this._bindingOperationInProgress = true;
|
||||||
|
button.progress = true;
|
||||||
|
try {
|
||||||
await unbindDeviceFromGroup(
|
await unbindDeviceFromGroup(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.selectedDevice!.ieee,
|
this.device!.ieee,
|
||||||
this._groupToBind!.group_id,
|
this._groupToBind!.group_id,
|
||||||
this._clustersToBind!
|
this._clustersToBind!
|
||||||
);
|
);
|
||||||
this._zhaClustersDataTable.clearSelection();
|
this._zhaClustersDataTable.clearSelection();
|
||||||
|
button.actionSuccess();
|
||||||
|
} catch (err: any) {
|
||||||
|
button.actionError();
|
||||||
|
} finally {
|
||||||
|
this._bindingOperationInProgress = false;
|
||||||
|
button.progress = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,9 +185,9 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
|
|
||||||
private async _fetchClustersForZhaNode(): Promise<void> {
|
private async _fetchClustersForZhaNode(): Promise<void> {
|
||||||
if (this.hass) {
|
if (this.hass) {
|
||||||
this._clusters = await fetchClustersForZhaNode(
|
this._clusters = await fetchClustersForZhaDevice(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.selectedDevice!.ieee
|
this.device!.ieee
|
||||||
);
|
);
|
||||||
this._clusters = this._clusters
|
this._clusters = this._clusters
|
||||||
.filter((cluster) => cluster.type.toLowerCase() === "out")
|
.filter((cluster) => cluster.type.toLowerCase() === "out")
|
||||||
@ -245,7 +200,7 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
this._groupToBind &&
|
this._groupToBind &&
|
||||||
this._clustersToBind &&
|
this._clustersToBind &&
|
||||||
this._clustersToBind?.length > 0 &&
|
this._clustersToBind?.length > 0 &&
|
||||||
this.selectedDevice
|
this.device
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,18 +212,6 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-card {
|
|
||||||
max-width: 680px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions.warning ha-call-service-button {
|
|
||||||
color: var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.command-picker {
|
.command-picker {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
@ -285,30 +228,6 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
.sectionHeader {
|
.sectionHeader {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.helpText {
|
|
||||||
color: grey;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-help-icon {
|
|
||||||
float: right;
|
|
||||||
top: -6px;
|
|
||||||
right: 0;
|
|
||||||
padding-right: 0px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-service-description {
|
|
||||||
display: block;
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,198 @@
|
|||||||
|
import "@material/mwc-list/mwc-list-item";
|
||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { cache } from "lit/directives/cache";
|
||||||
|
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
||||||
|
import "../../../../../components/ha-card";
|
||||||
|
import "../../../../../components/ha-select";
|
||||||
|
import {
|
||||||
|
Cluster,
|
||||||
|
fetchClustersForZhaDevice,
|
||||||
|
ZHADevice,
|
||||||
|
} from "../../../../../data/zha";
|
||||||
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
|
import { HomeAssistant } from "../../../../../types";
|
||||||
|
import { computeClusterKey } from "./functions";
|
||||||
|
import "@material/mwc-tab-bar/mwc-tab-bar";
|
||||||
|
import "@material/mwc-tab/mwc-tab";
|
||||||
|
import "./zha-cluster-attributes";
|
||||||
|
import "./zha-cluster-commands";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// for fire event
|
||||||
|
interface HASSDomEvents {
|
||||||
|
"zha-cluster-selected": {
|
||||||
|
cluster?: Cluster;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabs = ["attributes", "commands"] as const;
|
||||||
|
|
||||||
|
@customElement("zha-manage-clusters")
|
||||||
|
export class ZHAManageClusters extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public isWide?: boolean;
|
||||||
|
|
||||||
|
@property() public device?: ZHADevice;
|
||||||
|
|
||||||
|
@state() private _selectedClusterIndex = -1;
|
||||||
|
|
||||||
|
@state() private _clusters: Cluster[] = [];
|
||||||
|
|
||||||
|
@state() private _selectedCluster?: Cluster;
|
||||||
|
|
||||||
|
@state() private _currTab: typeof tabs[number] = "attributes";
|
||||||
|
|
||||||
|
@state() private _clustersLoaded = false;
|
||||||
|
|
||||||
|
protected willUpdate(changedProps: PropertyValues) {
|
||||||
|
super.willUpdate(changedProps);
|
||||||
|
if (!this.device) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!tabs.includes(this._currTab)) {
|
||||||
|
this._currTab = tabs[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
|
if (changedProperties.has("device")) {
|
||||||
|
this._clusters = [];
|
||||||
|
this._selectedClusterIndex = -1;
|
||||||
|
this._clustersLoaded = false;
|
||||||
|
this._fetchClustersForZhaDevice();
|
||||||
|
}
|
||||||
|
super.updated(changedProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.device || !this._clustersLoaded) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<ha-card class="content">
|
||||||
|
<div class="node-picker">
|
||||||
|
<ha-select
|
||||||
|
.label=${this.hass!.localize("ui.panel.config.zha.common.clusters")}
|
||||||
|
class="menu"
|
||||||
|
.value=${String(this._selectedClusterIndex)}
|
||||||
|
@selected=${this._selectedClusterChanged}
|
||||||
|
@closed=${stopPropagation}
|
||||||
|
fixedMenuPosition
|
||||||
|
naturalMenuWidth
|
||||||
|
>
|
||||||
|
${this._clusters.map(
|
||||||
|
(entry, idx) => html`
|
||||||
|
<mwc-list-item .value=${String(idx)}
|
||||||
|
>${computeClusterKey(entry)}</mwc-list-item
|
||||||
|
>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-select>
|
||||||
|
</div>
|
||||||
|
${this._selectedCluster
|
||||||
|
? html`
|
||||||
|
<mwc-tab-bar
|
||||||
|
.activeIndex=${tabs.indexOf(this._currTab)}
|
||||||
|
@MDCTabBar:activated=${this._handleTabChanged}
|
||||||
|
>
|
||||||
|
${tabs.map(
|
||||||
|
(tab) => html`
|
||||||
|
<mwc-tab
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
`ui.panel.config.zha.clusters.tabs.${tab}`
|
||||||
|
)}
|
||||||
|
></mwc-tab>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</mwc-tab-bar>
|
||||||
|
|
||||||
|
<div class="content" tabindex="-1" dialogInitialFocus>
|
||||||
|
${cache(
|
||||||
|
this._currTab === "attributes"
|
||||||
|
? html`
|
||||||
|
<zha-cluster-attributes
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this.device}
|
||||||
|
.selectedCluster=${this._selectedCluster}
|
||||||
|
></zha-cluster-attributes>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<zha-cluster-commands
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this.device}
|
||||||
|
.selectedCluster=${this._selectedCluster}
|
||||||
|
></zha-cluster-commands>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</ha-card>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _fetchClustersForZhaDevice(): Promise<void> {
|
||||||
|
if (this.hass) {
|
||||||
|
this._clusters = await fetchClustersForZhaDevice(
|
||||||
|
this.hass,
|
||||||
|
this.device!.ieee
|
||||||
|
);
|
||||||
|
this._clusters.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
if (this._clusters.length > 0) {
|
||||||
|
this._selectedClusterIndex = 0;
|
||||||
|
this._selectedCluster = this._clusters[0];
|
||||||
|
}
|
||||||
|
this._clustersLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleTabChanged(ev: CustomEvent): void {
|
||||||
|
const newTab = tabs[ev.detail.index];
|
||||||
|
if (newTab === this._currTab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._currTab = newTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _selectedClusterChanged(event): void {
|
||||||
|
this._selectedClusterIndex = Number(event.target!.value);
|
||||||
|
this._selectedCluster = this._clusters[this._selectedClusterIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
|
ha-select {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
.menu {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.node-picker {
|
||||||
|
align-items: center;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"zha-manage-clusters": ZHAManageClusters;
|
||||||
|
}
|
||||||
|
}
|
@ -1002,6 +1002,15 @@
|
|||||||
"attribute": "Attribute",
|
"attribute": "Attribute",
|
||||||
"min_max_change": "min/max/change"
|
"min_max_change": "min/max/change"
|
||||||
},
|
},
|
||||||
|
"zha_manage_device": {
|
||||||
|
"heading": "Manage Zigbee Device",
|
||||||
|
"tabs": {
|
||||||
|
"clusters": "Clusters",
|
||||||
|
"bindings": "Bindings",
|
||||||
|
"signature": "Signature",
|
||||||
|
"children": "Children"
|
||||||
|
}
|
||||||
|
},
|
||||||
"zha_device_info": {
|
"zha_device_info": {
|
||||||
"manuf": "by {manufacturer}",
|
"manuf": "by {manufacturer}",
|
||||||
"no_area": "No Area",
|
"no_area": "No Area",
|
||||||
@ -1010,10 +1019,8 @@
|
|||||||
"buttons": {
|
"buttons": {
|
||||||
"add": "Add devices via this device",
|
"add": "Add devices via this device",
|
||||||
"remove": "Remove",
|
"remove": "Remove",
|
||||||
"clusters": "Manage clusters",
|
"manage": "Manage zigbee device",
|
||||||
"reconfigure": "Reconfigure",
|
"reconfigure": "Reconfigure",
|
||||||
"zigbee_information": "Zigbee signature",
|
|
||||||
"device_children": "View children",
|
|
||||||
"view_network": "View network"
|
"view_network": "View network"
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
@ -3078,17 +3085,17 @@
|
|||||||
"clusters": {
|
"clusters": {
|
||||||
"header": "Clusters",
|
"header": "Clusters",
|
||||||
"help_cluster_dropdown": "Select a cluster to view attributes and commands.",
|
"help_cluster_dropdown": "Select a cluster to view attributes and commands.",
|
||||||
"introduction": "Clusters are the building blocks for Zigbee functionality. They separate functionality into logical units. There are client and server types and that are comprised of attributes and commands."
|
"tabs": {
|
||||||
|
"attributes": "Attributes",
|
||||||
|
"commands": "Commands"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"cluster_attributes": {
|
"cluster_attributes": {
|
||||||
"header": "Cluster Attributes",
|
"header": "Cluster Attributes",
|
||||||
"introduction": "View and edit cluster attributes.",
|
"introduction": "View and edit cluster attributes.",
|
||||||
"attributes_of_cluster": "Attributes of the selected cluster",
|
"attributes_of_cluster": "Attributes of the selected cluster",
|
||||||
"get_zigbee_attribute": "Get Zigbee Attribute",
|
"read_zigbee_attribute": "Read Attribute",
|
||||||
"set_zigbee_attribute": "Set Zigbee Attribute",
|
"write_zigbee_attribute": "Write Attribute"
|
||||||
"help_attribute_dropdown": "Select an attribute to view or set its value.",
|
|
||||||
"help_get_zigbee_attribute": "Get the value for the selected attribute.",
|
|
||||||
"help_set_zigbee_attribute": "Set attribute value for the specified cluster on the specified entity."
|
|
||||||
},
|
},
|
||||||
"cluster_commands": {
|
"cluster_commands": {
|
||||||
"header": "Cluster Commands",
|
"header": "Cluster Commands",
|
||||||
@ -3138,6 +3145,11 @@
|
|||||||
"enable_physics": "Enable Physics",
|
"enable_physics": "Enable Physics",
|
||||||
"refresh_topology": "Refresh Topology"
|
"refresh_topology": "Refresh Topology"
|
||||||
},
|
},
|
||||||
|
"device_binding": {
|
||||||
|
"bind": "Bind",
|
||||||
|
"unbind": "Unbind",
|
||||||
|
"picker_label": "Bindable Devices"
|
||||||
|
},
|
||||||
"group_binding": {
|
"group_binding": {
|
||||||
"header": "Group Binding",
|
"header": "Group Binding",
|
||||||
"introduction": "Bind and unbind groups.",
|
"introduction": "Bind and unbind groups.",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user