Enhance ZHA device pairing feedback (#7843)

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
David F. Mulcahey 2020-11-29 16:33:46 -05:00 committed by GitHub
parent fe31d15d27
commit 335354d962
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 196 additions and 11 deletions

View File

@ -27,6 +27,7 @@ export interface ZHADevice {
device_type: string;
signature: any;
neighbors: Neighbor[];
pairing_status?: string;
}
export interface Neighbor {
@ -270,3 +271,23 @@ export const addGroup = (
group_name: groupName,
members: membersToAdd,
});
export const INITIALIZED = "INITIALIZED";
export const INTERVIEW_COMPLETE = "INTERVIEW_COMPLETE";
export const CONFIGURED = "CONFIGURED";
export const PAIRED = "PAIRED";
export const INCOMPLETE_PAIRING_STATUSES = [
PAIRED,
CONFIGURED,
INTERVIEW_COMPLETE,
];
export const DEVICE_JOINED = "device_joined";
export const RAW_DEVICE_INITIALIZED = "raw_device_initialized";
export const DEVICE_FULLY_INITIALIZED = "device_fully_initialized";
export const DEVICE_MESSAGE_TYPES = [
DEVICE_JOINED,
RAW_DEVICE_INITIALIZED,
DEVICE_FULLY_INITIALIZED,
];
export const LOG_OUTPUT = "log_output";

View File

@ -14,13 +14,17 @@ import {
} from "lit-element";
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 "./zha-device-pairing-status-card";
import { zhaTabs } from "./zha-config-dashboard";
import { IronAutogrowTextareaElement } from "@polymer/iron-autogrow-textarea";
import {
DEVICE_MESSAGE_TYPES,
LOG_OUTPUT,
ZHADevice,
} from "../../../../../data/zha";
@customElement("zha-add-devices-page")
class ZHAAddDevicesPage extends LitElement {
@ -34,7 +38,10 @@ class ZHAAddDevicesPage extends LitElement {
@internalProperty() private _error?: string;
@internalProperty() private _discoveredDevices: ZHADevice[] = [];
@internalProperty() private _discoveredDevices: Record<
string,
ZHADevice
> = {};
@internalProperty() private _formattedEvents = "";
@ -64,7 +71,7 @@ class ZHAAddDevicesPage extends LitElement {
super.disconnectedCallback();
this._unsubscribe();
this._error = undefined;
this._discoveredDevices = [];
this._discoveredDevices = {};
this._formattedEvents = "";
}
@ -115,7 +122,7 @@ class ZHAAddDevicesPage extends LitElement {
</div>
${this._error ? html` <div class="error">${this._error}</div> ` : ""}
<div class="content">
${this._discoveredDevices.length < 1
${Object.keys(this._discoveredDevices).length < 1
? html`
<div class="discovery-text">
<h4>
@ -133,15 +140,15 @@ class ZHAAddDevicesPage extends LitElement {
</div>
`
: html`
${this._discoveredDevices.map(
${Object.values(this._discoveredDevices).map(
(device) => html`
<zha-device-card
<zha-device-pairing-status-card
class="card"
.hass=${this.hass}
.device=${device}
.narrow=${this.narrow}
.showHelp=${this._showHelp}
></zha-device-card>
></zha-device-pairing-status-card>
`
)}
`}
@ -164,7 +171,7 @@ class ZHAAddDevicesPage extends LitElement {
}
private _handleMessage(message: any): void {
if (message.type === "log_output") {
if (message.type === LOG_OUTPUT) {
this._formattedEvents += message.log_entry.message + "\n";
if (this.shadowRoot) {
const paperTextArea = this.shadowRoot.querySelector("paper-textarea");
@ -175,8 +182,8 @@ class ZHAAddDevicesPage extends LitElement {
}
}
}
if (message.type && message.type === "device_fully_initialized") {
this._discoveredDevices.push(message.device_info);
if (message.type && DEVICE_MESSAGE_TYPES.includes(message.type)) {
this._discoveredDevices[message.device_info.ieee] = message.device_info;
}
}

View File

@ -0,0 +1,147 @@
import "@polymer/paper-input/paper-input";
import "@polymer/paper-listbox/paper-listbox";
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
internalProperty,
TemplateResult,
} from "lit-element";
import "../../../../../components/buttons/ha-call-service-button";
import "../../../../../components/entity/state-badge";
import "../../../../../components/ha-card";
import "../../../../../components/ha-service-description";
import {
CONFIGURED,
INCOMPLETE_PAIRING_STATUSES,
INITIALIZED,
INTERVIEW_COMPLETE,
ZHADevice,
} from "../../../../../data/zha";
import { haStyle } from "../../../../../resources/styles";
import { HomeAssistant } from "../../../../../types";
import "../../../../../components/ha-area-picker";
import { formatAsPaddedHex } from "./functions";
import "./zha-device-card";
import { classMap } from "lit-html/directives/class-map";
@customElement("zha-device-pairing-status-card")
class ZHADevicePairingStatusCard extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public device?: ZHADevice;
@property({ type: Boolean }) public narrow?: boolean;
@internalProperty() private _showHelp = false;
protected render(): TemplateResult {
if (!this.hass || !this.device) {
return html``;
}
return html`
<ha-card
outlined
class="discovered ${classMap({
initialized: this.device.pairing_status === INITIALIZED,
})}"
><div
class="header"
>
<h1>
${this.hass!.localize(
`ui.panel.config.zha.device_pairing_card.${this.device.pairing_status}`
)}
</h1>
<h4>
${this.hass!.localize(
`ui.panel.config.zha.device_pairing_card.${this.device.pairing_status}_status_text`
)}
</h4>
</div>
<div class="card-content">
${[INTERVIEW_COMPLETE, CONFIGURED].includes(
this.device.pairing_status!
)
? html`
<div class="model">${this.device.model}</div>
<div class="manuf">
${this.hass.localize(
"ui.dialogs.zha_device_info.manuf",
"manufacturer",
this.device.manufacturer
)}
</div>
`
: html``}
<div class="info">
${INCOMPLETE_PAIRING_STATUSES.includes(this.device.pairing_status!)
? html`
<div class="text">IEEE: ${this.device.ieee}</div>
<div class="text">
NWK: ${formatAsPaddedHex(this.device.nwk)}
</div>
`
: html``}
</div>
${this.device.pairing_status === INITIALIZED
? html`
<zha-device-card
class="card"
.hass=${this.hass}
.device=${this.device}
.narrow=${this.narrow}
.showHelp=${this._showHelp}
></zha-device-card>
`
: html``}
</div>
</ha-card>
`;
}
static get styles(): CSSResult[] {
return [
haStyle,
css`
.discovered {
--ha-card-border-color: var(--primary-color);
}
.discovered.initialized {
--ha-card-border-color: var(--success-color);
}
.discovered .header {
background: var(--primary-color);
color: var(--text-primary-color);
padding: 8px;
text-align: center;
margin-bottom: 20px;
}
.discovered.initialized .header {
background: var(--success-color);
}
h1 {
margin: 0;
}
h4 {
margin: 0;
}
.text,
.manuf,
.model {
color: var(--secondary-text-color);
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"zha-device-pairing-status-card": ZHADevicePairingStatusCard;
}
}

View File

@ -2198,6 +2198,16 @@
"issue_zigbee_command": "Issue Zigbee Command",
"help_command_dropdown": "Select a command to interact with."
},
"device_pairing_card": {
"PAIRED": "Device Found",
"PAIRED_status_text": "Starting Interview",
"INTERVIEW_COMPLETE": "Interview Complete",
"INTERVIEW_COMPLETE_status_text": "Configuring",
"CONFIGURED": "Configuration Complete",
"CONFIGURED_status_text": "Initializing",
"INITIALIZED": "Initialization Complete",
"INITIALIZED_status_text": "The device is ready to use"
},
"network": {
"caption": "Network"
},