From a919d07847c22a5f009ed50e18e1d384ab067735 Mon Sep 17 00:00:00 2001 From: DollarSign23 Date: Tue, 20 Aug 2024 07:34:49 +0200 Subject: [PATCH 01/12] Add new dashboard widget --- .../opnsense/www/js/widgets/Metadata/Nut.xml | 42 ++++ .../nut/src/opnsense/www/js/widgets/Nut.js | 213 ++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml create mode 100644 sysutils/nut/src/opnsense/www/js/widgets/Nut.js diff --git a/sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml b/sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml new file mode 100644 index 0000000000..235f524f01 --- /dev/null +++ b/sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml @@ -0,0 +1,42 @@ + + + Nut.js + + /api/nut/service/status + /api/nut/settings/get + /api/nut/diagnostics/upsstatus + + + NUT + UPS Model + UPS Status + Battery status + UPS Load + Battery level + Battery runtime + Output Power + Input Power + Self test + On line + On battery + Low battery + High battery + Battery needs to be replaced + Battery is charging + Battery is discharging + UPS bypass circuit is active + Performing runtime calibration + UPS is offline + UPS is overloaded + UPS is trimming voltage + UPS is boosting voltage + Forced Shutdown + Nut is not started. Click to configure Nut. + This widget only works with the Netclient driver. Click to configure the Netclient driver. + Remote NUT Server + h + m + s + + + \ No newline at end of file diff --git a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js new file mode 100644 index 0000000000..0e30757d44 --- /dev/null +++ b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2024 Ben 'DollarSign23'x + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +import BaseTableWidget from 'widget-base-table'; + +export default class NutNetclient extends BaseTableWidget { + constructor() { + super(); + this.timeoutPeriod = 1000; // Set a timeout period for AJAX calls or other timed operations. + } + + // Creates and returns the HTML structure for the widget, including a table without a header. + getMarkup() { + let $container = $('
'); // Create a container div. + let $nut_netclient_table = this.createTable('nut-netclient-table', { + headerPosition: 'none', // Disable table headers. + }); + $container.append($nut_netclient_table); // Append the table to the container. + return $container; // Return the container with the table. + } + + // Periodically called to update the widget's data and UI. + async onWidgetTick() { + // Fetch the NUT service status from the server. + const nut_status = await this.ajaxCall('/api/nut/service/status'); + + // If the service is not running, display a message and stop further processing. + if (nut_status.status !== 'running') { + $('#nut-netclient-table').html(`${this.translations.unconfigured}`); + return; + } + + // Fetch the NUT settings from the server. + const nut_settings = await this.ajaxCall('/api/nut/settings/get'); + + // // If netclient is not enabled, display a message and stop further processing. + // if (nut_settings.nut?.netclient?.enable !== "1") { + // $('#nut-netclient-table').html(`${this.translations.netclient_unconfigured}`); + // return; + // } + + // Fetch the UPS status data from the server. + const { response } = await this.ajaxCall('/api/nut/diagnostics/upsstatus'); + + // Parse the UPS status data into a key-value object. + const data = response.split('\n').reduce((acc, line) => { + const [key, value] = line.split(': '); + if (key) acc[key] = value; // Only add non-empty keys. + return acc; + }, {}); + + // Prepare the rows for the table based on the fetched data. + const rows = [ + // Display the remote server address if available. + nut_settings.nut?.netclient?.address && nut_settings.nut?.netclient?.address && nut_settings.nut?.netclient?.user && this.makeTextRow("netclient_remote_server", `${nut_settings.nut?.netclient?.user}@${nut_settings.nut?.netclient?.address}:${nut_settings.nut?.netclient?.port}`), + // Display the manufacturer and model if available. + data['device.mfr'] && data['device.model'] && this.makeTextRow("status_model", `${data['device.mfr']} - ${data['device.model']}`), + // Display the UPS Status if available. + data['ups.status'] && this.makeColoredTextRow('status_status', this.nutMapStatus(data['ups.status']), /OL/, /OB|LB|RB|DISCHRG/, data['ups.status']), + // Display the UPS load with percentage and optional nominal power. + data['ups.load'] && data['ups.realpower'] && this.makeUpsLoadRow('status_load', parseFloat(data['ups.load']), parseFloat(data['ups.realpower'])), + // Display the battery charge as a progress bar if available. + data['battery.charge'] && this.makeProgressBarRow("status_bcharge", parseFloat(data['battery.charge'])), + // Display the battery status if available. + data['battery.charger.status'] && this.makeTextRow('status_battery', data['battery.charger.status']), + // Display the formatted battery runtime if available. + data['battery.runtime'] && this.makeTextRow('status_timeleft', this.formatRuntime(parseInt(data['battery.runtime'], 10))), + // Display the input voltage and frequency if available. + data['input.voltage'] && data['input.frequency'] && this.makeTextRow('status_input_power', `${data['input.voltage']} V | ${data['input.frequency']} Hz`), + // Display the output voltage and frequency if available. + data['output.voltage'] && data['output.frequency'] && this.makeTextRow('status_output_power', `${data['output.voltage']} V | ${data['output.frequency']} Hz`), + // Display the result of the UPS self-test if available. + data['ups.test.result'] && this.makeTextRow('status_selftest', data['ups.test.result']), + ].filter(Boolean); // Remove any undefined or null rows. + + // Update the table with the prepared rows. + this.updateTable('nut-netclient-table', rows); + } + + // Formats the runtime (in seconds) into a human-readable format (hours, minutes, seconds). + formatRuntime(seconds) { + const hours = Math.floor(seconds / 3600); // Calculate full hours. + const minutes = Math.floor((seconds % 3600) / 60); // Calculate remaining full minutes. + const remainingSeconds = seconds % 60; // Calculate remaining seconds. + + let formattedTime = ''; + + if (hours > 0) { + formattedTime += `${hours}${this.translate('time_hours')} `; + } + if (minutes > 0 || hours > 0) { // Only show minutes if they are > 0 or hours are present. + formattedTime += `${minutes}${this.translate('time_minutes')} `; + } + formattedTime += `${remainingSeconds}${this.translate('time_seconds')}`; // Always show seconds. + + return formattedTime.trim(); // Remove any trailing spaces. + } + + // Create a mapping between UPS status codes and their corresponding translations + nutMapStatus(statusCode) { + const statusMapping = { + 'OL': this.translate('status_ol'), // On line (mains is present) + 'OB': this.translate('status_ob'), // On battery (mains is not present) + 'LB': this.translate('status_lb'), // Low battery + 'HB': this.translate('status_hb'), // High battery + 'RB': this.translate('status_rb'), // Battery needs to be replaced + 'CHRG': this.translate('status_chrg'), // Battery is charging + 'DISCHRG': this.translate('status_dischrg'), // Battery is discharging + 'BYPASS': this.translate('status_bypass'), // UPS bypass circuit is active (no battery protection available) + 'CAL': this.translate('status_cal'), // Performing runtime calibration (on battery) + 'OFF': this.translate('status_off'), // UPS is offline + 'OVER': this.translate('status_over'), // UPS is overloaded + 'TRIM': this.translate('status_trim'), // UPS is trimming incoming voltage + 'BOOST': this.translate('status_boost'), // UPS is boosting incoming voltage + 'FSD': this.translate('status_fsd'), // Forced Shutdown + }; + + // Return the mapped translation or the original status code if no translation is found + return statusMapping[statusCode] || statusCode; + } + + // Creates a row for the UPS load, including the percentage and optional nominal power. + makeUpsLoadRow(labelKey, loadpct, nompower) { + let text = loadpct.toFixed(1) + ' %'; + if (nompower) { + text += ` ( ~ ${nompower} W )`; + } + return this.makeProgressBarRow(labelKey, loadpct, text); + } + + // Creates a row with a progress bar, optionally including custom text. + makeProgressBarRow(labelKey, progress, progressText = `${progress.toFixed(1)} %`) { + const pb = this.makeProgressBar(progress, progressText); // Create the progress bar. + return this.makeRow(labelKey, pb); // Create a row with the progress bar. + } + + // Creates a row with text, applying color based on regular expressions. + makeColoredTextRow(labelKey, value, okRegexp, errRegexp, check_value = value) { + const textEl = $('').text(value); // Create a bold text element with the value. + + // Apply CSS classes based on regex matches. + if (okRegexp?.exec(check_value)) { + textEl.addClass('text-success'); + } else if (errRegexp?.exec(check_value)) { + textEl.addClass('text-danger'); + } else { + textEl.addClass('text-warning'); + } + + return this.makeRow(labelKey, textEl.prop('outerHTML')); // Create a row with the colored text. + } + + // Creates a progress bar with a text overlay. + makeProgressBar(progress, text) { + const $textEl = $('').text(text).css({ + position: 'absolute', + left: 0, + right: 0 + }); + + const $barEl = $('
').css({ + width: `${progress}%`, + zIndex: 0 + }); + + return $('
').append($barEl, $textEl).prop("outerHTML"); + } + + // Creates a text row for the table. + makeTextRow(labelKey, content) { + content = typeof content === 'string' ? content : content.value; // Ensure content is a string. + return this.makeRow(labelKey, content); // Create a row with the text content. + } + + // Creates a row with a label and content. + makeRow(labelKey, content) { + return [this.translate(labelKey), content]; + } + + // Translates a key into the corresponding text. + translate(key) { + let value = this.translations[key]; + if (value === undefined) { + console.error('Missing translation for ' + key); + value = key; // Fallback to the key itself if translation is missing. + } + return value; + } +} \ No newline at end of file From 98139ac910f79acee500eb15a503938df69229ce Mon Sep 17 00:00:00 2001 From: DollarSign23 Date: Tue, 20 Aug 2024 07:36:04 +0200 Subject: [PATCH 02/12] Fix Copyright notice --- sysutils/nut/src/opnsense/www/js/widgets/Nut.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js index 0e30757d44..88e5aa63d4 100644 --- a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js +++ b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js @@ -1,5 +1,6 @@ /* - * Copyright (C) 2024 Ben 'DollarSign23'x + * Copyright (C) 2024 Ben 'DollarSign23' + * Copyright (C) 2024 Nicola Pellegrini * All rights reserved. * * Redistribution and use in source and binary forms, with or without From a2f4f125cf1152bdc2080d2ffb752d020299cbb8 Mon Sep 17 00:00:00 2001 From: DollarSign23 Date: Tue, 20 Aug 2024 07:36:15 +0200 Subject: [PATCH 03/12] Add Changelog --- sysutils/nut/Makefile | 4 ++-- sysutils/nut/pkg-descr | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sysutils/nut/Makefile b/sysutils/nut/Makefile index 99334db4ce..727dd5766d 100644 --- a/sysutils/nut/Makefile +++ b/sysutils/nut/Makefile @@ -1,6 +1,6 @@ PLUGIN_NAME= nut -PLUGIN_VERSION= 1.8.1 -PLUGIN_REVISION= 2 +PLUGIN_VERSION= 1.9.0 +PLUGIN_REVISION= 1 PLUGIN_COMMENT= Network UPS Tools PLUGIN_DEPENDS= nut PLUGIN_MAINTAINER= m.muenz@gmail.com diff --git a/sysutils/nut/pkg-descr b/sysutils/nut/pkg-descr index 9f9fe6b37a..15131a87ad 100644 --- a/sysutils/nut/pkg-descr +++ b/sysutils/nut/pkg-descr @@ -9,6 +9,10 @@ and management interface. Plugin Changelog ---------------- +1.9 + +* Add dashboard widget + 1.8 * Add apcupsd-ups driver support From 0998a01f8e1c6904b52492f5db8d39cd538bb71a Mon Sep 17 00:00:00 2001 From: Franco Fichtner Date: Tue, 20 Aug 2024 07:51:25 +0200 Subject: [PATCH 04/12] Update sysutils/nut/Makefile --- sysutils/nut/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/sysutils/nut/Makefile b/sysutils/nut/Makefile index 727dd5766d..6a95cd0cf3 100644 --- a/sysutils/nut/Makefile +++ b/sysutils/nut/Makefile @@ -1,6 +1,5 @@ PLUGIN_NAME= nut PLUGIN_VERSION= 1.9.0 -PLUGIN_REVISION= 1 PLUGIN_COMMENT= Network UPS Tools PLUGIN_DEPENDS= nut PLUGIN_MAINTAINER= m.muenz@gmail.com From 3da477ae8d58d2b6bfa34d8c93492acf7e75962b Mon Sep 17 00:00:00 2001 From: Franco Fichtner Date: Tue, 20 Aug 2024 07:51:54 +0200 Subject: [PATCH 05/12] Update sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml --- sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml b/sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml index 235f524f01..139bd04861 100644 --- a/sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml +++ b/sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml @@ -39,4 +39,4 @@ s - \ No newline at end of file + From 324faa79ab9639b90479d1a98716544b0283348c Mon Sep 17 00:00:00 2001 From: Franco Fichtner Date: Tue, 20 Aug 2024 07:52:13 +0200 Subject: [PATCH 06/12] Update sysutils/nut/src/opnsense/www/js/widgets/Nut.js --- sysutils/nut/src/opnsense/www/js/widgets/Nut.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js index 88e5aa63d4..2ac9339902 100644 --- a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js +++ b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js @@ -211,4 +211,4 @@ export default class NutNetclient extends BaseTableWidget { } return value; } -} \ No newline at end of file +} From b904111646f18e91ad84a26b0bd9a942cfd31f6a Mon Sep 17 00:00:00 2001 From: DollarSign23 Date: Tue, 20 Aug 2024 15:06:14 +0200 Subject: [PATCH 07/12] Add overflow-y:scroll --- sysutils/nut/src/opnsense/www/js/widgets/Nut.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js index 2ac9339902..c7ff9827b9 100644 --- a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js +++ b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js @@ -34,6 +34,13 @@ export default class NutNetclient extends BaseTableWidget { this.timeoutPeriod = 1000; // Set a timeout period for AJAX calls or other timed operations. } + getGridOptions() { + return { + // Trigger overflow-y:scroll after 650px height + sizeToContent: 650 + }; + } + // Creates and returns the HTML structure for the widget, including a table without a header. getMarkup() { let $container = $('
'); // Create a container div. From 6063a3c3bb605e84612eb36bccb3cfcc059941b3 Mon Sep 17 00:00:00 2001 From: DollarSign23 Date: Tue, 20 Aug 2024 15:09:22 +0200 Subject: [PATCH 08/12] Improve variable names --- .../nut/src/opnsense/www/js/widgets/Nut.js | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js index c7ff9827b9..bb90ea25bc 100644 --- a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js +++ b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js @@ -54,10 +54,10 @@ export default class NutNetclient extends BaseTableWidget { // Periodically called to update the widget's data and UI. async onWidgetTick() { // Fetch the NUT service status from the server. - const nut_status = await this.ajaxCall('/api/nut/service/status'); + const nut_service_status = await this.ajaxCall('/api/nut/service/status'); // If the service is not running, display a message and stop further processing. - if (nut_status.status !== 'running') { + if (nut_service_status.status !== 'running') { $('#nut-netclient-table').html(`${this.translations.unconfigured}`); return; } @@ -72,10 +72,10 @@ export default class NutNetclient extends BaseTableWidget { // } // Fetch the UPS status data from the server. - const { response } = await this.ajaxCall('/api/nut/diagnostics/upsstatus'); + const { response: nut_ups_status_response } = await this.ajaxCall('/api/nut/diagnostics/upsstatus'); // Parse the UPS status data into a key-value object. - const data = response.split('\n').reduce((acc, line) => { + const nut_ups_status = nut_ups_status_response.split('\n').reduce((acc, line) => { const [key, value] = line.split(': '); if (key) acc[key] = value; // Only add non-empty keys. return acc; @@ -86,23 +86,23 @@ export default class NutNetclient extends BaseTableWidget { // Display the remote server address if available. nut_settings.nut?.netclient?.address && nut_settings.nut?.netclient?.address && nut_settings.nut?.netclient?.user && this.makeTextRow("netclient_remote_server", `${nut_settings.nut?.netclient?.user}@${nut_settings.nut?.netclient?.address}:${nut_settings.nut?.netclient?.port}`), // Display the manufacturer and model if available. - data['device.mfr'] && data['device.model'] && this.makeTextRow("status_model", `${data['device.mfr']} - ${data['device.model']}`), + nut_ups_status['device.mfr'] && nut_ups_status['device.model'] && this.makeTextRow("status_model", `${nut_ups_status['device.mfr']} - ${nut_ups_status['device.model']}`), // Display the UPS Status if available. - data['ups.status'] && this.makeColoredTextRow('status_status', this.nutMapStatus(data['ups.status']), /OL/, /OB|LB|RB|DISCHRG/, data['ups.status']), + nut_ups_status['ups.status'] && this.makeColoredTextRow('status_status', this.nutMapStatus(nut_ups_status['ups.status']), /OL/, /OB|LB|RB|DISCHRG/, nut_ups_status['ups.status']), // Display the UPS load with percentage and optional nominal power. - data['ups.load'] && data['ups.realpower'] && this.makeUpsLoadRow('status_load', parseFloat(data['ups.load']), parseFloat(data['ups.realpower'])), + nut_ups_status['ups.load'] && nut_ups_status['ups.realpower'] && this.makeUpsLoadRow('status_load', parseFloat(nut_ups_status['ups.load']), parseFloat(nut_ups_status['ups.realpower'])), // Display the battery charge as a progress bar if available. - data['battery.charge'] && this.makeProgressBarRow("status_bcharge", parseFloat(data['battery.charge'])), + nut_ups_status['battery.charge'] && this.makeProgressBarRow("status_bcharge", parseFloat(nut_ups_status['battery.charge'])), // Display the battery status if available. - data['battery.charger.status'] && this.makeTextRow('status_battery', data['battery.charger.status']), + nut_ups_status['battery.charger.status'] && this.makeTextRow('status_battery', nut_ups_status['battery.charger.status']), // Display the formatted battery runtime if available. - data['battery.runtime'] && this.makeTextRow('status_timeleft', this.formatRuntime(parseInt(data['battery.runtime'], 10))), + nut_ups_status['battery.runtime'] && this.makeTextRow('status_timeleft', this.formatRuntime(parseInt(nut_ups_status['battery.runtime'], 10))), // Display the input voltage and frequency if available. - data['input.voltage'] && data['input.frequency'] && this.makeTextRow('status_input_power', `${data['input.voltage']} V | ${data['input.frequency']} Hz`), + nut_ups_status['input.voltage'] && nut_ups_status['input.frequency'] && this.makeTextRow('status_input_power', `${nut_ups_status['input.voltage']} V | ${nut_ups_status['input.frequency']} Hz`), // Display the output voltage and frequency if available. - data['output.voltage'] && data['output.frequency'] && this.makeTextRow('status_output_power', `${data['output.voltage']} V | ${data['output.frequency']} Hz`), + nut_ups_status['output.voltage'] && nut_ups_status['output.frequency'] && this.makeTextRow('status_output_power', `${nut_ups_status['output.voltage']} V | ${nut_ups_status['output.frequency']} Hz`), // Display the result of the UPS self-test if available. - data['ups.test.result'] && this.makeTextRow('status_selftest', data['ups.test.result']), + nut_ups_status['ups.test.result'] && this.makeTextRow('status_selftest', nut_ups_status['ups.test.result']), ].filter(Boolean); // Remove any undefined or null rows. // Update the table with the prepared rows. From 5574ff13dd4d8808469c4bacbd1d730b30080e0e Mon Sep 17 00:00:00 2001 From: DollarSign23 Date: Tue, 20 Aug 2024 15:12:49 +0200 Subject: [PATCH 09/12] Add better error handling --- sysutils/nut/src/opnsense/www/js/widgets/Nut.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js index bb90ea25bc..da6a48f1de 100644 --- a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js +++ b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js @@ -57,7 +57,7 @@ export default class NutNetclient extends BaseTableWidget { const nut_service_status = await this.ajaxCall('/api/nut/service/status'); // If the service is not running, display a message and stop further processing. - if (nut_service_status.status !== 'running') { + if (!nut_service_status || nut_service_status.status !== 'running') { $('#nut-netclient-table').html(`${this.translations.unconfigured}`); return; } From 9a0abd06628ce1444303da0341c22ac9f6e766dc Mon Sep 17 00:00:00 2001 From: DollarSign23 Date: Tue, 20 Aug 2024 15:14:58 +0200 Subject: [PATCH 10/12] Add dataChanged method --- sysutils/nut/src/opnsense/www/js/widgets/Nut.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js index da6a48f1de..d2c528b398 100644 --- a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js +++ b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js @@ -81,6 +81,11 @@ export default class NutNetclient extends BaseTableWidget { return acc; }, {}); + // Use the dataChanged method to check if the data has changed since the last tick + if (!this.dataChanged('ups_status', nut_ups_status)) { + return; + } + // Prepare the rows for the table based on the fetched data. const rows = [ // Display the remote server address if available. From 719b74fc06195346b435093df9380c968a76621f Mon Sep 17 00:00:00 2001 From: DollarSign23 Date: Tue, 20 Aug 2024 15:25:21 +0200 Subject: [PATCH 11/12] Improve variable names --- sysutils/nut/src/opnsense/www/js/widgets/Nut.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js index d2c528b398..1b993b9afb 100644 --- a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js +++ b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js @@ -44,10 +44,10 @@ export default class NutNetclient extends BaseTableWidget { // Creates and returns the HTML structure for the widget, including a table without a header. getMarkup() { let $container = $('
'); // Create a container div. - let $nut_netclient_table = this.createTable('nut-netclient-table', { + let $nut_table = this.createTable('nut-table', { headerPosition: 'none', // Disable table headers. }); - $container.append($nut_netclient_table); // Append the table to the container. + $container.append($nut_table); // Append the table to the container. return $container; // Return the container with the table. } @@ -58,7 +58,7 @@ export default class NutNetclient extends BaseTableWidget { // If the service is not running, display a message and stop further processing. if (!nut_service_status || nut_service_status.status !== 'running') { - $('#nut-netclient-table').html(`${this.translations.unconfigured}`); + $('#nut-table').html(`${this.translations.unconfigured}`); return; } @@ -67,7 +67,7 @@ export default class NutNetclient extends BaseTableWidget { // // If netclient is not enabled, display a message and stop further processing. // if (nut_settings.nut?.netclient?.enable !== "1") { - // $('#nut-netclient-table').html(`${this.translations.netclient_unconfigured}`); + // $('#nut-table').html(`${this.translations.netclient_unconfigured}`); // return; // } @@ -111,7 +111,7 @@ export default class NutNetclient extends BaseTableWidget { ].filter(Boolean); // Remove any undefined or null rows. // Update the table with the prepared rows. - this.updateTable('nut-netclient-table', rows); + this.updateTable('nut-table', rows); } // Formats the runtime (in seconds) into a human-readable format (hours, minutes, seconds). From d063a3bf6c5adae43aabe0e652ab8649a79b4b62 Mon Sep 17 00:00:00 2001 From: DollarSign23 Date: Tue, 20 Aug 2024 15:59:28 +0200 Subject: [PATCH 12/12] Add UPS efficiency to the widget --- sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml | 1 + sysutils/nut/src/opnsense/www/js/widgets/Nut.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml b/sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml index 139bd04861..a3ebebf193 100644 --- a/sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml +++ b/sysutils/nut/src/opnsense/www/js/widgets/Metadata/Nut.xml @@ -12,6 +12,7 @@ UPS Status Battery status UPS Load + UPS Efficiency Battery level Battery runtime Output Power diff --git a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js index 1b993b9afb..af2e4c928f 100644 --- a/sysutils/nut/src/opnsense/www/js/widgets/Nut.js +++ b/sysutils/nut/src/opnsense/www/js/widgets/Nut.js @@ -106,6 +106,8 @@ export default class NutNetclient extends BaseTableWidget { nut_ups_status['input.voltage'] && nut_ups_status['input.frequency'] && this.makeTextRow('status_input_power', `${nut_ups_status['input.voltage']} V | ${nut_ups_status['input.frequency']} Hz`), // Display the output voltage and frequency if available. nut_ups_status['output.voltage'] && nut_ups_status['output.frequency'] && this.makeTextRow('status_output_power', `${nut_ups_status['output.voltage']} V | ${nut_ups_status['output.frequency']} Hz`), + // Display the result of the UPS efficiency if available. + nut_ups_status['ups.efficiency'] && this.makeTextRow('status_efficiency', `${nut_ups_status['ups.efficiency']}%`), // Display the result of the UPS self-test if available. nut_ups_status['ups.test.result'] && this.makeTextRow('status_selftest', nut_ups_status['ups.test.result']), ].filter(Boolean); // Remove any undefined or null rows.