Skip to content

Config backup/restore, and don't key fan labels/groups to volatile hwmonN sysfs paths #11

Closed

Description

@mrjacobarussell

Labels and fan-group assignments in pwm_labels.cfg (and the per-group .cfg files) are keyed to full sysfs paths, e.g.:

/sys/devices/platform/nct6775.656/hwmon/hwmon4/pwm2=cpu
/sys/devices/pci0000:00/0000:00:14.0/usb1/1-14/1-14:1.0/0003:3904:F001.0005/hwmon/hwmon5/pwm9=JBOD_

Two parts of that path aren't stable across reboots/driver reloads:

  1. The hwmonN index itself is assigned by driver probe order at boot, not fixed per-device.
  2. For USB HID devices, the path includes a per-enumeration instance suffix (0003:3904:F001.0005 above) that increments every time the device re-enumerates — e.g. after a driver module reload/rebuild. I hit this directly: after rebuilding an out-of-tree USB HID fan-controller driver (unrelated kernel update), the device's instance suffix bumped from .0005 to .0008. Every saved label/group pointing at the old .0005 path is now permanently orphaned — the plugin can't match it to anything, so from the UI's perspective those fan assignments are just gone. Motherboard-header fans (nct6775, no USB enumeration) survived fine; only the USB-controller-driven group was wiped.

Asks:

  1. Export/import (backup/restore) for plugin config — one-click dump of pwm_labels.cfg + group .cfg files, and restore from a saved copy, so a renumbering event is at least recoverable instead of requiring a full manual re-assignment of every port.
  2. Key labels/groups by something less volatile than the full sysfs path — e.g. driver name + relative pwm index for platform devices, and for USB devices the VID:PID:serial (if the device exposes a serial) instead of the kernel-assigned enumeration instance, so labels survive re-probing/renumbering events.

Happy to test against a WIP branch if useful — this hit me twice during a driver rebuild cycle and cost a full re-assignment of a 10-port USB fan hub each time.

