diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/SystemController.php b/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/SystemController.php
index b4f585c01..048b92293 100644
--- a/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/SystemController.php
+++ b/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/SystemController.php
@@ -236,10 +236,12 @@ class SystemController extends ApiControllerBase
foreach ($temps as $name => $value) {
$tempItem = [];
$tempItem['device'] = $name;
- $tempItem['device_seq'] = filter_var($tempItem['device'], FILTER_SANITIZE_NUMBER_INT); /* XXX too opportunistic */
+ $tempItem['device_seq'] = (int)filter_var($tempItem['device'], FILTER_SANITIZE_NUMBER_INT);
$tempItem['temperature'] = trim(str_replace('C', '', $value));
- $tempItem['type_translated'] = gettext('CPU');
- $tempItem['type'] = 'cpu';
+ $tempItem['type_translated'] = gettext('Other');
+ $tempItem['type'] = 'other';
+
+ /* try to categorize a few of the readings just for labels */
if (str_starts_with($tempItem['device'], 'hw.acpi.')) {
$tempItem['type_translated'] = gettext('Zone');
$tempItem['type'] = 'zone';
@@ -247,9 +249,13 @@ class SystemController extends ApiControllerBase
$tempItem['type_translated'] = gettext('AMD');
$tempItem['type'] = 'amd';
} else if (str_starts_with($tempItem['device'], 'dev.pchtherm.')) {
- $tempItem['type'] = 'platform';
$tempItem['type_translated'] = gettext('Platform');
+ $tempItem['type'] = 'platform';
+ } else if (str_starts_with($tempItem['device'], 'dev.cpu.')) {
+ $tempItem['type_translated'] = gettext('CPU');
+ $tempItem['type'] = 'cpu';
}
+
$result[] = $tempItem;
}
diff --git a/src/opnsense/www/js/widgets/ThermalSensors.js b/src/opnsense/www/js/widgets/ThermalSensors.js
index c7071f894..cc8792045 100644
--- a/src/opnsense/www/js/widgets/ThermalSensors.js
+++ b/src/opnsense/www/js/widgets/ThermalSensors.js
@@ -25,19 +25,22 @@
*/
export default class ThermalSensors extends BaseWidget {
- constructor() {
- super();
+ constructor(config) {
+ super(config);
this.chart = null;
this.width = null;
this.height = null;
this.colors = [];
+
+ this.configurable = true;
+ this.cachedSensors = []; // prevent fetch when loading options
}
getMarkup() {
return $(`
-
@@ -70,20 +73,20 @@ export default class ThermalSensors extends BaseWidget {
}
return this.colors;
},
+ categoryPercentage: 1.0,
barPercentage: 0.8,
borderWidth: 1,
borderSkipped: false,
borderRadius: 20,
- barThickness: 20
},
{
+ categoryPercentage: 1.0,
data: [],
backgroundColor: ['#E5E5E5'],
borderRadius: 20,
barPercentage: 0.5,
borderWidth: 1,
borderSkipped: true,
- barThickness: 10,
pointHitRadius: 0
}
]
@@ -98,15 +101,20 @@ export default class ThermalSensors extends BaseWidget {
}
let count = data.datasets[0].data.length;
ctx.save();
+
+ const margin = 10;
+ ctx.textBaseline = 'middle';
for (let i = 0; i < count; i++) {
const meta = chart.getDatasetMeta(0);
const xPos = meta.data[i].x;
const yPos = meta.data[i].y;
const barHeight = meta.data[i].height;
+ const textX = Math.max(chartArea.left + margin, xPos - 50);
+
ctx.font = 'semibold 12px sans-serif';
ctx.fillStyle = '#ffffff';
- ctx.fillText(`${data.datasets[0].data[i]}°C`, xPos - 50, yPos + barHeight / 4);
+ ctx.fillText(`${data.datasets[0].data[i]}°C`, textX, yPos);
}
ctx.restore();
}
@@ -177,33 +185,74 @@ export default class ThermalSensors extends BaseWidget {
$('.thermalsensors-info-icon').tooltip({container: 'body'});
}
+ async onWidgetOptionsChanged(options) {
+ // Intentionally not awaited to avoid blocking dialog close
+ this._updateSensors();
+ }
+
+ async getWidgetOptions() {
+ const data = this.cachedSensors.length > 0 ? this.cachedSensors : await this._fetchSensors();
+
+ return {
+ sensors: {
+ title: this.translations.title,
+ type: 'select_multiple',
+ options: data.map(({ device, device_seq, type_translated }) => {
+ return {
+ value: device,
+ label: `${type_translated} ${device_seq}`,
+ };
+ }),
+ default:data.map(({ device }) => device),
+ },
+ };
+ }
+
async onWidgetTick() {
+ const data = await this._fetchSensors();
+ this.cachedSensors = this._parseSensors(data);
+ this._updateSensors();
+ }
+
+ async _fetchSensors() {
const data = await this.ajaxCall('/api/diagnostics/system/systemTemperature');
- if (!data || !data.length) {
+ return data;
+ }
+
+ async _updateSensors() {
+ const data = this.cachedSensors;
+
+ if (!this.chart || data.length === 0) {
$(`.${this.id}-chart-container`).html(`
${this.translations.unconfigured}
`).css('margin', '2em auto')
return;
}
- let parsed = this._parseSensors(data);
- this._update(parsed);
- }
- _update(data = []) {
- if (!this.chart || data.length === 0) {
- return;
- }
+ const config = await this.getWidgetConfig();
this.colors = new Array(data.length).fill(0);
- data.forEach((value, index) => {
- this.chart.data.labels[index] = `${value.type_translated} ${value.device_seq}`;
- this.chart.data.datasets[0].data[index] = Math.max(1, Math.min(100, value.temperature));
- this.chart.data.datasets[0].metadata[index] = value;
- this.chart.data.datasets[1].data[index] = 100 - value.temperature;
+ this.chart.data.labels = [];
+ this.chart.data.datasets[0].data = [];
+ this.chart.data.datasets[0].metadata = [];
+ this.chart.data.datasets[1].data = [];
+
+ data.forEach((value) => {
+ if (!config.sensors.includes(value.device)) {
+ return;
+ }
+ this.chart.data.labels.push(`${value.type_translated} ${value.device_seq}`);
+ this.chart.data.datasets[0].data.push(Math.max(1, Math.min(100, value.temperature)));
+ this.chart.data.datasets[0].metadata.push(value);
+ this.chart.data.datasets[1].data.push(100 - value.temperature);
});
this.chart.canvas.parentNode.style.height = `${30 + (data.length * 30)}px`;
this.chart.update();
+
+ // Since we are modifying the chart height based on the data length,
+ // make sure we force the manager to recalculate the widget size.
+ this.config.callbacks.updateGrid();
}
_parseSensors(data) {