Skip to content
3 changes: 2 additions & 1 deletion src/data/zha.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface ZHADevice {
manufacturer_code: number;
device_reg_id: string;
user_given_name: string;
area_id: string;
}

export interface Attribute {
Expand All @@ -42,7 +43,7 @@ export interface ReadAttributeServiceData {
cluster_id: number;
cluster_type: string;
attribute: number;
manufacturer: number;
manufacturer?: number;
}

export const reconfigureNode = (
Expand Down
4 changes: 2 additions & 2 deletions src/panels/config/ha-panel-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
41 changes: 14 additions & 27 deletions src/panels/config/zha/ha-config-zha.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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}"
Expand Down Expand Up @@ -86,7 +77,7 @@ export class HaConfigZha extends LitElement {
></zha-binding-control>
`
: ""}
</ha-app-layout>
</hass-subpage>
`;
}

Expand Down Expand Up @@ -117,10 +108,6 @@ export class HaConfigZha extends LitElement {
static get styles(): CSSResult[] {
return [haStyle];
}

private _onBackTapped(): void {
history.back();
}
}

declare global {
Expand Down
8 changes: 7 additions & 1 deletion src/panels/config/zha/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ export interface ItemSelectedEvent {
target?: PickerTarget;
}

export interface ZHADeviceRemovedEvent {
detail?: {
device?: ZHADevice;
};
}

export interface ChangeEvent {
detail?: {
value?: any;
Expand All @@ -22,7 +28,7 @@ export interface SetAttributeServiceData {
cluster_type: string;
attribute: number;
value: any;
manufacturer: number;
manufacturer?: number;
}

export interface IssueCommandServiceData {
Expand Down
246 changes: 246 additions & 0 deletions src/panels/config/zha/zha-add-devices-page.ts
Original file line number Diff line number Diff line change
@@ -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;
}
}
Loading