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
22 changes: 17 additions & 5 deletions src/data/zha.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { HomeAssistant } from "../types";

export interface ZHAEntityReference extends HassEntity {
name: string;
original_name?: string;
}

export interface ZHADevice {
Expand All @@ -26,6 +27,12 @@ export interface ZHADevice {
signature: any;
}

export interface ZHADeviceEndpoint {
device: ZHADevice;
endpoint_id: number;
entities: ZHAEntityReference[];
}

export interface Attribute {
name: string;
id: number;
Expand Down Expand Up @@ -56,7 +63,12 @@ export interface ReadAttributeServiceData {
export interface ZHAGroup {
name: string;
group_id: number;
members: ZHADevice[];
members: ZHADeviceEndpoint[];
}

export interface ZHAGroupMember {
ieee: string;
endpoint_id: string;
}

export const reconfigureNode = (
Expand Down Expand Up @@ -213,15 +225,15 @@ export const fetchGroup = (

export const fetchGroupableDevices = (
hass: HomeAssistant
): Promise<ZHADevice[]> =>
): Promise<ZHADeviceEndpoint[]> =>
hass.callWS({
type: "zha/devices/groupable",
});

export const addMembersToGroup = (
hass: HomeAssistant,
groupId: number,
membersToAdd: string[]
membersToAdd: ZHAGroupMember[]
): Promise<ZHAGroup> =>
hass.callWS({
type: "zha/group/members/add",
Expand All @@ -232,7 +244,7 @@ export const addMembersToGroup = (
export const removeMembersFromGroup = (
hass: HomeAssistant,
groupId: number,
membersToRemove: string[]
membersToRemove: ZHAGroupMember[]
): Promise<ZHAGroup> =>
hass.callWS({
type: "zha/group/members/remove",
Expand All @@ -243,7 +255,7 @@ export const removeMembersFromGroup = (
export const addGroup = (
hass: HomeAssistant,
groupName: string,
membersToAdd?: string[]
membersToAdd?: ZHAGroupMember[]
): Promise<ZHAGroup> =>
hass.callWS({
type: "zha/group/add",
Expand Down
34 changes: 17 additions & 17 deletions src/panels/config/zha/zha-add-group-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,31 @@ import type { SelectionChangedEvent } from "../../../components/data-table/ha-da
import {
addGroup,
fetchGroupableDevices,
ZHADevice,
ZHAGroup,
ZHADeviceEndpoint,
} from "../../../data/zha";
import "../../../layouts/hass-error-screen";
import "../../../layouts/hass-subpage";
import type { PolymerChangedEvent } from "../../../polymer-types";
import type { HomeAssistant } from "../../../types";
import "../ha-config-section";
import "./zha-devices-data-table";
import type { ZHADevicesDataTable } from "./zha-devices-data-table";
import "./zha-device-endpoint-data-table";
import type { ZHADeviceEndpointDataTable } from "./zha-device-endpoint-data-table";

@customElement("zha-add-group-page")
export class ZHAAddGroupPage extends LitElement {
@property() public hass!: HomeAssistant;
@property({ type: Object }) public hass!: HomeAssistant;

@property() public narrow!: boolean;
@property({ type: Boolean }) public narrow!: boolean;

@property() public devices: ZHADevice[] = [];
@property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = [];

@property() private _processingAdd = false;

@property() private _groupName = "";

@query("zha-devices-data-table")
private _zhaDevicesDataTable!: ZHADevicesDataTable;
@query("zha-device-endpoint-data-table")
private _zhaDevicesDataTable!: ZHADeviceEndpointDataTable;

private _firstUpdatedCalled = false;

Expand Down Expand Up @@ -87,14 +87,14 @@ export class ZHAAddGroupPage extends LitElement {
${this.hass.localize("ui.panel.config.zha.groups.add_members")}
</div>

<zha-devices-data-table
<zha-device-endpoint-data-table
.hass=${this.hass}
.devices=${this.devices}
.deviceEndpoints=${this.deviceEndpoints}
.narrow=${this.narrow}
selectable
@selection-changed=${this._handleAddSelectionChanged}
>
</zha-devices-data-table>
</zha-device-endpoint-data-table>

<div class="paper-dialog-buttons">
<mwc-button
Expand All @@ -121,7 +121,7 @@ export class ZHAAddGroupPage extends LitElement {
}

private async _fetchData() {
this.devices = await fetchGroupableDevices(this.hass!);
this.deviceEndpoints = await fetchGroupableDevices(this.hass!);
}

private _handleAddSelectionChanged(
Expand All @@ -132,11 +132,11 @@ export class ZHAAddGroupPage extends LitElement {

private async _createGroup(): Promise<void> {
this._processingAdd = true;
const group: ZHAGroup = await addGroup(
this.hass,
this._groupName,
this._selectedDevicesToAdd
);
const members = this._selectedDevicesToAdd.map((member) => {
const memberParts = member.split("_");
return { ieee: memberParts[0], endpoint_id: memberParts[1] };
});
const group: ZHAGroup = await addGroup(this.hass, this._groupName, members);
this._selectedDevicesToAdd = [];
this._processingAdd = false;
this._groupName = "";
Expand Down
13 changes: 7 additions & 6 deletions src/panels/config/zha/zha-config-dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import "../../../components/data-table/ha-data-table";
import type {
DataTableColumnContainer,
RowClickedEvent,
DataTableRowData,
} from "../../../components/data-table/ha-data-table";
import "../../../components/ha-card";
import "../../../components/ha-icon-next";
Expand All @@ -27,19 +28,19 @@ import type { HomeAssistant, Route } from "../../../types";
import "../ha-config-section";
import { formatAsPaddedHex, sortZHADevices } from "./functions";

export interface DeviceRowData extends ZHADevice {
export interface DeviceRowData extends DataTableRowData {
device?: DeviceRowData;
}

@customElement("zha-config-dashboard")
class ZHAConfigDashboard extends LitElement {
@property() public hass!: HomeAssistant;
@property({ type: Object }) public hass!: HomeAssistant;

@property() public route!: Route;
@property({ type: Object }) public route!: Route;

@property() public narrow!: boolean;
@property({ type: Boolean }) public narrow!: boolean;

@property() public isWide!: boolean;
@property({ type: Boolean }) public isWide!: boolean;

@property() private _devices: ZHADevice[] = [];

Expand Down Expand Up @@ -91,7 +92,7 @@ class ZHAConfigDashboard extends LitElement {
title: "IEEE",
sortable: true,
filterable: true,
width: "25%",
width: "30%",
},
}
);
Expand Down
182 changes: 182 additions & 0 deletions src/panels/config/zha/zha-device-endpoint-data-table.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import {
customElement,
html,
LitElement,
property,
query,
TemplateResult,
css,
CSSResult,
} from "lit-element";
import memoizeOne from "memoize-one";
import "../../../components/data-table/ha-data-table";
import type {
DataTableColumnContainer,
HaDataTable,
DataTableRowData,
} from "../../../components/data-table/ha-data-table";
import "../../../components/entity/ha-state-icon";
import type { ZHADeviceEndpoint, ZHAEntityReference } from "../../../data/zha";
import { showZHADeviceInfoDialog } from "../../../dialogs/zha-device-info-dialog/show-dialog-zha-device-info";
import type { HomeAssistant } from "../../../types";

export interface DeviceEndpointRowData extends DataTableRowData {
id: string;
name: string;
model: string;
manufacturer: string;
endpoint_id: number;
entities: ZHAEntityReference[];
}

@customElement("zha-device-endpoint-data-table")
export class ZHADeviceEndpointDataTable extends LitElement {
@property({ type: Object }) public hass!: HomeAssistant;

@property({ type: Boolean }) public narrow = false;

@property({ type: Boolean }) public selectable = false;

@property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = [];

@query("ha-data-table") private _dataTable!: HaDataTable;

private _deviceEndpoints = memoizeOne(
(deviceEndpoints: ZHADeviceEndpoint[]) => {
const outputDevices: DeviceEndpointRowData[] = [];

deviceEndpoints.forEach((deviceEndpoint) => {
outputDevices.push({
name:
deviceEndpoint.device.user_given_name || deviceEndpoint.device.name,
model: deviceEndpoint.device.model,
manufacturer: deviceEndpoint.device.manufacturer,
id: deviceEndpoint.device.ieee + "_" + deviceEndpoint.endpoint_id,
ieee: deviceEndpoint.device.ieee,
endpoint_id: deviceEndpoint.endpoint_id,
entities: deviceEndpoint.entities,
});
});

return outputDevices;
}
);

private _columns = memoizeOne(
(narrow: boolean): DataTableColumnContainer =>
narrow
? {
name: {
title: "Devices",
sortable: true,
filterable: true,
direction: "asc",
grows: true,
template: (name) => html`
<div
class="mdc-data-table__cell table-cell-text"
@click=${this._handleClicked}
style="cursor: pointer;"
>
${name}
</div>
`,
},
endpoint_id: {
title: "Endpoint",
sortable: true,
filterable: true,
},
}
: {
name: {
title: "Name",
sortable: true,
filterable: true,
direction: "asc",
grows: true,
template: (name) => html`
<div
class="mdc-data-table__cell table-cell-text"
@click=${this._handleClicked}
style="cursor: pointer;"
>
${name}
</div>
`,
},
endpoint_id: {
title: "Endpoint",
sortable: true,
filterable: true,
},
entities: {
title: "Associated Entities",
sortable: false,
filterable: false,
width: "50%",
template: (entities) => html`
${entities.length
? entities.length > 3
? html`${entities.slice(0, 2).map(
(entity) =>
html`<div
style="overflow: hidden; text-overflow: ellipsis;"
>
${entity.name || entity.original_name}
</div>`
)}
<div>And ${entities.length - 2} more...</div>`
: entities.map(
(entity) =>
html`<div
style="overflow: hidden; text-overflow: ellipsis;"
>
${entity.name || entity.original_name}
</div>`
)
: "This endpoint has no associated entities"}
`,
},
}
);

public clearSelection() {
this._dataTable.clearSelection();
}

protected render(): TemplateResult {
return html`
<ha-data-table
.columns=${this._columns(this.narrow)}
.data=${this._deviceEndpoints(this.deviceEndpoints)}
.selectable=${this.selectable}
auto-height
></ha-data-table>
`;
}

private async _handleClicked(ev: CustomEvent) {
const rowId = ((ev.target as HTMLElement).closest(
".mdc-data-table__row"
) as any).rowId;
const ieee = rowId.substring(0, rowId.indexOf("_"));
showZHADeviceInfoDialog(this, { ieee });
}

static get styles(): CSSResult[] {
return [
css`
.table-cell-text {
word-break: break-word;
}
`,
];
}
}

declare global {
interface HTMLElementTagNameMap {
"zha-device-endpoint-data-table": ZHADeviceEndpointDataTable;
}
}
Loading