mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-09 10:26:35 +00:00
Add migration wizard for zwave -> zwave_js (#10097)
This commit is contained in:
parent
a89da0dac0
commit
8721776839
@ -73,14 +73,6 @@ export interface OZWDeviceConfig {
|
|||||||
help: string;
|
help: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OZWMigrationData {
|
|
||||||
migration_device_map: Record<string, string>;
|
|
||||||
zwave_entity_ids: string[];
|
|
||||||
ozw_entity_ids: string[];
|
|
||||||
migration_entity_map: Record<string, string>;
|
|
||||||
migrated: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const nodeQueryStages = [
|
export const nodeQueryStages = [
|
||||||
"ProtocolInfo",
|
"ProtocolInfo",
|
||||||
"Probe",
|
"Probe",
|
||||||
@ -219,12 +211,3 @@ export const refreshNodeInfo = (
|
|||||||
ozw_instance,
|
ozw_instance,
|
||||||
node_id,
|
node_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const migrateZwave = (
|
|
||||||
hass: HomeAssistant,
|
|
||||||
dry_run = true
|
|
||||||
): Promise<OZWMigrationData> =>
|
|
||||||
hass.callWS({
|
|
||||||
type: "ozw/migrate_zwave",
|
|
||||||
dry_run,
|
|
||||||
});
|
|
||||||
|
@ -60,11 +60,11 @@ export const fetchNetworkStatus = (
|
|||||||
type: "zwave/network_status",
|
type: "zwave/network_status",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const startOzwConfigFlow = (
|
export const startZwaveJsConfigFlow = (
|
||||||
hass: HomeAssistant
|
hass: HomeAssistant
|
||||||
): Promise<{ flow_id: string }> =>
|
): Promise<{ flow_id: string }> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zwave/start_ozw_config_flow",
|
type: "zwave/start_zwave_js_config_flow",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const fetchMigrationConfig = (
|
export const fetchMigrationConfig = (
|
||||||
|
@ -174,6 +174,25 @@ export interface RequestedGrant {
|
|||||||
|
|
||||||
export const nodeStatus = ["unknown", "asleep", "awake", "dead", "alive"];
|
export const nodeStatus = ["unknown", "asleep", "awake", "dead", "alive"];
|
||||||
|
|
||||||
|
export interface ZWaveJsMigrationData {
|
||||||
|
migration_device_map: Record<string, string>;
|
||||||
|
zwave_entity_ids: string[];
|
||||||
|
zwave_js_entity_ids: string[];
|
||||||
|
migration_entity_map: Record<string, string>;
|
||||||
|
migrated: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const migrateZwave = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry_id: string,
|
||||||
|
dry_run = true
|
||||||
|
): Promise<ZWaveJsMigrationData> =>
|
||||||
|
hass.callWS({
|
||||||
|
type: "zwave_js/migrate_zwave",
|
||||||
|
entry_id,
|
||||||
|
dry_run,
|
||||||
|
});
|
||||||
|
|
||||||
export const fetchNetworkStatus = (
|
export const fetchNetworkStatus = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entry_id: string
|
entry_id: string
|
||||||
@ -307,8 +326,8 @@ export const reinterviewNode = (
|
|||||||
(message: any) => callbackFunction(message),
|
(message: any) => callbackFunction(message),
|
||||||
{
|
{
|
||||||
type: "zwave_js/refresh_node_info",
|
type: "zwave_js/refresh_node_info",
|
||||||
entry_id: entry_id,
|
entry_id,
|
||||||
node_id: node_id,
|
node_id,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -319,8 +338,8 @@ export const healNode = (
|
|||||||
): Promise<boolean> =>
|
): Promise<boolean> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zwave_js/heal_node",
|
type: "zwave_js/heal_node",
|
||||||
entry_id: entry_id,
|
entry_id,
|
||||||
node_id: node_id,
|
node_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const removeFailedNode = (
|
export const removeFailedNode = (
|
||||||
@ -333,8 +352,8 @@ export const removeFailedNode = (
|
|||||||
(message: any) => callbackFunction(message),
|
(message: any) => callbackFunction(message),
|
||||||
{
|
{
|
||||||
type: "zwave_js/remove_failed_node",
|
type: "zwave_js/remove_failed_node",
|
||||||
entry_id: entry_id,
|
entry_id,
|
||||||
node_id: node_id,
|
node_id,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -344,7 +363,7 @@ export const healNetwork = (
|
|||||||
): Promise<UnsubscribeFunc> =>
|
): Promise<UnsubscribeFunc> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zwave_js/begin_healing_network",
|
type: "zwave_js/begin_healing_network",
|
||||||
entry_id: entry_id,
|
entry_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const stopHealNetwork = (
|
export const stopHealNetwork = (
|
||||||
@ -353,9 +372,24 @@ export const stopHealNetwork = (
|
|||||||
): Promise<UnsubscribeFunc> =>
|
): Promise<UnsubscribeFunc> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zwave_js/stop_healing_network",
|
type: "zwave_js/stop_healing_network",
|
||||||
entry_id: entry_id,
|
entry_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const subscribeNodeReady = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry_id: string,
|
||||||
|
node_id: number,
|
||||||
|
callbackFunction: (message) => void
|
||||||
|
): Promise<UnsubscribeFunc> =>
|
||||||
|
hass.connection.subscribeMessage(
|
||||||
|
(message: any) => callbackFunction(message),
|
||||||
|
{
|
||||||
|
type: "zwave_js/node_ready",
|
||||||
|
entry_id,
|
||||||
|
node_id,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export const subscribeHealNetworkProgress = (
|
export const subscribeHealNetworkProgress = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entry_id: string,
|
entry_id: string,
|
||||||
@ -365,7 +399,7 @@ export const subscribeHealNetworkProgress = (
|
|||||||
(message: any) => callbackFunction(message),
|
(message: any) => callbackFunction(message),
|
||||||
{
|
{
|
||||||
type: "zwave_js/subscribe_heal_network_progress",
|
type: "zwave_js/subscribe_heal_network_progress",
|
||||||
entry_id: entry_id,
|
entry_id,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -104,28 +104,14 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
<ha-config-section is-wide="[[isWide]]">
|
<ha-config-section is-wide="[[isWide]]">
|
||||||
<ha-card
|
<ha-card
|
||||||
class="content"
|
class="content"
|
||||||
header="[[localize('ui.panel.config.zwave.migration.ozw.header')]]"
|
header="[[localize('ui.panel.config.zwave.migration.zwave_js.header')]]"
|
||||||
>
|
>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p>
|
[[localize('ui.panel.config.zwave.migration.zwave_js.introduction')]]
|
||||||
If you are experiencing problems with your Z-Wave devices, you
|
|
||||||
can migrate to the newer OZW integration, that is currently in
|
|
||||||
beta.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Be aware that the future of OZW is not guaranteed, as the
|
|
||||||
development has stopped.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
If you are currently not experiencing issues with your Z-Wave
|
|
||||||
devices, we recommend you to wait for the successor of the OZW
|
|
||||||
integration, Z-Wave JS, that is in active development at the
|
|
||||||
moment.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<a href="/config/zwave/migration"
|
<a href="/config/zwave/migration"
|
||||||
><mwc-button>Start Migration to OZW</mwc-button></a
|
><mwc-button>Start Migration to Z-Wave JS</mwc-button></a
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
|
@ -6,7 +6,6 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { isComponentLoaded } from "../../../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../../../common/config/is_component_loaded";
|
||||||
import { computeStateName } from "../../../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../../../common/entity/compute_state_name";
|
||||||
import { navigate } from "../../../../../common/navigate";
|
|
||||||
import "../../../../../components/buttons/ha-call-api-button";
|
import "../../../../../components/buttons/ha-call-api-button";
|
||||||
import "../../../../../components/buttons/ha-call-service-button";
|
import "../../../../../components/buttons/ha-call-service-button";
|
||||||
import "../../../../../components/ha-card";
|
import "../../../../../components/ha-card";
|
||||||
@ -15,16 +14,25 @@ import "../../../../../components/ha-icon";
|
|||||||
import "../../../../../components/ha-icon-button";
|
import "../../../../../components/ha-icon-button";
|
||||||
import {
|
import {
|
||||||
computeDeviceName,
|
computeDeviceName,
|
||||||
|
DeviceRegistryEntry,
|
||||||
|
fetchDeviceRegistry,
|
||||||
subscribeDeviceRegistry,
|
subscribeDeviceRegistry,
|
||||||
} from "../../../../../data/device_registry";
|
} from "../../../../../data/device_registry";
|
||||||
import { migrateZwave, OZWMigrationData } from "../../../../../data/ozw";
|
import {
|
||||||
|
migrateZwave,
|
||||||
|
ZWaveJsMigrationData,
|
||||||
|
fetchNetworkStatus as fetchZwaveJsNetworkStatus,
|
||||||
|
fetchNodeStatus,
|
||||||
|
getIdentifiersFromDevice,
|
||||||
|
subscribeNodeReady,
|
||||||
|
} from "../../../../../data/zwave_js";
|
||||||
import {
|
import {
|
||||||
fetchMigrationConfig,
|
fetchMigrationConfig,
|
||||||
fetchNetworkStatus,
|
startZwaveJsConfigFlow,
|
||||||
startOzwConfigFlow,
|
|
||||||
ZWaveMigrationConfig,
|
ZWaveMigrationConfig,
|
||||||
ZWaveNetworkStatus,
|
ZWaveNetworkStatus,
|
||||||
ZWAVE_NETWORK_STATE_STOPPED,
|
ZWAVE_NETWORK_STATE_STOPPED,
|
||||||
|
fetchNetworkStatus,
|
||||||
} from "../../../../../data/zwave";
|
} from "../../../../../data/zwave";
|
||||||
import { showConfigFlowDialog } from "../../../../../dialogs/config-flow/show-dialog-config-flow";
|
import { showConfigFlowDialog } from "../../../../../dialogs/config-flow/show-dialog-config-flow";
|
||||||
import { showAlertDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
import { showAlertDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
||||||
@ -32,6 +40,8 @@ import "../../../../../layouts/hass-subpage";
|
|||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import type { HomeAssistant, Route } from "../../../../../types";
|
import type { HomeAssistant, Route } from "../../../../../types";
|
||||||
import "../../../ha-config-section";
|
import "../../../ha-config-section";
|
||||||
|
import { computeStateDomain } from "../../../../../common/entity/compute_state_domain";
|
||||||
|
import "../../../../../components/ha-alert";
|
||||||
|
|
||||||
@customElement("zwave-migration")
|
@customElement("zwave-migration")
|
||||||
export class ZwaveMigration extends LitElement {
|
export class ZwaveMigration extends LitElement {
|
||||||
@ -51,12 +61,18 @@ export class ZwaveMigration extends LitElement {
|
|||||||
|
|
||||||
@state() private _migrationConfig?: ZWaveMigrationConfig;
|
@state() private _migrationConfig?: ZWaveMigrationConfig;
|
||||||
|
|
||||||
@state() private _migrationData?: OZWMigrationData;
|
@state() private _migrationData?: ZWaveJsMigrationData;
|
||||||
|
|
||||||
@state() private _migratedZwaveEntities?: string[];
|
@state() private _migratedZwaveEntities?: string[];
|
||||||
|
|
||||||
@state() private _deviceNameLookup: { [id: string]: string } = {};
|
@state() private _deviceNameLookup: { [id: string]: string } = {};
|
||||||
|
|
||||||
|
@state() private _waitingOnDevices?: DeviceRegistryEntry[];
|
||||||
|
|
||||||
|
private _zwaveJsEntryId?: string;
|
||||||
|
|
||||||
|
private _nodeReadySubscriptions?: Promise<UnsubscribeFunc>[];
|
||||||
|
|
||||||
private _unsub?: Promise<UnsubscribeFunc>;
|
private _unsub?: Promise<UnsubscribeFunc>;
|
||||||
|
|
||||||
private _unsubDevices?: UnsubscribeFunc;
|
private _unsubDevices?: UnsubscribeFunc;
|
||||||
@ -79,259 +95,272 @@ export class ZwaveMigration extends LitElement {
|
|||||||
>
|
>
|
||||||
<ha-config-section .narrow=${this.narrow} .isWide=${this.isWide}>
|
<ha-config-section .narrow=${this.narrow} .isWide=${this.isWide}>
|
||||||
<div slot="header">
|
<div slot="header">
|
||||||
${this.hass.localize("ui.panel.config.zwave.migration.ozw.header")}
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave.migration.zwave_js.header"
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div slot="introduction">
|
<div slot="introduction">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.zwave.migration.ozw.introduction"
|
"ui.panel.config.zwave.migration.zwave_js.introduction"
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
${!isComponentLoaded(this.hass, "hassio") &&
|
${html`
|
||||||
!isComponentLoaded(this.hass, "mqtt")
|
${this._step === 0
|
||||||
? html`
|
? html`
|
||||||
<ha-card class="content" header="MQTT Required">
|
<ha-card class="content" header="Introduction">
|
||||||
|
<div class="card-content">
|
||||||
|
<p>
|
||||||
|
This wizard will walk through the following steps to
|
||||||
|
migrate from the legacy Z-Wave integration to Z-Wave JS.
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
<li>Stop the Z-Wave network</li>
|
||||||
|
${!isComponentLoaded(this.hass, "hassio")
|
||||||
|
? html`<li>Configure and start Z-Wave JS</li>`
|
||||||
|
: ""}
|
||||||
|
<li>Set up the Z-Wave JS integration</li>
|
||||||
|
<li>
|
||||||
|
Migrate entities and devices to the new integration
|
||||||
|
</li>
|
||||||
|
<li>Remove legacy Z-Wave integration</li>
|
||||||
|
</ol>
|
||||||
|
<p>
|
||||||
|
<b>
|
||||||
|
${isComponentLoaded(this.hass, "hassio")
|
||||||
|
? html`Please
|
||||||
|
<a href="/hassio/backups">make a backup</a>
|
||||||
|
before proceeding.`
|
||||||
|
: "Please make a backup of your installation before proceeding."}
|
||||||
|
</b>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="card-actions">
|
||||||
|
<mwc-button @click=${this._continue}>
|
||||||
|
Continue
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
`
|
||||||
|
: this._step === 1
|
||||||
|
? html`
|
||||||
|
<ha-card class="content" header="Stop Z-Wave Network">
|
||||||
|
<div class="card-content">
|
||||||
|
<p>
|
||||||
|
We need to stop the Z-Wave network to perform the
|
||||||
|
migration. Home Assistant will not be able to control
|
||||||
|
Z-Wave devices while the network is stopped.
|
||||||
|
</p>
|
||||||
|
${Object.values(this.hass.states)
|
||||||
|
.filter(
|
||||||
|
(entityState) =>
|
||||||
|
computeStateDomain(entityState) === "zwave" &&
|
||||||
|
entityState.state !== "ready"
|
||||||
|
)
|
||||||
|
.map(
|
||||||
|
(entityState) =>
|
||||||
|
html`<ha-alert alert-type="warning">
|
||||||
|
Device ${computeStateName(entityState)}
|
||||||
|
(${entityState.entity_id}) is not ready yet! For
|
||||||
|
the best result, wake the device up if it is
|
||||||
|
battery powered and wait for this device to become
|
||||||
|
ready.
|
||||||
|
</ha-alert>`
|
||||||
|
)}
|
||||||
|
${this._stoppingNetwork
|
||||||
|
? html`
|
||||||
|
<div class="flex-container">
|
||||||
|
<ha-circular-progress
|
||||||
|
active
|
||||||
|
></ha-circular-progress>
|
||||||
|
<div><p>Stopping Z-Wave Network...</p></div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ``}
|
||||||
|
</div>
|
||||||
|
<div class="card-actions">
|
||||||
|
<mwc-button @click=${this._stopNetwork}>
|
||||||
|
Stop Network
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
`
|
||||||
|
: this._step === 2
|
||||||
|
? html`
|
||||||
|
<ha-card class="content" header="Set up Z-Wave JS">
|
||||||
|
<div class="card-content">
|
||||||
|
<p>Now it's time to set up the Z-Wave JS integration.</p>
|
||||||
|
${isComponentLoaded(this.hass, "hassio")
|
||||||
|
? html`
|
||||||
|
<p>
|
||||||
|
Z-Wave JS runs as a Home Assistant add-on that
|
||||||
|
will be setup next. Make sure to check the
|
||||||
|
checkbox to use the add-on.
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<p>
|
||||||
|
You are not running Home Assistant OS (the default
|
||||||
|
installation type) or Home Assistant Supervised,
|
||||||
|
so we can not setup Z-Wave JS automaticaly. Follow
|
||||||
|
the
|
||||||
|
<a
|
||||||
|
href="https://www.home-assistant.io/integrations/zwave_js/#advanced-installation-instructions"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>advanced installation instructions</a
|
||||||
|
>
|
||||||
|
to install Z-Wave JS.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Here's the current Z-Wave configuration. You'll
|
||||||
|
need these values when setting up Z-Wave JS.
|
||||||
|
</p>
|
||||||
|
${this._migrationConfig
|
||||||
|
? html`<blockquote>
|
||||||
|
USB Path: ${this._migrationConfig.usb_path}<br />
|
||||||
|
Network Key:
|
||||||
|
${this._migrationConfig.network_key}
|
||||||
|
</blockquote>`
|
||||||
|
: ``}
|
||||||
|
<p>
|
||||||
|
Once Z-Wave JS is installed and running, click
|
||||||
|
'Continue' to set up the Z-Wave JS integration and
|
||||||
|
migrate your devices and entities.
|
||||||
|
</p>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
|
<div class="card-actions">
|
||||||
|
<mwc-button @click=${this._setupZwaveJs}>
|
||||||
|
Continue
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
`
|
||||||
|
: this._step === 3
|
||||||
|
? html`
|
||||||
|
<ha-card
|
||||||
|
class="content"
|
||||||
|
header="Migrate devices and entities"
|
||||||
|
>
|
||||||
|
<div class="card-content">
|
||||||
|
<p>
|
||||||
|
Now it's time to migrate your devices and entities from
|
||||||
|
the legacy Z-Wave integration to the Z-Wave JS
|
||||||
|
integration, to make sure all your UI's and automations
|
||||||
|
keep working.
|
||||||
|
</p>
|
||||||
|
${this._waitingOnDevices?.map(
|
||||||
|
(device) =>
|
||||||
|
html`<ha-alert alert-type="warning">
|
||||||
|
Device ${computeDeviceName(device, this.hass)} is
|
||||||
|
not ready yet! For the best result, wake the device
|
||||||
|
up if it is battery powered and wait for this device
|
||||||
|
to become ready.
|
||||||
|
</ha-alert>`
|
||||||
|
)}
|
||||||
|
${this._migrationData
|
||||||
|
? html`
|
||||||
|
<p>Below is a list of what will be migrated.</p>
|
||||||
|
${this._migratedZwaveEntities!.length !==
|
||||||
|
this._migrationData.zwave_entity_ids.length
|
||||||
|
? html`<ha-alert
|
||||||
|
alert-type="warning"
|
||||||
|
title="Not all entities can be migrated!"
|
||||||
|
>
|
||||||
|
The following entities will not be migrated
|
||||||
|
and might need manual adjustments to your
|
||||||
|
config:
|
||||||
|
</ha-alert>
|
||||||
|
<ul>
|
||||||
|
${this._migrationData.zwave_entity_ids.map(
|
||||||
|
(entity_id) =>
|
||||||
|
!this._migratedZwaveEntities!.includes(
|
||||||
|
entity_id
|
||||||
|
)
|
||||||
|
? html`<li>
|
||||||
|
${entity_id in this.hass.states
|
||||||
|
? computeStateName(
|
||||||
|
this.hass.states[entity_id]
|
||||||
|
)
|
||||||
|
: ""}
|
||||||
|
(${entity_id})
|
||||||
|
</li>`
|
||||||
|
: ""
|
||||||
|
)}
|
||||||
|
</ul>`
|
||||||
|
: ""}
|
||||||
|
${Object.keys(
|
||||||
|
this._migrationData.migration_device_map
|
||||||
|
).length
|
||||||
|
? html`<h3>Devices that will be migrated:</h3>
|
||||||
|
<ul>
|
||||||
|
${Object.keys(
|
||||||
|
this._migrationData.migration_device_map
|
||||||
|
).map(
|
||||||
|
(device_id) =>
|
||||||
|
html`<li>
|
||||||
|
${this._deviceNameLookup[device_id] ||
|
||||||
|
device_id}
|
||||||
|
</li>`
|
||||||
|
)}
|
||||||
|
</ul>`
|
||||||
|
: ""}
|
||||||
|
${Object.keys(
|
||||||
|
this._migrationData.migration_entity_map
|
||||||
|
).length
|
||||||
|
? html`<h3>Entities that will be migrated:</h3>
|
||||||
|
<ul>
|
||||||
|
${Object.keys(
|
||||||
|
this._migrationData.migration_entity_map
|
||||||
|
).map(
|
||||||
|
(entity_id) => html`<li>
|
||||||
|
${entity_id in this.hass.states
|
||||||
|
? computeStateName(
|
||||||
|
this.hass.states[entity_id]
|
||||||
|
)
|
||||||
|
: ""}
|
||||||
|
(${entity_id})
|
||||||
|
</li>`
|
||||||
|
)}
|
||||||
|
</ul>`
|
||||||
|
: ""}
|
||||||
|
`
|
||||||
|
: html` <div class="flex-container">
|
||||||
|
<p>Loading migration data...</p>
|
||||||
|
<ha-circular-progress active>
|
||||||
|
</ha-circular-progress>
|
||||||
|
</div>`}
|
||||||
|
</div>
|
||||||
|
<div class="card-actions">
|
||||||
|
<mwc-button @click=${this._doMigrate}>
|
||||||
|
Migrate
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
`
|
||||||
|
: this._step === 4
|
||||||
|
? html`<ha-card class="content" header="Done!">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
|
That was all! You are now migrated to the new Z-Wave JS
|
||||||
|
integration, check if all your devices and entities are back
|
||||||
|
the way they where, if not all entities could be migrated
|
||||||
|
you might have to change those manually.
|
||||||
<p>
|
<p>
|
||||||
OpenZWave requires MQTT. Please setup an MQTT broker and
|
If you have 'zwave' in your configurtion.yaml file, you
|
||||||
the MQTT integration to proceed with the migration.
|
should remove it now.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
<div class="card-actions">
|
||||||
`
|
<a
|
||||||
: html`
|
href=${`/config/zwave_js?config_entry=${this._zwaveJsEntryId}`}
|
||||||
${this._step === 0
|
>
|
||||||
? html`
|
<mwc-button> Go to Z-Wave JS config panel </mwc-button>
|
||||||
<ha-card class="content" header="Introduction">
|
</a>
|
||||||
<div class="card-content">
|
</div>
|
||||||
<p>
|
</ha-card>`
|
||||||
This wizard will walk through the following steps to
|
: ""}
|
||||||
migrate from the legacy Z-Wave integration to
|
`}
|
||||||
OpenZWave.
|
|
||||||
</p>
|
|
||||||
<ol>
|
|
||||||
<li>Stop the Z-Wave network</li>
|
|
||||||
<li>
|
|
||||||
<i
|
|
||||||
>If running Home Assistant Core in Docker or in
|
|
||||||
Python venv:</i
|
|
||||||
>
|
|
||||||
Configure and start OZWDaemon
|
|
||||||
</li>
|
|
||||||
<li>Set up the OpenZWave integration</li>
|
|
||||||
<li>
|
|
||||||
Migrate entities and devices to the new
|
|
||||||
integration
|
|
||||||
</li>
|
|
||||||
<li>Remove legacy Z-Wave integration</li>
|
|
||||||
</ol>
|
|
||||||
<p>
|
|
||||||
<b>
|
|
||||||
Please take a backup of your environment before
|
|
||||||
proceeding.
|
|
||||||
</b>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="card-actions">
|
|
||||||
<mwc-button @click=${this._continue}>
|
|
||||||
Continue
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`
|
|
||||||
: ``}
|
|
||||||
${this._step === 1
|
|
||||||
? html`
|
|
||||||
<ha-card class="content" header="Stop Z-Wave Network">
|
|
||||||
<div class="card-content">
|
|
||||||
<p>
|
|
||||||
We need to stop the Z-Wave network to perform the
|
|
||||||
migration. Home Assistant will not be able to
|
|
||||||
control Z-Wave devices while the network is stopped.
|
|
||||||
</p>
|
|
||||||
${this._stoppingNetwork
|
|
||||||
? html`
|
|
||||||
<div class="flex-container">
|
|
||||||
<ha-circular-progress
|
|
||||||
active
|
|
||||||
></ha-circular-progress>
|
|
||||||
<div><p>Stopping Z-Wave Network...</p></div>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ``}
|
|
||||||
</div>
|
|
||||||
<div class="card-actions">
|
|
||||||
<mwc-button @click=${this._stopNetwork}>
|
|
||||||
Stop Network
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`
|
|
||||||
: ``}
|
|
||||||
${this._step === 2
|
|
||||||
? html`
|
|
||||||
<ha-card class="content" header="Set up OZWDaemon">
|
|
||||||
<div class="card-content">
|
|
||||||
<p>Now it's time to set up the OZW integration.</p>
|
|
||||||
${isComponentLoaded(this.hass, "hassio")
|
|
||||||
? html`
|
|
||||||
<p>
|
|
||||||
The OZWDaemon runs in a Home Assistant addon
|
|
||||||
that will be setup next. Make sure to check
|
|
||||||
the checkbox for the addon.
|
|
||||||
</p>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<p>
|
|
||||||
If you're using Home Assistant Core in Docker
|
|
||||||
or a Python venv, see the
|
|
||||||
<a
|
|
||||||
href="https://github.com/OpenZWave/qt-openzwave/blob/master/README.md"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
OZWDaemon readme
|
|
||||||
</a>
|
|
||||||
for setup instructions.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Here's the current Z-Wave configuration.
|
|
||||||
You'll need these values when setting up OZW
|
|
||||||
daemon.
|
|
||||||
</p>
|
|
||||||
${this._migrationConfig
|
|
||||||
? html` <blockquote>
|
|
||||||
USB Path:
|
|
||||||
${this._migrationConfig.usb_path}<br />
|
|
||||||
Network Key:
|
|
||||||
${this._migrationConfig.network_key}
|
|
||||||
</blockquote>`
|
|
||||||
: ``}
|
|
||||||
<p>
|
|
||||||
Once OZWDaemon is installed, running, and
|
|
||||||
connected to the MQTT broker click Continue to
|
|
||||||
set up the OpenZWave integration and migrate
|
|
||||||
your devices and entities.
|
|
||||||
</p>
|
|
||||||
`}
|
|
||||||
</div>
|
|
||||||
<div class="card-actions">
|
|
||||||
<mwc-button @click=${this._setupOzw}>
|
|
||||||
Continue
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`
|
|
||||||
: ``}
|
|
||||||
${this._step === 3
|
|
||||||
? html`
|
|
||||||
<ha-card
|
|
||||||
class="content"
|
|
||||||
header="Migrate devices and entities"
|
|
||||||
>
|
|
||||||
<div class="card-content">
|
|
||||||
<p>
|
|
||||||
Now it's time to migrate your devices and entities
|
|
||||||
from the legacy Z-Wave integration to the OZW
|
|
||||||
integration, to make sure all your UI and
|
|
||||||
automations keep working.
|
|
||||||
</p>
|
|
||||||
${this._migrationData
|
|
||||||
? html`
|
|
||||||
<p>Below is a list of what will be migrated.</p>
|
|
||||||
${this._migratedZwaveEntities!.length !==
|
|
||||||
this._migrationData.zwave_entity_ids.length
|
|
||||||
? html`<h3 class="warning">
|
|
||||||
Not all entities can be migrated! The
|
|
||||||
following entities will not be migrated
|
|
||||||
and might need manual adjustments to
|
|
||||||
your config:
|
|
||||||
</h3>
|
|
||||||
<ul>
|
|
||||||
${this._migrationData.zwave_entity_ids.map(
|
|
||||||
(entity_id) =>
|
|
||||||
!this._migratedZwaveEntities!.includes(
|
|
||||||
entity_id
|
|
||||||
)
|
|
||||||
? html`<li>
|
|
||||||
${computeStateName(
|
|
||||||
this.hass.states[entity_id]
|
|
||||||
)}
|
|
||||||
(${entity_id})
|
|
||||||
</li>`
|
|
||||||
: ""
|
|
||||||
)}
|
|
||||||
</ul>`
|
|
||||||
: ""}
|
|
||||||
${Object.keys(
|
|
||||||
this._migrationData.migration_device_map
|
|
||||||
).length
|
|
||||||
? html`<h3>Devices that will be migrated:</h3>
|
|
||||||
<ul>
|
|
||||||
${Object.keys(
|
|
||||||
this._migrationData
|
|
||||||
.migration_device_map
|
|
||||||
).map(
|
|
||||||
(device_id) =>
|
|
||||||
html`<li>
|
|
||||||
${this._deviceNameLookup[
|
|
||||||
device_id
|
|
||||||
] || device_id}
|
|
||||||
</li>`
|
|
||||||
)}
|
|
||||||
</ul>`
|
|
||||||
: ""}
|
|
||||||
${Object.keys(
|
|
||||||
this._migrationData.migration_entity_map
|
|
||||||
).length
|
|
||||||
? html`<h3>
|
|
||||||
Entities that will be migrated:
|
|
||||||
</h3>
|
|
||||||
<ul>
|
|
||||||
${Object.keys(
|
|
||||||
this._migrationData
|
|
||||||
.migration_entity_map
|
|
||||||
).map(
|
|
||||||
(entity_id) => html`<li>
|
|
||||||
${computeStateName(
|
|
||||||
this.hass.states[entity_id]
|
|
||||||
)}
|
|
||||||
(${entity_id})
|
|
||||||
</li>`
|
|
||||||
)}
|
|
||||||
</ul>`
|
|
||||||
: ""}
|
|
||||||
`
|
|
||||||
: html` <div class="flex-container">
|
|
||||||
<p>Loading migration data...</p>
|
|
||||||
<ha-circular-progress active>
|
|
||||||
</ha-circular-progress>
|
|
||||||
</div>`}
|
|
||||||
</div>
|
|
||||||
<div class="card-actions">
|
|
||||||
<mwc-button @click=${this._doMigrate}>
|
|
||||||
Migrate
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`
|
|
||||||
: ``}
|
|
||||||
${this._step === 4
|
|
||||||
? html`<ha-card class="content" header="Done!">
|
|
||||||
<div class="card-content">
|
|
||||||
That was all! You are now migrated to the new OZW
|
|
||||||
integration, check if all your devices and entities are
|
|
||||||
back the way they where, if not all entities could be
|
|
||||||
migrated you might have to change those manually.
|
|
||||||
</div>
|
|
||||||
<div class="card-actions">
|
|
||||||
<mwc-button @click=${this._navigateOzw}>
|
|
||||||
Go to OZW config panel
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
</ha-card>`
|
|
||||||
: ""}
|
|
||||||
`}
|
|
||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
`;
|
`;
|
||||||
@ -367,29 +396,63 @@ export class ZwaveMigration extends LitElement {
|
|||||||
this.hass!.callService("zwave", "stop_network");
|
this.hass!.callService("zwave", "stop_network");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _setupOzw() {
|
private async _setupZwaveJs() {
|
||||||
const ozwConfigFlow = await startOzwConfigFlow(this.hass);
|
const zwaveJsConfigFlow = await startZwaveJsConfigFlow(this.hass);
|
||||||
if (isComponentLoaded(this.hass, "ozw")) {
|
|
||||||
this._getMigrationData();
|
|
||||||
this._step = 3;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
showConfigFlowDialog(this, {
|
showConfigFlowDialog(this, {
|
||||||
continueFlowId: ozwConfigFlow.flow_id,
|
continueFlowId: zwaveJsConfigFlow.flow_id,
|
||||||
dialogClosedCallback: () => {
|
dialogClosedCallback: (params) => {
|
||||||
if (isComponentLoaded(this.hass, "ozw")) {
|
if (params.entryId) {
|
||||||
this._getMigrationData();
|
this._zwaveJsEntryId = params.entryId;
|
||||||
|
this._getZwaveJSNodesStatus();
|
||||||
this._step = 3;
|
this._step = 3;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showAdvanced: this.hass.userData?.showAdvanced,
|
showAdvanced: this.hass.userData?.showAdvanced,
|
||||||
});
|
});
|
||||||
this.hass.loadBackendTranslation("title", "ozw", true);
|
this.hass.loadBackendTranslation("title", "zwave_js", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _getZwaveJSNodesStatus() {
|
||||||
|
if (this._nodeReadySubscriptions?.length) {
|
||||||
|
const unsubs = await Promise.all(this._nodeReadySubscriptions);
|
||||||
|
unsubs.forEach((unsub) => {
|
||||||
|
unsub();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this._nodeReadySubscriptions = [];
|
||||||
|
const networkStatus = await fetchZwaveJsNetworkStatus(
|
||||||
|
this.hass,
|
||||||
|
this._zwaveJsEntryId!
|
||||||
|
);
|
||||||
|
const nodeStatePromisses = networkStatus.controller.nodes.map((nodeId) =>
|
||||||
|
fetchNodeStatus(this.hass, this._zwaveJsEntryId!, nodeId)
|
||||||
|
);
|
||||||
|
const nodesNotReady = (await Promise.all(nodeStatePromisses)).filter(
|
||||||
|
(node) => !node.ready
|
||||||
|
);
|
||||||
|
this._getMigrationData();
|
||||||
|
if (nodesNotReady.length === 0) {
|
||||||
|
this._waitingOnDevices = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._nodeReadySubscriptions = nodesNotReady.map((node) =>
|
||||||
|
subscribeNodeReady(this.hass, this._zwaveJsEntryId!, node.node_id, () => {
|
||||||
|
this._getZwaveJSNodesStatus();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const deviceReg = await fetchDeviceRegistry(this.hass);
|
||||||
|
this._waitingOnDevices = deviceReg
|
||||||
|
.map((device) => getIdentifiersFromDevice(device))
|
||||||
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _getMigrationData() {
|
private async _getMigrationData() {
|
||||||
try {
|
try {
|
||||||
this._migrationData = await migrateZwave(this.hass, true);
|
this._migrationData = await migrateZwave(
|
||||||
|
this.hass,
|
||||||
|
this._zwaveJsEntryId!,
|
||||||
|
true
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Failed to get migration data!",
|
title: "Failed to get migration data!",
|
||||||
@ -430,7 +493,7 @@ export class ZwaveMigration extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _doMigrate() {
|
private async _doMigrate() {
|
||||||
const data = await migrateZwave(this.hass, false);
|
const data = await migrateZwave(this.hass, this._zwaveJsEntryId!, false);
|
||||||
if (!data.migrated) {
|
if (!data.migrated) {
|
||||||
showAlertDialog(this, { title: "Migration failed!" });
|
showAlertDialog(this, { title: "Migration failed!" });
|
||||||
return;
|
return;
|
||||||
@ -438,10 +501,6 @@ export class ZwaveMigration extends LitElement {
|
|||||||
this._step = 4;
|
this._step = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _navigateOzw() {
|
|
||||||
navigate("/config/ozw");
|
|
||||||
}
|
|
||||||
|
|
||||||
private _networkStopped(): void {
|
private _networkStopped(): void {
|
||||||
this._unsubscribe();
|
this._unsubscribe();
|
||||||
this._getMigrationConfig();
|
this._getMigrationConfig();
|
||||||
|
@ -2667,9 +2667,9 @@
|
|||||||
"wakeup_interval": "Wake-up Interval"
|
"wakeup_interval": "Wake-up Interval"
|
||||||
},
|
},
|
||||||
"migration": {
|
"migration": {
|
||||||
"ozw": {
|
"zwave_js": {
|
||||||
"header": "Migrate to OpenZWave",
|
"header": "Migrate to Z-Wave JS",
|
||||||
"introduction": "This wizard will help you migrate from the legacy Z-Wave integration to the OpenZWave integration that is currently in beta."
|
"introduction": "This integration is no longer maintained, and we advise you to move to the new Z-Wave JS integration. This wizard will help you migrate from the legacy Z-Wave integration to the new Z-Wave JS integration."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"network_management": {
|
"network_management": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user