Add support for zwave_js controller firmware updates (#15515)

This commit is contained in:
Raman Gupta 2023-02-22 11:54:53 -05:00 committed by GitHub
parent 5629346fc3
commit 19d721f193
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 140 additions and 84 deletions

View File

@ -108,7 +108,7 @@ enum RFRegion {
"Default (EU)" = 0xff,
}
export enum FirmwareUpdateStatus {
export enum NodeFirmwareUpdateStatus {
Error_Timeout = -1,
Error_Checksum = 0,
Error_TransmissionFailed = 1,
@ -124,6 +124,19 @@ export enum FirmwareUpdateStatus {
OK_RestartPending = 0xff,
}
export enum ControllerFirmwareUpdateStatus {
// An expected response was not received from the controller in time
Error_Timeout = 0,
/** The maximum number of retry attempts for a firmware fragments were reached */
Error_RetryLimitReached,
/** The update was aborted by the bootloader */
Error_Aborted,
/** This controller does not support firmware updates */
Error_NotSupported,
OK = 0xff,
}
export interface QRProvisioningInformation {
version: QRCodeVersion;
securityClasses: SecurityClass[];
@ -322,7 +335,7 @@ export interface ZWaveJSNodeStatusUpdatedMessage {
status: NodeStatus;
}
export interface ZWaveJSNodeFirmwareUpdateProgressMessage {
export interface ZWaveJSFirmwareUpdateProgressMessage {
event: "firmware update progress";
current_file: number;
total_files: number;
@ -333,12 +346,18 @@ export interface ZWaveJSNodeFirmwareUpdateProgressMessage {
export interface ZWaveJSNodeFirmwareUpdateFinishedMessage {
event: "firmware update finished";
status: FirmwareUpdateStatus;
status: NodeFirmwareUpdateStatus;
success: boolean;
wait_time?: number;
reinterview: boolean;
}
export interface ZWaveJSControllerFirmwareUpdateFinishedMessage {
event: "firmware update finished";
status: ControllerFirmwareUpdateStatus;
success: boolean;
}
export type ZWaveJSNodeFirmwareUpdateCapabilities =
| { firmware_upgradable: false }
| {
@ -760,8 +779,9 @@ export const subscribeZwaveNodeFirmwareUpdate = (
device_id: string,
callbackFunction: (
message:
| ZWaveJSFirmwareUpdateProgressMessage
| ZWaveJSControllerFirmwareUpdateFinishedMessage
| ZWaveJSNodeFirmwareUpdateFinishedMessage
| ZWaveJSNodeFirmwareUpdateProgressMessage
) => void
): Promise<UnsubscribeFunc> =>
hass.connection.subscribeMessage(

View File

@ -43,11 +43,14 @@ export const getZwaveDeviceActions = async (
const nodeStatus = await fetchZwaveNodeStatus(hass, device.id);
if (!nodeStatus || nodeStatus.is_controller_node) {
if (!nodeStatus) {
return [];
}
const actions = [
const actions: DeviceAction[] = [];
if (!nodeStatus.is_controller_node) {
actions.push(
{
label: hass.localize(
"ui.panel.config.zwave_js.device_info.device_config"
@ -92,10 +95,16 @@ export const getZwaveDeviceActions = async (
showZWaveJSNodeStatisticsDialog(el, {
device,
}),
},
];
}
);
}
if (!nodeStatus.ready || !nodeStatus.has_firmware_update_cc) {
if (
!(
nodeStatus.ready &&
(nodeStatus.is_controller_node || nodeStatus.has_firmware_update_cc)
)
) {
return actions;
}
@ -117,7 +126,9 @@ export const getZwaveDeviceActions = async (
(await fetchZwaveIsNodeFirmwareUpdateInProgress(hass, device.id)) ||
(await showConfirmationDialog(el, {
text: hass.localize(
"ui.panel.config.zwave_js.update_firmware.warning"
`ui.panel.config.zwave_js.update_firmware.${
nodeStatus.is_controller_node ? "warning_controller" : "warning"
}`
),
dismissText: hass.localize("ui.common.no"),
confirmText: hass.localize("ui.common.yes"),

View File

@ -15,17 +15,19 @@ import {
} from "../../../../../data/device_registry";
import {
abortZwaveNodeFirmwareUpdate,
ControllerFirmwareUpdateStatus,
fetchZwaveIsNodeFirmwareUpdateInProgress,
fetchZwaveNodeStatus,
FirmwareUpdateStatus,
NodeFirmwareUpdateStatus,
NodeStatus,
subscribeZwaveNodeStatus,
subscribeZwaveNodeFirmwareUpdate,
uploadFirmwareAndBeginUpdate,
ZWaveJSNodeFirmwareUpdateFinishedMessage,
ZWaveJSNodeFirmwareUpdateProgressMessage,
ZWaveJSFirmwareUpdateProgressMessage,
ZWaveJSNodeStatusUpdatedMessage,
ZWaveJSNodeStatus,
ZWaveJSControllerFirmwareUpdateFinishedMessage,
} from "../../../../../data/zwave_js";
import { haStyleDialog } from "../../../../../resources/styles";
import { HomeAssistant } from "../../../../../types";
@ -44,10 +46,12 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
@state() private _uploading = false;
@state()
private _updateFinishedMessage?: ZWaveJSNodeFirmwareUpdateFinishedMessage;
private _updateFinishedMessage?:
| ZWaveJSNodeFirmwareUpdateFinishedMessage
| ZWaveJSControllerFirmwareUpdateFinishedMessage;
@state()
private _updateProgressMessage?: ZWaveJSNodeFirmwareUpdateProgressMessage;
private _updateProgressMessage?: ZWaveJSFirmwareUpdateProgressMessage;
@state() private _updateInProgress = false;
@ -71,12 +75,11 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
public closeDialog(): void {
this._unsubscribeNodeFirmwareUpdate();
this._unsubscribeNodeStatus();
this.device =
this._updateProgressMessage =
this._updateFinishedMessage =
this._firmwareFile =
this._nodeStatus =
undefined;
this.device = undefined;
this._updateProgressMessage = undefined;
this._updateFinishedMessage = undefined;
this._firmwareFile = undefined;
this._nodeStatus = undefined;
this._uploading = this._updateInProgress = false;
fireEvent(this, "dialog-closed", { dialog: this.localName });
@ -111,18 +114,26 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
)}
</mwc-button>`;
const abortFirmwareUpdateButton = html`
const status = this._updateFinishedMessage
? this._updateFinishedMessage.success
? "success"
: "error"
: undefined;
const localizationKeySuffix = this._nodeStatus.is_controller_node
? "_controller"
: "";
const abortFirmwareUpdateButton = this._nodeStatus.is_controller_node
? html``
: html`
<mwc-button slot="primaryAction" @click=${this._abortFirmwareUpdate}>
${this.hass.localize("ui.panel.config.zwave_js.update_firmware.abort")}
${this.hass.localize(
"ui.panel.config.zwave_js.update_firmware.abort"
)}
</mwc-button>
`;
const status = this._updateFinishedMessage
? FirmwareUpdateStatus[this._updateFinishedMessage.status]
.split("_")[0]
.toLowerCase()
: undefined;
return html`
<ha-dialog
open
@ -137,7 +148,7 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
? html`
<p>
${this.hass.localize(
"ui.panel.config.zwave_js.update_firmware.introduction",
`ui.panel.config.zwave_js.update_firmware.introduction${localizationKeySuffix}`,
{
device: html`<strong>${this._deviceName}</strong>`,
}
@ -210,7 +221,9 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
: html`
<div class="flex-container">
<ha-svg-icon
.path=${status === "ok" ? mdiCheckCircle : mdiCloseCircle}
.path=${this._updateFinishedMessage!.success
? mdiCheckCircle
: mdiCloseCircle}
.class=${status}
></ha-svg-icon>
<div class="status">
@ -221,7 +234,11 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
device: html`<strong>${this._deviceName}</strong>`,
message: this.hass.localize(
`ui.panel.config.zwave_js.update_firmware.finished_status.${
FirmwareUpdateStatus[
this._nodeStatus.is_controller_node
? ControllerFirmwareUpdateStatus[
this._updateFinishedMessage!.status
]
: NodeFirmwareUpdateStatus[
this._updateFinishedMessage!.status
]
}`
@ -231,10 +248,10 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
</p>
</div>
</div>
${status === "ok"
${this._updateFinishedMessage!.success
? html`<p>
${this.hass.localize(
"ui.panel.config.zwave_js.update_firmware.finished_status.done"
`ui.panel.config.zwave_js.update_firmware.finished_status.done${localizationKeySuffix}`
)}
</p>`
: html`<p>
@ -345,8 +362,9 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
this.device.id,
(
message:
| ZWaveJSFirmwareUpdateProgressMessage
| ZWaveJSControllerFirmwareUpdateFinishedMessage
| ZWaveJSNodeFirmwareUpdateFinishedMessage
| ZWaveJSNodeFirmwareUpdateProgressMessage
) => {
if (message.event === "firmware update progress") {
if (!this._updateFinishedMessage) {
@ -378,7 +396,7 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
return [
haStyleDialog,
css`
.ok {
.success {
color: var(--success-color);
}

View File

@ -3688,7 +3688,9 @@
"update_firmware": {
"title": "Update Device Firmware",
"warning": "WARNING: Firmware updates can brick your device if you do not correctly follow the manufacturer's guidance. The Home Assistant and Z-Wave JS teams do not take any responsibility for any damages to your device as a result of the firmware update and will not be able to help you if you brick your device. Would you still like to continue?",
"warning_controller": "WARNING: Firmware updates can brick your controller if you do not use the right firmware files, or if you attempt to stop the firmware update before it completes. The Home Assistant and Z-Wave JS teams do not take any responsibility for any damages to your controller as a result of the firmware update and will not be able to help you if you brick your controller. Would you still like to continue?",
"introduction": "Select the firmware file you would like to use to update {device}.",
"introduction_controller": "Select the firmware file you would like to use to update {device}. Note that once you start a firmware update, you MUST wait for the update to complete.",
"upload_firmware": "Upload Firmware",
"upload_failed": "Upload Failed",
"begin_update": "Begin Firmware Update",
@ -3701,10 +3703,11 @@
"abort_failed": "Abort Failed",
"confirm_abort": "Are you sure you want to abort the firmware update on {device}?",
"finished_status": {
"ok": "Successfully updated firmware on {device}: {message}.",
"success": "Successfully updated firmware on {device}: {message}.",
"error": "Unable to update firmware on {device}: {message}.",
"try_again": "To attempt the firmware update again, select the new firmware file you would like to use.",
"done": "The firmware update is complete! If you want to attempt another firmware update on this device, please wait until it gets re-interviewed.",
"done_controller": "The firmware update is complete! Your controller is being restarted and your network will temporarily be unavailable.",
"Error_Timeout": "Timed Out",
"Error_Checksum": "Checksum Error",
"Error_TransmissionFailed": "Transmission Failed",
@ -3717,7 +3720,11 @@
"Error_InvalidHardwareVersion": "Invalid Hardware Version",
"OK_WaitingForActivation": "Waiting for Activation",
"OK_NoRestart": "No Restart",
"OK_RestartPending": "Restart Pending"
"OK_RestartPending": "Restart Pending",
"Error_RetryLimitReached": "Retry Limit Reached",
"Error_Aborted": "Update Aborted by Bootloader",
"Error_NotSupported": "Firmware Updates Not Supported",
"OK": "Success"
}
},
"logs": {