Repository navigation
Releases: ST-DEVPT/rack-fan-control
Releases · ST-DEVPT/rack-fan-control
Release list
v2.7.1
- An alerts file with an empty section (
"colors": null, an event set tonull), edited by hand, no
longer stops every alert and the control loop's checks; the defaults fill in. - The dashboard's polling never stops for good after one unexpected error, and the 24 h and 7 d charts
no longer show an error while the dashboard is offline (the banner already says so). - Bursts of connections through a reverse proxy wait in a deeper queue (64) instead of being refused.
v2.7.0
- Fan calibration: one button under the fan list steps the fans from 100 % down to 0 %, measures each
fan's RPM and the power draw at every step, and draws the curve. It says below which speed the fans turn
no slower, the lowest speed at which every fan kept turning, and what the fans cost in watts at full
speed, and puts the suggested minimum speed into the settings with one click. Every protection stays on;
when a fan stops at a low step, the steps above it still count. - Hand the fans to the BMC for a while: 1, 4 or 12 hours (any time up to a week through the API), for
maintenance or a stress test; control comes back on its own, also across a restart. - History as CSV: a button next to the chart's time range downloads it.
v2.6.2
- Dell: the BMC's warning thresholds are read again on servers that have one unreadable sensor (an empty
CPU socket, a PSU).ipmitool sensorlists every sensor and then exits with an error over that one; the
whole list was thrown away and the log said the thresholds could not be read. When they really cannot be,
the log now says why. - Errors say what happened: when a reverse proxy answers instead of Fan Control (502, 503, 504), the
message says so instead of a JSON parse error, and a request that never got an answer shows an error
instead of nothing. Every button reports failures the same way.
v2.6.1
- Minimum speed goes down to 0 % (it stopped at 10 %): fixed, curve and smart modes can run the fans as
slowly as the hardware allows. Lowering it still asks first, and a stopped fan still trips the failsafe. - A request that fails inside Fan Control answers 500 with the reason, and the log gets the traceback.
Before, the connection just closed, which a reverse proxy (Nginx Proxy Manager and the like) shows as an
opaque 502 with the cause nowhere. - Refusals no longer reset the connection: the request body is read before a 403, 415 or 400, so a proxy
passes the refusal on instead of a 502. A server busy with 64 requests answers 503 instead of dropping
the 65th.Content-Type: application/json; charset=utf-8is accepted.
v2.6.0
Engineering, from an independent review: what keeps the other five areas true over time.
- Browser tests run against the built image on every push: every page loads without a script error and
passes axe (WCAG 2 AA), the curve is edited by field and by keyboard, a change that reduces cooling asks
first, invalid values say so, Portuguese is complete on screen, the phone layout fits, a widget token reads
widgets and nothing else, a viewer cannot change anything. They found and fixed: curve points losing the
keyboard focus on every refresh in current Chromium, faded text under contrast, small buttons on touch
screens, an unlabelled file field and scroll areas the keyboard could not reach. - CI: ruff, a check that each page's scripts never declare a name twice, shellcheck, promtool on the
alert rules, tests on Python 3.10 to 3.13, Docker's health check,docker stophanding the fans back, and a
Trivy scan of the image. Actions are pinned by commit, the base image by digest, both kept current by
Dependabot; images carry an SBOM and provenance; a tag without its CHANGELOG section is refused. - The image has no pip or setuptools (the app installs nothing), and with them went the four HIGH
vulnerabilities of the libraries they bundle. - Routes declare their access (public, widget, viewer, admin) and one dispatcher checks it; a test walks
the table. No route can be open because of where it sits. - Logging through the standard library, with ISO-8601 times;
LOG_FORMAT=jsonfor log collectors. - Metrics: counters for BMC errors, fan commands, refused commands, failsafe trips and alerts, the
control loop's last tick, failed fans; and a file of Prometheus alert rules. - Backups include what smart mode learned. Tests load data files as 1.x and 2.0 wrote them.
fan-guard.shis shellcheck-clean and tested in the suite. One sharedutil.jsfor every page.- Quiet hours from a time to the same time now mean the whole day, as schedule profiles already did.
v2.5.0
The dashboard, for people who are not engineers and for phones, from an independent review.
- The control panel puts the essentials first: mode, failsafe, minimum speed and quiet hours. Exhaust
and sensor limits, ramp-down, schedule, dry run and PCIe cooling sit under More protection and
smoothing. Help texts say what happens ("the BMC takes the fans back"). - Applying a change that reduces cooling asks first and lists what is reduced: a lower minimum speed,
a higher failsafe, a limit turned off, a curve that runs the fans slow when hot. - Out-of-range values are no longer dropped in silence: the field turns red and says what it accepts.
- The fan curve works by touch and keyboard: every point is also a pair of fields, points can be added
and removed with buttons, and a focused point moves with the arrow keys (Shift for steps of 5) or goes
with Delete. - Phones: a compact header that scrolls away (pages and servers each slide sideways), and 40 px touch
targets on touch screens. - Contrast meets WCAG AA in both themes (secondary text, the accent, alerts); the two themes come from
one set of colour tokens. - Offline is visible: a banner says when the dashboard cannot be reached and since when, and the
readings below are dimmed. Polling pauses in hidden tabs and never piles up requests. - The status dots in the sidebar have text for screen readers, and "hot" means the same everywhere: within
5 °C of that server's failsafe. The BMC error box is no longer re-announced every 5 seconds. - The chart keeps its crosshair under the pointer across refreshes; resizing redraws once.
- Leaving the Alerts page with unsaved changes asks first, like the server page.
- Adding a server leads with the network scan; an empty name becomes the address, never the example.
- Navigation: Overview, then servers, then settings (Alerts, Prometheus, Grafana, Homarr, Backup).
- Portuguese: sentences split by links or code are translated whole; the one-word fragments that used to
translate any matching text anywhere are gone, and a test keeps it that way.
v2.4.0
Security, from an independent review.
- X-Forwarded-For is read from the right and only believed from trusted proxies (
TRUSTED_PROXIES,
by default loopback and Docker's networks). Before, the leftmost address, which the client writes, was
used, so a client could dodge the sign-in limit by inventing a new address for every guess. - Sessions can be revoked: signing out ends that session on the server, even if the cookie was copied,
and Sign out everywhere on the Backup page ends them all. Sessions from before this version end once. - BMC certificates are pinned on first use: a Redfish BMC that suddenly shows another certificate is
refused instead of being sent the password. A replaced certificate is accepted from the server's page. - At most 64 requests at once; the table of failed sign-ins is bounded.
- Alert channels refuse redirects to other hosts and link-local addresses.
- Viewers can no longer read BMC account names; diagnostics leave the BMC address out of events too.
- The BMC error box is announced to screen readers only when it changes.
v2.3.0
Hardware safety: when the controller does not know, the BMC decides.
- No CPU reading means automatic. Another sensor (inlet air, a DIMM) no longer stands in for the CPU.
- An unreadable BMC gets the fans back as soon as it takes a command, instead of keeping the last
manual speed with nobody watching. - Lost or faulty sensors and failed fans trip the failsafe, and so does a BMC that ignored a fan
command (manual control is tried again after 10 minutes). - The failsafe holds for at least 5 minutes, and manual control resumes from 50 %, easing down, so
fans no longer flap between the BMC and the controller. - Minimum speed is 20 % by default and 10 % at the lowest; the failsafe goes up to 90 °C. Older
settings outside these limits are brought inside them, never refused. - Supermicro: the fan mode the BMC had (HeavyIO on a GPU box, say) is read once, kept on disk and
restored, instead of always Optimal; never below 25 %; X9 is no longer claimed (it needs other commands). - HPE iLO 4 unlocked: a failed release is now reported instead of silently leaving a low cap.
- docker stop releases every server at once after stopping every loop, and the example compose file
allows 60 s. The watchdog no longer waits on a stuck loop's lock. - BMC warning thresholds that could not be read are retried every 10 minutes, and the dashboard says so.
- Smart mode takes the fans' own power out of the load signal and carries the learned map at most
15 % past its last point. It was re-checked against a harsher simulation: readings every 15 s and 10 s
old, fans that stall below 8 %, heat transfer that saturates with airflow, two CPUs sharing air. - The control loop is split into read, protect, choose speed, command and report.
v2.2.1
Fixes from an independent review of 2.2.0.
- fan-guard found the container by a fixed name,
idrac_fan_web, which the example compose file does
not use: with it, the guard took a running Fan Control for dead and handed the fans to the BMC every
minute. It now finds the container by its image, leaves a removed container alone, also acts when Docker
is down, and covers Supermicro and HPE iLO 4 unlocked as well as Dell. It refuses an.envothers can
write and keeps its state in/run. - Data files are written atomically and durably: a unique temporary file, flushed to disk, renamed,
and the folder flushed too. Two writers can no longer collide on one temporary file, and files with
passwords or tokens are private from the first byte. - A corrupt or invalid settings file now means automatic fans, logged once, instead of falling back
to the default curve. A corruptservers.json,alerts.jsonortokens.jsonis kept aside as
<name>.corrupt-<time>instead of being overwritten by the next save. - A negative or malformed
Content-Lengthis refused before anything is read. - The server page and history are copied under the lock and sent after it, so a slow browser can no
longer hold up a control loop. Events are logged under the lock. - A backup without secrets no longer contains the ntfy, Gotify or webhook addresses and tokens.
v2.2.0
- Watchdog. A control loop that stops turning for 3 minutes hands every fan back to its BMC and
restarts the process. The health check follows the control loops (/livez), not the BMCs.
scripts/fan-guard.sh, run from the host's cron, hands Dell fans back to the iDRAC when the container
itself is gone. - Fans are checked. New alerts for a fan that stops while the others spin, a BMC whose fans do not
follow a 20-point speed change within 30 s, a failsafe that lasts longer than a set time, and inlet air
above a warning temperature. - Alerts on ntfy, Gotify and any webhook, besides Discord. The page is now called Alerts.
- Tokens in the dashboard. Widget and metrics tokens are created and revoked on the Homarr and
Prometheus pages, shown once and stored as a hash. - Schedule. Up to 8 profiles by day and time, each with a speed cap and/or a smart mode target.
- Diagnostics. A server page downloads what its BMC answers, without passwords or addresses, for bug
reports about untested hardware. - Smart mode metrics in Prometheus, and two Grafana panels that show why it chose each speed.
- The sidebar shows when a newer release is out (
UPDATE_CHECK=falseturns it off). - The docs pin the image to its major version,
:2. - A test fails on any page text without a Portuguese translation; the 40 it found are translated.
- Code:
metrics.py,widgets.py,backup.py,tokens.pyandupdates.pycome out ofweb.py;
editor.jsout ofapp.js.