iobroker.nut2
v0.17.0
Published
ioBroker adapter for Network UPS Tools (NUT) monitoring
Readme
ioBroker.nut2
Monitors uninterruptible power supplies via Network UPS Tools (NUT). All UPS devices connected to a NUT server are automatically discovered and polled.
NUT support in ioBroker goes back to Apollon77's iobroker.nut adapter (2016); this adapter is an independent rewrite and shares no code with it.
Features
- Automatic discovery of all UPS devices on a NUT server via
LIST UPS— also while running: a UPS added to or removed from the server shows up (or disappears) at the next poll - Dynamic state creation from
LIST VAR— whatever your UPS reports appears as ioBroker states - Proper data types: numeric values as numbers (not strings), with units (V, Hz, A, Ah, %, W, VA, s, min, °C, °)
- Parsed
ups.statusflags as individual booleans (online, onBattery, lowBattery, charging, ...) plus computed severity (0–4) - Every device shows a pictogram for its NUT device type (UPS, PDU, solar charge controller, power supply, transfer switch) in the object tree
- Every data point comes with a short explanation, and status texts, severity levels and selection lists appear in your ioBroker language (11 languages)
- Instant commands (INSTCMD) via button states — beeper control, load management, self-test — plus one text data point for commands that take a value, such as a delay
- When the NUT server tracks commands, the adapter reports whether the driver really carried out a command or a new setting
- Writable variables (SET VAR) — change UPS settings directly from ioBroker
- Instant updates on UPS events — a writable
notifytrigger state lets upsmon push ONBATT/LOWBATT/SHUTDOWN the moment they happen - Persistent TCP connection with automatic reconnect and exponential backoff; kept alive while idle, so long poll intervals no longer lose it
- Network interface selector for multi-homed servers
- Connection test button in the admin UI — it really logs in, and says what it checked
Sentry / Error reporting
This adapter uses Sentry libraries to automatically report exceptions and code errors to the developers. Reporting is active by default. It stays off when the ioBroker diagnostics setting is none (diag in the system configuration), when data reporting is disabled for this instance or its host (disableDataReporting), and on CI systems. A report contains the error with its stack trace and technical context such as versions and platform, plus an anonymous installation ID.
For details and how to disable it, see the Sentry plugin documentation. Error reporting requires js-controller 3.0 or newer.
Requirements
- Node.js >= 22
- ioBroker js-controller >= 7.2.2
- ioBroker Admin >= 8.0.11
- A running NUT server (upsd) with at least one UPS configured
The adapter CANNOT be installed via GitHub: The adapter must be installed via the ioBroker repository (stable or latest).
Configuration
Connection
| Option | Description | Default |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
| NUT Server Host | Hostname or IP address of the NUT server | — |
| Port | NUT server port | 3493 |
| Network Interface | Bind outgoing connections to a specific local IP (optional) | all |
| Poll Interval (s) | How often to query the NUT server (2–300) | 15 |
| Username | NUT username (optional — needed for commands and writable variables; the adapter also verifies it once at startup) | — |
| Password | NUT password | — |
| Use TLS (STARTTLS) | Encrypt the connection via STARTTLS | off |
| Require valid certificate | Reject self-signed/invalid certificates (only shown when TLS is on) | off |
| CA certificate file | PEM file to trust for the strict check — your own certificate authority or the self-signed server certificate (only shown when the strict check is on) | — |
Use the Test Connection button to verify the server is reachable and see discovered UPS devices. With a username and password it also logs in and out again, so the result tells you whether the credentials really work — and whether the connection is encrypted.
About the credentials: the NUT server only stores a username and password when they are sent — it checks them
when a client logs in. The adapter therefore logs in once at startup, on a short extra connection that is closed again,
purely to tell you whether the credentials work; the connection test does the same on demand. A login needs an
upsmon secondary (or upsmon primary) line for that user in the server's upsd.users.
Reading UPS values needs no login at all, so refused credentials never stop the monitoring: the adapter logs a
warning, keeps polling, and only switching a UPS or writing a variable is refused. The instance stays green, because
the connection to the NUT server is up and the values are current — info.connection reports that connection, not the
credentials. That matches NUT's own tools: upsc, upscmd and upsrw never log in either. The reason the adapter does not simply stay logged in is that the
server counts logins: during a power failure a primary upsmon waits until every other login is gone before it shuts
its machine down, so a monitoring client sitting in that count would delay the shutdown while running on battery.
About TLS: enabling STARTTLS encrypts the connection so your NUT username and password are no longer sent in clear text over the network. With the default settings it protects against passive eavesdropping, but not against an active man-in-the-middle, because most NUT servers use a self-signed certificate that cannot be verified. For full protection, configure a certificate the client can validate on the NUT server and enable Require valid certificate. The NUT server must be built with TLS support (upsd with CERTFILE/CERTPATH); otherwise the connection test reports a TLS error.
Advanced
| Option | Description | Default |
| ----------------------- | --------------------------------------------------- | ------- |
| Command Timeout (s) | Timeout for individual NUT protocol commands (1–30) | 5 |
| Enable Commands | Allow sending instant commands (INSTCMD) to the UPS | off |
| Enable SET VAR | Allow changing writable UPS variables | off |
Both command features require a NUT user with appropriate permissions configured on the NUT server.
State Tree
States are organized by NUT domain. The exact set of states depends on what your UPS driver reports.
nut2.0.
├── info/
│ ├── connection — Connection to NUT server (bool)
│ ├── upsTotal — UPS devices found (number)
│ ├── upsReachable — How many of them answer right now (number)
│ └── allUpsReachable — All of them answering? (bool)
├── notify — Writable trigger: poll now / record an upsmon event
└── {ups_name}/ — Device (e.g. "ups0")
├── info/
│ ├── reachable — UPS responds / data is fresh (bool)
│ └── notify — Last upsmon event routed to this UPS (string)
├── battery/
│ ├── charge — Battery level (%, number)
│ ├── charge-low — Low battery threshold (%)
│ ├── runtime — Remaining runtime (s)
│ ├── type — Battery chemistry (string)
│ └── ...
├── device/
│ ├── mfr — Manufacturer (string)
│ ├── model — Model name (string)
│ ├── serial — Serial number (string)
│ └── ...
├── driver/
│ ├── name — NUT driver name
│ ├── version — Driver version
│ └── ...
├── input/
│ ├── voltage — Input voltage (V, number)
│ ├── frequency — Input frequency (Hz, number)
│ └── ...
├── output/
│ ├── voltage — Output voltage (V, number)
│ ├── frequency — Output frequency (Hz, number)
│ └── ...
├── outlet/ — Switchable outlets and outlet groups (if the UPS has them)
│ ├── id — Outlet identifier (string)
│ ├── desc — Outlet description (string)
│ ├── status — on / off (enum)
│ └── ...
├── ambient/ — Environment sensors (if the UPS or an EMP has them)
│ ├── temperature — Ambient temperature (°C, number)
│ ├── humidity — Ambient humidity (%, number)
│ └── ...
├── ups/
│ ├── load — UPS load (%, number)
│ ├── power — Apparent power (VA, number)
│ ├── realpower — Real power (W, number)
│ ├── status — Raw status string (e.g. "OL CHRG")
│ └── ...
├── status/ — Parsed status flags
│ ├── raw — Original status string
│ ├── display — Human-readable status (e.g. "On line power, Charging")
│ ├── severity — 0=OK, 1=Info, 2=Warning, 3=Critical, 4=Emergency (empty: no power source reported)
│ ├── online — On line power (bool)
│ ├── onBattery — Running on battery (bool)
│ ├── lowBattery — Battery is low (bool)
│ ├── charging — Battery is charging (bool)
│ ├── discharging — Battery is discharging (bool)
│ ├── replaceBattery — Battery needs replacement (bool)
│ ├── overloaded — UPS is overloaded (bool)
│ ├── forcedShutdown — Forced shutdown in progress (bool)
│ ├── alarm — Alarm active (bool)
│ ├── ecoMode — ECO / high efficiency mode (bool)
│ ├── testing — Self-test in progress (bool)
│ ├── overheat — UPS overheated (bool)
│ └── ... — (19 flags total)
└── commands/ — Instant commands (if enabled and the UPS offers any)
├── execute — Text: a command with its value, e.g. "load.off.delay 120"
├── beeper-enable — Button: enable beeper
├── beeper-disable — Button: disable beeper
├── test-battery-start — Button: start battery test
└── ... — (from LIST CMD)State IDs: the first dot in a NUT variable name is the channel separator; any further dots become dashes. So
battery.charge.lowis stored asbattery.charge-low, and the instant commandtest.battery.startbecomescommands.test-battery-start. A NUT variable without any dot has no channel and is created directly under the device.
Status Severity Levels
| Level | Meaning | Typical Flags | | ----- | --------- | --------------------------- | | 0 | OK | OL, OL CHRG, OL HB | | 1 | Info | TRIM, BOOST, CAL | | 2 | Warning | OB (without LB), RB, BYPASS | | 3 | Critical | OB + LB | | 4 | Emergency | FSD | | empty | — | none of OL, OB, BYPASS, FSD |
Severity describes the power source only. A status without one — OFF alone, WAIT while the driver starts, a PDU that reports no status — leaves it empty instead of claiming "OK".
Instant updates from upsmon (notify trigger)
NUT has no server push, so the adapter polls on a fixed interval. upsmon — NUT's own monitoring client — sees events the moment they happen and can run a command via NOTIFYCMD. Point it at the writable state nut2.0.notify and the adapter refreshes at once.
On the NUT server, save a small helper script — for example as /etc/nut/iobroker-notify.sh — and make it executable (chmod +x). curl has to be installed there. upsmon hands the event over in $NOTIFYTYPE and the UPS in $UPSNAME:
#!/bin/sh
curl -fsS "http://<iobroker-host>:8093/v1/state/nut2.0.notify?value=${NOTIFYTYPE}%20${UPSNAME}" > /dev/nullIn upsmon.conf:
NOTIFYCMD /etc/nut/iobroker-notify.sh
NOTIFYFLAG ONLINE SYSLOG+EXEC
NOTIFYFLAG ONBATT SYSLOG+EXEC
NOTIFYFLAG LOWBATT SYSLOG+EXEC
NOTIFYFLAG FSD SYSLOG+EXEC
NOTIFYFLAG SHUTDOWN SYSLOG+EXEC
NOTIFYFLAG REPLBATT SYSLOG+EXECOnly NOTIFYFLAG lines carrying EXEC run the command. A script works with every NUT version: from the release after NUT 2.8.5 on, upsmon starts NOTIFYCMD without a shell, so a command line with $NOTIFYTYPE written into upsmon.conf itself would no longer be expanded. The URL is served by the rest-api adapter (port 8093), so this works from a container as well — no ioBroker binaries on the NUT host. With the older simple-api adapter the path is http://<iobroker-host>:8087/set/nut2.0.notify?value=… (8087 when it runs on its own, 8082 when it runs inside the web adapter); its own README points to rest-api as the replacement.
Any write to nut2.0.notify triggers an immediate poll of all UPS devices; an empty value is a plain refresh. With $NOTIFYTYPE $UPSNAME the event also lands on that UPS's {ups_name}.info.notify, so an automation can react per device. The event is recorded before the poll starts, which is why a SHUTDOWN still reaches ioBroker when the NUT host dies moments later.
Troubleshooting
Connection failed
- Verify the NUT server is reachable from the ioBroker host:
nc -zv <host> 3493 - Check firewall rules for TCP port 3493
- Use the Test Connection button in the admin UI
Credentials rejected
- Reading the UPS data continues regardless — only commands and writable variables are affected
- The NUT server answers the same way for a wrong password and for a user that may not log in — check both
- The user needs an
upsmon secondary(orupsmon primary) line in the server'supsd.usersto be verifiable; a user with onlyactionsorinstcmdsentries cannot log in, yet its commands still work - Without a username and password the adapter reads the UPS data anonymously; commands and writable variables then stay unavailable
Commands not working
- Ensure Enable Commands is checked in the Advanced tab
- A NUT username and password with
instcmdspermission must be configured - Check the NUT server's
upsd.usersconfiguration - A UPS whose driver offers no instant commands gets no
commandschannel at all (upscmd -l <ups>on the server lists them) - "the driver has not confirmed it (yet)" in the log means the NUT server accepted the command but the driver did not report back within the command timeout
Writable variables not working
- Ensure Enable SET VAR is checked in the Advanced tab
- The NUT user needs
actions = SETpermission on the NUT server
States not updating
- Check
info.connection— iffalse, the connection to the NUT server is down (rejected credentials do not affect it) - Check the ioBroker log for NUT error codes (e.g.
DATA-STALEmeans the UPS driver lost contact) - Verify the poll interval is appropriate for your setup
Changelog
0.17.0 (2026-09-25)
- New: a UPS command that needs a value, such as a delay, can be sent through the new
commands.executedata point, written the way upscmd takes it - New: when the NUT server tracks commands, the log says whether the driver really carried out a command or a new setting, not only that it was sent
- New: every device shows a pictogram for its NUT device type in the object tree — UPS, PDU, solar charge controller, power supply or transfer switch
- Fixed: the connection to the NUT server no longer drops during long poll intervals — the adapter keeps it alive while it is idle
- Fixed: apparent power, real power and percentages carry the right unit and role, and writable temperatures, voltages and currents are settable levels
- Fixed: text values such as test results, contact states or ups.conf settings stay text instead of turning into numbers or being discarded
- Fixed: a word or an empty value in a measurement, such as LoadTooLow, leaves the data point empty instead of keeping an old number, without a warning
- Fixed: renamed data points keep the rooms and functions you assigned them to, and a unit or explanation that no longer applies is removed
- Fixed: a UPS that is missing from the NUT server for a moment keeps its data points and history; it is removed only after three polls without it
- Fixed: the status severity stays empty when the status names no power source, instead of claiming OK for a UPS that is off or still starting
- Fixed: command buttons follow the driver's command list — buttons of commands it no longer offers disappear, and a UPS without commands gets none
- Fixed: values containing #, quotes or backslashes are read correctly; writing a value with # is refused with an explanation, as NUT drivers cannot report it back
- Fixed: a TLS certificate problem stops the retries with one clear message, and a UPS reporting several value ranges shows the full range
- Improved: names and explanations for every variable and command of the NUT 2.8.5 catalog in all eleven languages, including outlets, groups and sensors
- Improved: the warning sign marks exactly the commands that can cut power or stop the driver; switching something on is never marked
- Changed: the upsmon connection is documented as a small helper script, which keeps working with the NUT releases after 2.8.5
0.16.0 (2026-09-15) — stable
- Fixed: every adapter start silently removed the status severity, the device type, every dropdown and every bounded value from the rooms and functions the user had assigned them to
- Fixed: when a dropdown list or a value range really shrinks, the data point keeps its value, its recording settings and its room and function assignments
- Fixed: a data point that is renamed by an update keeps its room and function assignments, exactly as it already kept its recording settings
- Fixed: a UPS without a
descin ups.conf lost its manufacturer + model name on the first reconnect and was called by its config name until the next restart - Fixed: after a fatal TLS error on a reconnect the adapter kept polling a connection that no longer existed and promised a retry that never came
- Fixed: stopping the instance while the NUT server was unreachable could leave two error lines in the log
- Improved: dropdown lists and value ranges are no longer rewritten on every start and every reconnect when nothing changed — less load on the object database and on every adapter listening to it
- Improved: the adapter reads its object tree once per discovery instead of once per data point — a lighter start on large installations
- Improved: a value written to a data point the UPS reports as read-only is ignored quietly instead of producing an error
- Improved: a UPS reported without a description by a non-standard NUT server no longer goes missing
0.15.1 (2026-09-07)
- New: ten more data points explain themselves — the battery date, the UPS's own clock, the three driver versions, the UPS identifier, the UPS type and the USB vendor and product IDs
- Fixed: the battery maintenance date is the date of the NEXT change or service, not of the last one — its name said the opposite in all eleven languages
- Improved: setting up the upsmon trigger is one line in upsmon.conf instead of a shell script, and points at the rest-api adapter; the older simple-api path stays documented
0.15.0 (2026-09-07)
- Fixed: a data point no longer holds a value of the wrong kind — a reading that stops matching the data point's type is discarded with one warning instead of being written into it
- Fixed: a NUT server that is switched off or restarting no longer makes the instance look broken — the adapter names the server it cannot reach and keeps retrying
- Fixed: value limits taken from the UPS disappear again when the UPS stops reporting them, instead of standing forever and causing warnings about every value outside them
- Fixed: credentials containing a space are now refused with an explanation instead of a bare protocol error nobody can act on
- Fixed: enabling instant commands now says why no command buttons appear when the UPS does not answer the command list
- Fixed: a UPS variable without a dot in its name is now writable, and can no longer take over one of the adapter's own channels
- Fixed: over a third of the data points carried an English label in every language — 157 more variable names are now translated into all eleven
- Fixed: the phases of a three-phase UPS, the sensors of a multi-sensor probe and the individual outlets no longer all share one name — each keeps the marker that says which one it is
- Fixed: the outlet buttons of a PDU are now named and explained like every other command instead of showing their raw NUT name
- New: explanations for the battery voltage, battery temperature, battery health and input current, which stood without one next to explained siblings
0.14.0 (2026-09-04)
- Fixed: a certificate file left over in the settings no longer stops the adapter — it is only read while strict certificate checking is actually switched on
- Fixed: value lists of writable data points stay in your language instead of falling back to the raw NUT wording after the first poll
- Fixed: the connection test no longer reports an error when only the credentials are refused — it says so and confirms that reading works, matching what the adapter does
- Fixed: the connection test now answers in your language when something goes wrong, not only when it succeeds
- Fixed: a UPS that disappears from the NUT server and comes back gets its manufacturer and model name again instead of keeping the bare UPS name
- Fixed: renamed data points of the adapter itself now reach existing installations instead of only new ones
- Fixed: enabling instant commands without credentials no longer fails silently — the adapter now explains why no command buttons are created
- New: detailed user documentation in English and German is now part of the repository and shown in the ioBroker documentation portal
Older changelogs can be found there
Support
Support Development
This adapter is free and open source. If you find it useful, consider buying me a coffee:
License
MIT License
Copyright (c) 2026 krobi [email protected]
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Developed with assistance from Claude.ai
