diff --git a/src/data/zha.ts b/src/data/zha.ts
index 5f4cb3aa18..96c8166a24 100644
--- a/src/data/zha.ts
+++ b/src/data/zha.ts
@@ -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";
diff --git a/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts b/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts
index 6c2fdcc897..7f56d95d9e 100644
--- a/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts
+++ b/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts
@@ -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 {
${this._error ? html`
- ${this._discoveredDevices.length < 1
+ ${Object.keys(this._discoveredDevices).length < 1
? html`
@@ -133,15 +140,15 @@ class ZHAAddDevicesPage extends LitElement {
`
: html`
- ${this._discoveredDevices.map(
+ ${Object.values(this._discoveredDevices).map(
(device) => html`
-
+ >
`
)}
`}
@@ -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;
}
}
diff --git a/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts
new file mode 100644
index 0000000000..c6b4181e85
--- /dev/null
+++ b/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts
@@ -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`
+
+
+ ${[INTERVIEW_COMPLETE, CONFIGURED].includes(
+ this.device.pairing_status!
+ )
+ ? html`
+
${this.device.model}
+
+ ${this.hass.localize(
+ "ui.dialogs.zha_device_info.manuf",
+ "manufacturer",
+ this.device.manufacturer
+ )}
+
+ `
+ : html``}
+
+ ${INCOMPLETE_PAIRING_STATUSES.includes(this.device.pairing_status!)
+ ? html`
+
IEEE: ${this.device.ieee}
+
+ NWK: ${formatAsPaddedHex(this.device.nwk)}
+
+ `
+ : html``}
+
+ ${this.device.pairing_status === INITIALIZED
+ ? html`
+
+ `
+ : html``}
+
+
+ `;
+ }
+
+ 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;
+ }
+}
diff --git a/src/translations/en.json b/src/translations/en.json
index eceb15c8e3..e1902f4fc3 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -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"
},