From b0cd97a15cc267c54370b2861105a832eb646d9c Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Wed, 18 Dec 2019 07:50:49 -0500 Subject: [PATCH 1/3] add ability to view zigbee groups --- src/data/zha.ts | 11 ++ src/panels/config/zha/functions.ts | 8 +- src/panels/config/zha/ha-config-zha.ts | 6 + src/panels/config/zha/zha-config-panel.ts | 9 ++ src/panels/config/zha/zha-groups-dashboard.ts | 79 +++++++++++++ .../config/zha/zha-groups-data-table.ts | 106 +++++++++++++++++ src/panels/config/zha/zha-groups-tile.ts | 108 ++++++++++++++++++ src/translations/en.json | 9 ++ 8 files changed, 335 insertions(+), 1 deletion(-) create mode 100644 src/panels/config/zha/zha-groups-dashboard.ts create mode 100644 src/panels/config/zha/zha-groups-data-table.ts create mode 100644 src/panels/config/zha/zha-groups-tile.ts diff --git a/src/data/zha.ts b/src/data/zha.ts index 4ae16c680aad..2f60c313e4c5 100644 --- a/src/data/zha.ts +++ b/src/data/zha.ts @@ -51,6 +51,12 @@ export interface ReadAttributeServiceData { manufacturer?: number; } +export interface ZHAGroup { + name: string; + group_id: number; + members: ZHADevice[]; +} + export const reconfigureNode = ( hass: HomeAssistant, ieeeAddress: string @@ -153,3 +159,8 @@ export const fetchClustersForZhaNode = ( type: "zha/devices/clusters", ieee: ieeeAddress, }); + +export const fetchGroups = (hass: HomeAssistant): Promise => + hass.callWS({ + type: "zha/groups", + }); diff --git a/src/panels/config/zha/functions.ts b/src/panels/config/zha/functions.ts index 72ce4d8bdff8..1e7a2858de34 100644 --- a/src/panels/config/zha/functions.ts +++ b/src/panels/config/zha/functions.ts @@ -1,4 +1,4 @@ -import { ZHADevice } from "../../../data/zha"; +import { ZHADevice, ZHAGroup } from "../../../data/zha"; export const formatAsPaddedHex = (value: string | number): string => { let hex = value; @@ -13,3 +13,9 @@ export const sortZHADevices = (a: ZHADevice, b: ZHADevice): number => { const nameb = b.user_given_name ? b.user_given_name : b.name; return nameA.localeCompare(nameb); }; + +export const sortZHAGroups = (a: ZHAGroup, b: ZHAGroup): number => { + const nameA = a.name; + const nameb = b.name; + return nameA.localeCompare(nameb); +}; diff --git a/src/panels/config/zha/ha-config-zha.ts b/src/panels/config/zha/ha-config-zha.ts index 47db6ae3dff1..7ea5d1976909 100755 --- a/src/panels/config/zha/ha-config-zha.ts +++ b/src/panels/config/zha/ha-config-zha.ts @@ -5,6 +5,7 @@ import "./zha-cluster-attributes"; import "./zha-cluster-commands"; import "./zha-network"; import "./zha-node"; +import "./zha-groups-tile"; import "@polymer/paper-icon-button/paper-icon-button"; import { @@ -45,6 +46,11 @@ export class HaConfigZha extends LitElement { .hass="${this.hass}" > + + + import( + /* webpackChunkName: "zha-groups-dashboard" */ "./zha-groups-dashboard" + ), + }, }, }; @@ -39,6 +47,7 @@ class ZHAConfigPanel extends HassRouterPage { el.route = this.routeTail; el.hass = this.hass; el.isWide = this.isWide; + el.narrow = this.narrow; } } diff --git a/src/panels/config/zha/zha-groups-dashboard.ts b/src/panels/config/zha/zha-groups-dashboard.ts new file mode 100644 index 000000000000..b3ebaea50994 --- /dev/null +++ b/src/panels/config/zha/zha-groups-dashboard.ts @@ -0,0 +1,79 @@ +import "../../../layouts/hass-subpage"; +import "./zha-groups-data-table"; + +import { + LitElement, + html, + TemplateResult, + property, + customElement, + CSSResult, + css, +} from "lit-element"; +import { HomeAssistant } from "../../../types"; +import { haStyleDialog } from "../../../resources/styles"; +import { ZHAGroup, fetchGroups } from "../../../data/zha"; +import { sortZHAGroups } from "./functions"; + +@customElement("zha-groups-dashboard") +export class ZHAGroupsDashboard extends LitElement { + @property() public hass!: HomeAssistant; + @property() public narrow = false; + @property() public _groups!: ZHAGroup[]; + + public connectedCallback(): void { + super.connectedCallback(); + this._fetchGroups(); + } + + protected render(): TemplateResult { + return html` + +
+ +
+
+ `; + } + + private async _fetchGroups() { + this._groups = (await fetchGroups(this.hass!)).sort(sortZHAGroups); + } + + static get styles(): CSSResult[] { + return [ + haStyleDialog, + css` + .content { + padding: 4px; + } + zha-groups-data-table { + width: 100%; + } + .button { + float: right; + } + + .table { + height: 200px; + overflow: auto; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-groups-dashboard": ZHAGroupsDashboard; + } +} diff --git a/src/panels/config/zha/zha-groups-data-table.ts b/src/panels/config/zha/zha-groups-data-table.ts new file mode 100644 index 000000000000..12023f64aa24 --- /dev/null +++ b/src/panels/config/zha/zha-groups-data-table.ts @@ -0,0 +1,106 @@ +import "../../../components/data-table/ha-data-table"; +import "../../../components/entity/ha-state-icon"; + +import memoizeOne from "memoize-one"; + +import { + LitElement, + html, + TemplateResult, + property, + customElement, +} from "lit-element"; +import { HomeAssistant } from "../../../types"; +// tslint:disable-next-line +import { DataTableColumnContainer } from "../../../components/data-table/ha-data-table"; +// tslint:disable-next-line +import { ZHAGroup, ZHADevice } from "../../../data/zha"; +import { formatAsPaddedHex } from "./functions"; + +export interface GroupRowData extends ZHAGroup { + group?: GroupRowData; + id?: number; +} + +@customElement("zha-groups-data-table") +export class ZHAGroupsDataTable extends LitElement { + @property() public hass!: HomeAssistant; + @property() public narrow = false; + @property() public groups: ZHAGroup[] = []; + @property() public selectable = false; + + private _groups = memoizeOne((groups: ZHAGroup[]) => { + let outputGroups: GroupRowData[] = groups || []; + + outputGroups = outputGroups.map((group) => { + return { + ...group, + name: group.name, + group_id: group.group_id, + members: group.members, + id: group.group_id, + }; + }); + + return outputGroups; + }); + + private _columns = memoizeOne( + (narrow: boolean): DataTableColumnContainer => + narrow + ? { + name: { + title: "Group", + sortable: true, + filterable: true, + direction: "asc", + }, + } + : { + name: { + title: this.hass.localize("ui.panel.config.zha.groups.groups"), + sortable: true, + filterable: true, + direction: "asc", + }, + group_id: { + title: this.hass.localize("ui.panel.config.zha.groups.group_id"), + template: (groupId: number) => { + return html` + ${formatAsPaddedHex(groupId)} + `; + }, + sortable: true, + filterable: true, + direction: "asc", + }, + members: { + title: this.hass.localize("ui.panel.config.zha.groups.members"), + template: (members: ZHADevice[]) => { + return html` + ${members.length} + `; + }, + sortable: true, + filterable: true, + direction: "asc", + }, + } + ); + + protected render(): TemplateResult { + return html` + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-groups-data-table": ZHAGroupsDataTable; + } +} diff --git a/src/panels/config/zha/zha-groups-tile.ts b/src/panels/config/zha/zha-groups-tile.ts new file mode 100644 index 000000000000..e14139618c67 --- /dev/null +++ b/src/panels/config/zha/zha-groups-tile.ts @@ -0,0 +1,108 @@ +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` + +
+ + ${this.hass!.localize("ui.panel.config.zha.groups.header")} + + +
+ + ${this.hass!.localize("ui.panel.config.zha.groups.introduction")} + + + +
+ + ${this.hass!.localize("ui.panel.config.zha.groups.manage_groups")} + +
+
+
+ `; + } + + private _onHelpTap(): void { + this._showHelp = !this._showHelp; + } + + private _onAddDevicesClick() { + 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; + } +} diff --git a/src/translations/en.json b/src/translations/en.json index 0641d1e52fcf..9afee83ad5c9 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1437,6 +1437,15 @@ "commands_of_cluster": "Commands of the selected cluster", "issue_zigbee_command": "Issue Zigbee Command", "help_command_dropdown": "Select a command to interact with." + }, + "groups": { + "zha_zigbee_groups": "ZHA Zigbee Groups", + "manage_groups": "Manage Zigbee Groups", + "groups": "Groups", + "group_id": "Group ID", + "members": "Members", + "header": "Zigbee Group Management", + "introduction": "Create and modify zigbee groups" } }, "zwave": { From b03217fd0bf1ced0463bd96848348e4b45bf4b6d Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Mon, 23 Dec 2019 09:06:16 -0500 Subject: [PATCH 2/3] review comments --- src/panels/config/zha/zha-groups-dashboard.ts | 2 -- .../config/zha/zha-groups-data-table.ts | 23 ++----------------- src/panels/config/zha/zha-groups-tile.ts | 4 ++-- 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/src/panels/config/zha/zha-groups-dashboard.ts b/src/panels/config/zha/zha-groups-dashboard.ts index b3ebaea50994..d9cde8cbd48b 100644 --- a/src/panels/config/zha/zha-groups-dashboard.ts +++ b/src/panels/config/zha/zha-groups-dashboard.ts @@ -11,7 +11,6 @@ import { css, } from "lit-element"; import { HomeAssistant } from "../../../types"; -import { haStyleDialog } from "../../../resources/styles"; import { ZHAGroup, fetchGroups } from "../../../data/zha"; import { sortZHAGroups } from "./functions"; @@ -51,7 +50,6 @@ export class ZHAGroupsDashboard extends LitElement { static get styles(): CSSResult[] { return [ - haStyleDialog, css` .content { padding: 4px; diff --git a/src/panels/config/zha/zha-groups-data-table.ts b/src/panels/config/zha/zha-groups-data-table.ts index 12023f64aa24..fa23a31a1312 100644 --- a/src/panels/config/zha/zha-groups-data-table.ts +++ b/src/panels/config/zha/zha-groups-data-table.ts @@ -29,22 +29,6 @@ export class ZHAGroupsDataTable extends LitElement { @property() public groups: ZHAGroup[] = []; @property() public selectable = false; - private _groups = memoizeOne((groups: ZHAGroup[]) => { - let outputGroups: GroupRowData[] = groups || []; - - outputGroups = outputGroups.map((group) => { - return { - ...group, - name: group.name, - group_id: group.group_id, - members: group.members, - id: group.group_id, - }; - }); - - return outputGroups; - }); - private _columns = memoizeOne( (narrow: boolean): DataTableColumnContainer => narrow @@ -71,8 +55,6 @@ export class ZHAGroupsDataTable extends LitElement { `; }, sortable: true, - filterable: true, - direction: "asc", }, members: { title: this.hass.localize("ui.panel.config.zha.groups.members"), @@ -82,8 +64,6 @@ export class ZHAGroupsDataTable extends LitElement { `; }, sortable: true, - filterable: true, - direction: "asc", }, } ); @@ -92,8 +72,9 @@ export class ZHAGroupsDataTable extends LitElement { return html` `; } diff --git a/src/panels/config/zha/zha-groups-tile.ts b/src/panels/config/zha/zha-groups-tile.ts index e14139618c67..e7229814610e 100644 --- a/src/panels/config/zha/zha-groups-tile.ts +++ b/src/panels/config/zha/zha-groups-tile.ts @@ -42,7 +42,7 @@ export class ZHAGroupsTile extends LitElement {
- + ${this.hass!.localize("ui.panel.config.zha.groups.manage_groups")}
@@ -55,7 +55,7 @@ export class ZHAGroupsTile extends LitElement { this._showHelp = !this._showHelp; } - private _onAddDevicesClick() { + private _onManageGroupsClick() { navigate(this, "groups"); } From 37cab84006ad2705cbc7e77fe365e6d887333ec4 Mon Sep 17 00:00:00 2001 From: David Mulcahey Date: Mon, 23 Dec 2019 10:31:52 -0500 Subject: [PATCH 3/3] remove selectable until used --- src/panels/config/zha/zha-groups-data-table.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/panels/config/zha/zha-groups-data-table.ts b/src/panels/config/zha/zha-groups-data-table.ts index fa23a31a1312..0f9e6dc6cda4 100644 --- a/src/panels/config/zha/zha-groups-data-table.ts +++ b/src/panels/config/zha/zha-groups-data-table.ts @@ -27,7 +27,6 @@ export class ZHAGroupsDataTable extends LitElement { @property() public hass!: HomeAssistant; @property() public narrow = false; @property() public groups: ZHAGroup[] = []; - @property() public selectable = false; private _columns = memoizeOne( (narrow: boolean): DataTableColumnContainer => @@ -73,7 +72,6 @@ export class ZHAGroupsDataTable extends LitElement { `;