mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-22 08:46:35 +00:00
ZHA add devices page (#2969)
* zha add device page add device join dialog stub update dialog stub fix spinner add messages and devices to dialog dialog updates update dialog update dialog add debug info fix reference add header update dialog test zha gateway message subscription add device join dialog stub add messages and devices to dialog dialog updates update dialog add debug info update dialog start transitioning to a page instead of a dialog fix import subpage update router remove old dialog handle remove dialog parts make add button call navigate change extract page add devices page cleanup * update device join page * auto scroll log * update css and add device page layout * fix padding * fix missing imports * fix imports * add -> permit * left justify device cards to prevent jumping * conditionally display entity ids * cleanup * fix vertical alignment * review comments * fix manufacturer overrides
This commit is contained in:
parent
435b7d9cee
commit
669358bf1a
@ -16,6 +16,7 @@ export interface ZHADevice {
|
||||
manufacturer_code: number;
|
||||
device_reg_id: string;
|
||||
user_given_name: string;
|
||||
area_id: string;
|
||||
}
|
||||
|
||||
export interface Attribute {
|
||||
@ -42,7 +43,7 @@ export interface ReadAttributeServiceData {
|
||||
cluster_id: number;
|
||||
cluster_type: string;
|
||||
attribute: number;
|
||||
manufacturer: number;
|
||||
manufacturer?: number;
|
||||
}
|
||||
|
||||
export const reconfigureNode = (
|
||||
|
@ -73,9 +73,9 @@ class HaPanelConfig extends HassRouterPage {
|
||||
import(/* webpackChunkName: "panel-config-users" */ "./users/ha-config-users"),
|
||||
},
|
||||
zha: {
|
||||
tag: "ha-config-zha",
|
||||
tag: "zha-config-panel",
|
||||
load: () =>
|
||||
import(/* webpackChunkName: "panel-config-zha" */ "./zha/ha-config-zha"),
|
||||
import(/* webpackChunkName: "panel-config-zha" */ "./zha/zha-config-panel"),
|
||||
},
|
||||
zwave: {
|
||||
tag: "ha-config-zwave",
|
||||
|
@ -1,26 +1,26 @@
|
||||
import "@polymer/app-layout/app-header/app-header";
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import "../../../components/ha-paper-icon-button-arrow-prev";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import "./zha-binding";
|
||||
import "./zha-cluster-attributes";
|
||||
import "./zha-cluster-commands";
|
||||
import "./zha-network";
|
||||
import "./zha-node";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
|
||||
import {
|
||||
CSSResult,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
|
||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { Cluster, ZHADevice, fetchBindableDevices } from "../../../data/zha";
|
||||
import "../../../layouts/ha-app-layout";
|
||||
import "../../../components/ha-paper-icon-button-arrow-prev";
|
||||
import { Cluster, fetchBindableDevices, ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ZHAClusterSelectedParams, ZHADeviceSelectedParams } from "./types";
|
||||
import "./zha-cluster-attributes";
|
||||
import "./zha-cluster-commands";
|
||||
import "./zha-network";
|
||||
import "./zha-node";
|
||||
import "./zha-binding";
|
||||
|
||||
export class HaConfigZha extends LitElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
@ -38,16 +38,7 @@ export class HaConfigZha extends LitElement {
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<ha-app-layout>
|
||||
<app-header slot="header">
|
||||
<app-toolbar>
|
||||
<ha-paper-icon-button-arrow-prev
|
||||
@click="${this._onBackTapped}"
|
||||
></ha-paper-icon-button-arrow-prev>
|
||||
<div main-title>Zigbee Home Automation</div>
|
||||
</app-toolbar>
|
||||
</app-header>
|
||||
|
||||
<hass-subpage header="Zigbee Home Automation">
|
||||
<zha-network
|
||||
.isWide="${this.isWide}"
|
||||
.hass="${this.hass}"
|
||||
@ -86,7 +77,7 @@ export class HaConfigZha extends LitElement {
|
||||
></zha-binding-control>
|
||||
`
|
||||
: ""}
|
||||
</ha-app-layout>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -117,10 +108,6 @@ export class HaConfigZha extends LitElement {
|
||||
static get styles(): CSSResult[] {
|
||||
return [haStyle];
|
||||
}
|
||||
|
||||
private _onBackTapped(): void {
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -8,6 +8,12 @@ export interface ItemSelectedEvent {
|
||||
target?: PickerTarget;
|
||||
}
|
||||
|
||||
export interface ZHADeviceRemovedEvent {
|
||||
detail?: {
|
||||
device?: ZHADevice;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ChangeEvent {
|
||||
detail?: {
|
||||
value?: any;
|
||||
@ -22,7 +28,7 @@ export interface SetAttributeServiceData {
|
||||
cluster_type: string;
|
||||
attribute: number;
|
||||
value: any;
|
||||
manufacturer: number;
|
||||
manufacturer?: number;
|
||||
}
|
||||
|
||||
export interface IssueCommandServiceData {
|
||||
|
246
src/panels/config/zha/zha-add-devices-page.ts
Normal file
246
src/panels/config/zha/zha-add-devices-page.ts
Normal file
@ -0,0 +1,246 @@
|
||||
import "../../../components/ha-service-description";
|
||||
import "../../../components/ha-textarea";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import "./zha-device-card";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import { ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("zha-add-devices-page")
|
||||
class ZHAAddDevicesPage extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@property() public isWide?: boolean;
|
||||
@property() private _error?: string;
|
||||
@property() private _discoveredDevices: ZHADevice[] = [];
|
||||
@property() private _formattedEvents: string = "";
|
||||
@property() private _active: boolean = false;
|
||||
@property() private _showHelp: boolean = false;
|
||||
private _addDevicesTimeoutHandle: any = undefined;
|
||||
private _subscribed?: Promise<() => Promise<void>>;
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this._subscribe();
|
||||
}
|
||||
|
||||
public disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._unsubscribe();
|
||||
this._error = undefined;
|
||||
this._discoveredDevices = [];
|
||||
this._formattedEvents = "";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<hass-subpage
|
||||
header="${this.hass!.localize(
|
||||
"ui.panel.config.zha.add_device_page.header"
|
||||
)}"
|
||||
>
|
||||
${this._active
|
||||
? html`
|
||||
<h2>
|
||||
<paper-spinner
|
||||
?active="${this._active}"
|
||||
alt="Searching"
|
||||
></paper-spinner>
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.add_device_page.spinner"
|
||||
)}
|
||||
</h2>
|
||||
`
|
||||
: html`
|
||||
<div class="card-actions">
|
||||
<mwc-button @click=${this._subscribe} class="search-button">
|
||||
Search again
|
||||
</mwc-button>
|
||||
<paper-icon-button
|
||||
class="toggle-help-icon"
|
||||
@click="${this._onHelpTap}"
|
||||
icon="hass:help-circle"
|
||||
></paper-icon-button>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="permit"
|
||||
class="help-text"
|
||||
/>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`}
|
||||
${this._error
|
||||
? html`
|
||||
<div class="error">${this._error}</div>
|
||||
`
|
||||
: ""}
|
||||
<div class="content-header"></div>
|
||||
<div class="content">
|
||||
${this._discoveredDevices.length < 1
|
||||
? html`
|
||||
<div class="discovery-text">
|
||||
<h4>
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.add_device_page.discovery_text"
|
||||
)}
|
||||
</h4>
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
${this._discoveredDevices.map(
|
||||
(device) => html`
|
||||
<zha-device-card
|
||||
class="card"
|
||||
.hass="${this.hass}"
|
||||
.device="${device}"
|
||||
.narrow="${!this.isWide}"
|
||||
.showHelp="${this._showHelp}"
|
||||
.showActions="${!this._active}"
|
||||
.isJoinPage="${true}"
|
||||
></zha-device-card>
|
||||
`
|
||||
)}
|
||||
`}
|
||||
</div>
|
||||
<ha-textarea class="events" value="${this._formattedEvents}">
|
||||
</ha-textarea>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleMessage(message: any): void {
|
||||
if (message.type === "log_output") {
|
||||
this._formattedEvents += message.log_entry.message + "\n";
|
||||
if (this.shadowRoot) {
|
||||
const textArea = this.shadowRoot.querySelector("ha-textarea");
|
||||
if (textArea) {
|
||||
textArea.scrollTop = textArea.scrollHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (message.type && message.type === "device_fully_initialized") {
|
||||
this._discoveredDevices.push(message.device_info);
|
||||
}
|
||||
}
|
||||
|
||||
private _unsubscribe(): void {
|
||||
this._active = false;
|
||||
if (this._addDevicesTimeoutHandle) {
|
||||
clearTimeout(this._addDevicesTimeoutHandle);
|
||||
}
|
||||
if (this._subscribed) {
|
||||
this._subscribed.then((unsub) => unsub());
|
||||
this._subscribed = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private _subscribe(): void {
|
||||
this._subscribed = this.hass!.connection.subscribeMessage(
|
||||
(message) => this._handleMessage(message),
|
||||
{ type: "zha/devices/permit" }
|
||||
);
|
||||
this._active = true;
|
||||
this._addDevicesTimeoutHandle = setTimeout(
|
||||
() => this._unsubscribe(),
|
||||
60000
|
||||
);
|
||||
}
|
||||
|
||||
private _onHelpTap(): void {
|
||||
this._showHelp = !this._showHelp;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.discovery-text,
|
||||
.content-header {
|
||||
margin: 16px;
|
||||
}
|
||||
.content {
|
||||
border-top: 1px solid var(--light-primary-color);
|
||||
min-height: 500px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px;
|
||||
justify-content: left;
|
||||
overflow: scroll;
|
||||
}
|
||||
.error {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
paper-spinner {
|
||||
display: none;
|
||||
margin-right: 20px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
paper-spinner[active] {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 20px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
.card {
|
||||
margin-left: 16px;
|
||||
margin-right: 16px;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.events {
|
||||
margin: 16px;
|
||||
border-top: 1px solid var(--light-primary-color);
|
||||
padding-top: 16px;
|
||||
min-height: 200px;
|
||||
max-height: 200px;
|
||||
overflow: scroll;
|
||||
}
|
||||
.toggle-help-icon {
|
||||
position: absolute;
|
||||
margin-top: 16px;
|
||||
margin-right: 16px;
|
||||
top: -6px;
|
||||
right: 0;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
ha-service-description {
|
||||
margin-top: 16px;
|
||||
margin-left: 16px;
|
||||
display: block;
|
||||
color: grey;
|
||||
}
|
||||
.search-button {
|
||||
margin-top: 16px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding-left: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-add-devices-page": ZHAAddDevicesPage;
|
||||
}
|
||||
}
|
@ -1,20 +1,26 @@
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
customElement,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import { ZHADevice, bindDevices, unbindDevices } from "../../../data/zha";
|
||||
|
||||
import { bindDevices, unbindDevices, ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { ItemSelectedEvent } from "./types";
|
||||
|
||||
@customElement("zha-binding-control")
|
||||
|
@ -1,17 +1,24 @@
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
|
||||
import {
|
||||
Attribute,
|
||||
Cluster,
|
||||
@ -22,13 +29,12 @@ import {
|
||||
} from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
import {
|
||||
ChangeEvent,
|
||||
ItemSelectedEvent,
|
||||
SetAttributeServiceData,
|
||||
} from "./types";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
|
||||
export class ZHAClusterAttributes extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
@ -115,7 +121,7 @@ export class ZHAClusterAttributes extends LitElement {
|
||||
</div>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div style="color: grey; padding: 16px">
|
||||
<div class="help-text">
|
||||
Select an attribute to view or set its value
|
||||
</div>
|
||||
`
|
||||
@ -152,6 +158,13 @@ export class ZHAClusterAttributes extends LitElement {
|
||||
<mwc-button @click="${this._onGetZigbeeAttributeClick}"
|
||||
>Get Zigbee Attribute</mwc-button
|
||||
>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div class="help-text2">
|
||||
Get the value for the selected attribute
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
<ha-call-service-button
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
@ -165,6 +178,7 @@ export class ZHAClusterAttributes extends LitElement {
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="set_zigbee_cluster_attribute"
|
||||
class="help-text2"
|
||||
></ha-service-description>
|
||||
`
|
||||
: ""}
|
||||
@ -201,7 +215,7 @@ export class ZHAClusterAttributes extends LitElement {
|
||||
attribute: this._attributes[this._selectedAttributeIndex].id,
|
||||
manufacturer: this._manufacturerCodeOverride
|
||||
? parseInt(this._manufacturerCodeOverride as string, 10)
|
||||
: this.selectedNode!.manufacturer_code,
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@ -220,7 +234,7 @@ export class ZHAClusterAttributes extends LitElement {
|
||||
value: this._attributeValue,
|
||||
manufacturer: this._manufacturerCodeOverride
|
||||
? parseInt(this._manufacturerCodeOverride as string, 10)
|
||||
: this.selectedNode!.manufacturer_code,
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@ -312,6 +326,16 @@ export class ZHAClusterAttributes extends LitElement {
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.help-text2 {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -1,15 +1,23 @@
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
|
||||
import {
|
||||
Cluster,
|
||||
Command,
|
||||
@ -18,13 +26,12 @@ import {
|
||||
} from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
import {
|
||||
ChangeEvent,
|
||||
IssueCommandServiceData,
|
||||
ItemSelectedEvent,
|
||||
} from "./types";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
|
||||
export class ZHAClusterCommands extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
@ -107,7 +114,7 @@ export class ZHAClusterCommands extends LitElement {
|
||||
</div>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<div class="helpText">Select a command to interact with</div>
|
||||
<div class="help-text">Select a command to interact with</div>
|
||||
`
|
||||
: ""}
|
||||
${this._selectedCommandIndex !== -1
|
||||
@ -135,6 +142,7 @@ export class ZHAClusterCommands extends LitElement {
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="issue_zigbee_cluster_command"
|
||||
class="help-text2"
|
||||
></ha-service-description>
|
||||
`
|
||||
: ""}
|
||||
@ -242,7 +250,14 @@ export class ZHAClusterCommands extends LitElement {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.helpText {
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.help-text2 {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
|
@ -1,22 +1,27 @@
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
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 { ItemSelectedEvent } from "./types";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
import { ItemSelectedEvent } from "./types";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
@ -90,7 +95,7 @@ export class ZHAClusters extends LitElement {
|
||||
</div>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div class="helpText">
|
||||
<div class="help-text">
|
||||
Select cluster to view attributes and commands
|
||||
</div>
|
||||
`
|
||||
@ -143,9 +148,11 @@ export class ZHAClusters extends LitElement {
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.helpText {
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
70
src/panels/config/zha/zha-config-panel.ts
Normal file
70
src/panels/config/zha/zha-config-panel.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import "../../../layouts/hass-loading-screen";
|
||||
|
||||
import { customElement, property } from "lit-element";
|
||||
|
||||
import { listenMediaQuery } from "../../../common/dom/media_query";
|
||||
import {
|
||||
HassRouterPage,
|
||||
RouterOptions,
|
||||
} from "../../../layouts/hass-router-page";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("zha-config-panel")
|
||||
class ZHAConfigPanel extends HassRouterPage {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@property() public _wideSidebar: boolean = false;
|
||||
@property() public _wide: boolean = false;
|
||||
|
||||
protected routerOptions: RouterOptions = {
|
||||
defaultPage: "configuration",
|
||||
cacheAll: true,
|
||||
preloadAll: true,
|
||||
routes: {
|
||||
configuration: {
|
||||
tag: "ha-config-zha",
|
||||
load: () =>
|
||||
import(/* webpackChunkName: "zha-configuration-page" */ "./ha-config-zha"),
|
||||
},
|
||||
add: {
|
||||
tag: "zha-add-devices-page",
|
||||
load: () =>
|
||||
import(/* webpackChunkName: "zha-add-devices-page" */ "./zha-add-devices-page"),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
private _listeners: Array<() => void> = [];
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this._listeners.push(
|
||||
listenMediaQuery("(min-width: 1040px)", (matches) => {
|
||||
this._wide = matches;
|
||||
})
|
||||
);
|
||||
this._listeners.push(
|
||||
listenMediaQuery("(min-width: 1296px)", (matches) => {
|
||||
this._wideSidebar = matches;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
while (this._listeners.length) {
|
||||
this._listeners.pop()!();
|
||||
}
|
||||
}
|
||||
|
||||
protected updatePageEl(el): void {
|
||||
el.route = this.routeTail;
|
||||
el.hass = this.hass;
|
||||
el.isWide = this.hass.dockedSidebar ? this._wideSidebar : this._wide;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-config-panel": ZHAConfigPanel;
|
||||
}
|
||||
}
|
@ -1,40 +1,123 @@
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/entity/state-badge";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-icon-item";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-item/paper-icon-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import compare from "../../../common/string/compare";
|
||||
import {
|
||||
AreaRegistryEntry,
|
||||
fetchAreaRegistry,
|
||||
} from "../../../data/area_registry";
|
||||
import {
|
||||
DeviceRegistryEntryMutableParams,
|
||||
updateDeviceRegistryEntry,
|
||||
} from "../../../data/device_registry";
|
||||
import { reconfigureNode, ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ItemSelectedEvent, NodeServiceData } from "./types";
|
||||
|
||||
import "../../../components/entity/state-badge";
|
||||
import { ZHADevice } from "../../../data/zha";
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"zha-device-removed": {
|
||||
device?: ZHADevice;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("zha-device-card")
|
||||
class ZHADeviceCard extends LitElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
@property() public narrow?: boolean;
|
||||
@property() public device?: ZHADevice;
|
||||
@property() public showHelp: boolean = false;
|
||||
@property() public showActions?: boolean;
|
||||
@property() public isJoinPage?: boolean;
|
||||
@property() private _serviceData?: NodeServiceData;
|
||||
@property() private _areas: AreaRegistryEntry[] = [];
|
||||
@property() private _selectedAreaIndex: number = -1;
|
||||
|
||||
public firstUpdated(changedProperties: PropertyValues): void {
|
||||
super.firstUpdated(changedProperties);
|
||||
this.addEventListener("hass-service-called", (ev) =>
|
||||
this.serviceCalled(ev)
|
||||
);
|
||||
this._serviceData = {
|
||||
ieee_address: this.device!.ieee,
|
||||
};
|
||||
fetchAreaRegistry(this.hass!).then((areas) => {
|
||||
this._areas = areas.sort((a, b) => compare(a.name, b.name));
|
||||
});
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
if (changedProperties.has("device")) {
|
||||
this._selectedAreaIndex =
|
||||
this._areas.findIndex((area) => area.area_id === this.device!.area_id) +
|
||||
1;
|
||||
}
|
||||
super.update(changedProperties);
|
||||
}
|
||||
|
||||
protected serviceCalled(ev): void {
|
||||
// Check if this is for us
|
||||
if (ev.detail.success && ev.detail.service === "remove") {
|
||||
fireEvent(this, "zha-device-removed", {
|
||||
device: this.device,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<paper-card>
|
||||
<paper-card heading="${this.isJoinPage ? this.device!.name : ""}">
|
||||
${
|
||||
this.isJoinPage
|
||||
? html`
|
||||
<div class="info">
|
||||
<div class="model">${this.device!.model}</div>
|
||||
<div class="manuf">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.integrations.config_entry.manuf",
|
||||
"manufacturer",
|
||||
this.device!.manufacturer
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
<div class="card-content">
|
||||
<dl>
|
||||
<dt class="label">IEEE:</dt>
|
||||
<dd class="info">${this.device!.ieee}</dd>
|
||||
<dt class="label">Quirk applied:</dt>
|
||||
<dd class="info">${this.device!.quirk_applied}</dd>
|
||||
<dt class="label">Quirk:</dt>
|
||||
<dd class="info">${this.device!.quirk_class}</dd>
|
||||
<dt>IEEE:</dt>
|
||||
<dd class="zha-info">${this.device!.ieee}</dd>
|
||||
${
|
||||
this.device!.quirk_applied
|
||||
? html`
|
||||
<dt>Quirk:</dt>
|
||||
<dd class="zha-info">${this.device!.quirk_class}</dd>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
@ -49,24 +132,145 @@ class ZHADeviceCard extends LitElement {
|
||||
.stateObj="${this.hass!.states[entity.entity_id]}"
|
||||
slot="item-icon"
|
||||
></state-badge>
|
||||
${!this.isJoinPage
|
||||
? html`
|
||||
<paper-item-body>
|
||||
<div class="name">${entity.name}</div>
|
||||
<div class="secondary entity-id">${entity.entity_id}</div>
|
||||
<div class="secondary entity-id">
|
||||
${entity.entity_id}
|
||||
</div>
|
||||
</paper-item-body>
|
||||
`
|
||||
: ""}
|
||||
</paper-icon-item>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
<div class="editable">
|
||||
<paper-input
|
||||
type="string"
|
||||
@change="${this._saveCustomName}"
|
||||
placeholder="${this.hass!.localize(
|
||||
"ui.panel.config.zha.device_card.device_name_placeholder"
|
||||
)}"
|
||||
></paper-input>
|
||||
</div>
|
||||
<div class="node-picker">
|
||||
<paper-dropdown-menu
|
||||
label="${this.hass!.localize(
|
||||
"ui.panel.config.zha.device_card.area_picker_label"
|
||||
)}"
|
||||
class="flex"
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
.selected="${this._selectedAreaIndex}"
|
||||
@iron-select="${this._selectedAreaChanged}"
|
||||
>
|
||||
<paper-item>
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.integrations.config_entry.no_area"
|
||||
)}
|
||||
</paper-item>
|
||||
|
||||
${this._areas.map(
|
||||
(entry) => html`
|
||||
<paper-item area="${entry}">${entry.name}</paper-item>
|
||||
`
|
||||
)}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
${
|
||||
this.showActions
|
||||
? html`
|
||||
<div class="card-actions">
|
||||
<mwc-button @click="${this._onReconfigureNodeClick}"
|
||||
>Reconfigure Device</mwc-button
|
||||
>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div class="help-text">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.services.reconfigure"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
|
||||
<ha-call-service-button
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="remove"
|
||||
.serviceData="${this._serviceData}"
|
||||
>Remove Device</ha-call-service-button
|
||||
>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div class="help-text">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.services.remove"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
</paper-card>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _onReconfigureNodeClick(): Promise<void> {
|
||||
if (this.hass) {
|
||||
await reconfigureNode(this.hass, this.device!.ieee);
|
||||
}
|
||||
}
|
||||
|
||||
private async _saveCustomName(event): Promise<void> {
|
||||
if (this.hass) {
|
||||
const values: DeviceRegistryEntryMutableParams = {
|
||||
name_by_user: event.target.value,
|
||||
area_id: this.device!.area_id ? this.device!.area_id : undefined,
|
||||
};
|
||||
|
||||
await updateDeviceRegistryEntry(
|
||||
this.hass,
|
||||
this.device!.device_reg_id,
|
||||
values
|
||||
);
|
||||
|
||||
this.device!.user_given_name = event.target.value;
|
||||
}
|
||||
}
|
||||
|
||||
private _openMoreInfo(ev: MouseEvent): void {
|
||||
fireEvent(this, "hass-more-info", {
|
||||
entityId: (ev.currentTarget as any).entity.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private async _selectedAreaChanged(event: ItemSelectedEvent) {
|
||||
if (!this.device || !this._areas) {
|
||||
return;
|
||||
}
|
||||
this._selectedAreaIndex = event!.target!.selected;
|
||||
const area = this._areas[this._selectedAreaIndex - 1]; // account for No Area
|
||||
if (
|
||||
(!area && !this.device.area_id) ||
|
||||
(area && area.area_id === this.device.area_id)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
await updateDeviceRegistryEntry(this.hass!, this.device.device_reg_id, {
|
||||
area_id: area ? area.area_id : undefined,
|
||||
name_by_user: this.device!.user_given_name,
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
@ -74,29 +278,43 @@ class ZHADeviceCard extends LitElement {
|
||||
:host(:not([narrow])) .device-entities {
|
||||
max-height: 225px;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px;
|
||||
justify-content: left;
|
||||
}
|
||||
paper-card {
|
||||
flex: 1 0 100%;
|
||||
padding-bottom: 10px;
|
||||
min-width: 0;
|
||||
min-width: 425px;
|
||||
}
|
||||
.device {
|
||||
width: 30%;
|
||||
}
|
||||
.label {
|
||||
.device .name {
|
||||
font-weight: bold;
|
||||
}
|
||||
.device .manuf {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.extra-info {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.manuf,
|
||||
.zha-info,
|
||||
.entity-id {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.info {
|
||||
color: var(--secondary-text-color);
|
||||
font-weight: bold;
|
||||
margin-left: 16px;
|
||||
}
|
||||
dl dt {
|
||||
padding-left: 12px;
|
||||
float: left;
|
||||
width: 100px;
|
||||
width: 50px;
|
||||
text-align: left;
|
||||
}
|
||||
dt dd {
|
||||
margin-left: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
paper-icon-item {
|
||||
@ -104,6 +322,36 @@ class ZHADeviceCard extends LitElement {
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
.editable {
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
.flex {
|
||||
-ms-flex: 1 1 0.000000001px;
|
||||
-webkit-flex: 1;
|
||||
flex: 1;
|
||||
-webkit-flex-basis: 0.000000001px;
|
||||
flex-basis: 0.000000001px;
|
||||
}
|
||||
.node-picker {
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-ms-flex-direction: row;
|
||||
-webkit-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-ms-flex-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
@ -114,5 +362,3 @@ declare global {
|
||||
"zha-device-card": ZHADeviceCard;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("zha-device-card", ZHADeviceCard);
|
||||
|
@ -1,19 +1,22 @@
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
|
||||
export class ZHANetwork extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
@ -30,6 +33,7 @@ export class ZHANetwork extends LitElement {
|
||||
hass: {},
|
||||
isWide: {},
|
||||
_showHelp: {},
|
||||
_joinParams: {},
|
||||
};
|
||||
}
|
||||
|
||||
@ -38,28 +42,30 @@ export class ZHANetwork extends LitElement {
|
||||
<ha-config-section .isWide="${this.isWide}">
|
||||
<div style="position: relative" slot="header">
|
||||
<span>Network Management</span>
|
||||
<paper-icon-button class="toggle-help-icon" @click="${
|
||||
this._onHelpTap
|
||||
}" icon="hass:help-circle"></paper-icon-button>
|
||||
<paper-icon-button
|
||||
class="toggle-help-icon"
|
||||
@click="${this._onHelpTap}"
|
||||
icon="hass:help-circle"
|
||||
></paper-icon-button>
|
||||
</div>
|
||||
<span slot="introduction">Commands that affect entire network</span>
|
||||
|
||||
<paper-card class="content">
|
||||
<div class="card-actions">
|
||||
<ha-call-service-button .hass="${
|
||||
this.hass
|
||||
}" domain="zha" service="permit">Permit</ha-call-service-button>
|
||||
${
|
||||
this._showHelp
|
||||
<mwc-button @click=${this._onAddDevicesClick}>
|
||||
Add Devices
|
||||
</mwc-button>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="permit"
|
||||
class="help-text2"
|
||||
/>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
: ""}
|
||||
</div>
|
||||
</paper-card>
|
||||
</ha-config-section>
|
||||
`;
|
||||
@ -69,6 +75,10 @@ export class ZHANetwork extends LitElement {
|
||||
this._showHelp = !this._showHelp;
|
||||
}
|
||||
|
||||
private _onAddDevicesClick() {
|
||||
navigate(this, "add");
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
@ -102,6 +112,11 @@ export class ZHANetwork extends LitElement {
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.help-text2 {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -1,32 +1,30 @@
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
PropertyValues,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
import "./zha-clusters";
|
||||
import "./zha-device-card";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import { fetchDevices, ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { ItemSelectedEvent, NodeServiceData, ChangeEvent } from "./types";
|
||||
import "./zha-clusters";
|
||||
import "./zha-device-card";
|
||||
import {
|
||||
updateDeviceRegistryEntry,
|
||||
DeviceRegistryEntryMutableParams,
|
||||
} from "../../../data/device_registry";
|
||||
import { reconfigureNode, fetchDevices, ZHADevice } from "../../../data/zha";
|
||||
import { ItemSelectedEvent, ZHADeviceRemovedEvent } from "./types";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
@ -37,60 +35,25 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("zha-node")
|
||||
export class ZHANode extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
public isWide?: boolean;
|
||||
private _showHelp: boolean;
|
||||
private _selectedNodeIndex: number;
|
||||
private _selectedNode?: ZHADevice;
|
||||
private _serviceData?: {};
|
||||
private _nodes: ZHADevice[];
|
||||
private _userSelectedName?: string;
|
||||
@property() public hass?: HomeAssistant;
|
||||
@property() public isWide?: boolean;
|
||||
@property() private _showHelp: boolean = false;
|
||||
@property() private _selectedDeviceIndex: number = -1;
|
||||
@property() private _selectedDevice?: ZHADevice;
|
||||
@property() private _nodes: ZHADevice[] = [];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._showHelp = false;
|
||||
this._selectedNodeIndex = -1;
|
||||
this._nodes = [];
|
||||
}
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
isWide: {},
|
||||
_showHelp: {},
|
||||
_selectedNodeIndex: {},
|
||||
_selectedNode: {},
|
||||
_entities: {},
|
||||
_serviceData: {},
|
||||
_nodes: {},
|
||||
_userSelectedName: {},
|
||||
};
|
||||
}
|
||||
|
||||
public firstUpdated(changedProperties: PropertyValues): void {
|
||||
super.firstUpdated(changedProperties);
|
||||
if (this._nodes.length === 0) {
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this._fetchDevices();
|
||||
}
|
||||
this.addEventListener("hass-service-called", (ev) =>
|
||||
this.serviceCalled(ev)
|
||||
);
|
||||
}
|
||||
|
||||
protected serviceCalled(ev): void {
|
||||
// Check if this is for us
|
||||
if (ev.detail.success && ev.detail.service === "remove") {
|
||||
this._selectedNodeIndex = -1;
|
||||
this._fetchDevices();
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<ha-config-section .isWide="${this.isWide}">
|
||||
<div class="sectionHeader" slot="header">
|
||||
<span>Node Management</span>
|
||||
<span>Device Management</span>
|
||||
<paper-icon-button
|
||||
class="toggle-help-icon"
|
||||
@click="${this._onHelpTap}"
|
||||
@ -98,8 +61,8 @@ export class ZHANode extends LitElement {
|
||||
></paper-icon-button>
|
||||
</div>
|
||||
<span slot="introduction">
|
||||
Run ZHA commands that affect a single node. Pick a node to see a list
|
||||
of available commands. <br /><br />Note: Sleepy (battery powered)
|
||||
Run ZHA commands that affect a single device. Pick a device to see a
|
||||
list of available commands. <br /><br />Note: Sleepy (battery powered)
|
||||
devices need to be awake when executing commands against them. You can
|
||||
generally wake a sleepy device by triggering it. <br /><br />Some
|
||||
devices such as Xiaomi sensors have a wake up button that you can
|
||||
@ -108,11 +71,15 @@ export class ZHANode extends LitElement {
|
||||
</span>
|
||||
<paper-card class="content">
|
||||
<div class="node-picker">
|
||||
<paper-dropdown-menu label="Nodes" class="flex">
|
||||
<paper-dropdown-menu
|
||||
label="Devices"
|
||||
class="flex"
|
||||
id="zha-device-selector"
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
@iron-select="${this._selectedNodeChanged}"
|
||||
.selected="${this._selectedNodeIndex}"
|
||||
@iron-select="${this._selectedDeviceChanged}"
|
||||
.selected="${this._selectedDeviceIndex}"
|
||||
>
|
||||
${this._nodes.map(
|
||||
(entry) => html`
|
||||
@ -128,95 +95,36 @@ export class ZHANode extends LitElement {
|
||||
</div>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<div class="helpText">
|
||||
Select node to view per-node options
|
||||
<div class="help-text">
|
||||
Select device to view per-device options
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
${this._selectedNodeIndex !== -1
|
||||
${this._selectedDeviceIndex !== -1
|
||||
? html`
|
||||
<zha-device-card
|
||||
class="card"
|
||||
.hass="${this.hass}"
|
||||
.device="${this._selectedNode}"
|
||||
.device="${this._selectedDevice}"
|
||||
.narrow="${!this.isWide}"
|
||||
.showHelp="${this._showHelp}"
|
||||
.showActions="${true}"
|
||||
@zha-device-removed="${this._onDeviceRemoved}"
|
||||
.isJoinPage="${false}"
|
||||
></zha-device-card>
|
||||
`
|
||||
: ""}
|
||||
${this._selectedNodeIndex !== -1
|
||||
? html`
|
||||
<div class="input-text">
|
||||
<paper-input
|
||||
type="string"
|
||||
.value="${this._userSelectedName}"
|
||||
@value-changed="${this._onUserSelectedNameChanged}"
|
||||
placeholder="User given name"
|
||||
></paper-input>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
${this._selectedNodeIndex !== -1 ? this._renderNodeActions() : ""}
|
||||
${this._selectedNode ? this._renderClusters() : ""}
|
||||
${this._selectedDevice ? this._renderClusters() : ""}
|
||||
</paper-card>
|
||||
</ha-config-section>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderNodeActions(): TemplateResult {
|
||||
return html`
|
||||
<div class="card-actions">
|
||||
<mwc-button @click="${this._onReconfigureNodeClick}"
|
||||
>Reconfigure Node</mwc-button
|
||||
>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<div class="helpText">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.services.reconfigure"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
<ha-call-service-button
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="remove"
|
||||
.serviceData="${this._serviceData}"
|
||||
>Remove Node</ha-call-service-button
|
||||
>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="remove"
|
||||
/>
|
||||
`
|
||||
: ""}
|
||||
<mwc-button
|
||||
@click="${this._onUpdateDeviceNameClick}"
|
||||
.disabled="${!this._userSelectedName ||
|
||||
this._userSelectedName === ""}"
|
||||
>Update Name</mwc-button
|
||||
>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<div class="helpText">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.services.updateDeviceName"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderClusters(): TemplateResult {
|
||||
return html`
|
||||
<zha-clusters
|
||||
.hass="${this.hass}"
|
||||
.selectedDevice="${this._selectedNode}"
|
||||
.selectedDevice="${this._selectedDevice}"
|
||||
.showHelp="${this._showHelp}"
|
||||
></zha-clusters>
|
||||
`;
|
||||
@ -226,45 +134,10 @@ export class ZHANode extends LitElement {
|
||||
this._showHelp = !this._showHelp;
|
||||
}
|
||||
|
||||
private _selectedNodeChanged(event: ItemSelectedEvent): void {
|
||||
this._selectedNodeIndex = event!.target!.selected;
|
||||
this._selectedNode = this._nodes[this._selectedNodeIndex];
|
||||
this._userSelectedName = "";
|
||||
fireEvent(this, "zha-node-selected", { node: this._selectedNode });
|
||||
this._serviceData = this._computeNodeServiceData();
|
||||
}
|
||||
|
||||
private async _onReconfigureNodeClick(): Promise<void> {
|
||||
if (this.hass) {
|
||||
await reconfigureNode(this.hass, this._selectedNode!.ieee);
|
||||
}
|
||||
}
|
||||
|
||||
private _onUserSelectedNameChanged(value: ChangeEvent): void {
|
||||
this._userSelectedName = value.detail!.value;
|
||||
}
|
||||
|
||||
private async _onUpdateDeviceNameClick(): Promise<void> {
|
||||
if (this.hass) {
|
||||
const values: DeviceRegistryEntryMutableParams = {
|
||||
name_by_user: this._userSelectedName,
|
||||
};
|
||||
|
||||
await updateDeviceRegistryEntry(
|
||||
this.hass,
|
||||
this._selectedNode!.device_reg_id,
|
||||
values
|
||||
);
|
||||
|
||||
this._selectedNode!.user_given_name = this._userSelectedName!;
|
||||
this._userSelectedName = "";
|
||||
}
|
||||
}
|
||||
|
||||
private _computeNodeServiceData(): NodeServiceData {
|
||||
return {
|
||||
ieee_address: this._selectedNode!.ieee,
|
||||
};
|
||||
private _selectedDeviceChanged(event: ItemSelectedEvent): void {
|
||||
this._selectedDeviceIndex = event!.target!.selected;
|
||||
this._selectedDevice = this._nodes[this._selectedDeviceIndex];
|
||||
fireEvent(this, "zha-node-selected", { node: this._selectedDevice });
|
||||
}
|
||||
|
||||
private async _fetchDevices() {
|
||||
@ -273,6 +146,13 @@ export class ZHANode extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _onDeviceRemoved(event: ZHADeviceRemovedEvent): void {
|
||||
this._selectedDeviceIndex = -1;
|
||||
this._nodes.splice(this._nodes.indexOf(event.detail!.device!), 1);
|
||||
this._selectedDevice = undefined;
|
||||
fireEvent(this, "zha-node-selected", { node: this._selectedDevice });
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
@ -298,13 +178,10 @@ export class ZHANode extends LitElement {
|
||||
}
|
||||
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
}
|
||||
|
||||
.helpText {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
paper-card {
|
||||
@ -355,12 +232,6 @@ export class ZHANode extends LitElement {
|
||||
right: 0;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.input-text {
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
@ -371,5 +242,3 @@ declare global {
|
||||
"zha-node": ZHANode;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("zha-node", ZHANode);
|
||||
|
@ -877,7 +877,18 @@
|
||||
"description": "Zigbee Home Automation network management",
|
||||
"services": {
|
||||
"reconfigure": "Reconfigure ZHA device (heal device). Use this if you are having issues with the device. If the device in question is a battery powered device please ensure it is awake and accepting commands when you use this service.",
|
||||
"updateDeviceName": "Set a custom name for this device in the device registry."
|
||||
"updateDeviceName": "Set a custom name for this device in the device registry.",
|
||||
"remove": "Remove a device from the ZigBee network."
|
||||
},
|
||||
"device_card": {
|
||||
"device_name_placeholder": "User given name",
|
||||
"area_picker_label": "Area",
|
||||
"update_name_button": "Update Name"
|
||||
},
|
||||
"add_device_page": {
|
||||
"header": "Zigbee Home Automation - Add Devices",
|
||||
"spinner": "Searching for ZHA Zigbee devices...",
|
||||
"discovery_text": "Discovered devices will show up here. Follow the instructions for your device(s) and place the device(s) in pairing mode."
|
||||
}
|
||||
},
|
||||
"zwave": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user