mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-22 08:46:35 +00:00
Rework the ZHA config panel (#4415)
* convert zha config panel to tabs * add spacer to prevent combobox from hitting bottom * break clusters out into their own section * cleanup buttons * remove header * make devices default tab * convert from tabs to a list view * convert to table on dashboard * fix anchor on mobile safari * cleanup CSS to fix display on mobile * cleanup card css * more css cleanup * fix group page * remove translations changes * Update src/panels/config/zha/zha-clusters.ts Co-Authored-By: Bram Kragten <mail@bramkragten.nl> * Update src/panels/config/zha/zha-config-dashboard.ts Co-Authored-By: Bram Kragten <mail@bramkragten.nl> * Update src/panels/config/zha/zha-device-page.ts Co-Authored-By: Bram Kragten <mail@bramkragten.nl> * Update src/panels/config/zha/zha-groups-dashboard.ts Co-Authored-By: Bram Kragten <mail@bramkragten.nl> * review comments * fix dangling quote after commit suggestion * css cleanup * remove flex rules * remove flex rules * css cleanup * remove dialog per review comments Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
357a67c00d
commit
5415068917
@ -127,10 +127,10 @@ class HaPanelConfig extends HassRouterPage {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
zha: {
|
zha: {
|
||||||
tag: "zha-config-panel",
|
tag: "zha-config-dashboard-router",
|
||||||
load: () =>
|
load: () =>
|
||||||
import(
|
import(
|
||||||
/* webpackChunkName: "panel-config-zha" */ "./zha/zha-config-panel"
|
/* webpackChunkName: "panel-config-zha" */ "./zha/zha-config-dashboard-router"
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
zwave: {
|
zwave: {
|
||||||
|
@ -44,7 +44,7 @@ export class ZHABindingControl extends LitElement {
|
|||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html`
|
return html`
|
||||||
<ha-config-section .isWide="${this.isWide}">
|
<ha-config-section .isWide="${this.isWide}">
|
||||||
<div class="sectionHeader" slot="header">
|
<div class="header" slot="header">
|
||||||
<span>Device Binding</span>
|
<span>Device Binding</span>
|
||||||
<paper-icon-button
|
<paper-icon-button
|
||||||
class="toggle-help-icon"
|
class="toggle-help-icon"
|
||||||
@ -57,7 +57,7 @@ export class ZHABindingControl extends LitElement {
|
|||||||
|
|
||||||
<ha-card class="content">
|
<ha-card class="content">
|
||||||
<div class="command-picker">
|
<div class="command-picker">
|
||||||
<paper-dropdown-menu label="Bindable Devices" class="flex">
|
<paper-dropdown-menu label="Bindable Devices" class="menu">
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
slot="dropdown-content"
|
slot="dropdown-content"
|
||||||
.selected="${this._bindTargetIndex}"
|
.selected="${this._bindTargetIndex}"
|
||||||
@ -149,12 +149,8 @@ export class ZHABindingControl extends LitElement {
|
|||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
.flex {
|
.menu {
|
||||||
-ms-flex: 1 1 0.000000001px;
|
width: 100%;
|
||||||
-webkit-flex: 1;
|
|
||||||
flex: 1;
|
|
||||||
-webkit-flex-basis: 0.000000001px;
|
|
||||||
flex-basis: 0.000000001px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@ -171,37 +167,23 @@ export class ZHABindingControl extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.command-picker {
|
.command-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;
|
align-items: center;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
padding-right: 28px;
|
padding-right: 28px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-text {
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sectionHeader {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.helpText {
|
.helpText {
|
||||||
color: grey;
|
color: grey;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.toggle-help-icon {
|
.toggle-help-icon {
|
||||||
position: absolute;
|
float: right;
|
||||||
top: -6px;
|
top: -6px;
|
||||||
right: 0;
|
right: 0;
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
|
@ -61,7 +61,7 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html`
|
return html`
|
||||||
<ha-config-section .isWide="${this.isWide}">
|
<ha-config-section .isWide="${this.isWide}">
|
||||||
<div style="position: relative" slot="header">
|
<div class="header" slot="header">
|
||||||
<span>
|
<span>
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.config.zha.cluster_attributes.header"
|
"ui.panel.config.zha.cluster_attributes.header"
|
||||||
@ -86,7 +86,7 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
label="${this.hass!.localize(
|
label="${this.hass!.localize(
|
||||||
"ui.panel.config.zha.cluster_attributes.attributes_of_cluster"
|
"ui.panel.config.zha.cluster_attributes.attributes_of_cluster"
|
||||||
)}"
|
)}"
|
||||||
class="flex"
|
class="menu"
|
||||||
>
|
>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
slot="dropdown-content"
|
slot="dropdown-content"
|
||||||
@ -270,12 +270,8 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
.flex {
|
.menu {
|
||||||
-ms-flex: 1 1 0.000000001px;
|
width: 100%;
|
||||||
-webkit-flex: 1;
|
|
||||||
flex: 1;
|
|
||||||
-webkit-flex-basis: 0.000000001px;
|
|
||||||
flex-basis: 0.000000001px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@ -292,14 +288,6 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.attribute-picker {
|
.attribute-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;
|
align-items: center;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
padding-right: 28px;
|
padding-right: 28px;
|
||||||
@ -312,8 +300,12 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.toggle-help-icon {
|
.toggle-help-icon {
|
||||||
position: absolute;
|
float: right;
|
||||||
top: -6px;
|
top: -6px;
|
||||||
right: 0;
|
right: 0;
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
|
@ -56,7 +56,7 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html`
|
return html`
|
||||||
<ha-config-section .isWide="${this.isWide}">
|
<ha-config-section .isWide="${this.isWide}">
|
||||||
<div class="sectionHeader" slot="header">
|
<div class="header" slot="header">
|
||||||
<span>
|
<span>
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.config.zha.cluster_commands.header"
|
"ui.panel.config.zha.cluster_commands.header"
|
||||||
@ -81,7 +81,7 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
label="${this.hass!.localize(
|
label="${this.hass!.localize(
|
||||||
"ui.panel.config.zha.cluster_commands.commands_of_cluster"
|
"ui.panel.config.zha.cluster_commands.commands_of_cluster"
|
||||||
)}"
|
)}"
|
||||||
class="flex"
|
class="menu"
|
||||||
>
|
>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
slot="dropdown-content"
|
slot="dropdown-content"
|
||||||
@ -203,12 +203,8 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
.flex {
|
.menu {
|
||||||
-ms-flex: 1 1 0.000000001px;
|
width: 100%;
|
||||||
-webkit-flex: 1;
|
|
||||||
flex: 1;
|
|
||||||
-webkit-flex-basis: 0.000000001px;
|
|
||||||
flex-basis: 0.000000001px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@ -225,14 +221,6 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.command-picker {
|
.command-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;
|
align-items: center;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
padding-right: 28px;
|
padding-right: 28px;
|
||||||
@ -245,10 +233,6 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sectionHeader {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-text {
|
.help-text {
|
||||||
color: grey;
|
color: grey;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
@ -261,8 +245,12 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.toggle-help-icon {
|
.toggle-help-icon {
|
||||||
position: absolute;
|
float: right;
|
||||||
top: -6px;
|
top: -6px;
|
||||||
right: 0;
|
right: 0;
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
|
@ -3,6 +3,7 @@ import "../../../components/ha-service-description";
|
|||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||||
|
import "@polymer/paper-icon-button/paper-icon-button";
|
||||||
import "@polymer/paper-item/paper-item";
|
import "@polymer/paper-item/paper-item";
|
||||||
import "@polymer/paper-listbox/paper-listbox";
|
import "@polymer/paper-listbox/paper-listbox";
|
||||||
|
|
||||||
@ -41,8 +42,8 @@ const computeClusterKey = (cluster: Cluster): string => {
|
|||||||
export class ZHAClusters extends LitElement {
|
export class ZHAClusters extends LitElement {
|
||||||
@property() public hass?: HomeAssistant;
|
@property() public hass?: HomeAssistant;
|
||||||
@property() public isWide?: boolean;
|
@property() public isWide?: boolean;
|
||||||
@property() public showHelp = false;
|
|
||||||
@property() public selectedDevice?: ZHADevice;
|
@property() public selectedDevice?: ZHADevice;
|
||||||
|
@property() public showHelp = false;
|
||||||
@property() private _selectedClusterIndex = -1;
|
@property() private _selectedClusterIndex = -1;
|
||||||
@property() private _clusters: Cluster[] = [];
|
@property() private _clusters: Cluster[] = [];
|
||||||
|
|
||||||
@ -60,10 +61,29 @@ export class ZHAClusters extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html`
|
return html`
|
||||||
|
<ha-config-section .isWide="${this.isWide}">
|
||||||
|
<div class="header" slot="header">
|
||||||
|
<span>
|
||||||
|
${this.hass!.localize("ui.panel.config.zha.clusters.header")}
|
||||||
|
</span>
|
||||||
|
<paper-icon-button
|
||||||
|
class="toggle-help-icon"
|
||||||
|
@click="${this._onHelpTap}"
|
||||||
|
icon="hass:help-circle"
|
||||||
|
>
|
||||||
|
</paper-icon-button>
|
||||||
|
</div>
|
||||||
|
<span slot="introduction">
|
||||||
|
${this.hass!.localize("ui.panel.config.zha.clusters.introduction")}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<ha-card class="content">
|
||||||
<div class="node-picker">
|
<div class="node-picker">
|
||||||
<paper-dropdown-menu
|
<paper-dropdown-menu
|
||||||
label="${this.hass!.localize("ui.panel.config.zha.common.clusters")}"
|
.label=${this.hass!.localize(
|
||||||
class="flex"
|
"ui.panel.config.zha.common.clusters"
|
||||||
|
)}
|
||||||
|
class="menu"
|
||||||
>
|
>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
slot="dropdown-content"
|
slot="dropdown-content"
|
||||||
@ -87,6 +107,8 @@ export class ZHAClusters extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
|
</ha-card>
|
||||||
|
</ha-config-section>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,32 +131,49 @@ export class ZHAClusters extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _onHelpTap(): void {
|
||||||
|
this.showHelp = !this.showHelp;
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
.flex {
|
.menu {
|
||||||
-ms-flex: 1 1 0.000000001px;
|
width: 100%;
|
||||||
-webkit-flex: 1;
|
}
|
||||||
flex: 1;
|
|
||||||
-webkit-flex-basis: 0.000000001px;
|
.content {
|
||||||
flex-basis: 0.000000001px;
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-card {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.node-picker {
|
.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;
|
align-items: center;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
padding-right: 28px;
|
padding-right: 28px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toggle-help-icon {
|
||||||
|
float: right;
|
||||||
|
top: -6px;
|
||||||
|
right: 0;
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.help-text {
|
.help-text {
|
||||||
color: grey;
|
color: grey;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
|
@ -1,29 +1,34 @@
|
|||||||
import "../../../layouts/hass-loading-screen";
|
|
||||||
|
|
||||||
import { customElement, property } from "lit-element";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
HassRouterPage,
|
HassRouterPage,
|
||||||
RouterOptions,
|
RouterOptions,
|
||||||
} from "../../../layouts/hass-router-page";
|
} from "../../../layouts/hass-router-page";
|
||||||
|
import { customElement, property } from "lit-element";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
|
|
||||||
@customElement("zha-config-panel")
|
@customElement("zha-config-dashboard-router")
|
||||||
class ZHAConfigPanel extends HassRouterPage {
|
class ZHAConfigDashboardRouter extends HassRouterPage {
|
||||||
@property() public hass!: HomeAssistant;
|
@property() public hass!: HomeAssistant;
|
||||||
@property() public isWide!: boolean;
|
@property() public isWide!: boolean;
|
||||||
@property() public narrow!: boolean;
|
@property() public narrow!: boolean;
|
||||||
|
|
||||||
protected routerOptions: RouterOptions = {
|
protected routerOptions: RouterOptions = {
|
||||||
defaultPage: "configuration",
|
defaultPage: "dashboard",
|
||||||
cacheAll: true,
|
cacheAll: true,
|
||||||
preloadAll: true,
|
preloadAll: true,
|
||||||
|
showLoading: true,
|
||||||
routes: {
|
routes: {
|
||||||
configuration: {
|
dashboard: {
|
||||||
tag: "ha-config-zha",
|
tag: "zha-config-dashboard",
|
||||||
load: () =>
|
load: () =>
|
||||||
import(
|
import(
|
||||||
/* webpackChunkName: "zha-configuration-page" */ "./ha-config-zha"
|
/* webpackChunkName: "zha-config-dashboard" */ "./zha-config-dashboard"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
device: {
|
||||||
|
tag: "zha-device-page",
|
||||||
|
load: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "zha-devices-page" */ "./zha-device-page"
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
add: {
|
add: {
|
||||||
@ -62,12 +67,14 @@ class ZHAConfigPanel extends HassRouterPage {
|
|||||||
el.narrow = this.narrow;
|
el.narrow = this.narrow;
|
||||||
if (this._currentPage === "group") {
|
if (this._currentPage === "group") {
|
||||||
el.groupId = this.routeTail.path.substr(1);
|
el.groupId = this.routeTail.path.substr(1);
|
||||||
|
} else if (this._currentPage === "device") {
|
||||||
|
el.ieee = this.routeTail.path.substr(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"zha-config-panel": ZHAConfigPanel;
|
"zha-config-dashboard-router": ZHAConfigDashboardRouter;
|
||||||
}
|
}
|
||||||
}
|
}
|
175
src/panels/config/zha/zha-config-dashboard.ts
Normal file
175
src/panels/config/zha/zha-config-dashboard.ts
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
import {
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
html,
|
||||||
|
CSSResultArray,
|
||||||
|
css,
|
||||||
|
customElement,
|
||||||
|
property,
|
||||||
|
PropertyValues,
|
||||||
|
} from "lit-element";
|
||||||
|
import "@polymer/paper-item/paper-item-body";
|
||||||
|
import "@polymer/paper-item/paper-item";
|
||||||
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-icon-next";
|
||||||
|
import "../../../layouts/hass-subpage";
|
||||||
|
import "../ha-config-section";
|
||||||
|
|
||||||
|
import { haStyle } from "../../../resources/styles";
|
||||||
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
|
import { fetchDevices, ZHADevice } from "../../../data/zha";
|
||||||
|
import { sortZHADevices, formatAsPaddedHex } from "./functions";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import {
|
||||||
|
DataTableColumnContainer,
|
||||||
|
RowClickedEvent,
|
||||||
|
} from "../../../components/data-table/ha-data-table";
|
||||||
|
import { navigate } from "../../../common/navigate";
|
||||||
|
|
||||||
|
export interface DeviceRowData extends ZHADevice {
|
||||||
|
device?: DeviceRowData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("zha-config-dashboard")
|
||||||
|
class ZHAConfigDashboard extends LitElement {
|
||||||
|
@property() public hass!: HomeAssistant;
|
||||||
|
@property() public route!: Route;
|
||||||
|
@property() public narrow!: boolean;
|
||||||
|
@property() public isWide!: boolean;
|
||||||
|
@property() private _devices: ZHADevice[] = [];
|
||||||
|
private pages: string[] = ["add", "groups"];
|
||||||
|
private _firstUpdatedCalled: boolean = false;
|
||||||
|
|
||||||
|
private _memoizeDevices = memoizeOne((devices: ZHADevice[]) => {
|
||||||
|
let outputDevices: DeviceRowData[] = devices;
|
||||||
|
|
||||||
|
outputDevices = outputDevices.map((device) => {
|
||||||
|
return {
|
||||||
|
...device,
|
||||||
|
name: device.user_given_name ? device.user_given_name : device.name,
|
||||||
|
nwk: formatAsPaddedHex(device.nwk),
|
||||||
|
id: device.ieee,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return outputDevices;
|
||||||
|
});
|
||||||
|
|
||||||
|
private _columns = memoizeOne(
|
||||||
|
(narrow: boolean): DataTableColumnContainer =>
|
||||||
|
narrow
|
||||||
|
? {
|
||||||
|
name: {
|
||||||
|
title: "Devices",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
direction: "asc",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
name: {
|
||||||
|
title: "Name",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
direction: "asc",
|
||||||
|
},
|
||||||
|
nwk: {
|
||||||
|
title: "Nwk",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
ieee: {
|
||||||
|
title: "IEEE",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
public connectedCallback(): void {
|
||||||
|
super.connectedCallback();
|
||||||
|
if (this.hass && this._firstUpdatedCalled) {
|
||||||
|
this._fetchDevices();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProperties: PropertyValues): void {
|
||||||
|
super.firstUpdated(changedProperties);
|
||||||
|
if (this.hass) {
|
||||||
|
this._fetchDevices();
|
||||||
|
}
|
||||||
|
this._firstUpdatedCalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult | void {
|
||||||
|
return html`
|
||||||
|
<hass-subpage .header=${this.hass.localize("ui.panel.config.zha.title")}>
|
||||||
|
<ha-config-section .narrow=${this.narrow} .isWide=${this.isWide}>
|
||||||
|
<div slot="header">
|
||||||
|
${this.hass.localize("ui.panel.config.zha.header")}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div slot="introduction">
|
||||||
|
${this.hass.localize("ui.panel.config.zha.introduction")}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ha-card>
|
||||||
|
${this.pages.map((page) => {
|
||||||
|
return html`
|
||||||
|
<a href=${`/config/zha/${page}`}>
|
||||||
|
<paper-item>
|
||||||
|
<paper-item-body two-line="">
|
||||||
|
${this.hass.localize(
|
||||||
|
`ui.panel.config.zha.${page}.caption`
|
||||||
|
)}
|
||||||
|
<div secondary>
|
||||||
|
${this.hass.localize(
|
||||||
|
`ui.panel.config.zha.${page}.description`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</paper-item-body>
|
||||||
|
<ha-icon-next></ha-icon-next>
|
||||||
|
</paper-item>
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</ha-card>
|
||||||
|
<ha-card>
|
||||||
|
<ha-data-table
|
||||||
|
.columns=${this._columns(this.narrow)}
|
||||||
|
.data=${this._memoizeDevices(this._devices)}
|
||||||
|
@row-click=${this._handleDeviceClicked}
|
||||||
|
></ha-data-table>
|
||||||
|
</ha-card>
|
||||||
|
</ha-config-section>
|
||||||
|
</hass-subpage>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _fetchDevices() {
|
||||||
|
this._devices = (await fetchDevices(this.hass!)).sort(sortZHADevices);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _handleDeviceClicked(ev: CustomEvent) {
|
||||||
|
const deviceId = (ev.detail as RowClickedEvent).id;
|
||||||
|
navigate(this, `/config/zha/device/${deviceId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultArray {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"zha-config-dashboard": ZHAConfigDashboard;
|
||||||
|
}
|
||||||
|
}
|
@ -233,7 +233,7 @@ class ZHADeviceCard extends LitElement {
|
|||||||
label="${this.hass!.localize(
|
label="${this.hass!.localize(
|
||||||
"ui.dialogs.zha_device_info.zha_device_card.area_picker_label"
|
"ui.dialogs.zha_device_info.zha_device_card.area_picker_label"
|
||||||
)}"
|
)}"
|
||||||
class="flex"
|
class="menu"
|
||||||
>
|
>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
slot="dropdown-content"
|
slot="dropdown-content"
|
||||||
@ -385,7 +385,7 @@ class ZHADeviceCard extends LitElement {
|
|||||||
css`
|
css`
|
||||||
:host(:not([narrow])) .device-entities {
|
:host(:not([narrow])) .device-entities {
|
||||||
max-height: 225px;
|
max-height: 225px;
|
||||||
overflow: auto;
|
overflow-y: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
@ -394,7 +394,7 @@ class ZHADeviceCard extends LitElement {
|
|||||||
ha-card {
|
ha-card {
|
||||||
flex: 1 0 100%;
|
flex: 1 0 100%;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
min-width: 425px;
|
min-width: 300px;
|
||||||
}
|
}
|
||||||
.device {
|
.device {
|
||||||
width: 30%;
|
width: 30%;
|
||||||
@ -411,25 +411,35 @@ class ZHADeviceCard extends LitElement {
|
|||||||
}
|
}
|
||||||
.manuf,
|
.manuf,
|
||||||
.zha-info,
|
.zha-info,
|
||||||
|
.name {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
.entity-id {
|
.entity-id {
|
||||||
|
text-overflow: ellipsis;
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
.info {
|
.info {
|
||||||
margin-left: 16px;
|
margin-left: 16px;
|
||||||
}
|
}
|
||||||
dl {
|
dl {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: 125px 1fr;
|
flex-wrap: wrap;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
dl dt {
|
dl dt {
|
||||||
|
display: inline-block;
|
||||||
|
width: 30%;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
float: left;
|
float: left;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
dl dd {
|
dl dd {
|
||||||
max-width: 200px;
|
width: 60%;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
margin-inline-start: 20px;
|
||||||
}
|
}
|
||||||
paper-icon-item {
|
paper-icon-item {
|
||||||
|
overflow-x: hidden;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
@ -443,22 +453,10 @@ class ZHADeviceCard extends LitElement {
|
|||||||
color: grey;
|
color: grey;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
.flex {
|
.menu {
|
||||||
-ms-flex: 1 1 0.000000001px;
|
width: 100%;
|
||||||
-webkit-flex: 1;
|
|
||||||
flex: 1;
|
|
||||||
-webkit-flex-basis: 0.000000001px;
|
|
||||||
flex-basis: 0.000000001px;
|
|
||||||
}
|
}
|
||||||
.node-picker {
|
.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;
|
align-items: center;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
padding-right: 28px;
|
padding-right: 28px;
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import "../../../components/ha-paper-icon-button-arrow-prev";
|
|
||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
|
import "../../../components/ha-paper-icon-button-arrow-prev";
|
||||||
import "./zha-binding";
|
import "./zha-binding";
|
||||||
import "./zha-cluster-attributes";
|
import "./zha-cluster-attributes";
|
||||||
import "./zha-cluster-commands";
|
import "./zha-cluster-commands";
|
||||||
import "./zha-network";
|
import "./zha-clusters";
|
||||||
import "./zha-node";
|
import "./zha-node";
|
||||||
import "./zha-groups-tile";
|
|
||||||
import "@polymer/paper-icon-button/paper-icon-button";
|
import "@polymer/paper-icon-button/paper-icon-button";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -15,75 +14,82 @@ import {
|
|||||||
property,
|
property,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
|
customElement,
|
||||||
|
css,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
|
|
||||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||||
import { Cluster, fetchBindableDevices, ZHADevice } from "../../../data/zha";
|
import {
|
||||||
|
Cluster,
|
||||||
|
fetchBindableDevices,
|
||||||
|
ZHADevice,
|
||||||
|
fetchZHADevice,
|
||||||
|
} from "../../../data/zha";
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { sortZHADevices } from "./functions";
|
import { sortZHADevices } from "./functions";
|
||||||
import { ZHAClusterSelectedParams, ZHADeviceSelectedParams } from "./types";
|
import { ZHAClusterSelectedParams } from "./types";
|
||||||
|
|
||||||
export class HaConfigZha extends LitElement {
|
@customElement("zha-device-page")
|
||||||
|
export class ZHADevicePage extends LitElement {
|
||||||
@property() public hass?: HomeAssistant;
|
@property() public hass?: HomeAssistant;
|
||||||
@property() public isWide?: boolean;
|
@property() public isWide?: boolean;
|
||||||
@property() private _selectedDevice?: ZHADevice;
|
@property() public ieee?: string;
|
||||||
|
@property() public device?: ZHADevice;
|
||||||
@property() private _selectedCluster?: Cluster;
|
@property() private _selectedCluster?: Cluster;
|
||||||
@property() private _bindableDevices: ZHADevice[] = [];
|
@property() private _bindableDevices: ZHADevice[] = [];
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
if (changedProperties.has("_selectedDevice")) {
|
if (changedProperties.has("ieee")) {
|
||||||
this._fetchBindableDevices();
|
this._fetchData();
|
||||||
}
|
}
|
||||||
super.update(changedProperties);
|
super.update(changedProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html`
|
return html`
|
||||||
<hass-subpage header="Zigbee Home Automation">
|
<hass-subpage
|
||||||
<zha-network
|
.header=${this.hass!.localize("ui.panel.config.zha.devices.header")}
|
||||||
.isWide="${this.isWide}"
|
>
|
||||||
.hass="${this.hass}"
|
|
||||||
></zha-network>
|
|
||||||
|
|
||||||
<zha-groups-tile
|
|
||||||
.isWide="${this.isWide}"
|
|
||||||
.hass="${this.hass}"
|
|
||||||
></zha-groups-tile>
|
|
||||||
|
|
||||||
<zha-node
|
<zha-node
|
||||||
.isWide="${this.isWide}"
|
.isWide="${this.isWide}"
|
||||||
.hass="${this.hass}"
|
.hass="${this.hass}"
|
||||||
@zha-cluster-selected="${this._onClusterSelected}"
|
.device=${this.device}
|
||||||
@zha-node-selected="${this._onDeviceSelected}"
|
|
||||||
></zha-node>
|
></zha-node>
|
||||||
|
<zha-clusters
|
||||||
|
.hass="${this.hass}"
|
||||||
|
.isWide="${this.isWide}"
|
||||||
|
.selectedDevice="${this.device}"
|
||||||
|
@zha-cluster-selected="${this._onClusterSelected}"
|
||||||
|
></zha-clusters>
|
||||||
${this._selectedCluster
|
${this._selectedCluster
|
||||||
? html`
|
? html`
|
||||||
<zha-cluster-attributes
|
<zha-cluster-attributes
|
||||||
.isWide="${this.isWide}"
|
.isWide="${this.isWide}"
|
||||||
.hass="${this.hass}"
|
.hass="${this.hass}"
|
||||||
.selectedNode="${this._selectedDevice}"
|
.selectedNode="${this.device}"
|
||||||
.selectedCluster="${this._selectedCluster}"
|
.selectedCluster="${this._selectedCluster}"
|
||||||
></zha-cluster-attributes>
|
></zha-cluster-attributes>
|
||||||
|
|
||||||
<zha-cluster-commands
|
<zha-cluster-commands
|
||||||
.isWide="${this.isWide}"
|
.isWide="${this.isWide}"
|
||||||
.hass="${this.hass}"
|
.hass="${this.hass}"
|
||||||
.selectedNode="${this._selectedDevice}"
|
.selectedNode="${this.device}"
|
||||||
.selectedCluster="${this._selectedCluster}"
|
.selectedCluster="${this._selectedCluster}"
|
||||||
></zha-cluster-commands>
|
></zha-cluster-commands>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this._selectedDevice && this._bindableDevices.length > 0
|
${this._bindableDevices.length > 0
|
||||||
? html`
|
? html`
|
||||||
<zha-binding-control
|
<zha-binding-control
|
||||||
.isWide="${this.isWide}"
|
.isWide="${this.isWide}"
|
||||||
.hass="${this.hass}"
|
.hass="${this.hass}"
|
||||||
.selectedDevice="${this._selectedDevice}"
|
.selectedDevice="${this.device}"
|
||||||
.bindableDevices="${this._bindableDevices}"
|
.bindableDevices="${this._bindableDevices}"
|
||||||
></zha-binding-control>
|
></zha-binding-control>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
|
<div class="spacer" />
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -94,30 +100,29 @@ export class HaConfigZha extends LitElement {
|
|||||||
this._selectedCluster = selectedClusterEvent.detail.cluster;
|
this._selectedCluster = selectedClusterEvent.detail.cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onDeviceSelected(
|
private async _fetchData(): Promise<void> {
|
||||||
selectedNodeEvent: HASSDomEvent<ZHADeviceSelectedParams>
|
if (this.ieee && this.hass) {
|
||||||
): void {
|
this.device = await fetchZHADevice(this.hass, this.ieee);
|
||||||
this._selectedDevice = selectedNodeEvent.detail.node;
|
|
||||||
this._selectedCluster = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _fetchBindableDevices(): Promise<void> {
|
|
||||||
if (this._selectedDevice && this.hass) {
|
|
||||||
this._bindableDevices = (
|
this._bindableDevices = (
|
||||||
await fetchBindableDevices(this.hass, this._selectedDevice!.ieee)
|
await fetchBindableDevices(this.hass, this.ieee)
|
||||||
).sort(sortZHADevices);
|
).sort(sortZHADevices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return [haStyle];
|
return [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
|
.spacer {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"ha-config-zha": HaConfigZha;
|
"zha-device-page": ZHADevicePage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("ha-config-zha", HaConfigZha);
|
|
@ -1,4 +1,3 @@
|
|||||||
import "../../../layouts/hass-subpage";
|
|
||||||
import "./zha-groups-data-table";
|
import "./zha-groups-data-table";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -19,6 +18,7 @@ import "@material/mwc-button";
|
|||||||
import "@polymer/paper-spinner/paper-spinner";
|
import "@polymer/paper-spinner/paper-spinner";
|
||||||
import "@polymer/paper-icon-button/paper-icon-button";
|
import "@polymer/paper-icon-button/paper-icon-button";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
|
import "../../../layouts/hass-subpage";
|
||||||
|
|
||||||
@customElement("zha-groups-dashboard")
|
@customElement("zha-groups-dashboard")
|
||||||
export class ZHAGroupsDashboard extends LitElement {
|
export class ZHAGroupsDashboard extends LitElement {
|
||||||
@ -47,9 +47,9 @@ export class ZHAGroupsDashboard extends LitElement {
|
|||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<hass-subpage
|
<hass-subpage
|
||||||
header=${this.hass.localize(
|
.header="${this.hass!.localize(
|
||||||
"ui.panel.config.zha.groups.zha_zigbee_groups"
|
"ui.panel.config.zha.groups.groups-header"
|
||||||
)}
|
)}"
|
||||||
>
|
>
|
||||||
<paper-icon-button
|
<paper-icon-button
|
||||||
slot="toolbar-icon"
|
slot="toolbar-icon"
|
||||||
|
@ -1,108 +0,0 @@
|
|||||||
import "../../../components/ha-card";
|
|
||||||
import "../ha-config-section";
|
|
||||||
import "@material/mwc-button";
|
|
||||||
import "@polymer/paper-icon-button/paper-icon-button";
|
|
||||||
|
|
||||||
import {
|
|
||||||
css,
|
|
||||||
CSSResult,
|
|
||||||
html,
|
|
||||||
LitElement,
|
|
||||||
TemplateResult,
|
|
||||||
property,
|
|
||||||
customElement,
|
|
||||||
} from "lit-element";
|
|
||||||
|
|
||||||
import { navigate } from "../../../common/navigate";
|
|
||||||
import { haStyle } from "../../../resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../types";
|
|
||||||
|
|
||||||
@customElement("zha-groups-tile")
|
|
||||||
export class ZHAGroupsTile extends LitElement {
|
|
||||||
@property() public hass?: HomeAssistant;
|
|
||||||
@property() public isWide?: boolean;
|
|
||||||
@property() private _showHelp = false;
|
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
|
||||||
return html`
|
|
||||||
<ha-config-section .isWide="${this.isWide}">
|
|
||||||
<div style="position: relative" slot="header">
|
|
||||||
<span>
|
|
||||||
${this.hass!.localize("ui.panel.config.zha.groups.header")}
|
|
||||||
</span>
|
|
||||||
<paper-icon-button
|
|
||||||
class="toggle-help-icon"
|
|
||||||
@click="${this._onHelpTap}"
|
|
||||||
icon="hass:help-circle"
|
|
||||||
></paper-icon-button>
|
|
||||||
</div>
|
|
||||||
<span slot="introduction">
|
|
||||||
${this.hass!.localize("ui.panel.config.zha.groups.introduction")}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<ha-card class="content">
|
|
||||||
<div class="card-actions">
|
|
||||||
<mwc-button @click=${this._onManageGroupsClick}>
|
|
||||||
${this.hass!.localize("ui.panel.config.zha.groups.manage_groups")}
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
</ha-config-section>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
|
||||||
this._showHelp = !this._showHelp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onManageGroupsClick() {
|
|
||||||
navigate(this, "groups");
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
|
||||||
return [
|
|
||||||
haStyle,
|
|
||||||
css`
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-card {
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions.warning ha-call-service-button {
|
|
||||||
color: var(--google-red-500);
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-help-icon {
|
|
||||||
position: absolute;
|
|
||||||
top: -6px;
|
|
||||||
right: 0;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-service-description {
|
|
||||||
display: block;
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-text2 {
|
|
||||||
color: grey;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"zha-groups-tile": ZHAGroupsTile;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,124 +0,0 @@
|
|||||||
import "../../../components/buttons/ha-call-service-button";
|
|
||||||
import "../../../components/ha-service-description";
|
|
||||||
import "../../../components/ha-card";
|
|
||||||
import "../ha-config-section";
|
|
||||||
import "@material/mwc-button";
|
|
||||||
import "@polymer/paper-icon-button/paper-icon-button";
|
|
||||||
|
|
||||||
import {
|
|
||||||
css,
|
|
||||||
CSSResult,
|
|
||||||
html,
|
|
||||||
LitElement,
|
|
||||||
TemplateResult,
|
|
||||||
property,
|
|
||||||
} from "lit-element";
|
|
||||||
|
|
||||||
import { navigate } from "../../../common/navigate";
|
|
||||||
import { haStyle } from "../../../resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../types";
|
|
||||||
|
|
||||||
export class ZHANetwork extends LitElement {
|
|
||||||
@property() public hass?: HomeAssistant;
|
|
||||||
@property() public isWide?: boolean;
|
|
||||||
@property() private _showHelp = false;
|
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
|
||||||
return html`
|
|
||||||
<ha-config-section .isWide="${this.isWide}">
|
|
||||||
<div style="position: relative" slot="header">
|
|
||||||
<span>
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.network_management.header"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<paper-icon-button
|
|
||||||
class="toggle-help-icon"
|
|
||||||
@click="${this._onHelpTap}"
|
|
||||||
icon="hass:help-circle"
|
|
||||||
></paper-icon-button>
|
|
||||||
</div>
|
|
||||||
<span slot="introduction">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.network_management.introduction"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<ha-card class="content">
|
|
||||||
<div class="card-actions">
|
|
||||||
<mwc-button @click=${this._onAddDevicesClick}>
|
|
||||||
${this.hass!.localize("ui.panel.config.zha.common.add_devices")}
|
|
||||||
</mwc-button>
|
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<ha-service-description
|
|
||||||
.hass="${this.hass}"
|
|
||||||
domain="zha"
|
|
||||||
service="permit"
|
|
||||||
class="help-text2"
|
|
||||||
/>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
</ha-config-section>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
|
||||||
this._showHelp = !this._showHelp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onAddDevicesClick() {
|
|
||||||
navigate(this, "add");
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
|
||||||
return [
|
|
||||||
haStyle,
|
|
||||||
css`
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-card {
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions.warning ha-call-service-button {
|
|
||||||
color: var(--google-red-500);
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-help-icon {
|
|
||||||
position: absolute;
|
|
||||||
top: -6px;
|
|
||||||
right: 0;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-service-description {
|
|
||||||
display: block;
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-text2 {
|
|
||||||
color: grey;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"zha-network": ZHANetwork;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("zha-network", ZHANetwork);
|
|
@ -2,13 +2,8 @@ import "../../../components/buttons/ha-call-service-button";
|
|||||||
import "../../../components/ha-service-description";
|
import "../../../components/ha-service-description";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import "./zha-clusters";
|
|
||||||
import "./zha-device-card";
|
import "./zha-device-card";
|
||||||
import "@material/mwc-button";
|
|
||||||
import "@polymer/paper-icon-button/paper-icon-button";
|
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 {
|
import {
|
||||||
css,
|
css,
|
||||||
@ -20,40 +15,22 @@ import {
|
|||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
|
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { ZHADevice } from "../../../data/zha";
|
||||||
import { fetchDevices, ZHADevice } from "../../../data/zha";
|
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { sortZHADevices } from "./functions";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { ItemSelectedEvent, ZHADeviceRemovedEvent } from "./types";
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
// for fire event
|
|
||||||
interface HASSDomEvents {
|
|
||||||
"zha-node-selected": {
|
|
||||||
node?: ZHADevice;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("zha-node")
|
@customElement("zha-node")
|
||||||
export class ZHANode extends LitElement {
|
export class ZHANode extends LitElement {
|
||||||
@property() public hass?: HomeAssistant;
|
@property() public hass?: HomeAssistant;
|
||||||
@property() public isWide?: boolean;
|
@property() public isWide?: boolean;
|
||||||
|
@property() public device?: ZHADevice;
|
||||||
@property() private _showHelp: boolean = false;
|
@property() private _showHelp: boolean = false;
|
||||||
@property() private _selectedDeviceIndex: number = -1;
|
|
||||||
@property() private _selectedDevice?: ZHADevice;
|
|
||||||
@property() private _nodes: ZHADevice[] = [];
|
|
||||||
|
|
||||||
public connectedCallback(): void {
|
|
||||||
super.connectedCallback();
|
|
||||||
this._fetchDevices();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html`
|
return html`
|
||||||
<ha-config-section .isWide="${this.isWide}">
|
<ha-config-section .isWide="${this.isWide}">
|
||||||
<div class="sectionHeader" slot="header">
|
<div class="header" slot="header">
|
||||||
<span
|
<span
|
||||||
>${this.hass!.localize(
|
>${this.hass!.localize(
|
||||||
"ui.panel.config.zha.node_management.header"
|
"ui.panel.config.zha.node_management.header"
|
||||||
@ -78,115 +55,37 @@ export class ZHANode extends LitElement {
|
|||||||
"ui.panel.config.zha.node_management.hint_wakeup"
|
"ui.panel.config.zha.node_management.hint_wakeup"
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
<ha-card class="content">
|
|
||||||
<div class="node-picker">
|
|
||||||
<paper-dropdown-menu
|
|
||||||
label="${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.common.devices"
|
|
||||||
)}"
|
|
||||||
class="flex"
|
|
||||||
id="zha-device-selector"
|
|
||||||
>
|
|
||||||
<paper-listbox
|
|
||||||
slot="dropdown-content"
|
|
||||||
@iron-select="${this._selectedDeviceChanged}"
|
|
||||||
.selected="${this._selectedDeviceIndex}"
|
|
||||||
>
|
|
||||||
${this._nodes.map(
|
|
||||||
(entry) => html`
|
|
||||||
<paper-item
|
|
||||||
>${entry.user_given_name
|
|
||||||
? entry.user_given_name
|
|
||||||
: entry.name}</paper-item
|
|
||||||
>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</paper-listbox>
|
|
||||||
</paper-dropdown-menu>
|
|
||||||
</div>
|
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="help-text">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.node_management.help_node_dropdown"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._selectedDeviceIndex !== -1
|
|
||||||
? html`
|
|
||||||
<zha-device-card
|
<zha-device-card
|
||||||
class="card"
|
class="card"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.device=${this._selectedDevice}
|
.device=${this.device}
|
||||||
.narrow=${!this.isWide}
|
.narrow=${!this.isWide}
|
||||||
.showHelp=${this._showHelp}
|
.showHelp=${this._showHelp}
|
||||||
|
isJoinPage
|
||||||
showActions
|
showActions
|
||||||
@zha-device-removed=${this._onDeviceRemoved}
|
@zha-device-removed=${this._onDeviceRemoved}
|
||||||
></zha-device-card>
|
></zha-device-card>
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._selectedDevice ? this._renderClusters() : ""}
|
|
||||||
</ha-card>
|
|
||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderClusters(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<zha-clusters
|
|
||||||
.hass="${this.hass}"
|
|
||||||
.selectedDevice="${this._selectedDevice}"
|
|
||||||
.showHelp="${this._showHelp}"
|
|
||||||
></zha-clusters>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
private _onHelpTap(): void {
|
||||||
this._showHelp = !this._showHelp;
|
this._showHelp = !this._showHelp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _selectedDeviceChanged(event: ItemSelectedEvent): void {
|
private _onDeviceRemoved(): void {
|
||||||
this._selectedDeviceIndex = event!.target!.selected;
|
this.device = undefined;
|
||||||
this._selectedDevice = this._nodes[this._selectedDeviceIndex];
|
navigate(this, `/config/zha`, true);
|
||||||
fireEvent(this, "zha-node-selected", { node: this._selectedDevice });
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _fetchDevices() {
|
|
||||||
this._nodes = (await fetchDevices(this.hass!)).sort(sortZHADevices);
|
|
||||||
}
|
|
||||||
|
|
||||||
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[] {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
.flex {
|
|
||||||
-ms-flex: 1 1 0.000000001px;
|
|
||||||
-webkit-flex: 1;
|
|
||||||
flex: 1;
|
|
||||||
-webkit-flex-basis: 0.000000001px;
|
|
||||||
flex-basis: 0.000000001px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.node-info {
|
.node-info {
|
||||||
margin-left: 16px;
|
margin-left: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sectionHeader {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-text {
|
.help-text {
|
||||||
color: grey;
|
color: grey;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
@ -199,30 +98,11 @@ export class ZHANode extends LitElement {
|
|||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
|
margin-top: 24px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1 0 300px;
|
flex: 1;
|
||||||
min-width: 0;
|
|
||||||
max-width: 600px;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,8 +115,12 @@ export class ZHANode extends LitElement {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.toggle-help-icon {
|
.toggle-help-icon {
|
||||||
position: absolute;
|
float: right;
|
||||||
top: 6px;
|
top: 6px;
|
||||||
right: 0;
|
right: 0;
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
|
@ -1424,6 +1424,9 @@
|
|||||||
},
|
},
|
||||||
"zha": {
|
"zha": {
|
||||||
"caption": "ZHA",
|
"caption": "ZHA",
|
||||||
|
"title": "Zigbee Home Automation",
|
||||||
|
"header": "Configure Zigbee Home Automation",
|
||||||
|
"introduction": "Here it is possible to configure the ZHA component. Not everything is possible to configure from the UI yet, but we're working on it.",
|
||||||
"description": "Zigbee Home Automation network management",
|
"description": "Zigbee Home Automation network management",
|
||||||
"common": {
|
"common": {
|
||||||
"add_devices": "Add Devices",
|
"add_devices": "Add Devices",
|
||||||
@ -1442,6 +1445,13 @@
|
|||||||
"header": "Network Management",
|
"header": "Network Management",
|
||||||
"introduction": "Commands that affect the entire network"
|
"introduction": "Commands that affect the entire network"
|
||||||
},
|
},
|
||||||
|
"add": {
|
||||||
|
"caption": "Add Devices",
|
||||||
|
"description": "Add devices to the Zigbee network"
|
||||||
|
},
|
||||||
|
"devices": {
|
||||||
|
"header": "Zigbee Home Automation - Device"
|
||||||
|
},
|
||||||
"node_management": {
|
"node_management": {
|
||||||
"header": "Device Management",
|
"header": "Device Management",
|
||||||
"introduction": "Run ZHA commands that affect a single device. Pick a device to see a list of available commands.",
|
"introduction": "Run ZHA commands that affect a single device. Pick a device to see a list of available commands.",
|
||||||
@ -1450,7 +1460,9 @@
|
|||||||
"help_node_dropdown": "Select a device to view per-device options."
|
"help_node_dropdown": "Select a device to view per-device options."
|
||||||
},
|
},
|
||||||
"clusters": {
|
"clusters": {
|
||||||
"help_cluster_dropdown": "Select a cluster to view attributes and commands."
|
"header": "Clusters",
|
||||||
|
"help_cluster_dropdown": "Select a cluster to view attributes and commands.",
|
||||||
|
"introduction": "Clusters are the building blocks for Zigbee functionality. They seperate functionality into logical units. There are client and server types and that are comprised of attributes and commands."
|
||||||
},
|
},
|
||||||
"cluster_attributes": {
|
"cluster_attributes": {
|
||||||
"header": "Cluster Attributes",
|
"header": "Cluster Attributes",
|
||||||
@ -1470,12 +1482,16 @@
|
|||||||
"help_command_dropdown": "Select a command to interact with."
|
"help_command_dropdown": "Select a command to interact with."
|
||||||
},
|
},
|
||||||
"groups": {
|
"groups": {
|
||||||
|
"caption": "Groups",
|
||||||
|
"description": "Create and modify Zigbee groups",
|
||||||
"zha_zigbee_groups": "ZHA Zigbee Groups",
|
"zha_zigbee_groups": "ZHA Zigbee Groups",
|
||||||
"manage_groups": "Manage Zigbee Groups",
|
"manage_groups": "Manage Zigbee Groups",
|
||||||
"groups": "Groups",
|
"groups": "Groups",
|
||||||
"group_id": "Group ID",
|
"group_id": "Group ID",
|
||||||
"members": "Members",
|
"members": "Members",
|
||||||
"header": "Zigbee Group Management",
|
"header": "Zigbee Home Automation - Group Management",
|
||||||
|
"groups-header": "Zigbee Home Automation - Group Management",
|
||||||
|
"group-header": "Zigbee Home Automation - Group Details",
|
||||||
"introduction": "Create and modify zigbee groups",
|
"introduction": "Create and modify zigbee groups",
|
||||||
"remove_groups": "Remove Groups",
|
"remove_groups": "Remove Groups",
|
||||||
"removing_groups": "Removing Groups",
|
"removing_groups": "Removing Groups",
|
||||||
@ -1488,7 +1504,7 @@
|
|||||||
"removing_members": "Removing Members",
|
"removing_members": "Removing Members",
|
||||||
"create_group_details": "Enter the required details to create a new zigbee group",
|
"create_group_details": "Enter the required details to create a new zigbee group",
|
||||||
"group_name_placeholder": "Group Name",
|
"group_name_placeholder": "Group Name",
|
||||||
"create_group": "Create New ZHA Zigbee Group",
|
"create_group": "Zigbee Home Automation - Create Group",
|
||||||
"create": "Create Group",
|
"create": "Create Group",
|
||||||
"creating_group": "Creating Group"
|
"creating_group": "Creating Group"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user