Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/data/zha.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -153,3 +159,8 @@ export const fetchClustersForZhaNode = (
type: "zha/devices/clusters",
ieee: ieeeAddress,
});

export const fetchGroups = (hass: HomeAssistant): Promise<ZHAGroup[]> =>
hass.callWS({
type: "zha/groups",
});
8 changes: 7 additions & 1 deletion src/panels/config/zha/functions.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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);
};
6 changes: 6 additions & 0 deletions src/panels/config/zha/ha-config-zha.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -45,6 +46,11 @@ export class HaConfigZha extends LitElement {
.hass="${this.hass}"
></zha-network>

<zha-groups-tile
.isWide="${this.isWide}"
.hass="${this.hass}"
></zha-groups-tile>

<zha-node
.isWide="${this.isWide}"
.hass="${this.hass}"
Expand Down
9 changes: 9 additions & 0 deletions src/panels/config/zha/zha-config-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { HomeAssistant } from "../../../types";
class ZHAConfigPanel extends HassRouterPage {
@property() public hass!: HomeAssistant;
@property() public isWide!: boolean;
@property() public narrow!: boolean;

protected routerOptions: RouterOptions = {
defaultPage: "configuration",
Expand All @@ -32,13 +33,21 @@ class ZHAConfigPanel extends HassRouterPage {
/* webpackChunkName: "zha-add-devices-page" */ "./zha-add-devices-page"
),
},
groups: {
tag: "zha-groups-dashboard",
load: () =>
import(
/* webpackChunkName: "zha-groups-dashboard" */ "./zha-groups-dashboard"
),
},
},
};

protected updatePageEl(el): void {
el.route = this.routeTail;
el.hass = this.hass;
el.isWide = this.isWide;
el.narrow = this.narrow;
}
}

Expand Down
77 changes: 77 additions & 0 deletions src/panels/config/zha/zha-groups-dashboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
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 { 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`
<hass-subpage
header=${this.hass.localize(
"ui.panel.config.zha.groups.zha_zigbee_groups"
)}
>
<div class="content">
<zha-groups-data-table
.hass=${this.hass}
.narrow=${this.narrow}
.groups=${this._groups}
class="table"
></zha-groups-data-table>
</div>
</hass-subpage>
`;
}

private async _fetchGroups() {
this._groups = (await fetchGroups(this.hass!)).sort(sortZHAGroups);
}

static get styles(): CSSResult[] {
return [
css`
.content {
padding: 4px;
}
zha-groups-data-table {
width: 100%;
}
.button {
float: right;
}

.table {
height: 200px;
overflow: auto;
Comment thread
dmulcahey marked this conversation as resolved.
}
`,
];
}
}

declare global {
interface HTMLElementTagNameMap {
"zha-groups-dashboard": ZHAGroupsDashboard;
}
}
85 changes: 85 additions & 0 deletions src/panels/config/zha/zha-groups-data-table.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
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[] = [];

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,
},
members: {
title: this.hass.localize("ui.panel.config.zha.groups.members"),
template: (members: ZHADevice[]) => {
return html`
${members.length}
`;
},
sortable: true,
},
}
);

protected render(): TemplateResult {
return html`
<ha-data-table
.columns=${this._columns(this.narrow)}
.data=${this.groups}
.id=${"group_id"}
></ha-data-table>
`;
}
}

declare global {
interface HTMLElementTagNameMap {
"zha-groups-data-table": ZHAGroupsDataTable;
}
}
108 changes: 108 additions & 0 deletions src/panels/config/zha/zha-groups-tile.ts
Original file line number Diff line number Diff line change
@@ -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`
<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;
}
}
9 changes: 9 additions & 0 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down