mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-29 12:16:39 +00:00
Add OZW Refresh Node Dialog (#6530)
This commit is contained in:
parent
39f24c41ad
commit
c4d8aba5c8
@ -1,4 +1,10 @@
|
|||||||
import { HomeAssistant } from "../types";
|
import { HomeAssistant } from "../types";
|
||||||
|
import { DeviceRegistryEntry } from "./device_registry";
|
||||||
|
|
||||||
|
export interface OZWNodeIdentifiers {
|
||||||
|
ozw_instance: number;
|
||||||
|
node_id: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OZWDevice {
|
export interface OZWDevice {
|
||||||
node_id: number;
|
node_id: number;
|
||||||
@ -7,15 +13,102 @@ export interface OZWDevice {
|
|||||||
is_failed: boolean;
|
is_failed: boolean;
|
||||||
is_zwave_plus: boolean;
|
is_zwave_plus: boolean;
|
||||||
ozw_instance: number;
|
ozw_instance: number;
|
||||||
|
event: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OZWDeviceMetaDataResponse {
|
||||||
|
node_id: number;
|
||||||
|
ozw_instance: number;
|
||||||
|
metadata: OZWDeviceMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OZWDeviceMetaData {
|
||||||
|
OZWInfoURL: string;
|
||||||
|
ZWAProductURL: string;
|
||||||
|
ProductPic: string;
|
||||||
|
Description: string;
|
||||||
|
ProductManualURL: string;
|
||||||
|
ProductPageURL: string;
|
||||||
|
InclusionHelp: string;
|
||||||
|
ExclusionHelp: string;
|
||||||
|
ResetHelp: string;
|
||||||
|
WakeupHelp: string;
|
||||||
|
ProductSupportURL: string;
|
||||||
|
Frequency: string;
|
||||||
|
Name: string;
|
||||||
|
ProductPicBase64: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const nodeQueryStages = [
|
||||||
|
"ProtocolInfo",
|
||||||
|
"Probe",
|
||||||
|
"WakeUp",
|
||||||
|
"ManufacturerSpecific1",
|
||||||
|
"NodeInfo",
|
||||||
|
"NodePlusInfo",
|
||||||
|
"ManufacturerSpecific2",
|
||||||
|
"Versions",
|
||||||
|
"Instances",
|
||||||
|
"Static",
|
||||||
|
"CacheLoad",
|
||||||
|
"Associations",
|
||||||
|
"Neighbors",
|
||||||
|
"Session",
|
||||||
|
"Dynamic",
|
||||||
|
"Configuration",
|
||||||
|
"Complete",
|
||||||
|
];
|
||||||
|
|
||||||
|
export const getIdentifiersFromDevice = function (
|
||||||
|
device: DeviceRegistryEntry
|
||||||
|
): OZWNodeIdentifiers | undefined {
|
||||||
|
if (!device) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ozwIdentifier = device.identifiers.find(
|
||||||
|
(identifier) => identifier[0] === "ozw"
|
||||||
|
);
|
||||||
|
if (!ozwIdentifier) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const identifiers = ozwIdentifier[1].split(".");
|
||||||
|
return {
|
||||||
|
node_id: parseInt(identifiers[1]),
|
||||||
|
ozw_instance: parseInt(identifiers[0]),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const fetchOZWNodeStatus = (
|
export const fetchOZWNodeStatus = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
ozw_instance: string,
|
ozw_instance: number,
|
||||||
node_id: string
|
node_id: number
|
||||||
): Promise<OZWDevice> =>
|
): Promise<OZWDevice> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "ozw/node_status",
|
type: "ozw/node_status",
|
||||||
ozw_instance: ozw_instance,
|
ozw_instance: ozw_instance,
|
||||||
node_id: node_id,
|
node_id: node_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const fetchOZWNodeMetadata = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
ozw_instance: number,
|
||||||
|
node_id: number
|
||||||
|
): Promise<OZWDeviceMetaDataResponse> =>
|
||||||
|
hass.callWS({
|
||||||
|
type: "ozw/node_metadata",
|
||||||
|
ozw_instance: ozw_instance,
|
||||||
|
node_id: node_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const refreshNodeInfo = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
ozw_instance: number,
|
||||||
|
node_id: number
|
||||||
|
): Promise<OZWDevice> =>
|
||||||
|
hass.callWS({
|
||||||
|
type: "ozw/refresh_node_info",
|
||||||
|
ozw_instance: ozw_instance,
|
||||||
|
node_id: node_id,
|
||||||
|
});
|
||||||
|
@ -12,7 +12,13 @@ import {
|
|||||||
import { DeviceRegistryEntry } from "../../../../../../data/device_registry";
|
import { DeviceRegistryEntry } from "../../../../../../data/device_registry";
|
||||||
import { haStyle } from "../../../../../../resources/styles";
|
import { haStyle } from "../../../../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../../../../types";
|
import { HomeAssistant } from "../../../../../../types";
|
||||||
import { OZWDevice, fetchOZWNodeStatus } from "../../../../../../data/ozw";
|
import {
|
||||||
|
OZWDevice,
|
||||||
|
fetchOZWNodeStatus,
|
||||||
|
getIdentifiersFromDevice,
|
||||||
|
OZWNodeIdentifiers,
|
||||||
|
} from "../../../../../../data/ozw";
|
||||||
|
import { showOZWRefreshNodeDialog } from "../../../../integrations/integration-panels/ozw/show-dialog-ozw-refresh-node";
|
||||||
|
|
||||||
@customElement("ha-device-info-ozw")
|
@customElement("ha-device-info-ozw")
|
||||||
export class HaDeviceInfoOzw extends LitElement {
|
export class HaDeviceInfoOzw extends LitElement {
|
||||||
@ -20,26 +26,34 @@ export class HaDeviceInfoOzw extends LitElement {
|
|||||||
|
|
||||||
@property() public device!: DeviceRegistryEntry;
|
@property() public device!: DeviceRegistryEntry;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
private node_id = 0;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
private ozw_instance = 1;
|
||||||
|
|
||||||
@internalProperty() private _ozwDevice?: OZWDevice;
|
@internalProperty() private _ozwDevice?: OZWDevice;
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues) {
|
protected updated(changedProperties: PropertyValues) {
|
||||||
if (changedProperties.has("device")) {
|
if (changedProperties.has("device")) {
|
||||||
this._fetchNodeDetails(this.device);
|
const identifiers:
|
||||||
|
| OZWNodeIdentifiers
|
||||||
|
| undefined = getIdentifiersFromDevice(this.device);
|
||||||
|
if (!identifiers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.ozw_instance = identifiers.ozw_instance;
|
||||||
|
this.node_id = identifiers.node_id;
|
||||||
|
|
||||||
|
this._fetchNodeDetails();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async _fetchNodeDetails(device) {
|
protected async _fetchNodeDetails() {
|
||||||
const ozwIdentifier = device.identifiers.find(
|
|
||||||
(identifier) => identifier[0] === "ozw"
|
|
||||||
);
|
|
||||||
if (!ozwIdentifier) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const identifiers = ozwIdentifier[1].split(".");
|
|
||||||
this._ozwDevice = await fetchOZWNodeStatus(
|
this._ozwDevice = await fetchOZWNodeStatus(
|
||||||
this.hass,
|
this.hass,
|
||||||
identifiers[0],
|
this.ozw_instance,
|
||||||
identifiers[1]
|
this.node_id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,9 +83,19 @@ export class HaDeviceInfoOzw extends LitElement {
|
|||||||
? this.hass.localize("ui.common.yes")
|
? this.hass.localize("ui.common.yes")
|
||||||
: this.hass.localize("ui.common.no")}
|
: this.hass.localize("ui.common.no")}
|
||||||
</div>
|
</div>
|
||||||
|
<mwc-button @click=${this._refreshNodeClicked}>
|
||||||
|
Refresh Node
|
||||||
|
</mwc-button>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _refreshNodeClicked() {
|
||||||
|
showOZWRefreshNodeDialog(this, {
|
||||||
|
node_id: this.node_id,
|
||||||
|
ozw_instance: this.ozw_instance,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
|
@ -0,0 +1,272 @@
|
|||||||
|
import {
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
internalProperty,
|
||||||
|
TemplateResult,
|
||||||
|
PropertyValues,
|
||||||
|
css,
|
||||||
|
} from "lit-element";
|
||||||
|
import "../../../../../components/ha-code-editor";
|
||||||
|
import "../../../../../components/ha-circular-progress";
|
||||||
|
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
||||||
|
import { haStyleDialog } from "../../../../../resources/styles";
|
||||||
|
import { HomeAssistant } from "../../../../../types";
|
||||||
|
import { OZWRefreshNodeDialogParams } from "./show-dialog-ozw-refresh-node";
|
||||||
|
|
||||||
|
import {
|
||||||
|
fetchOZWNodeMetadata,
|
||||||
|
OZWDeviceMetaData,
|
||||||
|
OZWDevice,
|
||||||
|
nodeQueryStages,
|
||||||
|
} from "../../../../../data/ozw";
|
||||||
|
|
||||||
|
@customElement("dialog-ozw-refresh-node")
|
||||||
|
class DialogOZWRefreshNode extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@internalProperty() private _node_id?: number;
|
||||||
|
|
||||||
|
@internalProperty() private _ozw_instance = 1;
|
||||||
|
|
||||||
|
@internalProperty() private _nodeMetaData?: OZWDeviceMetaData;
|
||||||
|
|
||||||
|
@internalProperty() private _node?: OZWDevice;
|
||||||
|
|
||||||
|
@internalProperty() private _active = false;
|
||||||
|
|
||||||
|
@internalProperty() private _complete = false;
|
||||||
|
|
||||||
|
private _refreshDevicesTimeoutHandle?: number;
|
||||||
|
|
||||||
|
private _subscribed?: Promise<() => Promise<void>>;
|
||||||
|
|
||||||
|
public disconnectedCallback(): void {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
this._unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
|
super.update(changedProperties);
|
||||||
|
if (changedProperties.has("node_id")) {
|
||||||
|
this._fetchData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _fetchData() {
|
||||||
|
if (!this._node_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const metaDataResponse = await fetchOZWNodeMetadata(
|
||||||
|
this.hass,
|
||||||
|
this._ozw_instance,
|
||||||
|
this._node_id
|
||||||
|
);
|
||||||
|
|
||||||
|
this._nodeMetaData = metaDataResponse.metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async showDialog(params: OZWRefreshNodeDialogParams): Promise<void> {
|
||||||
|
this._node_id = params.node_id;
|
||||||
|
this._ozw_instance = params.ozw_instance;
|
||||||
|
this._fetchData();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._node_id) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-dialog
|
||||||
|
open
|
||||||
|
@closing="${this._close}"
|
||||||
|
.heading=${createCloseHeading(
|
||||||
|
this.hass,
|
||||||
|
this.hass.localize("ui.panel.config.ozw.refresh_node.title")
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
${this._complete
|
||||||
|
? html`
|
||||||
|
<p>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.ozw.refresh_node.complete"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<mwc-button slot="primaryAction" @click=${this._close}>
|
||||||
|
${this.hass.localize("ui.common.close")}
|
||||||
|
</mwc-button>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
${this._active
|
||||||
|
? html`
|
||||||
|
<div class="flex-container">
|
||||||
|
<ha-circular-progress active></ha-circular-progress>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<b>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.ozw.refresh_node.refreshing_description"
|
||||||
|
)}
|
||||||
|
</b>
|
||||||
|
</p>
|
||||||
|
${this._node
|
||||||
|
? html`
|
||||||
|
<p>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.ozw.refresh_node.node_status"
|
||||||
|
)}:
|
||||||
|
${this._node.node_query_stage}
|
||||||
|
(${this.hass.localize(
|
||||||
|
"ui.panel.config.ozw.refresh_node.step"
|
||||||
|
)}
|
||||||
|
${nodeQueryStages.indexOf(
|
||||||
|
this._node.node_query_stage
|
||||||
|
) + 1}/17)
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<em>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.ozw.node_query_stages." +
|
||||||
|
this._node.node_query_stage.toLowerCase()
|
||||||
|
)}</em
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
: ``}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.ozw.refresh_node.description"
|
||||||
|
)}
|
||||||
|
<p>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.ozw.refresh_node.battery_note"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
`}
|
||||||
|
${this._nodeMetaData?.WakeupHelp !== ""
|
||||||
|
? html`
|
||||||
|
<b>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.ozw.refresh_node.wakeup_header"
|
||||||
|
)}
|
||||||
|
${this._nodeMetaData!.Name}
|
||||||
|
</b>
|
||||||
|
<blockquote>
|
||||||
|
${this._nodeMetaData!.WakeupHelp}
|
||||||
|
<br />
|
||||||
|
<em>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.ozw.refresh_node.wakeup_instructions_source"
|
||||||
|
)}
|
||||||
|
</em>
|
||||||
|
</blockquote>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${!this._active
|
||||||
|
? html`
|
||||||
|
<mwc-button
|
||||||
|
slot="primaryAction"
|
||||||
|
@click=${this._startRefresh}
|
||||||
|
>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.ozw.refresh_node.start_refresh_button"
|
||||||
|
)}
|
||||||
|
</mwc-button>
|
||||||
|
`
|
||||||
|
: html``}
|
||||||
|
`}
|
||||||
|
</ha-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _startRefresh(): void {
|
||||||
|
this._subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleMessage(message: any): void {
|
||||||
|
if (message.type === "node_updated") {
|
||||||
|
this._node = message;
|
||||||
|
if (message.node_query_stage === "Complete") {
|
||||||
|
this._unsubscribe();
|
||||||
|
this._complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _unsubscribe(): void {
|
||||||
|
this._active = false;
|
||||||
|
if (this._refreshDevicesTimeoutHandle) {
|
||||||
|
clearTimeout(this._refreshDevicesTimeoutHandle);
|
||||||
|
}
|
||||||
|
if (this._subscribed) {
|
||||||
|
this._subscribed.then((unsub) => unsub());
|
||||||
|
this._subscribed = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _subscribe(): void {
|
||||||
|
if (!this.hass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._active = true;
|
||||||
|
this._subscribed = this.hass.connection.subscribeMessage(
|
||||||
|
(message) => this._handleMessage(message),
|
||||||
|
{
|
||||||
|
type: "ozw/refresh_node_info",
|
||||||
|
node_id: this._node_id,
|
||||||
|
ozw_instance: this._ozw_instance,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this._refreshDevicesTimeoutHandle = window.setTimeout(
|
||||||
|
() => this._unsubscribe(),
|
||||||
|
120000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _close(): void {
|
||||||
|
this._complete = false;
|
||||||
|
this._node_id = undefined;
|
||||||
|
this._node = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return [
|
||||||
|
haStyleDialog,
|
||||||
|
css`
|
||||||
|
blockquote {
|
||||||
|
display: block;
|
||||||
|
background-color: #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
margin: 8px 0;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote em {
|
||||||
|
font-size: 0.9em;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-container ha-circular-progress {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"dialog-ozw-refresh-node": DialogOZWRefreshNode;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
|
|
||||||
|
export interface OZWRefreshNodeDialogParams {
|
||||||
|
ozw_instance: number;
|
||||||
|
node_id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loadRefreshNodeDialog = () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "dialog-ozw-refresh-node" */ "./dialog-ozw-refresh-node"
|
||||||
|
);
|
||||||
|
|
||||||
|
export const showOZWRefreshNodeDialog = (
|
||||||
|
element: HTMLElement,
|
||||||
|
refreshNodeDialogParams: OZWRefreshNodeDialogParams
|
||||||
|
): void => {
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "dialog-ozw-refresh-node",
|
||||||
|
dialogImport: loadRefreshNodeDialog,
|
||||||
|
dialogParams: refreshNodeDialogParams,
|
||||||
|
});
|
||||||
|
};
|
@ -1066,7 +1066,9 @@
|
|||||||
"label": "Repeat",
|
"label": "Repeat",
|
||||||
"type_select": "Repeat type",
|
"type_select": "Repeat type",
|
||||||
"type": {
|
"type": {
|
||||||
"count": { "label": "Count" },
|
"count": {
|
||||||
|
"label": "Count"
|
||||||
|
},
|
||||||
"while": {
|
"while": {
|
||||||
"label": "While",
|
"label": "While",
|
||||||
"conditions": "While conditions"
|
"conditions": "While conditions"
|
||||||
@ -1628,6 +1630,37 @@
|
|||||||
"zwave_info": "Z-Wave Info",
|
"zwave_info": "Z-Wave Info",
|
||||||
"stage": "Stage",
|
"stage": "Stage",
|
||||||
"node_failed": "Node Failed"
|
"node_failed": "Node Failed"
|
||||||
|
},
|
||||||
|
"node_query_stages": {
|
||||||
|
"protocolinfo": "Obtaining basic Z-Wave capabilities of this node from the controller",
|
||||||
|
"probe": "Checking if the node is awake/alive",
|
||||||
|
"wakeup": "Setting up support for wakeup queues and messages",
|
||||||
|
"manufacturerspecific1": "Obtaining manufacturer and product ID codes from the node",
|
||||||
|
"nodeinfo": "Obtaining supported command classes from the node",
|
||||||
|
"nodeplusinfo": "Obtaining Z-Wave+ information from the node",
|
||||||
|
"manufacturerspecific2": "Obtaining additional manufacturer and product ID codes from the node",
|
||||||
|
"versions": "Obtaining information about firmware and command class versions",
|
||||||
|
"instances": "Obtaining details about what instances or channels a device supports",
|
||||||
|
"static": "Obtaining static values from the device",
|
||||||
|
"cacheload": "Loading information from the OpenZWave cache file. Battery nodes will stay at this stage until the node wakes up.",
|
||||||
|
"associations": "Refreshing association groups and memberships",
|
||||||
|
"neighbors": "Obtaining a list of the node's neighbors",
|
||||||
|
"session": "Obtaining infrequently changing values from the node",
|
||||||
|
"dynamic": "Obtaining frequently changing values from the node",
|
||||||
|
"configuration": "Obtaining configuration values from the node",
|
||||||
|
"complete": "Interview process is complete"
|
||||||
|
},
|
||||||
|
"refresh_node": {
|
||||||
|
"title": "Refresh Node Information",
|
||||||
|
"complete": "Node Refresh Complete",
|
||||||
|
"description": "This will tell OpenZWave to re-interview a node and update the node's command classes, capabilities, and values.",
|
||||||
|
"battery_note": "If the node is battery powered, be sure to wake it before proceeding",
|
||||||
|
"wakeup_header": "Wakeup Instructions for",
|
||||||
|
"wakeup_instructions_source": "Wakeup instructions are sourced from the OpenZWave community device database.",
|
||||||
|
"start_refresh_button": "Start Refresh",
|
||||||
|
"refreshing_description": "Refreshing node information...",
|
||||||
|
"node_status": "Node Status",
|
||||||
|
"step": "Step"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"zha": {
|
"zha": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user