Skip to content

Dashboard: support custom fan names on Airflow tile#2662

Open
mrjacobarussell wants to merge 2 commits into
unraid:masterfrom
mrjacobarussell:dashboard-fan-labels
Open

Dashboard: support custom fan names on Airflow tile#2662
mrjacobarussell wants to merge 2 commits into
unraid:masterfrom
mrjacobarussell:dashboard-fan-labels

Conversation

@mrjacobarussell

@mrjacobarussell mrjacobarussell commented Jun 10, 2026

Copy link
Copy Markdown

Summary

  • The Dashboard's Airflow tile labels fans sequentially as "FAN 1", "FAN 2"... based on sensors -uA enumeration order. This order frequently doesn't match the physical header labels printed on the motherboard (e.g. dashboard "FAN 1" may actually be the "PWM2" header).
  • This adds support for an optional /boot/config/plugins/dynamix/fan_names.json file (a JSON array, indexed in the same order sensors -uA reports fans) whose values override the generic "FAN N" label when present and non-empty. If the file doesn't exist, behavior is unchanged.

Companion plugin

A small plugin (https://github.com/mrjacobarussell/dashboard-fan-labels) provides a settings page (Settings -> Dashboard Fan Labels) that lists each detected fan sensor (chip, sensor name, live RPM) in the same order as the Dashboard, with a text field to assign a custom name. It writes to the fan_names.json path this PR reads.

Test plan

  • Verified on Unraid with a Corsair Commander Pro + motherboard sensors: without fan_names.json, dashboard shows "FAN 1".."FAN 6" as before.
  • With fan_names.json populated (e.g. ["CPU","Case Top","","Pump"]), tile shows custom names for indices 0,1,3 and falls back to "FAN 3" for the empty entry.
  • RPM values (get.fan[k] via nchan) are unaffected - only the static label changes.

Summary by CodeRabbit

  • New Features
    • Dashboard fan display now supports optional custom fan names loaded from a local configuration file. When valid custom labels exist they replace the default "FAN " identifiers; missing or invalid entries fall back to standard labels. Custom labels are safely rendered to ensure proper display.

The Airflow tile labels each detected fan sequentially as "FAN 1",
"FAN 2", etc. based on `sensors -uA` enumeration order, which often
doesn't match the physical header labels printed on the motherboard
(e.g. dashboard FAN 1 may actually be the motherboard's PWM2 header).

This adds an optional /boot/config/plugins/dynamix/fan_names.json
(JSON array, indexed in the same order as `sensors -uA`) whose values
override the generic "FAN N" label when present. Falls back to the
existing behavior if the file doesn't exist or an entry is empty.

A companion plugin (https://github.com/mrjacobarussell/dashboard-fan-labels)
provides a settings page to manage this file - it lists each detected
fan sensor (chip, sensor, live RPM) in Dashboard order so users can
assign meaningful names.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8a5a0c2f-32b3-4f4f-b6f2-d148d9463394

📥 Commits

Reviewing files that changed from the base of the PR and between f83d3d3 and 6b359c2.

📒 Files selected for processing (1)
  • emhttp/plugins/dynamix/DashStats.page
🚧 Files skipped from review as they are similar to previous changes (1)
  • emhttp/plugins/dynamix/DashStats.page

Walkthrough

Dashboard fan labels now optionally use per-fan names from /boot/config/plugins/dynamix/fan_names.json, mapping keys derived from sensors -uA ("<chip> - <fanN>") to custom (HTML-escaped) labels with fallback to translated FAN <n>.

Changes

Custom fan labels

Layer / File(s) Summary
Custom fan labels with fallback to defaults
emhttp/plugins/dynamix/DashStats.page
Loads and JSON-decodes fan_names.json, parses sensors -uA to build "<chip> - <fanN>" keys, and renders each fan label using the custom (HTML-escaped) name when present, otherwise FAN <n>.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I nibble JSON carrots by the fan,
Names take root where sensors ran.
If custom blooms, I proudly show —
else "FAN n" steals the show.
🐰🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Dashboard: support custom fan names on Airflow tile' directly describes the main change: adding support for custom fan names in the Dashboard Airflow tile, which aligns with the PR objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@emhttp/plugins/dynamix/DashStats.page`:
- Around line 809-814: The code uses $fan_names[$fan] without ensuring it's a
string before calling htmlspecialchars, which can cause runtime errors for
non-string JSON values; update the logic around $fan_label in the loop (the
handling that reads $fan_names_file, $fan_names and assigns $fan_label) to first
validate the value is a non-empty string (e.g. is_string($fan_names[$fan]) &&
$fan_names[$fan] !== '') and only then call htmlspecialchars on it, otherwise
fall back to the default _('FAN')." ".($fan+1); ensure the check replaces the
current !== '' test so malformed fan_names.json entries won't reach
htmlspecialchars.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7c0ab7ce-1493-466b-a4de-c93beb075493

📥 Commits

Reviewing files that changed from the base of the PR and between d9c5bbc and f83d3d3.

📒 Files selected for processing (1)
  • emhttp/plugins/dynamix/DashStats.page

Comment on lines +809 to +814
$fan_names = file_exists($fan_names_file) ? (json_decode(file_get_contents($fan_names_file), true) ?: []) : [];
for ($fan=0; $fan<$fans; $fan++) {
if ($fan > 0 && $fan % 3 == 0) $i++;
$class = $fan % 3 == 2 ? "" : " class='fan'";
$label[$i][] = "<span{$class}>"._('FAN')." ".($fan+1)."</span>";
$fan_label = ($fan_names[$fan] ?? '') !== '' ? htmlspecialchars($fan_names[$fan]) : _('FAN')." ".($fan+1);
$label[$i][] = "<span{$class}>$fan_label</span>";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate custom fan-name type before escaping.

At Line 813, non-string JSON values can pass the !== '' check and then reach htmlspecialchars(...), which can trigger runtime errors and break Airflow tile rendering for malformed fan_names.json.

Suggested fix
-$fan_names = file_exists($fan_names_file) ? (json_decode(file_get_contents($fan_names_file), true) ?: []) : [];
+$fan_names = file_exists($fan_names_file) ? json_decode(file_get_contents($fan_names_file), true) : [];
+if (!is_array($fan_names)) $fan_names = [];
 ...
-    $fan_label = ($fan_names[$fan] ?? '') !== '' ? htmlspecialchars($fan_names[$fan]) : _('FAN')." ".($fan+1);
+    $custom_name = $fan_names[$fan] ?? null;
+    $fan_label = (is_string($custom_name) && trim($custom_name) !== '')
+      ? htmlspecialchars($custom_name)
+      : _('FAN')." ".($fan+1);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$fan_names = file_exists($fan_names_file) ? (json_decode(file_get_contents($fan_names_file), true) ?: []) : [];
for ($fan=0; $fan<$fans; $fan++) {
if ($fan > 0 && $fan % 3 == 0) $i++;
$class = $fan % 3 == 2 ? "" : " class='fan'";
$label[$i][] = "<span{$class}>"._('FAN')." ".($fan+1)."</span>";
$fan_label = ($fan_names[$fan] ?? '') !== '' ? htmlspecialchars($fan_names[$fan]) : _('FAN')." ".($fan+1);
$label[$i][] = "<span{$class}>$fan_label</span>";
$fan_names = file_exists($fan_names_file) ? json_decode(file_get_contents($fan_names_file), true) : [];
if (!is_array($fan_names)) $fan_names = [];
for ($fan=0; $fan<$fans; $fan++) {
if ($fan > 0 && $fan % 3 == 0) $i++;
$class = $fan % 3 == 2 ? "" : " class='fan'";
$custom_name = $fan_names[$fan] ?? null;
$fan_label = (is_string($custom_name) && trim($custom_name) !== '')
? htmlspecialchars($custom_name)
: _('FAN')." ".($fan+1);
$label[$i][] = "<span{$class}>$fan_label</span>";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@emhttp/plugins/dynamix/DashStats.page` around lines 809 - 814, The code uses
$fan_names[$fan] without ensuring it's a string before calling htmlspecialchars,
which can cause runtime errors for non-string JSON values; update the logic
around $fan_label in the loop (the handling that reads $fan_names_file,
$fan_names and assigns $fan_label) to first validate the value is a non-empty
string (e.g. is_string($fan_names[$fan]) && $fan_names[$fan] !== '') and only
then call htmlspecialchars on it, otherwise fall back to the default _('FAN')."
".($fan+1); ensure the check replaces the current !== '' test so malformed
fan_names.json entries won't reach htmlspecialchars.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant