Repository navigation
feature: NUT (Network UPS Tools) support, HMIB-style UPSes table sorting, in-place auto-refresh (1.4.0) - #55
Merged
Merged
Conversation
…rting, in-place auto-refresh NUT support (type_id 3, version 1.4.0): - Native PHP implementation of the upsd protocol (includes/nut.php): no upsc or other CLI needed. Optional USERNAME/PASSWORD, STARTTLS with certificate and host name verification, bounded reads, and strict validation of the host, UPS name and credentials before anything is sent. - New apcupsd_ups columns nut_ups_name, nut_username, nut_password, nut_tls; widen ups_status/model/serialno/firmware/driver/name on apcupsd_ups_stats. - Poller collects type 3 UPSes, translates NUT flags to the apcupsd status vocabulary, replaces the stats row each poll and clears stale errors. - UPS form, list and dashboard know the new type; README, CHANGELOG, INFO (1.4.0) and the i18n template updated. Fleet Dashboard UPSes card: - Sort like the HMIB dashboards (click or Enter/Space on a header, asc then desc, also in the maximize dialog); drop the button/localStorage variant. - Right-align Load, Charge, Time Left, Est. Power and Last Updated; the lone .apcupsdDashNum rule was outranked by .apcupsdDashTable th/td. - Auto-refresh refreshes the cards in place through Cacti's refreshFunction hook instead of reloading the page, keeps the chosen sort, skips overlapping rounds and falls back to the full-page refresh without the JS. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved polling reliability, configuration preservation, data accuracy and refresh compatibility defects block approval.
6 open findings
Enforce the overall deadline during buffered UPS reads · New Mark linked hosts unavailable after failed NUT queries · New Preserve existing UPS ports when opening edit forms · New Use a refresh hook compatible with supported Cacti versions · New Preserve the live sort when replacing AJAX content · New Avoid inventing timestamps for unreported NUT statistics · New
What changed in this PR
Adds NUT monitoring to the Cacti UPS plugin and updates dashboard interactions for version 1.4.0.
Changes:
- Adds a native NUT client, collector settings, polling and schema support.
- Reworks table sorting and introduces in-place dashboard refresh.
- Updates documentation, translations and tests.
| File | Description |
|---|---|
| upses.php | Adds NUT configuration and collector labels. |
| tests/Unit/NutWiringTest.php | Checks NUT integration wiring. |
| tests/Unit/NutClientTest.php | Tests protocol handling and sockets. |
| tests/Unit/EstimatedWattsTest.php | Updates sorting and alignment checks. |
| tests/Unit/DashboardRefreshTest.php | Adds refresh integration checks. |
| README.md | Documents NUT setup and requirements. |
| poller_apcupsd.php | Adds NUT collection and device creation. |
| phpunit.xml | Includes NUT client in coverage. |
| locales/po/cacti.pot | Adds NUT translation strings. |
| js/apcupsd_dashboard.js | Implements header sorting and card refresh. |
| INFO | Bumps version to 1.4.0. |
| includes/nut.php | Implements NUT transport and data mapping. |
| includes/database.php | Adds settings and widens stats columns. |
| includes/dashboard.php | Updates collector display and refresh wiring. |
| css/apcupsd.css | Styles sorting indicators and numeric alignment. |
| CHANGELOG.md | Records release changes. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- New apcupsd_ups.timeout (seconds, default 5, 1-120) with a narrow form field shown for the apcupsd and NUT types; apcupsd_normalize_timeout() clamps it everywhere it is used. - NUT: connect plus conversation now end within twice the timeout (sub-second per-read waits, so the deadline holds), and a timeout is reported as such instead of as a closed connection. - apcaccess runs through Cacti core's exec_with_timeout() instead of exec(), so a hung apcaccess is killed; a timed out or empty run now records an error on the UPS. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Per-UPS CA / Certificate File: the server is verified against that PEM file (chain and host name still checked), which is how a homelab self-signed certificate is trusted without weakening verification. - Per-UPS Allow Self-Signed Certificate: encrypts without verifying the server, for networks where a certificate file is impractical. - The CA file path must be a plain absolute path (no stream wrappers or control characters) and readable, otherwise the poll fails with a clear error before connecting. The form hides both options unless TLS is on. - Verified over a real TLS handshake: default fails, CA file and the self-signed option succeed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- NUT reads are now non-blocking and polled against the deadline, so a server that trickles bytes without finishing a line cannot hold a read open past it (fgets() blocked for the whole stream timeout per read). - A failed NUT query now marks the linked Cacti host down, like a status change does (those hosts have availability checking disabled). - The UPS edit form no longer rewrites an existing UPS's port when it opens; the default port is only swapped on a manual type change. - Auto-refresh no longer depends on Cacti's refreshFunction hook, which Cacti 1.2.x lacks: detect support, and otherwise run a timer of our own that stops when the dashboard leaves the screen. - Capture the live sort when a refreshed card replaces the old one, so a sort made while the request was in flight is kept. - Unreported start, manufacture, master update, last on battery and last self test times are stored as NULL instead of defaulting to the poll time. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
xmacan
approved these changes
Oct 16, 2026
bmfmancini
approved these changes
Oct 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Adds Network UPS Tools (NUT) as a third collector type, brings the Fleet Dashboard UPSes table in line with the HMIB plugin's sorting, and makes dashboard auto-refresh update the cards in place. Plugin version is now 1.4.0.
NUT support (
type_id3)includes/nut.php) for theupsdprotocol (TCP 3493). Noupscor other CLI is needed, so it works on any poller, including Windows and remote pollers.curlcan't speak the protocol, so it isn't used.upsd.usersusername/password can be set. Optional STARTTLS verifies the certificate and host name by default. For homelab self-signed certificates there is a per-UPS CA / Certificate File (verified against that PEM, chain and host name still checked; recommended) and an Allow Self-Signed Certificate option (encrypts but does not verify the server, documented as such).apcupsd_upscolumnsnut_ups_name,nut_username,nut_password,nut_tls. Widenedapcupsd_ups_statsups_status,ups_model,ups_serialno,ups_firmware,ups_driverandups_nameso multi-flag NUT values aren't truncated (applied on upgrade bydb_update_table()).OL->ONLINE,OB->ONBATT,LB->LOWBATT,RB->REPLACEBATT,OVER->OVERLOAD) so dashboards, fleet totals and the slave rule keep working unchanged, replaces the stats row each poll (no stale values) and clears the previous error. A Cacti device is auto-created like for apcupsd UPSes.apcaccessnow runs through Cacti'sexec_with_timeout()instead ofexec(), so a hungapcaccessis killed and recorded as an error rather than stalling the poller.upsd.confLISTENrequirement) and replaces the old "considering NUT" note.Fleet Dashboard UPSes card
localStoragevariant is removed..apcupsdDashNumrule was being outranked by.apcupsdDashTable th/td { text-align: left }.Auto-refresh refreshes panels, not the page
Auto-refresh now updates each card in place instead of reloading the page. Cacti 1.3+ has a
refreshFunctionhook in its page timer (the Graphs page uses it), so the dashboard uses that there. Cacti 1.2.x (this plugin's floor) has no such hook (its timer reloads#main), so on 1.2.x the dashboard stops core's page timer and runs a small timer of its own, which ends for good once the dashboard leaves the screen. Support is detected at runtime, and without the dashboard script core's normal page refresh still applies. The chosen table sort is kept across a refresh (the live one, captured when the card is swapped), and overlapping rounds are skipped.Review follow-ups included
Testing
NutClientTest(protocol logic over a scripted server, a connected stream pair, and loopback TCP),NutWiringTest(schema, poller, form, docs, version), and updatedEstimatedWattsTest/DashboardRefreshTest.includes/nut.phpis added to the coverage config so CI's 100% patch-coverage gate applies to it.upsdover TCP with authentication.check-i18n-potandvalidate-manifestpass.Notes for review
ups.realpower) is not stored yet; the plugin keeps estimating watts from nominal power x load.