Activity

  1. andrebrait commented on Oct 4, 2026

    @andrebrait
    Owner

    Thanks for the detailed report. The path you quoted made the cause easy to pin down.

    Status: #12 fixes the orphaned labels and fan groups for your case. When the plugin starts, it now finds a USB fan controller that kept its USB port but changed its HID instance suffix (0003:3904:F001.0005 → .0008) and its hwmonN index. Labels and fan assignments then move to the new path. If you had already re-entered some of them by hand, the entries saved for the current path win, and two fans never end up on the same PWM output.

    On keying by something more stable: Linux has no fixed identifier for a physical fan. The most it gives us is the controller chip plus the channel the fan is plugged into. What makes the chip identity stable depends on the device type:

    • USB: VID:PID plus the USB serial number, if the device reports one. This survives renumbering and a move to another USB port.
    • USB without a serial: VID:PID plus the USB port path (for example 1-14). This is what Preserve fan assignments across USB re-enumeration and port moves #12 matches on. It survives renumbering and reboots, but not a move to another port.
    • Motherboard chips (nct6775 and similar): the platform device name, which is already stable. That's why your motherboard fans survived.

    So storing VID:PID:serial only helps over #12 if your hub reports a serial number. Could you run the following on your server and paste the output? It lists every USB device that provides PWM outputs, with its port, IDs and serial:

    for h in /sys/class/hwmon/hwmon*; do
      d=$(readlink -f "$h/device")
      case "$d" in */usb*) ;; *) continue ;; esac
      u=${d%/*}; u=${u%/*}   # HID device -> interface -> USB device
      echo "$(basename "$h") $(cat "$h/name") port=$(basename "$u")"
      for f in idVendor idProduct serial manufacturer product; do
        printf '  %-12s %s\n' "$f" "$(cat "$u/$f" 2>/dev/null || echo '(none)')"
      done
    done

    It would also help to know:

    1. Do you ever move the hub to a different USB port, or is it always on the same one?
    2. Do you have more than one identical controller (same VID:PID)?

    If the hub has no serial number, or always stays on the same port, #12 already covers your case. If it reports a serial and you do move it, I'll add serial-based matching on top of #12.

  2. mrjacobarussell commented on Oct 4, 2026

    @mrjacobarussell
    Author

    Thanks for the quick fix and the clear explanation. Ran the diagnostic:

    hwmon5 arctic_fan port=1-14
      idVendor     3904
      idProduct    f001
      serial       2080376E4548
      manufacturer ARCTIC (HK)
      product      ARCTIC Fan Controller
    

    It does report a serial number.

    Answers:

    1. Port stability: always the same internal USB port, never moved. Verified by rebooting just now and re-running the diagnostic — port path (1-14) was identical before and after reboot.
    2. Duplicates: just the one controller, no other device shares that VID:PID.

    So in my case #12 alone should already cover it (same port, no serial needed), but since the hub does report a serial, happy to test serial-based matching too if you add it on top — would make it robust against a future port move as well. Let me know if you want me to pull #12 and verify directly.

  3. mrjacobarussell commented on Oct 4, 2026

    @mrjacobarussell
    Author

    One more thing for anyone finding this thread: this ARCTIC Fan Controller is a great option for cheap, easy 10-port PWM fan control. A few setups I've used it in:

    • JBODs — ran an external USB cable into an internal USB header, passed through both the JBOD case and the main case, to reach the controller. Heat-shrunk the connection at the controller end so it wouldn't come loose.
    • High-amp fans — paired with a SATA-to-fan breakout connector (bypassing the controller's own power limit) to drive higher-draw fans. Example fan: https://www.amazon.com/dp/B09VGS3LND
    • A similar high-power fan/adapter combo that works the same way: https://www.amazon.com/dp/B093ST9W5L
    • This is the exact ARCTIC Fan Controller used above: https://www.amazon.com/dp/B0H28X4SSY

    Just sharing in case it helps anyone else's build.

  4. andrebrait commented on Oct 5, 2026

    @andrebrait
    Owner

    Serial-based matching is now included in #12. The plugin records a unique VID:PID + USB serial + controller interface/channel when labels or fan configurations are saved, and at service startup for existing entries it can still identify. That lets assignments follow the controller to another USB port—even with an identical model occupying its old port.

    A serial must be recorded before the move; a dead old path cannot tell us the device's serial retrospectively. Controllers without a unique serial keep the same-port behavior. Existing duplicate-serial controllers retain separate port assignments; previously recorded identities that become missing or ambiguous remain saved but cannot drive another device.

    All 25 tests and an isolated runtime smoke passed; CI is green and CodeRabbit completed review without actionable comments. This is still in the PR, not a released plugin package, and has not yet been tested on physical hardware.

  5. andrebrait commented on Oct 5, 2026

    @andrebrait
    Owner

    Released in 1.9.0: https://github.com/andrebrait/fanctrlplus/releases/tag/1.9.0

    This includes PWM10+ discovery/numeric ordering from #10 and the label/group recovery and serial-based USB port-move support from #12. The normal installer on main now points to the verified 1.9.0 package.

    Please back up /boot/config/plugins/fanctrlplus2/ before updating. Let the upgraded service start while the controller is still identifiable at its saved location so its serial is recorded before any port move. Restart the service after a driver reload or move.

    If you can confirm your ARCTIC controller's labels and fan assignments survive re-enumeration on 1.9.0, that would provide the physical-hardware validation; automated tests and packaged runtime/install smoke checks passed. The separate export/import request remains open.

  6. andrebrait commented on Oct 5, 2026

    @andrebrait
    Owner

    The backup/restore half is now in 1.9.1: https://github.com/andrebrait/fanctrlplus/releases/tag/1.9.1

    General Settings → Export backup downloads a JSON file with saved fan configurations, PWM labels (including the USB serial identities from 1.9.0), dashboard switches and fan order. Restore backup checks the whole file before replacing anything, rolls back on failure, and keeps fan control running or stopped as it was. Custom sensor scripts aren't included, so back those up separately, and keep backups off the flash drive. Feedback from your ARCTIC setup is welcome.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions