Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions src/data/zwave_js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ enum RFRegion {
"Default (EU)" = 0xff,
}

export enum FirmwareUpdateStatus {
export enum NodeFirmwareUpdateStatus {
Error_Timeout = -1,
Error_Checksum = 0,
Error_TransmissionFailed = 1,
Expand All @@ -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[];
Expand Down Expand Up @@ -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;
Expand All @@ -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 }
| {
Expand Down Expand Up @@ -747,8 +766,9 @@ export const subscribeZwaveNodeFirmwareUpdate = (
device_id: string,
callbackFunction: (
message:
| ZWaveJSFirmwareUpdateProgressMessage
| ZWaveJSControllerFirmwareUpdateFinishedMessage
| ZWaveJSNodeFirmwareUpdateFinishedMessage
| ZWaveJSNodeFirmwareUpdateProgressMessage
) => void
): Promise<UnsubscribeFunc> =>
hass.connection.subscribeMessage(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,59 +43,68 @@ export const getZwaveDeviceActions = async (

const nodeStatus = await fetchZwaveNodeStatus(hass, device.id);

if (!nodeStatus || nodeStatus.is_controller_node) {
if (!nodeStatus) {
return [];
}

const actions = [
{
label: hass.localize(
"ui.panel.config.zwave_js.device_info.device_config"
),
icon: mdiCog,
href: `/config/zwave_js/node_config/${device.id}?config_entry=${entryId}`,
},
{
label: hass.localize(
"ui.panel.config.zwave_js.device_info.reinterview_device"
),
icon: mdiChatQuestion,
action: () =>
showZWaveJSReinterviewNodeDialog(el, {
device_id: device.id,
}),
},
{
label: hass.localize("ui.panel.config.zwave_js.device_info.heal_node"),
icon: mdiHospitalBox,
action: () =>
showZWaveJSHealNodeDialog(el, {
device,
}),
},
{
label: hass.localize(
"ui.panel.config.zwave_js.device_info.remove_failed"
),
icon: mdiDeleteForever,
action: () =>
showZWaveJSRemoveFailedNodeDialog(el, {
device_id: device.id,
}),
},
{
label: hass.localize(
"ui.panel.config.zwave_js.device_info.node_statistics"
),
icon: mdiInformation,
action: () =>
showZWaveJSNodeStatisticsDialog(el, {
device,
}),
},
];
const actions: DeviceAction[] = [];

if (!nodeStatus.is_controller_node) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this extra if, if we are only adding actions when not is_controller_node

Copy link
Copy Markdown
Contributor Author

@raman325 raman325 Feb 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are adding actions if there is a controller node just for the firmware update but all of these actions come before the firmware update action in the list

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this possibly the confusing part because I moved the not operator outside of each individual check? I can move it back inside so each individual statement is easier to understand: https://github.com/home-assistant/frontend/pull/15515/files#diff-4834eb73ab93f8dfa87c03847b42ab8539d6b51909e48038a784dc80d08e2472R103-R106

actions.push(
{
label: hass.localize(
"ui.panel.config.zwave_js.device_info.device_config"
),
icon: mdiCog,
href: `/config/zwave_js/node_config/${device.id}?config_entry=${entryId}`,
},
{
label: hass.localize(
"ui.panel.config.zwave_js.device_info.reinterview_device"
),
icon: mdiChatQuestion,
action: () =>
showZWaveJSReinterviewNodeDialog(el, {
device_id: device.id,
}),
},
{
label: hass.localize("ui.panel.config.zwave_js.device_info.heal_node"),
icon: mdiHospitalBox,
action: () =>
showZWaveJSHealNodeDialog(el, {
device,
}),
},
{
label: hass.localize(
"ui.panel.config.zwave_js.device_info.remove_failed"
),
icon: mdiDeleteForever,
action: () =>
showZWaveJSRemoveFailedNodeDialog(el, {
device_id: device.id,
}),
},
{
label: hass.localize(
"ui.panel.config.zwave_js.device_info.node_statistics"
),
icon: mdiInformation,
action: () =>
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;
}

Expand All @@ -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"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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;

Expand All @@ -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 });
Expand Down Expand Up @@ -111,18 +114,26 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
)}
</mwc-button>`;

const abortFirmwareUpdateButton = html`
<mwc-button slot="primaryAction" @click=${this._abortFirmwareUpdate}>
${this.hass.localize("ui.panel.config.zwave_js.update_firmware.abort")}
</mwc-button>
`;

const status = this._updateFinishedMessage
? FirmwareUpdateStatus[this._updateFinishedMessage.status]
.split("_")[0]
.toLowerCase()
? 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"
)}
</mwc-button>
`;

return html`
<ha-dialog
open
Expand All @@ -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>`,
}
Expand Down Expand Up @@ -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">
Expand All @@ -221,20 +234,24 @@ 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._updateFinishedMessage!.status
]
this._nodeStatus.is_controller_node
? ControllerFirmwareUpdateStatus[
this._updateFinishedMessage!.status
]
: NodeFirmwareUpdateStatus[
this._updateFinishedMessage!.status
]
}`
),
}
)}
</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>
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -378,7 +396,7 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
return [
haStyleDialog,
css`
.ok {
.success {
color: var(--success-color);
}

Expand Down
11 changes: 9 additions & 2 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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": {
Expand Down