mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-01 13:37:47 +00:00
Move integration config panels to integrations (#6122)
This commit is contained in:
parent
ccc9b73f9b
commit
4eb46bc275
@ -6,7 +6,7 @@ export const isValidEntityId = (entityId: string) =>
|
||||
export const createValidEntityId = (input: string) =>
|
||||
input
|
||||
.toLowerCase()
|
||||
.replace(/\s|'/g, "_") // replace spaces and quotes with underscore
|
||||
.replace(/\s|'|\./g, "_") // replace spaces, points and quotes with underscore
|
||||
.replace(/\W/g, "") // remove not allowed chars
|
||||
.replace(/_{2,}/g, "_") // replace multiple underscores with 1
|
||||
.replace(/_$/, ""); // remove underscores at the end
|
||||
|
@ -619,6 +619,11 @@ export class HaDataTable extends LitElement {
|
||||
text-transform: inherit;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--numeric {
|
||||
text-align: right;
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
Wrapper for paper-textarea.
|
||||
|
||||
paper-textarea crashes on iOS when created programmatically. This only impacts
|
||||
our automation and script editors as they are using Preact. Polymer is using
|
||||
template elements and does not have this issue.
|
||||
|
||||
paper-textarea issue: https://github.com/PolymerElements/paper-input/issues/556
|
||||
WebKit issue: https://bugs.webkit.org/show_bug.cgi?id=174629
|
||||
*/
|
||||
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
|
||||
class HaTextarea extends PolymerElement {
|
||||
static get template() {
|
||||
return html`
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<paper-textarea
|
||||
label="[[label]]"
|
||||
placeholder="[[placeholder]]"
|
||||
value="{{value}}"
|
||||
></paper-textarea>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
name: String,
|
||||
label: String,
|
||||
placeholder: String,
|
||||
value: {
|
||||
type: String,
|
||||
notify: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("ha-textarea", HaTextarea);
|
@ -1,113 +0,0 @@
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "../../components/dialog/ha-paper-dialog";
|
||||
import type { HaPaperDialog } from "../../components/dialog/ha-paper-dialog";
|
||||
import { fetchZHADevice, ZHADevice } from "../../data/zha";
|
||||
import "../../panels/config/zha/zha-device-card";
|
||||
import type { PolymerChangedEvent } from "../../polymer-types";
|
||||
import { haStyleDialog } from "../../resources/styles";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import type { ZHADeviceInfoDialogParams } from "./show-dialog-zha-device-info";
|
||||
|
||||
@customElement("dialog-zha-device-info")
|
||||
class DialogZHADeviceInfo extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
|
||||
@property() private _params?: ZHADeviceInfoDialogParams;
|
||||
|
||||
@property() private _error?: string;
|
||||
|
||||
@property() private _device?: ZHADevice;
|
||||
|
||||
public async showDialog(params: ZHADeviceInfoDialogParams): Promise<void> {
|
||||
this._params = params;
|
||||
this._device = await fetchZHADevice(this.hass, params.ieee);
|
||||
await this.updateComplete;
|
||||
this._dialog.open();
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._params || !this._device) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-paper-dialog
|
||||
with-backdrop
|
||||
opened
|
||||
@opened-changed=${this._openedChanged}
|
||||
>
|
||||
${this._error
|
||||
? html` <div class="error">${this._error}</div> `
|
||||
: html`
|
||||
<zha-device-card
|
||||
class="card"
|
||||
.hass=${this.hass}
|
||||
.device=${this._device}
|
||||
@zha-device-removed=${this._onDeviceRemoved}
|
||||
.showEntityDetail=${false}
|
||||
.showActions="${this._device.device_type !== "Coordinator"}"
|
||||
></zha-device-card>
|
||||
`}
|
||||
</ha-paper-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
private _openedChanged(ev: PolymerChangedEvent<boolean>): void {
|
||||
if (!ev.detail.value) {
|
||||
this._params = undefined;
|
||||
this._error = undefined;
|
||||
this._device = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private _onDeviceRemoved(): void {
|
||||
this._closeDialog();
|
||||
}
|
||||
|
||||
private get _dialog(): HaPaperDialog {
|
||||
return this.shadowRoot!.querySelector("ha-paper-dialog")!;
|
||||
}
|
||||
|
||||
private _closeDialog() {
|
||||
this._dialog.close();
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-paper-dialog > * {
|
||||
margin: 0;
|
||||
display: block;
|
||||
padding: 0;
|
||||
}
|
||||
.card {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1 0 300px;
|
||||
min-width: 0;
|
||||
max-width: 600px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.error {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"dialog-zha-device-info": DialogZHADeviceInfo;
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
|
||||
export interface ZHADeviceInfoDialogParams {
|
||||
ieee: string;
|
||||
}
|
||||
|
||||
export const loadZHADeviceInfoDialog = () =>
|
||||
import(
|
||||
/* webpackChunkName: "dialog-zha-device-info" */ "./dialog-zha-device-info"
|
||||
);
|
||||
|
||||
export const showZHADeviceInfoDialog = (
|
||||
element: HTMLElement,
|
||||
zhaDeviceInfoParams: ZHADeviceInfoDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-zha-device-info",
|
||||
dialogImport: loadZHADeviceInfoDialog,
|
||||
dialogParams: zhaDeviceInfoParams,
|
||||
});
|
||||
};
|
@ -1,4 +1,5 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { customElement, LitElement, property } from "lit-element";
|
||||
import { html } from "lit-html";
|
||||
import { WaitAction } from "../../../../../data/script";
|
||||
@ -19,7 +20,7 @@ export class HaWaitAction extends LitElement implements ActionElement {
|
||||
const { wait_template, timeout } = this.action;
|
||||
|
||||
return html`
|
||||
<ha-textarea
|
||||
<paper-textarea
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.wait_template.wait_template"
|
||||
)}
|
||||
@ -27,7 +28,7 @@ export class HaWaitAction extends LitElement implements ActionElement {
|
||||
.value=${wait_template}
|
||||
@value-changed=${this._valueChanged}
|
||||
dir="ltr"
|
||||
></ha-textarea>
|
||||
></paper-textarea>
|
||||
<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.wait_template.timeout"
|
||||
|
@ -2,7 +2,7 @@ import "@polymer/paper-input/paper-input";
|
||||
import { customElement, html, LitElement, property } from "lit-element";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../../components/ha-textarea";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { NumericStateCondition } from "../../../../../data/automation";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { handleChangeEvent } from "../ha-automation-condition-row";
|
||||
@ -45,7 +45,7 @@ export default class HaNumericStateCondition extends LitElement {
|
||||
.value=${below}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
<ha-textarea
|
||||
<paper-textarea
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.numeric_state.value_template"
|
||||
)}
|
||||
@ -53,7 +53,7 @@ export default class HaNumericStateCondition extends LitElement {
|
||||
.value=${value_template}
|
||||
@value-changed=${this._valueChanged}
|
||||
dir="ltr"
|
||||
></ha-textarea>
|
||||
></paper-textarea>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { customElement, html, LitElement, property } from "lit-element";
|
||||
import "../../../../../components/ha-textarea";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { TemplateCondition } from "../../../../../data/automation";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { handleChangeEvent } from "../ha-automation-condition-row";
|
||||
@ -17,7 +17,7 @@ export class HaTemplateCondition extends LitElement {
|
||||
protected render() {
|
||||
const { value_template } = this.condition;
|
||||
return html`
|
||||
<ha-textarea
|
||||
<paper-textarea
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.template.value_template"
|
||||
)}
|
||||
@ -25,7 +25,7 @@ export class HaTemplateCondition extends LitElement {
|
||||
.value=${value_template}
|
||||
@value-changed=${this._valueChanged}
|
||||
dir="ltr"
|
||||
></ha-textarea>
|
||||
></paper-textarea>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import "@polymer/app-layout/app-header/app-header";
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import "../../../components/ha-icon-button";
|
||||
import {
|
||||
css,
|
||||
@ -117,7 +118,7 @@ export class HaAutomationEditor extends LitElement {
|
||||
@value-changed=${this._valueChanged}
|
||||
>
|
||||
</paper-input>
|
||||
<ha-textarea
|
||||
<paper-textarea
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.description.label"
|
||||
)}
|
||||
@ -127,7 +128,7 @@ export class HaAutomationEditor extends LitElement {
|
||||
name="description"
|
||||
.value=${this._config.description}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-textarea>
|
||||
></paper-textarea>
|
||||
</div>
|
||||
${stateObj
|
||||
? html`
|
||||
|
@ -2,7 +2,7 @@ import "@polymer/paper-input/paper-input";
|
||||
import { customElement, html, LitElement, property } from "lit-element";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../../components/ha-textarea";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { ForDict, NumericStateTrigger } from "../../../../../data/automation";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { handleChangeEvent } from "../ha-automation-trigger-row";
|
||||
@ -61,7 +61,7 @@ export default class HaNumericStateTrigger extends LitElement {
|
||||
.value=${below}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
<ha-textarea
|
||||
<paper-textarea
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.numeric_state.value_template"
|
||||
)}
|
||||
@ -69,7 +69,7 @@ export default class HaNumericStateTrigger extends LitElement {
|
||||
.value=${value_template}
|
||||
@value-changed=${this._valueChanged}
|
||||
dir="ltr"
|
||||
></ha-textarea>
|
||||
></paper-textarea>
|
||||
<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.state.for"
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { customElement, html, LitElement, property } from "lit-element";
|
||||
import "../../../../../components/ha-textarea";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { TemplateTrigger } from "../../../../../data/automation";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { handleChangeEvent } from "../ha-automation-trigger-row";
|
||||
@ -17,7 +17,7 @@ export class HaTemplateTrigger extends LitElement {
|
||||
protected render() {
|
||||
const { value_template } = this.trigger;
|
||||
return html`
|
||||
<ha-textarea
|
||||
<paper-textarea
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.template.value_template"
|
||||
)}
|
||||
@ -25,7 +25,7 @@ export class HaTemplateTrigger extends LitElement {
|
||||
.value=${value_template}
|
||||
@value-changed=${this._valueChanged}
|
||||
dir="ltr"
|
||||
></ha-textarea>
|
||||
></paper-textarea>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,7 @@ export class HaDeviceCard extends LitElement {
|
||||
: ""}
|
||||
<slot></slot>
|
||||
</div>
|
||||
<slot name="actions"></slot>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
@ -100,7 +101,6 @@ export class HaDeviceCard extends LitElement {
|
||||
}
|
||||
ha-card {
|
||||
flex: 1 0 100%;
|
||||
padding-bottom: 10px;
|
||||
min-width: 0;
|
||||
}
|
||||
.device {
|
||||
|
@ -5,16 +5,17 @@ import {
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import { DeviceRegistryEntry } from "../../../../data/device_registry";
|
||||
import { removeMQTTDeviceEntry } from "../../../../data/mqtt";
|
||||
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
import { showMQTTDeviceDebugInfoDialog } from "../../../../dialogs/mqtt-device-debug-info-dialog/show-dialog-mqtt-device-debug-info";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { DeviceRegistryEntry } from "../../../../../data/device_registry";
|
||||
import { removeMQTTDeviceEntry } from "../../../../../data/mqtt";
|
||||
import { showConfirmationDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
||||
import { showMQTTDeviceDebugInfoDialog } from "../../../../../dialogs/mqtt-device-debug-info-dialog/show-dialog-mqtt-device-debug-info";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
|
||||
@customElement("ha-device-card-mqtt")
|
||||
export class HaDeviceCardMqtt extends LitElement {
|
||||
@customElement("ha-device-actions-mqtt")
|
||||
export class HaDeviceActionsMqtt extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
|
||||
@property() public device!: DeviceRegistryEntry;
|
||||
@ -47,7 +48,15 @@ export class HaDeviceCardMqtt extends LitElement {
|
||||
await showMQTTDeviceDebugInfoDialog(this, { device });
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return haStyle;
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
import {
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
css,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import { DeviceRegistryEntry } from "../../../../../data/device_registry";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import {
|
||||
ZHADevice,
|
||||
fetchZHADevice,
|
||||
reconfigureNode,
|
||||
} from "../../../../../data/zha";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
import { showZHADeviceZigbeeInfoDialog } from "../../../../../dialogs/zha-device-zigbee-signature-dialog/show-dialog-zha-device-zigbee-info";
|
||||
import { showConfirmationDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
||||
|
||||
@customElement("ha-device-actions-zha")
|
||||
export class HaDeviceActionsZha extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
|
||||
@property() public device!: DeviceRegistryEntry;
|
||||
|
||||
@property() private _zhaDevice?: ZHADevice;
|
||||
|
||||
protected updated(changedProperties: PropertyValues) {
|
||||
if (changedProperties.has("device")) {
|
||||
const zigbeeConnection = this.device.connections.find(
|
||||
(conn) => conn[0] === "zigbee"
|
||||
);
|
||||
if (!zigbeeConnection) {
|
||||
return;
|
||||
}
|
||||
fetchZHADevice(this.hass, zigbeeConnection[1]).then((device) => {
|
||||
this._zhaDevice = device;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._zhaDevice) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
${this._zhaDevice.device_type !== "Coordinator"
|
||||
? html`
|
||||
<mwc-button @click=${this._onReconfigureNodeClick}>
|
||||
${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.buttons.reconfigure"
|
||||
)}
|
||||
</mwc-button>
|
||||
`
|
||||
: ""}
|
||||
${this._zhaDevice.power_source === "Mains" &&
|
||||
(this._zhaDevice.device_type === "Router" ||
|
||||
this._zhaDevice.device_type === "Coordinator")
|
||||
? html`
|
||||
<mwc-button @click=${this._onAddDevicesClick}>
|
||||
${this.hass!.localize("ui.dialogs.zha_device_info.buttons.add")}
|
||||
</mwc-button>
|
||||
`
|
||||
: ""}
|
||||
${this._zhaDevice.device_type !== "Coordinator"
|
||||
? html`
|
||||
<mwc-button @click=${this._handleZigbeeInfoClicked}>
|
||||
${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.buttons.zigbee_information"
|
||||
)}
|
||||
</mwc-button>
|
||||
<mwc-button class="warning" @click=${this._removeDevice}>
|
||||
${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.buttons.remove"
|
||||
)}
|
||||
</mwc-button>
|
||||
`
|
||||
: ""}
|
||||
`;
|
||||
}
|
||||
|
||||
private async _onReconfigureNodeClick(): Promise<void> {
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
reconfigureNode(this.hass, this._zhaDevice!.ieee);
|
||||
}
|
||||
|
||||
private _onAddDevicesClick() {
|
||||
navigate(this, "/config/zha/add/" + this._zhaDevice!.ieee);
|
||||
}
|
||||
|
||||
private async _handleZigbeeInfoClicked() {
|
||||
showZHADeviceZigbeeInfoDialog(this, { device: this._zhaDevice! });
|
||||
}
|
||||
|
||||
private async _removeDevice() {
|
||||
const confirmed = await showConfirmationDialog(this, {
|
||||
text: this.hass.localize(
|
||||
"ui.dialogs.zha_device_info.confirmations.remove"
|
||||
),
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hass.callService("zha", "remove", {
|
||||
ieee_address: this._zhaDevice!.ieee,
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
import {
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
css,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import { DeviceRegistryEntry } from "../../../../../data/device_registry";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { ZHADevice, fetchZHADevice } from "../../../../../data/zha";
|
||||
import { formatAsPaddedHex } from "../../../integrations/integration-panels/zha/functions";
|
||||
|
||||
@customElement("ha-device-info-zha")
|
||||
export class HaDeviceActionsZha extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
|
||||
@property() public device!: DeviceRegistryEntry;
|
||||
|
||||
@property() private _zhaDevice?: ZHADevice;
|
||||
|
||||
protected updated(changedProperties: PropertyValues) {
|
||||
if (changedProperties.has("device")) {
|
||||
const zigbeeConnection = this.device.connections.find(
|
||||
(conn) => conn[0] === "zigbee"
|
||||
);
|
||||
if (!zigbeeConnection) {
|
||||
return;
|
||||
}
|
||||
fetchZHADevice(this.hass, zigbeeConnection[1]).then((device) => {
|
||||
this._zhaDevice = device;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._zhaDevice) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
<h4>Zigbee info</h4>
|
||||
<div>IEEE: ${this._zhaDevice.ieee}</div>
|
||||
<div>Nwk: ${formatAsPaddedHex(this._zhaDevice.nwk)}</div>
|
||||
<div>Device Type: ${this._zhaDevice.device_type}</div>
|
||||
<div>
|
||||
LQI:
|
||||
${this._zhaDevice.lqi ||
|
||||
this.hass!.localize("ui.dialogs.zha_device_info.unknown")}
|
||||
</div>
|
||||
<div>
|
||||
RSSI:
|
||||
${this._zhaDevice.rssi ||
|
||||
this.hass!.localize("ui.dialogs.zha_device_info.unknown")}
|
||||
</div>
|
||||
<div>
|
||||
${this.hass!.localize("ui.dialogs.zha_device_info.last_seen")}:
|
||||
${this._zhaDevice.last_seen ||
|
||||
this.hass!.localize("ui.dialogs.zha_device_info.unknown")}
|
||||
</div>
|
||||
<div>
|
||||
${this.hass!.localize("ui.dialogs.zha_device_info.power_source")}:
|
||||
${this._zhaDevice.power_source ||
|
||||
this.hass!.localize("ui.dialogs.zha_device_info.unknown")}
|
||||
</div>
|
||||
${this._zhaDevice.quirk_applied
|
||||
? html`
|
||||
<div>
|
||||
${this.hass!.localize("ui.dialogs.zha_device_info.quirk")}:
|
||||
${this._zhaDevice.quirk_class}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
h4 {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
div {
|
||||
word-break: break-all;
|
||||
margin-top: 2px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import {
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import memoizeOne from "memoize-one";
|
||||
@ -38,13 +39,12 @@ import "../../../layouts/hass-tabs-subpage";
|
||||
import { HomeAssistant, Route } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import "./device-detail/ha-device-card-mqtt";
|
||||
import "./device-detail/ha-device-entities-card";
|
||||
import "./device-detail/ha-device-info-card";
|
||||
import { showDeviceAutomationDialog } from "./device-detail/show-dialog-device-automation";
|
||||
|
||||
export interface EntityRegistryStateEntry extends EntityRegistryEntry {
|
||||
stateName?: string;
|
||||
stateName?: string | null;
|
||||
}
|
||||
|
||||
@customElement("ha-config-device-page")
|
||||
@ -226,16 +226,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
.devices=${this.devices}
|
||||
.device=${device}
|
||||
>
|
||||
${
|
||||
integrations.includes("mqtt")
|
||||
? html`
|
||||
<ha-device-card-mqtt
|
||||
.hass=${this.hass}
|
||||
.device=${device}
|
||||
></ha-device-card-mqtt>
|
||||
`
|
||||
: html``
|
||||
}
|
||||
${this._renderIntegrationInfo(device, integrations)}
|
||||
</ha-device-info-card>
|
||||
|
||||
${
|
||||
@ -439,7 +430,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
</hass-tabs-subpage> `;
|
||||
}
|
||||
|
||||
private _computeEntityName(entity) {
|
||||
private _computeEntityName(entity: EntityRegistryEntry) {
|
||||
if (entity.name) {
|
||||
return entity.name;
|
||||
}
|
||||
@ -480,6 +471,41 @@ export class HaConfigDevicePage extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _renderIntegrationInfo(
|
||||
device,
|
||||
integrations: string[]
|
||||
): TemplateResult[] {
|
||||
const templates: TemplateResult[] = [];
|
||||
if (integrations.includes("mqtt")) {
|
||||
import("./device-detail/integration-elements/ha-device-actions-mqtt");
|
||||
templates.push(html`
|
||||
<div class="card-actions" slot="actions">
|
||||
<ha-device-actions-mqtt
|
||||
.hass=${this.hass}
|
||||
.device=${device}
|
||||
></ha-device-actions-mqtt>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
if (integrations.includes("zha")) {
|
||||
import("./device-detail/integration-elements/ha-device-actions-zha");
|
||||
import("./device-detail/integration-elements/ha-device-info-zha");
|
||||
templates.push(html`
|
||||
<ha-device-info-zha
|
||||
.hass=${this.hass}
|
||||
.device=${device}
|
||||
></ha-device-info-zha>
|
||||
<div class="card-actions" slot="actions">
|
||||
<ha-device-actions-zha
|
||||
.hass=${this.hass}
|
||||
.device=${device}
|
||||
></ha-device-actions-zha>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
return templates;
|
||||
}
|
||||
|
||||
private async _showSettings() {
|
||||
const device = this._device(this.deviceId, this.devices)!;
|
||||
showDeviceRegistryDetailDialog(this, {
|
||||
|
@ -163,20 +163,6 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
||||
advancedOnly: true,
|
||||
},
|
||||
],
|
||||
other: [
|
||||
{
|
||||
component: "zha",
|
||||
path: "/config/zha",
|
||||
translationKey: "component.zha.title",
|
||||
icon: "hass:zigbee",
|
||||
},
|
||||
{
|
||||
component: "zwave",
|
||||
path: "/config/zwave",
|
||||
translationKey: "component.zwave.title",
|
||||
icon: "hass:z-wave",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@customElement("ha-panel-config")
|
||||
@ -327,14 +313,14 @@ class HaPanelConfig extends HassRouterPage {
|
||||
tag: "zha-config-dashboard-router",
|
||||
load: () =>
|
||||
import(
|
||||
/* webpackChunkName: "panel-config-zha" */ "./zha/zha-config-dashboard-router"
|
||||
/* webpackChunkName: "panel-config-zha" */ "./integrations/integration-panels/zha/zha-config-dashboard-router"
|
||||
),
|
||||
},
|
||||
zwave: {
|
||||
tag: "ha-config-zwave",
|
||||
load: () =>
|
||||
import(
|
||||
/* webpackChunkName: "panel-config-zwave" */ "./zwave/ha-config-zwave"
|
||||
/* webpackChunkName: "panel-config-zwave" */ "./integrations/integration-panels/zwave/ha-config-zwave"
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -45,6 +45,17 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
const integrationsWithPanel = {
|
||||
zha: {
|
||||
buttonLocalizeKey: "ui.panel.config.zha.button",
|
||||
path: "/config/zha/dashboard",
|
||||
},
|
||||
zwave: {
|
||||
buttonLocalizeKey: "ui.panel.config.zwave.button",
|
||||
path: "/config/zwave",
|
||||
},
|
||||
};
|
||||
|
||||
@customElement("ha-integration-card")
|
||||
export class HaIntegrationCard extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@ -180,13 +191,24 @@ export class HaIntegrationCard extends LitElement {
|
||||
"ui.panel.config.integrations.config_entry.rename"
|
||||
)}</mwc-button
|
||||
>
|
||||
${item.supports_options
|
||||
${item.domain in integrationsWithPanel
|
||||
? html`<a
|
||||
href=${`${
|
||||
integrationsWithPanel[item.domain].path
|
||||
}?config_entry=${item.entry_id}`}
|
||||
><mwc-button>
|
||||
${this.hass.localize(
|
||||
integrationsWithPanel[item.domain].buttonLocalizeKey
|
||||
)}
|
||||
</mwc-button></a
|
||||
>`
|
||||
: item.supports_options
|
||||
? html`
|
||||
<mwc-button @click=${this._showOptions}
|
||||
>${this.hass.localize(
|
||||
<mwc-button @click=${this._showOptions}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.options"
|
||||
)}</mwc-button
|
||||
>
|
||||
)}
|
||||
</mwc-button>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Cluster, ZHADevice, ZHAGroup } from "../../../data/zha";
|
||||
import { Cluster, ZHADevice, ZHAGroup } from "../../../../../data/zha";
|
||||
|
||||
export const formatAsPaddedHex = (value: string | number): string => {
|
||||
let hex = value;
|
||||
@ -8,6 +8,9 @@ export const formatAsPaddedHex = (value: string | number): string => {
|
||||
return "0x" + hex.toString(16).padStart(4, "0");
|
||||
};
|
||||
|
||||
export const getIeeeTail = (ieee: string) =>
|
||||
ieee.split(":").slice(-4).reverse().join("");
|
||||
|
||||
export const sortZHADevices = (a: ZHADevice, b: ZHADevice): number => {
|
||||
const nameA = a.user_given_name ? a.user_given_name : a.name;
|
||||
const nameb = b.user_given_name ? b.user_given_name : b.name;
|
@ -1,4 +1,4 @@
|
||||
import { Cluster, ZHADevice } from "../../../data/zha";
|
||||
import { Cluster, ZHADevice } from "../../../../../data/zha";
|
||||
|
||||
export interface PickerTarget extends EventTarget {
|
||||
selected: number;
|
@ -1,5 +1,5 @@
|
||||
import "@material/mwc-button";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
import {
|
||||
css,
|
||||
@ -9,19 +9,24 @@ import {
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../../../components/ha-textarea";
|
||||
import { ZHADevice } from "../../../data/zha";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant, Route } from "../../../types";
|
||||
import "../../../../../components/ha-service-description";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { ZHADevice } from "../../../../../data/zha";
|
||||
import "../../../../../layouts/hass-tabs-subpage";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant, Route } from "../../../../../types";
|
||||
import "./zha-device-card";
|
||||
import { zhaTabs } from "./zha-config-dashboard";
|
||||
import { IronAutogrowTextareaElement } from "@polymer/iron-autogrow-textarea";
|
||||
|
||||
@customElement("zha-add-devices-page")
|
||||
class ZHAAddDevicesPage extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
|
||||
@property() public narrow?: boolean;
|
||||
|
||||
@property() public isWide?: boolean;
|
||||
|
||||
@property() public route?: Route;
|
||||
@ -36,6 +41,8 @@ class ZHAAddDevicesPage extends LitElement {
|
||||
|
||||
@property() private _showHelp = false;
|
||||
|
||||
@property() private _showLogs = false;
|
||||
|
||||
private _ieeeAddress?: string;
|
||||
|
||||
private _addDevicesTimeoutHandle: any = undefined;
|
||||
@ -60,58 +67,63 @@ class ZHAAddDevicesPage extends LitElement {
|
||||
this._formattedEvents = "";
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
if (
|
||||
changedProps.has("hass") &&
|
||||
!this._active &&
|
||||
!changedProps.get("hass")
|
||||
) {
|
||||
this._subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<hass-subpage
|
||||
header="${this.hass!.localize(
|
||||
"ui.panel.config.zha.add_device_page.header"
|
||||
)}"
|
||||
<hass-tabs-subpage
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.route=${this.route}
|
||||
.tabs=${zhaTabs}
|
||||
>
|
||||
${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">
|
||||
<mwc-button slot="toolbar-icon" @click=${this._toggleLogs}
|
||||
>${this._showLogs ? "Hide logs" : "Show logs"}</mwc-button
|
||||
>
|
||||
<div class="searching">
|
||||
${this._active
|
||||
? html`
|
||||
<h1>
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.add_device_page.search_again"
|
||||
"ui.panel.config.zha.add_device_page.spinner"
|
||||
)}
|
||||
</mwc-button>
|
||||
<ha-icon-button
|
||||
class="toggle-help-icon"
|
||||
@click="${this._onHelpTap}"
|
||||
icon="hass:help-circle"
|
||||
></ha-icon-button>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass=${this.hass}
|
||||
domain="zha"
|
||||
service="permit"
|
||||
class="help-text"
|
||||
></ha-service-description>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`}
|
||||
</h1>
|
||||
<paper-spinner active alt="Searching"></paper-spinner>
|
||||
`
|
||||
: html`
|
||||
<div>
|
||||
<mwc-button @click=${this._subscribe} class="search-button">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.add_device_page.search_again"
|
||||
)}
|
||||
</mwc-button>
|
||||
</div>
|
||||
`}
|
||||
</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"
|
||||
"ui.panel.config.zha.add_device_page.pairing_mode"
|
||||
)}
|
||||
</h4>
|
||||
<h4>
|
||||
${this.hass!.localize(
|
||||
this._active
|
||||
? "ui.panel.config.zha.add_device_page.discovered_text"
|
||||
: "ui.panel.config.zha.add_device_page.no_devices_found"
|
||||
)}
|
||||
</h4>
|
||||
</div>
|
||||
@ -123,27 +135,38 @@ class ZHAAddDevicesPage extends LitElement {
|
||||
class="card"
|
||||
.hass=${this.hass}
|
||||
.device=${device}
|
||||
.narrow=${!this.isWide}
|
||||
.narrow=${this.narrow}
|
||||
.showHelp=${this._showHelp}
|
||||
.showActions=${!this._active}
|
||||
.showEntityDetail=${false}
|
||||
></zha-device-card>
|
||||
`
|
||||
)}
|
||||
`}
|
||||
</div>
|
||||
<ha-textarea class="events" value="${this._formattedEvents}">
|
||||
</ha-textarea>
|
||||
</hass-subpage>
|
||||
${this._showLogs
|
||||
? html`<paper-textarea
|
||||
readonly
|
||||
max-rows="10"
|
||||
class="log"
|
||||
value="${this._formattedEvents}"
|
||||
>
|
||||
</paper-textarea>`
|
||||
: ""}
|
||||
</hass-tabs-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
private _toggleLogs() {
|
||||
this._showLogs = !this._showLogs;
|
||||
}
|
||||
|
||||
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) {
|
||||
const paperTextArea = this.shadowRoot.querySelector("paper-textarea");
|
||||
if (paperTextArea) {
|
||||
const textArea = (paperTextArea.inputElement as IronAutogrowTextareaElement)
|
||||
.textarea;
|
||||
textArea.scrollTop = textArea.scrollHeight;
|
||||
}
|
||||
}
|
||||
@ -165,69 +188,58 @@ class ZHAAddDevicesPage extends LitElement {
|
||||
}
|
||||
|
||||
private _subscribe(): void {
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
this._active = true;
|
||||
const data: any = { type: "zha/devices/permit" };
|
||||
if (this._ieeeAddress) {
|
||||
data.ieee = this._ieeeAddress;
|
||||
}
|
||||
this._subscribed = this.hass!.connection.subscribeMessage(
|
||||
this._subscribed = this.hass.connection.subscribeMessage(
|
||||
(message) => this._handleMessage(message),
|
||||
data
|
||||
);
|
||||
this._active = true;
|
||||
this._addDevicesTimeoutHandle = setTimeout(
|
||||
() => this._unsubscribe(),
|
||||
120000
|
||||
);
|
||||
}
|
||||
|
||||
private _onHelpTap(): void {
|
||||
this._showHelp = !this._showHelp;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.discovery-text,
|
||||
.content-header {
|
||||
margin: 16px;
|
||||
.discovery-text {
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.content {
|
||||
border-top: 1px solid var(--light-primary-color);
|
||||
min-height: 500px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px;
|
||||
justify-content: left;
|
||||
overflow: scroll;
|
||||
justify-content: center;
|
||||
}
|
||||
.error {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
paper-spinner {
|
||||
display: none;
|
||||
margin-right: 20px;
|
||||
margin-left: 16px;
|
||||
padding: 20px;
|
||||
}
|
||||
paper-spinner[active] {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 20px;
|
||||
margin-left: 16px;
|
||||
.searching {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.card {
|
||||
margin-left: 16px;
|
||||
margin-right: 16px;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 10px;
|
||||
margin: 8px;
|
||||
}
|
||||
.events {
|
||||
margin: 16px;
|
||||
border-top: 1px solid var(--light-primary-color);
|
||||
padding-top: 16px;
|
||||
min-height: 200px;
|
||||
max-height: 200px;
|
||||
overflow: scroll;
|
||||
.log {
|
||||
padding: 16px;
|
||||
}
|
||||
.toggle-help-icon {
|
||||
position: absolute;
|
@ -12,20 +12,20 @@ import {
|
||||
PropertyValues,
|
||||
query,
|
||||
} from "lit-element";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import type { SelectionChangedEvent } from "../../../components/data-table/ha-data-table";
|
||||
import type { HASSDomEvent } from "../../../../../common/dom/fire_event";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
import type { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table";
|
||||
import {
|
||||
addGroup,
|
||||
fetchGroupableDevices,
|
||||
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";
|
||||
} 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-device-endpoint-data-table";
|
||||
import type { ZHADeviceEndpointDataTable } from "./zha-device-endpoint-data-table";
|
||||
|
@ -1,6 +1,6 @@
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
@ -13,9 +13,9 @@ import {
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-service-description";
|
||||
import {
|
||||
Attribute,
|
||||
Cluster,
|
||||
@ -23,10 +23,10 @@ import {
|
||||
ReadAttributeServiceData,
|
||||
readAttributeValue,
|
||||
ZHADevice,
|
||||
} from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
} from "../../../../../data/zha";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import "../../../ha-config-section";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
import {
|
||||
ChangeEvent,
|
@ -1,5 +1,5 @@
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
@ -12,18 +12,18 @@ import {
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-service-description";
|
||||
import {
|
||||
Cluster,
|
||||
Command,
|
||||
fetchCommandsForCluster,
|
||||
ZHADevice,
|
||||
} from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
} from "../../../../../data/zha";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import "../../../ha-config-section";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
import {
|
||||
ChangeEvent,
|
@ -7,14 +7,14 @@ import {
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import memoizeOne from "memoize-one";
|
||||
import "../../../components/data-table/ha-data-table";
|
||||
import "../../../../../components/data-table/ha-data-table";
|
||||
import type {
|
||||
DataTableColumnContainer,
|
||||
HaDataTable,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/entity/ha-state-icon";
|
||||
import type { Cluster } from "../../../data/zha";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
} from "../../../../../components/data-table/ha-data-table";
|
||||
import "../../../../../components/entity/ha-state-icon";
|
||||
import type { Cluster } from "../../../../../data/zha";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
|
||||
export interface ClusterRowData extends Cluster {
|
@ -1,5 +1,5 @@
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import {
|
||||
@ -11,14 +11,18 @@ import {
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-service-description";
|
||||
import { Cluster, fetchClustersForZhaNode, ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-service-description";
|
||||
import {
|
||||
Cluster,
|
||||
fetchClustersForZhaNode,
|
||||
ZHADevice,
|
||||
} from "../../../../../data/zha";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import "../../../ha-config-section";
|
||||
import { computeClusterKey } from "./functions";
|
||||
import { ItemSelectedEvent } from "./types";
|
||||
|
@ -2,8 +2,9 @@ import { customElement, property } from "lit-element";
|
||||
import {
|
||||
HassRouterPage,
|
||||
RouterOptions,
|
||||
} from "../../../layouts/hass-router-page";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
} from "../../../../../layouts/hass-router-page";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
|
||||
@customElement("zha-config-dashboard-router")
|
||||
class ZHAConfigDashboardRouter extends HassRouterPage {
|
||||
@ -13,6 +14,10 @@ class ZHAConfigDashboardRouter extends HassRouterPage {
|
||||
|
||||
@property() public narrow!: boolean;
|
||||
|
||||
private _configEntry = new URLSearchParams(window.location.search).get(
|
||||
"config_entry"
|
||||
);
|
||||
|
||||
protected routerOptions: RouterOptions = {
|
||||
defaultPage: "dashboard",
|
||||
showLoading: true,
|
||||
@ -24,13 +29,6 @@ class ZHAConfigDashboardRouter extends HassRouterPage {
|
||||
/* webpackChunkName: "zha-config-dashboard" */ "./zha-config-dashboard"
|
||||
),
|
||||
},
|
||||
device: {
|
||||
tag: "zha-device-page",
|
||||
load: () =>
|
||||
import(
|
||||
/* webpackChunkName: "zha-devices-page" */ "./zha-device-page"
|
||||
),
|
||||
},
|
||||
add: {
|
||||
tag: "zha-add-devices-page",
|
||||
load: () =>
|
||||
@ -65,11 +63,24 @@ class ZHAConfigDashboardRouter extends HassRouterPage {
|
||||
el.hass = this.hass;
|
||||
el.isWide = this.isWide;
|
||||
el.narrow = this.narrow;
|
||||
el.configEntryId = this._configEntry;
|
||||
if (this._currentPage === "group") {
|
||||
el.groupId = this.routeTail.path.substr(1);
|
||||
} else if (this._currentPage === "device") {
|
||||
el.ieee = this.routeTail.path.substr(1);
|
||||
}
|
||||
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
if (this._configEntry && !searchParams.has("config_entry")) {
|
||||
searchParams.append("config_entry", this._configEntry);
|
||||
navigate(
|
||||
this,
|
||||
`${this.routeTail.prefix}${
|
||||
this.routeTail.path
|
||||
}?${searchParams.toString()}`,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,132 @@
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import "@material/mwc-fab";
|
||||
import {
|
||||
css,
|
||||
CSSResultArray,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-icon-next";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../../../../types";
|
||||
import "../../../ha-config-section";
|
||||
import { mdiNetwork, mdiFolderMultipleOutline, mdiPlus } from "@mdi/js";
|
||||
import "../../../../../layouts/hass-tabs-subpage";
|
||||
import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage";
|
||||
import { computeRTL } from "../../../../../common/util/compute_rtl";
|
||||
|
||||
export const zhaTabs: PageNavigation[] = [
|
||||
{
|
||||
translationKey: "ui.panel.config.zha.network.caption",
|
||||
path: `/config/zha/dashboard`,
|
||||
iconPath: mdiNetwork,
|
||||
},
|
||||
{
|
||||
translationKey: "ui.panel.config.zha.groups.caption",
|
||||
path: `/config/zha/groups`,
|
||||
iconPath: mdiFolderMultipleOutline,
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("zha-config-dashboard")
|
||||
class ZHAConfigDashboard extends LitElement {
|
||||
@property({ type: Object }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Object }) public route!: Route;
|
||||
|
||||
@property({ type: Boolean }) public narrow!: boolean;
|
||||
|
||||
@property({ type: Boolean }) public isWide!: boolean;
|
||||
|
||||
@property() public configEntryId?: string;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<hass-tabs-subpage
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.route=${this.route}
|
||||
.tabs=${zhaTabs}
|
||||
back-path="/config/integrations"
|
||||
>
|
||||
<ha-card header="Zigbee Network">
|
||||
<div class="card-content">
|
||||
Network info/settings for specific config entry
|
||||
</div>
|
||||
${this.configEntryId
|
||||
? html`<div class="card-actions">
|
||||
<a
|
||||
href="${`/config/devices/dashboard?historyBack=1&config_entry=${this.configEntryId}`}"
|
||||
>
|
||||
<mwc-button>Devices</mwc-button>
|
||||
</a>
|
||||
<a
|
||||
href="${`/config/entities/dashboard?historyBack=1&config_entry=${this.configEntryId}`}"
|
||||
>
|
||||
<mwc-button>Entities</mwc-button>
|
||||
</a>
|
||||
</div>`
|
||||
: ""}
|
||||
</ha-card>
|
||||
<a href="/config/zha/add">
|
||||
<mwc-fab
|
||||
?is-wide=${this.isWide}
|
||||
?narrow=${this.narrow}
|
||||
title=${this.hass.localize("ui.panel.config.zha.add_device")}
|
||||
?rtl=${computeRTL(this.hass)}
|
||||
>
|
||||
<ha-svg-icon slot="icon" path=${mdiPlus}></ha-svg-icon>
|
||||
</mwc-fab>
|
||||
</a>
|
||||
</hass-tabs-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultArray {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
ha-card {
|
||||
margin: auto;
|
||||
margin-top: 16px;
|
||||
max-width: 500px;
|
||||
}
|
||||
mwc-fab {
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
mwc-fab[is-wide] {
|
||||
bottom: 24px;
|
||||
right: 24px;
|
||||
}
|
||||
mwc-fab[narrow] {
|
||||
bottom: 84px;
|
||||
}
|
||||
mwc-fab[rtl] {
|
||||
right: auto;
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
mwc-fab[rtl][is-wide] {
|
||||
bottom: 24px;
|
||||
right: auto;
|
||||
left: 24px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-config-dashboard": ZHAConfigDashboard;
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import {
|
||||
@ -13,13 +13,13 @@ import {
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-service-description";
|
||||
import { bindDevices, unbindDevices, ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-service-description";
|
||||
import { bindDevices, unbindDevices, ZHADevice } from "../../../../../data/zha";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import "../../../ha-config-section";
|
||||
import { ItemSelectedEvent } from "./types";
|
||||
|
||||
@customElement("zha-device-binding-control")
|
@ -0,0 +1,243 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { computeStateName } from "../../../../../common/entity/compute_state_name";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import "../../../../../components/entity/state-badge";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-service-description";
|
||||
import { updateDeviceRegistryEntry } from "../../../../../data/device_registry";
|
||||
import { ZHADevice } from "../../../../../data/zha";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import "../../../../../components/ha-area-picker";
|
||||
import { showAlertDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
||||
import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin";
|
||||
import {
|
||||
subscribeEntityRegistry,
|
||||
EntityRegistryEntry,
|
||||
updateEntityRegistryEntry,
|
||||
} from "../../../../../data/entity_registry";
|
||||
import { createValidEntityId } from "../../../../../common/entity/valid_entity_id";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { EntityRegistryStateEntry } from "../../../devices/ha-config-device-page";
|
||||
import { compare } from "../../../../../common/string/compare";
|
||||
import { getIeeeTail } from "./functions";
|
||||
|
||||
@customElement("zha-device-card")
|
||||
class ZHADeviceCard extends SubscribeMixin(LitElement) {
|
||||
@property() public hass!: HomeAssistant;
|
||||
|
||||
@property() public device?: ZHADevice;
|
||||
|
||||
@property({ type: Boolean }) public narrow?: boolean;
|
||||
|
||||
@property() private _entities: EntityRegistryEntry[] = [];
|
||||
|
||||
private _deviceEntities = memoizeOne(
|
||||
(
|
||||
deviceId: string,
|
||||
entities: EntityRegistryEntry[]
|
||||
): EntityRegistryStateEntry[] =>
|
||||
entities
|
||||
.filter((entity) => entity.device_id === deviceId)
|
||||
.map((entity) => {
|
||||
return { ...entity, stateName: this._computeEntityName(entity) };
|
||||
})
|
||||
.sort((ent1, ent2) =>
|
||||
compare(
|
||||
ent1.stateName || `zzz${ent1.entity_id}`,
|
||||
ent2.stateName || `zzz${ent2.entity_id}`
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public hassSubscribe(): UnsubscribeFunc[] {
|
||||
return [
|
||||
subscribeEntityRegistry(this.hass.connection, (entities) => {
|
||||
this._entities = entities;
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass || !this.device) {
|
||||
return html``;
|
||||
}
|
||||
const entities = this._deviceEntities(
|
||||
this.device.device_reg_id,
|
||||
this._entities
|
||||
);
|
||||
|
||||
return html`
|
||||
<ha-card .header=${this.device.user_given_name || this.device.name}>
|
||||
<div class="card-content">
|
||||
<div class="info">
|
||||
<div class="model">${this.device.model}</div>
|
||||
<div class="manuf">
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.zha_device_info.manuf",
|
||||
"manufacturer",
|
||||
this.device.manufacturer
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="device-entities">
|
||||
${entities.map(
|
||||
(entity) => html`
|
||||
<state-badge
|
||||
@click="${this._openMoreInfo}"
|
||||
.title=${entity.stateName!}
|
||||
.stateObj="${this.hass!.states[entity.entity_id]}"
|
||||
slot="item-icon"
|
||||
></state-badge>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
<paper-input
|
||||
type="string"
|
||||
@change=${this._rename}
|
||||
.value=${this.device.user_given_name || this.device.name}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.zha_device_info.zha_device_card.device_name_placeholder"
|
||||
)}
|
||||
></paper-input>
|
||||
<ha-area-picker
|
||||
.hass=${this.hass}
|
||||
.device=${this.device.device_reg_id}
|
||||
@value-changed=${this._areaPicked}
|
||||
></ha-area-picker>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _rename(event): Promise<void> {
|
||||
if (!this.hass || !this.device) {
|
||||
return;
|
||||
}
|
||||
const device = this.device;
|
||||
|
||||
const oldDeviceName = device.user_given_name || device.name;
|
||||
const newDeviceName = event.target.value;
|
||||
this.device.user_given_name = newDeviceName;
|
||||
await updateDeviceRegistryEntry(this.hass, device.device_reg_id, {
|
||||
name_by_user: newDeviceName,
|
||||
});
|
||||
|
||||
if (!oldDeviceName || !newDeviceName || oldDeviceName === newDeviceName) {
|
||||
return;
|
||||
}
|
||||
const entities = this._deviceEntities(device.device_reg_id, this._entities);
|
||||
|
||||
const oldDeviceEntityId = createValidEntityId(oldDeviceName);
|
||||
const newDeviceEntityId = createValidEntityId(newDeviceName);
|
||||
const ieeeTail = getIeeeTail(device.ieee);
|
||||
|
||||
const updateProms = entities.map((entity) => {
|
||||
const name = entity.name || entity.stateName;
|
||||
let newEntityId: string | null = null;
|
||||
let newName: string | null = null;
|
||||
|
||||
if (name && name.includes(oldDeviceName)) {
|
||||
newName = name.replace(` ${ieeeTail}`, "");
|
||||
newName = newName.replace(oldDeviceName, newDeviceName);
|
||||
newEntityId = entity.entity_id.replace(`_${ieeeTail}`, "");
|
||||
newEntityId = newEntityId.replace(oldDeviceEntityId, newDeviceEntityId);
|
||||
}
|
||||
|
||||
if (!newName && !newEntityId) {
|
||||
return new Promise((resolve) => resolve());
|
||||
}
|
||||
|
||||
return updateEntityRegistryEntry(this.hass!, entity.entity_id, {
|
||||
name: newName || name,
|
||||
disabled_by: entity.disabled_by,
|
||||
new_entity_id: newEntityId || entity.entity_id,
|
||||
});
|
||||
});
|
||||
await Promise.all(updateProms);
|
||||
}
|
||||
|
||||
private _openMoreInfo(ev: MouseEvent): void {
|
||||
fireEvent(this, "hass-more-info", {
|
||||
entityId: (ev.currentTarget as any).stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _computeEntityName(entity: EntityRegistryEntry): string {
|
||||
if (this.hass.states[entity.entity_id]) {
|
||||
return computeStateName(this.hass.states[entity.entity_id]);
|
||||
}
|
||||
return entity.name;
|
||||
}
|
||||
|
||||
private async _areaPicked(ev: CustomEvent) {
|
||||
const picker = ev.currentTarget as any;
|
||||
|
||||
const area = ev.detail.value;
|
||||
try {
|
||||
await updateDeviceRegistryEntry(this.hass, this.device!.device_reg_id, {
|
||||
area_id: area,
|
||||
});
|
||||
this.device!.area_id = area;
|
||||
} catch (err) {
|
||||
showAlertDialog(this, {
|
||||
text: this.hass.localize(
|
||||
"ui.panel.config.integrations.config_flow.error_saving_area",
|
||||
"error",
|
||||
err.message
|
||||
),
|
||||
});
|
||||
picker.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.device-entities {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px;
|
||||
justify-content: left;
|
||||
min-height: 48px;
|
||||
}
|
||||
.device {
|
||||
width: 30%;
|
||||
}
|
||||
.device .name {
|
||||
font-weight: bold;
|
||||
}
|
||||
.device .manuf {
|
||||
color: var(--secondary-text-color);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.extra-info {
|
||||
margin-top: 8px;
|
||||
}
|
||||
state-badge {
|
||||
cursor: pointer;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-device-card": ZHADeviceCard;
|
||||
}
|
||||
}
|
@ -9,16 +9,18 @@ import {
|
||||
CSSResult,
|
||||
} from "lit-element";
|
||||
import memoizeOne from "memoize-one";
|
||||
import "../../../components/data-table/ha-data-table";
|
||||
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";
|
||||
} from "../../../../../components/data-table/ha-data-table";
|
||||
import "../../../../../components/entity/ha-state-icon";
|
||||
import type {
|
||||
ZHADeviceEndpoint,
|
||||
ZHAEntityReference,
|
||||
} from "../../../../../data/zha";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
|
||||
export interface DeviceEndpointRowData extends DataTableRowData {
|
||||
id: string;
|
||||
@ -55,6 +57,7 @@ export class ZHADeviceEndpointDataTable extends LitElement {
|
||||
ieee: deviceEndpoint.device.ieee,
|
||||
endpoint_id: deviceEndpoint.endpoint_id,
|
||||
entities: deviceEndpoint.entities,
|
||||
dev_id: deviceEndpoint.device.device_reg_id,
|
||||
});
|
||||
});
|
||||
|
||||
@ -72,14 +75,10 @@ export class ZHADeviceEndpointDataTable extends LitElement {
|
||||
filterable: true,
|
||||
direction: "asc",
|
||||
grows: true,
|
||||
template: (name) => html`
|
||||
<div
|
||||
class="mdc-data-table__cell table-cell-text"
|
||||
@click=${this._handleClicked}
|
||||
style="cursor: pointer;"
|
||||
>
|
||||
template: (name, device: any) => html`
|
||||
<a href="${`/config/devices/device/${device.dev_id}`}">
|
||||
${name}
|
||||
</div>
|
||||
</a>
|
||||
`,
|
||||
},
|
||||
endpoint_id: {
|
||||
@ -95,14 +94,10 @@ export class ZHADeviceEndpointDataTable extends LitElement {
|
||||
filterable: true,
|
||||
direction: "asc",
|
||||
grows: true,
|
||||
template: (name) => html`
|
||||
<div
|
||||
class="mdc-data-table__cell table-cell-text"
|
||||
@click=${this._handleClicked}
|
||||
style="cursor: pointer;"
|
||||
>
|
||||
template: (name, device: any) => html`
|
||||
<a href="${`/config/devices/device/${device.dev_id}`}">
|
||||
${name}
|
||||
</div>
|
||||
</a>
|
||||
`,
|
||||
},
|
||||
endpoint_id: {
|
||||
@ -156,14 +151,6 @@ export class ZHADeviceEndpointDataTable extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
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`
|
@ -1,6 +1,6 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import {
|
||||
@ -14,11 +14,11 @@ import {
|
||||
query,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import { SelectionChangedEvent } from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-service-description";
|
||||
import type { HASSDomEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-service-description";
|
||||
import {
|
||||
bindDeviceToGroup,
|
||||
Cluster,
|
||||
@ -26,10 +26,10 @@ import {
|
||||
unbindDeviceFromGroup,
|
||||
ZHADevice,
|
||||
ZHAGroup,
|
||||
} from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
} from "../../../../../data/zha";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import "../../../ha-config-section";
|
||||
import { ItemSelectedEvent } from "./types";
|
||||
import "./zha-clusters-data-table";
|
||||
import type { ZHAClustersDataTable } from "./zha-clusters-data-table";
|
@ -1,5 +1,5 @@
|
||||
import "@material/mwc-button";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
import {
|
||||
css,
|
||||
@ -11,9 +11,9 @@ import {
|
||||
PropertyValues,
|
||||
query,
|
||||
} from "lit-element";
|
||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { SelectionChangedEvent } from "../../../components/data-table/ha-data-table";
|
||||
import { HASSDomEvent } from "../../../../../common/dom/fire_event";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
import { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table";
|
||||
import {
|
||||
addMembersToGroup,
|
||||
fetchGroup,
|
||||
@ -22,13 +22,12 @@ import {
|
||||
removeMembersFromGroup,
|
||||
ZHAGroup,
|
||||
ZHADeviceEndpoint,
|
||||
} from "../../../data/zha";
|
||||
import "../../../layouts/hass-error-screen";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
} from "../../../../../data/zha";
|
||||
import "../../../../../layouts/hass-error-screen";
|
||||
import "../../../../../layouts/hass-subpage";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import "../../../ha-config-section";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
import "./zha-device-card";
|
||||
import "./zha-device-endpoint-data-table";
|
||||
import type { ZHADeviceEndpointDataTable } from "./zha-device-endpoint-data-table";
|
||||
|
||||
@ -122,25 +121,26 @@ export class ZHAGroupPage extends LitElement {
|
||||
<div class="header">
|
||||
${this.hass.localize("ui.panel.config.zha.groups.members")}
|
||||
</div>
|
||||
|
||||
${this.group.members.length
|
||||
? this.group.members.map(
|
||||
(member) => html`
|
||||
<zha-device-card
|
||||
class="card"
|
||||
.hass=${this.hass}
|
||||
.device=${member.device}
|
||||
.narrow=${this.narrow}
|
||||
.showActions=${false}
|
||||
.showEditableInfo=${false}
|
||||
></zha-device-card>
|
||||
`
|
||||
)
|
||||
: html`
|
||||
<p>
|
||||
This group has no members
|
||||
</p>
|
||||
`}
|
||||
<ha-card>
|
||||
${this.group.members.length
|
||||
? this.group.members.map(
|
||||
(member) =>
|
||||
html`<a
|
||||
href="/config/devices/device/${member.device
|
||||
.device_reg_id}"
|
||||
>
|
||||
<paper-item
|
||||
>${member.device.user_given_name ||
|
||||
member.device.name}</paper-item
|
||||
>
|
||||
</a>`
|
||||
)
|
||||
: html`
|
||||
<paper-item>
|
||||
This group has no members
|
||||
</paper-item>
|
||||
`}
|
||||
</ha-card>
|
||||
${this.group.members.length
|
||||
? html`
|
||||
<div class="header">
|
||||
@ -285,6 +285,9 @@ export class ZHAGroupPage extends LitElement {
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
css`
|
||||
hass-subpage {
|
||||
--app-header-text-color: var(--sidebar-icon-color);
|
||||
}
|
||||
.header {
|
||||
font-family: var(--paper-font-display1_-_font-family);
|
||||
-webkit-font-smoothing: var(
|
||||
@ -297,14 +300,15 @@ export class ZHAGroupPage extends LitElement {
|
||||
opacity: var(--dark-primary-opacity);
|
||||
}
|
||||
|
||||
ha-config-section *:last-child {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
mwc-button paper-spinner {
|
||||
width: 14px;
|
||||
height: 14px;
|
@ -0,0 +1,193 @@
|
||||
import "@material/mwc-button";
|
||||
import "@material/mwc-fab";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import memoizeOne from "memoize-one";
|
||||
import {
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResultArray,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import { HASSDomEvent } from "../../../../../common/dom/fire_event";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
import {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
} from "../../../../../components/data-table/ha-data-table";
|
||||
import { fetchGroups, ZHAGroup, ZHADevice } from "../../../../../data/zha";
|
||||
import "../../../../../layouts/hass-tabs-subpage-data-table";
|
||||
import { HomeAssistant, Route } from "../../../../../types";
|
||||
import { sortZHAGroups, formatAsPaddedHex } from "./functions";
|
||||
import { zhaTabs } from "./zha-config-dashboard";
|
||||
import { computeRTL } from "../../../../../common/util/compute_rtl";
|
||||
import { mdiPlus } from "@mdi/js";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
|
||||
export interface GroupRowData extends ZHAGroup {
|
||||
group?: GroupRowData;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
@customElement("zha-groups-dashboard")
|
||||
export class ZHAGroupsDashboard extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Object }) public route!: Route;
|
||||
|
||||
@property({ type: Boolean }) public narrow!: boolean;
|
||||
|
||||
@property({ type: Boolean }) public isWide!: boolean;
|
||||
|
||||
@property() public _groups: ZHAGroup[] = [];
|
||||
|
||||
private _firstUpdatedCalled = false;
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
if (this.hass && this._firstUpdatedCalled) {
|
||||
this._fetchGroups();
|
||||
}
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProperties: PropertyValues): void {
|
||||
super.firstUpdated(changedProperties);
|
||||
if (this.hass) {
|
||||
this._fetchGroups();
|
||||
}
|
||||
this._firstUpdatedCalled = true;
|
||||
}
|
||||
|
||||
private _formattedGroups = memoizeOne((groups: ZHAGroup[]) => {
|
||||
let outputGroups: GroupRowData[] = groups;
|
||||
|
||||
outputGroups = outputGroups.map((group) => {
|
||||
return {
|
||||
...group,
|
||||
id: String(group.group_id),
|
||||
};
|
||||
});
|
||||
|
||||
return outputGroups;
|
||||
});
|
||||
|
||||
private _columns = memoizeOne(
|
||||
(narrow: boolean): DataTableColumnContainer =>
|
||||
narrow
|
||||
? {
|
||||
name: {
|
||||
title: "Group",
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
direction: "asc",
|
||||
grows: true,
|
||||
},
|
||||
}
|
||||
: {
|
||||
name: {
|
||||
title: this.hass.localize("ui.panel.config.zha.groups.groups"),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
direction: "asc",
|
||||
grows: true,
|
||||
},
|
||||
group_id: {
|
||||
title: this.hass.localize("ui.panel.config.zha.groups.group_id"),
|
||||
type: "numeric",
|
||||
width: "15%",
|
||||
template: (groupId: number) => {
|
||||
return html` ${formatAsPaddedHex(groupId)} `;
|
||||
},
|
||||
sortable: true,
|
||||
},
|
||||
members: {
|
||||
title: this.hass.localize("ui.panel.config.zha.groups.members"),
|
||||
type: "numeric",
|
||||
width: "15%",
|
||||
template: (members: ZHADevice[]) => {
|
||||
return html` ${members.length} `;
|
||||
},
|
||||
sortable: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<hass-tabs-subpage-data-table
|
||||
.tabs=${zhaTabs}
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.route=${this.route}
|
||||
.columns=${this._columns(this.narrow)}
|
||||
.data=${this._formattedGroups(this._groups)}
|
||||
@row-click=${this._handleRowClicked}
|
||||
>
|
||||
</hass-tabs-subpage-data-table>
|
||||
<a href="/config/zha/group-add">
|
||||
<mwc-fab
|
||||
?is-wide=${this.isWide}
|
||||
?narrow=${this.narrow}
|
||||
title=${this.hass!.localize("ui.panel.config.zha.groups.add_group")}
|
||||
?rtl=${computeRTL(this.hass)}
|
||||
>
|
||||
<ha-svg-icon slot="icon" path=${mdiPlus}></ha-svg-icon>
|
||||
</mwc-fab>
|
||||
</a>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _fetchGroups() {
|
||||
this._groups = (await fetchGroups(this.hass!)).sort(sortZHAGroups);
|
||||
}
|
||||
|
||||
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
|
||||
const groupId = ev.detail.id;
|
||||
navigate(this, `/config/zha/group/${groupId}`);
|
||||
}
|
||||
|
||||
static get styles(): CSSResultArray {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
mwc-fab {
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
mwc-fab[is-wide] {
|
||||
bottom: 24px;
|
||||
right: 24px;
|
||||
}
|
||||
mwc-fab[narrow] {
|
||||
bottom: 84px;
|
||||
}
|
||||
mwc-fab[rtl] {
|
||||
right: auto;
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
mwc-fab[rtl][is-wide] {
|
||||
bottom: 24px;
|
||||
right: auto;
|
||||
left: 24px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-groups-dashboard": ZHAGroupsDashboard;
|
||||
}
|
||||
}
|
@ -1,27 +1,27 @@
|
||||
import "@polymer/app-layout/app-header/app-header";
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { sortStatesByName } from "../../../common/entity/states_sort_by_name";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-menu-button";
|
||||
import "../../../components/ha-icon-button-arrow-prev";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../../../layouts/ha-app-layout";
|
||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||
import "../../../styles/polymer-ha-style";
|
||||
import "../ha-config-section";
|
||||
import "../ha-form-style";
|
||||
import { computeStateDomain } from "../../../../../common/entity/compute_state_domain";
|
||||
import { computeStateName } from "../../../../../common/entity/compute_state_name";
|
||||
import { sortStatesByName } from "../../../../../common/entity/states_sort_by_name";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-menu-button";
|
||||
import "../../../../../components/ha-icon-button-arrow-prev";
|
||||
import "../../../../../components/ha-service-description";
|
||||
import "../../../../../layouts/ha-app-layout";
|
||||
import { EventsMixin } from "../../../../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../../../../mixins/localize-mixin";
|
||||
import "../../../../../styles/polymer-ha-style";
|
||||
import "../../../ha-config-section";
|
||||
import "../../../ha-form-style";
|
||||
import "./zwave-groups";
|
||||
import "./zwave-log";
|
||||
import "./zwave-network";
|
@ -4,10 +4,10 @@ import "@polymer/paper-listbox/paper-listbox";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../styles/polymer-ha-style";
|
||||
import { computeStateName } from "../../../../../common/entity/compute_state_name";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../styles/polymer-ha-style";
|
||||
|
||||
class ZwaveGroups extends PolymerElement {
|
||||
static get template() {
|
@ -2,9 +2,9 @@ import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import "../../../components/dialog/ha-paper-dialog";
|
||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||
import "../../../styles/polymer-ha-style-dialog";
|
||||
import "../../../../../components/dialog/ha-paper-dialog";
|
||||
import { EventsMixin } from "../../../../../mixins/events-mixin";
|
||||
import "../../../../../styles/polymer-ha-style-dialog";
|
||||
|
||||
class ZwaveLogDialog extends EventsMixin(PolymerElement) {
|
||||
static get template() {
|
@ -4,12 +4,12 @@ import "@polymer/paper-input/paper-input";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import isPwa from "../../../common/config/is_pwa";
|
||||
import "../../../components/ha-card";
|
||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||
import "../ha-config-section";
|
||||
import "../../../styles/polymer-ha-style";
|
||||
import isPwa from "../../../../../common/config/is_pwa";
|
||||
import "../../../../../components/ha-card";
|
||||
import { EventsMixin } from "../../../../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../../../../mixins/localize-mixin";
|
||||
import "../../../ha-config-section";
|
||||
import "../../../../../styles/polymer-ha-style";
|
||||
|
||||
let registeredDialog = false;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import {
|
||||
@ -10,11 +10,11 @@ import {
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "../../../components/buttons/ha-call-api-button";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../../../../../components/buttons/ha-call-api-button";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-icon";
|
||||
import "../../../../../components/ha-service-description";
|
||||
import {
|
||||
fetchNetworkStatus,
|
||||
ZWaveNetworkStatus,
|
||||
@ -22,10 +22,10 @@ import {
|
||||
ZWAVE_NETWORK_STATE_READY,
|
||||
ZWAVE_NETWORK_STATE_STARTED,
|
||||
ZWAVE_NETWORK_STATE_STOPPED,
|
||||
} from "../../../data/zwave";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
} from "../../../../../data/zwave";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import "../../../ha-config-section";
|
||||
|
||||
@customElement("zwave-network")
|
||||
export class ZwaveNetwork extends LitElement {
|
@ -12,16 +12,16 @@ import {
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import {
|
||||
fetchNodeConfig,
|
||||
ZWaveConfigItem,
|
||||
ZWaveConfigServiceData,
|
||||
ZWaveNode,
|
||||
} from "../../../data/zwave";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
} from "../../../../../data/zwave";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
|
||||
@customElement("zwave-node-config")
|
||||
export class ZwaveNodeConfig extends LitElement {
|
@ -5,9 +5,9 @@ import "@polymer/paper-listbox/paper-listbox";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import "../../../components/buttons/ha-call-api-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../styles/polymer-ha-style";
|
||||
import "../../../../../components/buttons/ha-call-api-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../styles/polymer-ha-style";
|
||||
|
||||
class ZwaveNodeProtection extends PolymerElement {
|
||||
static get template() {
|
@ -5,9 +5,9 @@ import "@polymer/paper-listbox/paper-listbox";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../styles/polymer-ha-style";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../styles/polymer-ha-style";
|
||||
|
||||
class ZwaveUsercodes extends PolymerElement {
|
||||
static get template() {
|
@ -10,11 +10,11 @@ import {
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-card";
|
||||
import { ZWaveValue } from "../../../data/zwave";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import { ZWaveValue } from "../../../../../data/zwave";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
|
||||
@customElement("zwave-values")
|
||||
export class ZwaveValues extends LitElement {
|
@ -1,188 +0,0 @@
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import {
|
||||
css,
|
||||
CSSResultArray,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
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";
|
||||
import { fetchDevices } from "../../../data/zha";
|
||||
import type { ZHADevice } from "../../../data/zha";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { formatAsPaddedHex, sortZHADevices } from "./functions";
|
||||
|
||||
export interface DeviceRowData extends DataTableRowData {
|
||||
device?: DeviceRowData;
|
||||
}
|
||||
|
||||
@customElement("zha-config-dashboard")
|
||||
class ZHAConfigDashboard extends LitElement {
|
||||
@property({ type: Object }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Object }) public route!: Route;
|
||||
|
||||
@property({ type: Boolean }) public narrow!: boolean;
|
||||
|
||||
@property({ type: Boolean }) public isWide!: boolean;
|
||||
|
||||
@property() private _devices: ZHADevice[] = [];
|
||||
|
||||
private pages: string[] = ["add", "groups"];
|
||||
|
||||
private _firstUpdatedCalled = 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),
|
||||
};
|
||||
});
|
||||
|
||||
return outputDevices;
|
||||
});
|
||||
|
||||
private _columns = memoizeOne(
|
||||
(narrow: boolean): DataTableColumnContainer =>
|
||||
narrow
|
||||
? {
|
||||
name: {
|
||||
title: "Devices",
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
direction: "asc",
|
||||
grows: true,
|
||||
},
|
||||
}
|
||||
: {
|
||||
name: {
|
||||
title: "Name",
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
direction: "asc",
|
||||
grows: true,
|
||||
},
|
||||
nwk: {
|
||||
title: "Nwk",
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
width: "15%",
|
||||
},
|
||||
ieee: {
|
||||
title: "IEEE",
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
width: "30%",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
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 {
|
||||
return html`
|
||||
<hass-subpage .header=${this.hass.localize("component.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}
|
||||
.id=${"ieee"}
|
||||
auto-height
|
||||
></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;
|
||||
}
|
||||
}
|
@ -1,566 +0,0 @@
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-icon-item";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import { HassEvent, UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/entity/state-badge";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-service-description";
|
||||
import {
|
||||
AreaRegistryEntry,
|
||||
subscribeAreaRegistry,
|
||||
} from "../../../data/area_registry";
|
||||
import {
|
||||
DeviceRegistryEntryMutableParams,
|
||||
updateDeviceRegistryEntry,
|
||||
} from "../../../data/device_registry";
|
||||
import {
|
||||
reconfigureNode,
|
||||
ZHADevice,
|
||||
ZHAEntityReference,
|
||||
} from "../../../data/zha";
|
||||
import { showZHADeviceZigbeeInfoDialog } from "../../../dialogs/zha-device-zigbee-signature-dialog/show-dialog-zha-device-zigbee-info";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { addEntitiesToLovelaceView } from "../../lovelace/editor/add-entities-to-view";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
import { ItemSelectedEvent, NodeServiceData } from "./types";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"zha-device-removed": {
|
||||
device?: ZHADevice;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("zha-device-card")
|
||||
class ZHADeviceCard extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
|
||||
@property() public device?: ZHADevice;
|
||||
|
||||
@property({ type: Boolean }) public narrow?: boolean;
|
||||
|
||||
@property({ type: Boolean }) public showHelp?: boolean = false;
|
||||
|
||||
@property({ type: Boolean }) public showActions?: boolean = true;
|
||||
|
||||
@property({ type: Boolean }) public showName?: boolean = true;
|
||||
|
||||
@property({ type: Boolean }) public showEntityDetail?: boolean = true;
|
||||
|
||||
@property({ type: Boolean }) public showModelInfo?: boolean = true;
|
||||
|
||||
@property({ type: Boolean }) public showEditableInfo?: boolean = true;
|
||||
|
||||
@property() private _serviceData?: NodeServiceData;
|
||||
|
||||
@property() private _areas: AreaRegistryEntry[] = [];
|
||||
|
||||
@property() private _selectedAreaIndex = -1;
|
||||
|
||||
@property() private _userGivenName?: string;
|
||||
|
||||
private _unsubAreas?: UnsubscribeFunc;
|
||||
|
||||
private _unsubEntities?: UnsubscribeFunc;
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
if (this._unsubAreas) {
|
||||
this._unsubAreas();
|
||||
}
|
||||
if (this._unsubEntities) {
|
||||
this._unsubEntities();
|
||||
}
|
||||
}
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._unsubAreas = subscribeAreaRegistry(this.hass.connection, (areas) => {
|
||||
this._areas = areas;
|
||||
if (this.device) {
|
||||
this._selectedAreaIndex =
|
||||
this._areas.findIndex(
|
||||
(area) => area.area_id === this.device!.area_id
|
||||
) + 1; // account for the no area selected index
|
||||
}
|
||||
});
|
||||
this.hass.connection
|
||||
.subscribeEvents((event: HassEvent) => {
|
||||
if (this.device) {
|
||||
this.device!.entities.forEach((deviceEntity) => {
|
||||
if (event.data.old_entity_id === deviceEntity.entity_id) {
|
||||
deviceEntity.entity_id = event.data.entity_id;
|
||||
}
|
||||
});
|
||||
}
|
||||
}, "entity_registry_updated")
|
||||
.then((unsub) => {
|
||||
this._unsubEntities = unsub;
|
||||
});
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProperties: PropertyValues): void {
|
||||
super.firstUpdated(changedProperties);
|
||||
this.addEventListener("hass-service-called", (ev) =>
|
||||
this.serviceCalled(ev)
|
||||
);
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
if (changedProperties.has("device")) {
|
||||
if (!this._areas || !this.device || !this.device.area_id) {
|
||||
this._selectedAreaIndex = 0;
|
||||
} else {
|
||||
this._selectedAreaIndex =
|
||||
this._areas.findIndex(
|
||||
(area) => area.area_id === this.device!.area_id
|
||||
) + 1;
|
||||
}
|
||||
this._userGivenName = this.device!.user_given_name;
|
||||
this._serviceData = {
|
||||
ieee_address: this.device!.ieee,
|
||||
};
|
||||
}
|
||||
super.update(changedProperties);
|
||||
}
|
||||
|
||||
protected serviceCalled(ev): void {
|
||||
// Check if this is for us
|
||||
if (ev.detail.success && ev.detail.service === "remove") {
|
||||
fireEvent(this, "zha-device-removed", {
|
||||
device: this.device,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-card header="${this.showName ? this.device!.name : ""}">
|
||||
${
|
||||
this.showModelInfo
|
||||
? html`
|
||||
<div class="info">
|
||||
<div class="model">${this.device!.model}</div>
|
||||
<div class="manuf">
|
||||
${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.manuf",
|
||||
"manufacturer",
|
||||
this.device!.manufacturer
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
<div class="card-content">
|
||||
<dl>
|
||||
<dt>IEEE:</dt>
|
||||
<dd class="zha-info">${this.device!.ieee}</dd>
|
||||
<dt>Nwk:</dt>
|
||||
<dd class="zha-info">${formatAsPaddedHex(this.device!.nwk)}</dd>
|
||||
<dt>Device Type:</dt>
|
||||
<dd class="zha-info">${this.device!.device_type}</dd>
|
||||
<dt>LQI:</dt>
|
||||
<dd class="zha-info">${
|
||||
this.device!.lqi ||
|
||||
this.hass!.localize("ui.dialogs.zha_device_info.unknown")
|
||||
}</dd>
|
||||
<dt>RSSI:</dt>
|
||||
<dd class="zha-info">${
|
||||
this.device!.rssi ||
|
||||
this.hass!.localize("ui.dialogs.zha_device_info.unknown")
|
||||
}</dd>
|
||||
<dt>${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.last_seen"
|
||||
)}:</dt>
|
||||
<dd class="zha-info">${
|
||||
this.device!.last_seen ||
|
||||
this.hass!.localize("ui.dialogs.zha_device_info.unknown")
|
||||
}</dd>
|
||||
<dt>${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.power_source"
|
||||
)}:</dt>
|
||||
<dd class="zha-info">${
|
||||
this.device!.power_source ||
|
||||
this.hass!.localize("ui.dialogs.zha_device_info.unknown")
|
||||
}</dd>
|
||||
${
|
||||
this.device!.quirk_applied
|
||||
? html`
|
||||
<dt>
|
||||
${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.quirk"
|
||||
)}:
|
||||
</dt>
|
||||
<dd class="zha-info">${this.device!.quirk_class}</dd>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="device-entities">
|
||||
${this.device!.entities.map(
|
||||
(entity) => html`
|
||||
<paper-icon-item
|
||||
@click="${this._openMoreInfo}"
|
||||
.entity="${entity}"
|
||||
>
|
||||
<state-badge
|
||||
.stateObj="${this.hass!.states[entity.entity_id]}"
|
||||
slot="item-icon"
|
||||
></state-badge>
|
||||
${this.showEntityDetail
|
||||
? html`
|
||||
<paper-item-body>
|
||||
<div class="name">
|
||||
${this._computeEntityName(entity)}
|
||||
</div>
|
||||
<div class="secondary entity-id">
|
||||
${entity.entity_id}
|
||||
</div>
|
||||
</paper-item-body>
|
||||
`
|
||||
: ""}
|
||||
</paper-icon-item>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
${
|
||||
this.device!.entities && this.device!.entities.length > 0
|
||||
? html`
|
||||
<div class="card-actions">
|
||||
<mwc-button @click=${this._addToLovelaceView}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.entities.add_entities_lovelace"
|
||||
)}
|
||||
</mwc-button>
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
this.showEditableInfo
|
||||
? html`
|
||||
<div class="editable">
|
||||
<paper-input
|
||||
type="string"
|
||||
@change="${this._saveCustomName}"
|
||||
.value="${this._userGivenName || ""}"
|
||||
.placeholder="${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.zha_device_card.device_name_placeholder"
|
||||
)}"
|
||||
></paper-input>
|
||||
</div>
|
||||
<div class="node-picker">
|
||||
<paper-dropdown-menu
|
||||
.label="${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.zha_device_card.area_picker_label"
|
||||
)}"
|
||||
class="menu"
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
.selected="${this._selectedAreaIndex}"
|
||||
@iron-select="${this._selectedAreaChanged}"
|
||||
>
|
||||
<paper-item>
|
||||
${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.no_area"
|
||||
)}
|
||||
</paper-item>
|
||||
|
||||
${this._areas.map(
|
||||
(entry) => html`
|
||||
<paper-item>${entry.name}</paper-item>
|
||||
`
|
||||
)}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
this.showActions
|
||||
? html`
|
||||
<div class="card-actions">
|
||||
${this.device!.device_type !== "Coordinator"
|
||||
? html`
|
||||
<mwc-button @click=${this._onReconfigureNodeClick}>
|
||||
${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.buttons.reconfigure"
|
||||
)}
|
||||
</mwc-button>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div class="help-text">
|
||||
${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.services.reconfigure"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
|
||||
<ha-call-service-button
|
||||
.hass=${this.hass}
|
||||
domain="zha"
|
||||
service="remove"
|
||||
.confirmation=${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.confirmations.remove"
|
||||
)}
|
||||
.serviceData=${this._serviceData}
|
||||
>
|
||||
${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.buttons.remove"
|
||||
)}
|
||||
</ha-call-service-button>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div class="help-text">
|
||||
${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.services.remove"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
`
|
||||
: ""}
|
||||
${this.device!.power_source === "Mains" &&
|
||||
(this.device!.device_type === "Router" ||
|
||||
this.device!.device_type === "Coordinator")
|
||||
? html`
|
||||
<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"
|
||||
></ha-service-description>
|
||||
`
|
||||
: ""}
|
||||
`
|
||||
: ""}
|
||||
${this.device!.device_type !== "Coordinator"
|
||||
? html`
|
||||
<mwc-button @click=${this._handleZigbeeInfoClicked}>
|
||||
${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.buttons.zigbee_information"
|
||||
)}
|
||||
</mwc-button>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div class="help-text">
|
||||
${this.hass!.localize(
|
||||
"ui.dialogs.zha_device_info.services.zigbee_information"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _onReconfigureNodeClick(): Promise<void> {
|
||||
if (this.hass) {
|
||||
await reconfigureNode(this.hass, this.device!.ieee);
|
||||
}
|
||||
}
|
||||
|
||||
private _computeEntityName(entity: ZHAEntityReference): string {
|
||||
if (this.hass.states[entity.entity_id]) {
|
||||
return computeStateName(this.hass.states[entity.entity_id]);
|
||||
}
|
||||
return entity.name;
|
||||
}
|
||||
|
||||
private async _saveCustomName(event): Promise<void> {
|
||||
if (this.hass) {
|
||||
const values: DeviceRegistryEntryMutableParams = {
|
||||
name_by_user: event.target.value,
|
||||
area_id: this.device!.area_id ? this.device!.area_id : undefined,
|
||||
};
|
||||
|
||||
await updateDeviceRegistryEntry(
|
||||
this.hass,
|
||||
this.device!.device_reg_id,
|
||||
values
|
||||
);
|
||||
|
||||
this.device!.user_given_name = event.target.value;
|
||||
}
|
||||
}
|
||||
|
||||
private _openMoreInfo(ev: MouseEvent): void {
|
||||
fireEvent(this, "hass-more-info", {
|
||||
entityId: (ev.currentTarget as any).entity.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private async _selectedAreaChanged(event: ItemSelectedEvent) {
|
||||
if (!this.device || !this._areas) {
|
||||
return;
|
||||
}
|
||||
this._selectedAreaIndex = event!.target!.selected;
|
||||
const area = this._areas[this._selectedAreaIndex - 1]; // account for No Area
|
||||
if (
|
||||
(!area && !this.device.area_id) ||
|
||||
(area && area.area_id === this.device.area_id)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newAreaId = area ? area.area_id : undefined;
|
||||
await updateDeviceRegistryEntry(this.hass!, this.device.device_reg_id, {
|
||||
area_id: newAreaId,
|
||||
name_by_user: this.device!.user_given_name,
|
||||
});
|
||||
this.device!.area_id = newAreaId;
|
||||
}
|
||||
|
||||
private _onAddDevicesClick() {
|
||||
navigate(this, "/config/zha/add/" + this.device!.ieee);
|
||||
}
|
||||
|
||||
private async _handleZigbeeInfoClicked() {
|
||||
showZHADeviceZigbeeInfoDialog(this, { device: this.device! });
|
||||
}
|
||||
|
||||
private _addToLovelaceView(): void {
|
||||
addEntitiesToLovelaceView(
|
||||
this,
|
||||
this.hass,
|
||||
this.device!.entities.map((entity) => entity.entity_id)
|
||||
);
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
:host(:not([narrow])) .device-entities {
|
||||
max-height: 225px;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px;
|
||||
justify-content: left;
|
||||
}
|
||||
ha-card {
|
||||
flex: 1 0 100%;
|
||||
padding-bottom: 10px;
|
||||
min-width: 300px;
|
||||
}
|
||||
.device {
|
||||
width: 30%;
|
||||
}
|
||||
.device .name {
|
||||
font-weight: bold;
|
||||
}
|
||||
.device .manuf {
|
||||
color: var(--secondary-text-color);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.extra-info {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.manuf,
|
||||
.zha-info,
|
||||
.name {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.entity-id {
|
||||
text-overflow: ellipsis;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.info {
|
||||
margin-left: 16px;
|
||||
}
|
||||
dl {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
}
|
||||
dl dt {
|
||||
display: inline-block;
|
||||
width: 30%;
|
||||
padding-left: 12px;
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
dl dd {
|
||||
width: 60%;
|
||||
overflow-wrap: break-word;
|
||||
margin-inline-start: 20px;
|
||||
}
|
||||
paper-icon-item {
|
||||
overflow-x: hidden;
|
||||
cursor: pointer;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
.editable {
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
.menu {
|
||||
width: 100%;
|
||||
}
|
||||
.node-picker {
|
||||
align-items: center;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.buttons .icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-device-card": ZHADeviceCard;
|
||||
}
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import {
|
||||
Cluster,
|
||||
fetchBindableDevices,
|
||||
fetchGroups,
|
||||
fetchZHADevice,
|
||||
ZHADevice,
|
||||
ZHAGroup,
|
||||
} from "../../../data/zha";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { sortZHADevices, sortZHAGroups } from "./functions";
|
||||
import { ZHAClusterSelectedParams } from "./types";
|
||||
import "./zha-cluster-attributes";
|
||||
import "./zha-cluster-commands";
|
||||
import "./zha-clusters";
|
||||
import "./zha-device-binding";
|
||||
import "./zha-group-binding";
|
||||
import "./zha-node";
|
||||
|
||||
@customElement("zha-device-page")
|
||||
export class ZHADevicePage extends LitElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() public isWide?: boolean;
|
||||
|
||||
@property() public ieee?: string;
|
||||
|
||||
@property() public device?: ZHADevice;
|
||||
|
||||
@property() public narrow?: boolean;
|
||||
|
||||
@property() private _selectedCluster?: Cluster;
|
||||
|
||||
@property() private _bindableDevices: ZHADevice[] = [];
|
||||
|
||||
@property() private _groups: ZHAGroup[] = [];
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
if (changedProperties.has("ieee")) {
|
||||
this._fetchData();
|
||||
}
|
||||
super.update(changedProperties);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<hass-subpage
|
||||
.header=${this.hass!.localize("ui.panel.config.zha.devices.header")}
|
||||
.back=${!this.isWide}
|
||||
>
|
||||
<zha-node
|
||||
.isWide="${this.isWide}"
|
||||
.hass=${this.hass}
|
||||
.device=${this.device}
|
||||
></zha-node>
|
||||
|
||||
${this.device && this.device.device_type !== "Coordinator"
|
||||
? html`
|
||||
<zha-clusters
|
||||
.hass=${this.hass}
|
||||
.isWide="${this.isWide}"
|
||||
.selectedDevice="${this.device}"
|
||||
@zha-cluster-selected="${this._onClusterSelected}"
|
||||
></zha-clusters>
|
||||
${this._selectedCluster
|
||||
? html`
|
||||
<zha-cluster-attributes
|
||||
.isWide="${this.isWide}"
|
||||
.hass=${this.hass}
|
||||
.selectedNode="${this.device}"
|
||||
.selectedCluster="${this._selectedCluster}"
|
||||
></zha-cluster-attributes>
|
||||
|
||||
<zha-cluster-commands
|
||||
.isWide="${this.isWide}"
|
||||
.hass=${this.hass}
|
||||
.selectedNode="${this.device}"
|
||||
.selectedCluster="${this._selectedCluster}"
|
||||
></zha-cluster-commands>
|
||||
`
|
||||
: ""}
|
||||
${this._bindableDevices.length > 0
|
||||
? html`
|
||||
<zha-device-binding-control
|
||||
.isWide="${this.isWide}"
|
||||
.hass=${this.hass}
|
||||
.selectedDevice="${this.device}"
|
||||
.bindableDevices="${this._bindableDevices}"
|
||||
></zha-device-binding-control>
|
||||
`
|
||||
: ""}
|
||||
${this.device && this._groups.length > 0
|
||||
? html`
|
||||
<zha-group-binding-control
|
||||
.isWide="${this.isWide}"
|
||||
.narrow="${this.narrow}"
|
||||
.hass=${this.hass}
|
||||
.selectedDevice="${this.device}"
|
||||
.groups="${this._groups}"
|
||||
></zha-group-binding-control>
|
||||
`
|
||||
: ""}
|
||||
`
|
||||
: ""}
|
||||
<div class="spacer"></div>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
private _onClusterSelected(
|
||||
selectedClusterEvent: HASSDomEvent<ZHAClusterSelectedParams>
|
||||
): void {
|
||||
this._selectedCluster = selectedClusterEvent.detail.cluster;
|
||||
}
|
||||
|
||||
private async _fetchData(): Promise<void> {
|
||||
if (this.ieee && this.hass) {
|
||||
this.device = await fetchZHADevice(this.hass, this.ieee);
|
||||
this._bindableDevices =
|
||||
this.device && this.device.device_type !== "Coordinator"
|
||||
? (await fetchBindableDevices(this.hass, this.ieee)).sort(
|
||||
sortZHADevices
|
||||
)
|
||||
: [];
|
||||
this._groups = (await fetchGroups(this.hass!)).sort(sortZHAGroups);
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.spacer {
|
||||
height: 50px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-device-page": ZHADevicePage;
|
||||
}
|
||||
}
|
@ -1,172 +0,0 @@
|
||||
import "@material/mwc-button";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { SelectionChangedEvent } from "../../../components/data-table/ha-data-table";
|
||||
import { fetchGroups, removeGroups, ZHAGroup } from "../../../data/zha";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { sortZHAGroups } from "./functions";
|
||||
import "./zha-groups-data-table";
|
||||
|
||||
@customElement("zha-groups-dashboard")
|
||||
export class ZHAGroupsDashboard extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
|
||||
@property() public narrow = false;
|
||||
|
||||
@property() public _groups?: ZHAGroup[];
|
||||
|
||||
@property() private _processingRemove = false;
|
||||
|
||||
@property() private _selectedGroupsToRemove: number[] = [];
|
||||
|
||||
private _firstUpdatedCalled = false;
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
if (this.hass && this._firstUpdatedCalled) {
|
||||
this._fetchGroups();
|
||||
}
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProperties: PropertyValues): void {
|
||||
super.firstUpdated(changedProperties);
|
||||
if (this.hass) {
|
||||
this._fetchGroups();
|
||||
}
|
||||
this._firstUpdatedCalled = true;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<hass-subpage
|
||||
.header=${this.hass!.localize(
|
||||
"ui.panel.config.zha.groups.groups-header"
|
||||
)}
|
||||
>
|
||||
<ha-icon-button
|
||||
slot="toolbar-icon"
|
||||
icon="hass:plus"
|
||||
@click=${this._addGroup}
|
||||
></ha-icon-button>
|
||||
|
||||
<div class="content">
|
||||
${this._groups
|
||||
? html`
|
||||
<zha-groups-data-table
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.groups=${this._groups}
|
||||
.selectable=${true}
|
||||
@selection-changed=${this._handleRemoveSelectionChanged}
|
||||
class="table"
|
||||
></zha-groups-data-table>
|
||||
`
|
||||
: html`
|
||||
<paper-spinner
|
||||
active
|
||||
alt=${this.hass!.localize("ui.common.loading")}
|
||||
></paper-spinner>
|
||||
`}
|
||||
</div>
|
||||
<div class="paper-dialog-buttons">
|
||||
<mwc-button
|
||||
?disabled="${!this._selectedGroupsToRemove.length ||
|
||||
this._processingRemove}"
|
||||
@click="${this._removeGroup}"
|
||||
class="button"
|
||||
>
|
||||
<paper-spinner
|
||||
?active="${this._processingRemove}"
|
||||
alt=${this.hass!.localize(
|
||||
"ui.panel.config.zha.groups.removing_groups"
|
||||
)}
|
||||
></paper-spinner>
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.groups.remove_groups"
|
||||
)}</mwc-button
|
||||
>
|
||||
</div>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _fetchGroups() {
|
||||
this._groups = (await fetchGroups(this.hass!)).sort(sortZHAGroups);
|
||||
}
|
||||
|
||||
private _handleRemoveSelectionChanged(
|
||||
ev: HASSDomEvent<SelectionChangedEvent>
|
||||
): void {
|
||||
this._selectedGroupsToRemove = ev.detail.value.map((value) =>
|
||||
Number(value)
|
||||
);
|
||||
}
|
||||
|
||||
private async _removeGroup(): Promise<void> {
|
||||
this._processingRemove = true;
|
||||
this._groups = await removeGroups(this.hass, this._selectedGroupsToRemove);
|
||||
this._selectedGroupsToRemove = [];
|
||||
this._processingRemove = false;
|
||||
}
|
||||
|
||||
private async _addGroup(): Promise<void> {
|
||||
navigate(this, `/config/zha/group-add`);
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
css`
|
||||
.content {
|
||||
padding: 4px;
|
||||
}
|
||||
zha-groups-data-table {
|
||||
width: 100%;
|
||||
}
|
||||
.button {
|
||||
float: right;
|
||||
}
|
||||
.table {
|
||||
height: 200px;
|
||||
overflow: auto;
|
||||
}
|
||||
mwc-button paper-spinner {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
paper-spinner {
|
||||
display: none;
|
||||
}
|
||||
paper-spinner[active] {
|
||||
display: block;
|
||||
}
|
||||
.paper-dialog-buttons {
|
||||
align-items: flex-end;
|
||||
padding: 8px;
|
||||
}
|
||||
.paper-dialog-buttons .warning {
|
||||
--mdc-theme-primary: var(--google-red-500);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-groups-dashboard": ZHAGroupsDashboard;
|
||||
}
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
import {
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
query,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import "../../../components/data-table/ha-data-table";
|
||||
import type {
|
||||
DataTableColumnContainer,
|
||||
HaDataTable,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/entity/ha-state-icon";
|
||||
import type { ZHADevice, ZHAGroup } from "../../../data/zha";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
|
||||
export interface GroupRowData extends ZHAGroup {
|
||||
group?: GroupRowData;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
@query("ha-data-table") private _dataTable!: HaDataTable;
|
||||
|
||||
private _groups = memoizeOne((groups: ZHAGroup[]) => {
|
||||
let outputGroups: GroupRowData[] = groups;
|
||||
|
||||
outputGroups = outputGroups.map((group) => {
|
||||
return {
|
||||
...group,
|
||||
id: String(group.group_id),
|
||||
};
|
||||
});
|
||||
|
||||
return outputGroups;
|
||||
});
|
||||
|
||||
private _columns = memoizeOne(
|
||||
(narrow: boolean): DataTableColumnContainer =>
|
||||
narrow
|
||||
? {
|
||||
name: {
|
||||
title: "Group",
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
direction: "asc",
|
||||
grows: true,
|
||||
template: (name) => html`
|
||||
<div @click=${this._handleRowClicked} style="cursor: pointer;">
|
||||
${name}
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
}
|
||||
: {
|
||||
name: {
|
||||
title: this.hass.localize("ui.panel.config.zha.groups.groups"),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
direction: "asc",
|
||||
grows: true,
|
||||
template: (name) => html`
|
||||
<div @click=${this._handleRowClicked} style="cursor: pointer;">
|
||||
${name}
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
group_id: {
|
||||
title: this.hass.localize("ui.panel.config.zha.groups.group_id"),
|
||||
type: "numeric",
|
||||
width: "15%",
|
||||
template: (groupId: number) => {
|
||||
return html` ${formatAsPaddedHex(groupId)} `;
|
||||
},
|
||||
sortable: true,
|
||||
},
|
||||
members: {
|
||||
title: this.hass.localize("ui.panel.config.zha.groups.members"),
|
||||
type: "numeric",
|
||||
width: "15%",
|
||||
template: (members: ZHADevice[]) => {
|
||||
return html` ${members.length} `;
|
||||
},
|
||||
sortable: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
public clearSelection() {
|
||||
this._dataTable.clearSelection();
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-data-table
|
||||
.columns=${this._columns(this.narrow)}
|
||||
.data=${this._groups(this.groups)}
|
||||
.selectable=${this.selectable}
|
||||
auto-height
|
||||
></ha-data-table>
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleRowClicked(ev: CustomEvent) {
|
||||
const groupId = ((ev.target as HTMLElement).closest(
|
||||
".mdc-data-table__row"
|
||||
) as any).rowId;
|
||||
navigate(this, `/config/zha/group/${groupId}`);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-groups-data-table": ZHAGroupsDataTable;
|
||||
}
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
import "../../../components/ha-icon-button";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-service-description";
|
||||
import { ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import "./zha-device-card";
|
||||
|
||||
@customElement("zha-node")
|
||||
export class ZHANode extends LitElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() public isWide?: boolean;
|
||||
|
||||
@property() public device?: ZHADevice;
|
||||
|
||||
@property() private _showHelp = false;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-config-section .isWide="${this.isWide}">
|
||||
<div class="header" slot="header">
|
||||
<span
|
||||
>${this.hass!.localize(
|
||||
"ui.panel.config.zha.node_management.header"
|
||||
)}</span
|
||||
>
|
||||
<ha-icon-button
|
||||
class="toggle-help-icon"
|
||||
@click="${this._onHelpTap}"
|
||||
icon="hass:help-circle"
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
<span slot="introduction">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.node_management.introduction"
|
||||
)}
|
||||
<br /><br />
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.node_management.hint_battery_devices"
|
||||
)}
|
||||
<br /><br />
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.node_management.hint_wakeup"
|
||||
)}
|
||||
</span>
|
||||
<div class="content">
|
||||
${this.device
|
||||
? html`
|
||||
<zha-device-card
|
||||
class="card"
|
||||
.hass=${this.hass}
|
||||
.device=${this.device}
|
||||
.narrow=${!this.isWide}
|
||||
.showHelp=${this._showHelp}
|
||||
showName
|
||||
showModelInfo
|
||||
.showEntityDetail=${false}
|
||||
showActions
|
||||
@zha-device-removed=${this._onDeviceRemoved}
|
||||
></zha-device-card>
|
||||
`
|
||||
: html`
|
||||
<paper-spinner
|
||||
active
|
||||
alt=${this.hass!.localize("ui.common.loading")}
|
||||
></paper-spinner>
|
||||
`}
|
||||
</div>
|
||||
</ha-config-section>
|
||||
`;
|
||||
}
|
||||
|
||||
private _onHelpTap(): void {
|
||||
this._showHelp = !this._showHelp;
|
||||
}
|
||||
|
||||
private _onDeviceRemoved(): void {
|
||||
this.device = undefined;
|
||||
navigate(this, `/config/zha`, true);
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.node-info {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: 680px;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 28px 20px 0;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
ha-service-description {
|
||||
display: block;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.header {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.toggle-help-icon {
|
||||
float: right;
|
||||
top: 6px;
|
||||
right: 0;
|
||||
padding-right: 0px;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-node": ZHANode;
|
||||
}
|
||||
}
|
@ -12,7 +12,6 @@ import SidebarMixin from "./sidebar-mixin";
|
||||
import ThemesMixin from "./themes-mixin";
|
||||
import TranslationsMixin from "./translations-mixin";
|
||||
import { urlSyncMixin } from "./url-sync-mixin";
|
||||
import ZHADialogMixin from "./zha-dialog-mixin";
|
||||
|
||||
const ext = <T extends Constructor>(baseClass: T, mixins): T =>
|
||||
mixins.reduceRight((base, mixin) => mixin(base), baseClass);
|
||||
@ -28,7 +27,6 @@ export class HassElement extends ext(HassBaseEl, [
|
||||
NotificationMixin,
|
||||
dialogManagerMixin,
|
||||
urlSyncMixin,
|
||||
ZHADialogMixin,
|
||||
hapticMixin,
|
||||
panelTitleMixin,
|
||||
]) {}
|
||||
|
@ -1,30 +0,0 @@
|
||||
import { UpdatingElement } from "lit-element";
|
||||
import { HASSDomEvent } from "../common/dom/fire_event";
|
||||
import {
|
||||
showZHADeviceInfoDialog,
|
||||
ZHADeviceInfoDialogParams,
|
||||
} from "../dialogs/zha-device-info-dialog/show-dialog-zha-device-info";
|
||||
import { Constructor } from "../types";
|
||||
import { HassBaseEl } from "./hass-base-mixin";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"zha-show-device-dialog": {
|
||||
ieee: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default (superClass: Constructor<UpdatingElement & HassBaseEl>) =>
|
||||
class extends superClass {
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
this.addEventListener("zha-show-device-dialog", (e) =>
|
||||
showZHADeviceInfoDialog(
|
||||
e.target as HTMLElement,
|
||||
(e as HASSDomEvent<ZHADeviceInfoDialogParams>).detail
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
@ -441,10 +441,10 @@
|
||||
"no_area": "No Area",
|
||||
"device_signature": "Zigbee device signature",
|
||||
"buttons": {
|
||||
"add": "Add Devices",
|
||||
"add": "Add Devices via this device",
|
||||
"remove": "Remove Device",
|
||||
"reconfigure": "Reconfigure Device",
|
||||
"zigbee_information": "Zigbee Information"
|
||||
"zigbee_information": "Zigbee device signature"
|
||||
},
|
||||
"services": {
|
||||
"reconfigure": "Reconfigure ZHA device (heal device). Use this if you are having issues with the device. If the device in question is a battery powered device please ensure it is awake and accepting commands when you use this service.",
|
||||
@ -460,9 +460,7 @@
|
||||
"power_source": "Power Source",
|
||||
"unknown": "Unknown",
|
||||
"zha_device_card": {
|
||||
"device_name_placeholder": "User given name",
|
||||
"area_picker_label": "Area",
|
||||
"update_name_button": "Update Name"
|
||||
"device_name_placeholder": "Change device name"
|
||||
}
|
||||
},
|
||||
"domain_toggler": {
|
||||
@ -1504,6 +1502,7 @@
|
||||
}
|
||||
},
|
||||
"zha": {
|
||||
"button": "Configure",
|
||||
"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",
|
||||
@ -1515,9 +1514,10 @@
|
||||
"value": "Value"
|
||||
},
|
||||
"add_device_page": {
|
||||
"header": "Zigbee Home Automation - Add Devices",
|
||||
"spinner": "Searching for ZHA Zigbee devices...",
|
||||
"discovery_text": "Discovered devices will show up here. Follow the instructions for your device(s) and place the device(s) in pairing mode.",
|
||||
"pairing_mode": "Make sure your devices are in pairing mode. Check the instructions of your device on how to do this.",
|
||||
"discovered_text": "Devices will show up here once discovered.",
|
||||
"no_devices_found": "No devices where found, make sure they are in paring mode and keep them awake while discovering is running.",
|
||||
"search_again": "Search Again"
|
||||
},
|
||||
"network_management": {
|
||||
@ -1560,6 +1560,9 @@
|
||||
"issue_zigbee_command": "Issue Zigbee Command",
|
||||
"help_command_dropdown": "Select a command to interact with."
|
||||
},
|
||||
"network": {
|
||||
"caption": "Network"
|
||||
},
|
||||
"groups": {
|
||||
"caption": "Groups",
|
||||
"description": "Create and modify Zigbee groups",
|
||||
@ -1600,6 +1603,7 @@
|
||||
}
|
||||
},
|
||||
"zwave": {
|
||||
"button": "Configure",
|
||||
"description": "Manage your Z-Wave network",
|
||||
"learn_more": "Learn more about Z-Wave",
|
||||
"common": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user