diff --git a/sysutils/dmidecode/Makefile b/sysutils/dmidecode/Makefile
index 428d1621a..590aef8fa 100644
--- a/sysutils/dmidecode/Makefile
+++ b/sysutils/dmidecode/Makefile
@@ -1,6 +1,5 @@
PLUGIN_NAME= dmidecode
-PLUGIN_VERSION= 1.1
-PLUGIN_REVISION= 1
+PLUGIN_VERSION= 1.2
PLUGIN_COMMENT= Display hardware information on the dashboard
PLUGIN_DEPENDS= dmidecode
PLUGIN_MAINTAINER= evbevz@gmail.com
diff --git a/sysutils/dmidecode/src/www/widgets/widgets/dmidecode.widget.php b/sysutils/dmidecode/src/opnsense/mvc/app/controllers/OPNsense/DmiDecode/Api/ServiceController.php
similarity index 60%
rename from sysutils/dmidecode/src/www/widgets/widgets/dmidecode.widget.php
rename to sysutils/dmidecode/src/opnsense/mvc/app/controllers/OPNsense/DmiDecode/Api/ServiceController.php
index c1fc7723e..f586629bd 100644
--- a/sysutils/dmidecode/src/www/widgets/widgets/dmidecode.widget.php
+++ b/sysutils/dmidecode/src/opnsense/mvc/app/controllers/OPNsense/DmiDecode/Api/ServiceController.php
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2019 Smart-Soft
+ * Copyright (C) 2025 Neil Merchant
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,27 +27,18 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-require_once("widgets/include/dmidecode.inc");
+namespace OPNsense\DmiDecode\Api;
-$hardwareData = parse_ini_string(configd_run("dmidecode system"), FALSE, INI_SCANNER_RAW);
-$biosData = parse_ini_string(configd_run("dmidecode bios"), FALSE, INI_SCANNER_RAW);
+use OPNsense\Base\ApiControllerBase;
+use OPNsense\Core\Backend;
-?>
-
-
- | =gettext("Platform");?> |
- $val) { ?>
-
- | =gettext($key);?> |
- =html_safe($val);?> |
-
-
- | =gettext("BIOS");?> |
- $val) { ?>
-
- | =gettext($key);?> |
- =html_safe($val);?> |
-
-
-
-
+class ServiceController extends ApiControllerBase
+{
+ public function getAction()
+ {
+ $system = parse_ini_string(trim((new Backend())->configdRun('dmidecode system')), false, INI_SCANNER_RAW);
+ $bios = parse_ini_string(trim((new Backend())->configdRun('dmidecode bios')), false, INI_SCANNER_RAW);
+ $status = "ok";
+ return ["status" => $status, "system" => $system, "bios" => $bios];
+ }
+}
diff --git a/sysutils/dmidecode/src/opnsense/mvc/app/models/OPNsense/DmiDecode/ACL/ACL.xml b/sysutils/dmidecode/src/opnsense/mvc/app/models/OPNsense/DmiDecode/ACL/ACL.xml
new file mode 100644
index 000000000..a9f605462
--- /dev/null
+++ b/sysutils/dmidecode/src/opnsense/mvc/app/models/OPNsense/DmiDecode/ACL/ACL.xml
@@ -0,0 +1,8 @@
+
+
+ Service: DMI Decoder Widget
+
+ api/dmidecode/service/get
+
+
+
diff --git a/sysutils/dmidecode/src/opnsense/www/js/widgets/DmiDecode.js b/sysutils/dmidecode/src/opnsense/www/js/widgets/DmiDecode.js
new file mode 100644
index 000000000..89b5da183
--- /dev/null
+++ b/sysutils/dmidecode/src/opnsense/www/js/widgets/DmiDecode.js
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2025 Neil Merchant
+ * 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.
+ */
+
+export default class DmiDecode extends BaseTableWidget {
+ constructor() {
+ super();
+ this.title = 'DmiDecode Data';
+ }
+
+ getMarkup() {
+ let $container = $('');
+ // make table for system output, add header
+ let $system_table = super.createTable('system-table', { headerPosition: 'left' });
+ $container.append(`${this.translations.system}
`)
+ $container.append($system_table);
+ // same for bios output
+ let $bios_table = super.createTable('bios-table', { headerPosition: 'left' });
+ $container.append(`${this.translations.bios}
`)
+ $container.append($bios_table);
+ return $container;
+ }
+
+ async onMarkupRendered() {
+ const dmiData = await this.ajaxCall('/api/dmidecode/service/get');
+ if (!dmiData || dmiData?.status !== 'ok') {
+ this.displayError('dmi lookup failed');
+ return;
+ }
+ this.processDMIData(dmiData);
+ }
+
+ processDMIData(data) {
+ const sysrows = [];
+ for (const [key, value] of Object.entries(data.system)) {
+ const row = [];
+ // try to find translation for key, fallback to output value
+ // have to split on spaces here because those aren't valid in xml tags
+ const translationIndex = key.split(" ")[0]
+ const dispKey = this.translations[translationIndex] || key
+ row.push(`${dispKey}
`, `${value}
`);
+ sysrows.push(row);
+ }
+ const biosrows = [];
+ for (const [key, value] of Object.entries(data.bios)) {
+ const row = [];
+ // try to find translation for key, fallback to output value
+ // have to split on spaces here because those aren't valid in xml tags
+ const translationIndex = key.split(" ")[0]
+ const dispKey = this.translations[translationIndex] || key
+ row.push(`${dispKey}
`, `${value}
`);
+ biosrows.push(row);
+ }
+ super.updateTable('system-table', sysrows);
+ super.updateTable('bios-table', biosrows);
+ }
+
+ displayError(message) {
+ // if something went wrong, display error message in system table
+ const $error = $(`
+
+ ${message}
+
+ `);
+ $('#system-table').empty().append($error);
+}
+
+}
diff --git a/sysutils/dmidecode/src/opnsense/www/js/widgets/Metadata/DmiDecode.xml b/sysutils/dmidecode/src/opnsense/www/js/widgets/Metadata/DmiDecode.xml
new file mode 100644
index 000000000..6fedccf82
--- /dev/null
+++ b/sysutils/dmidecode/src/opnsense/www/js/widgets/Metadata/DmiDecode.xml
@@ -0,0 +1,20 @@
+
+
+ DmiDecode.js
+
+ /api/dmidecode/service/get
+
+
+ Hardware Information
+ Platform
+ BIOS
+ Manufacturer
+ Product Name
+ Version
+ Serial Number
+ Family
+ Vendor
+ Release Date
+
+
+
diff --git a/sysutils/dmidecode/src/www/widgets/include/dmidecode.inc b/sysutils/dmidecode/src/www/widgets/include/dmidecode.inc
deleted file mode 100644
index 0fd5de9f6..000000000
--- a/sysutils/dmidecode/src/www/widgets/include/dmidecode.inc
+++ /dev/null
@@ -1,3 +0,0 @@
-