Repository navigation
sms_ser: fix status for newer line-interactive models, validate replies, reopen the port, send delays as the vendor software does [#1987] - #3701
Open
diogot wants to merge 19 commits into
Conversation
|
A ZIP file with standard source tarball and another tarball with pre-built docs for commit 113a9eb is temporarily available: NUT-tarballs-PR-3701.zip. |
…networkupstools#1987] The protocol is binary and the driver had no way to show what went over the wire. Use upsdebug_hex() for every request sent and every reply read, to help diagnose the models this driver meets in the field. Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
…upstools#1987] The UPS reports tenths (e.g. 0x04ff for 127.9 V), but the long was divided by 10 before becoming a double, so NUT always showed 127.00, 59.00 etc. Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
… fake BYPASS of line-interactive models [networkupstools#1987] The status was picked by an exclusive if/else chain that tested the bypass flag first. Newer line-interactive models (SMS Premium, Gamer) raise that flag whenever the inverter runs, so an outage was reported as BYPASS and neither OB nor LB ever reached upsmon. The vendor confirmed to a user in issue networkupstools#1987 that these models have no bypass and the flag is not valid. The first byte of the 'Q' reply tells the topology ('=' line-interactive, '>' and '<' on-line types); the vendor's PowerView software uses it the same way to decide whether to believe the bypass flag. Store it, and: * always report OL or OB, plus LB, RB and BOOST as independent flags; * report BYPASS only for the on-line types and never while on battery; * report CAL and ups.test.result while the battery test flag is set, so upsmon can tell a test from an outage; * also raise LB while on battery when the charge is at or below battery.charge.low, if the user defined it (the vendor software derives low battery from a threshold too); * publish ups.mfr, ups.model and device.mfr (some clients, e.g. Synology DSM, refuse a server without ups.mfr and ups.model). The unreachable OFF branch is gone with the chain. Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
…ailures, add output.voltage.nominal and ups.type [networkupstools#1987] Move the send/receive sequence of the three queries into sms_query(), which flushes stale input, checks that the whole request was written (a return of -1 was not caught before), and rejects replies whose checksum or terminator is wrong. The checksum rule is the one used for requests and was checked against replies of three different models. After MAXTRIES failed polls close the port and reopen it by name without bailing out: a USB-serial adapter that was unplugged leaves a dead descriptor and may return under another device node. Publish ups.type from the topology byte and output.voltage.nominal from the number in the voltage range label. Drop a stray write of that label into battery.voltage.nominal, which was overwritten a few lines later. Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
… settings and test.battery.start.deep, bump version [networkupstools#1987] According to the vendor's PowerView software, the 'S', 'T' and 'R' commands carry 16-bit big-endian values with 0x00 in the unused pair. The driver put the low byte of the delay in the first parameter and 0xFF in the others (a delay of 64 went out as 0x40FF), and sent 'R' with four 0xFF bytes. * shutdown.return (and so upsdrv_shutdown) now sends the new offdelay and ondelay settings, also writable as ups.delay.shutdown and ups.delay.start; ups.delay.reboot is now published too; * delays given in ups.conf, by setvar or as a command argument are checked to be numbers that fit 16 bits; the argument of shutdown.reboot was parsed with the delay as the numeric base; * test.battery.start.quick sent 'L' (test until battery low): it now runs the timed test for 10 seconds, and the new test.battery.start.deep sends 'L'; test.battery.start still takes an optional duration; * one helper sends a prepared command and checks the full write. Not verified on hardware: the unit and effect of the delay values on the UPS side; frames were checked against a protocol simulator only. Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
networkupstools#1987] Describe the offdelay, ondelay and (so far undocumented) rebootdelay settings, the instant commands, how ups.status is composed, why BYPASS is not reported for line-interactive models, and what the battery level of these devices means while charging. Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
… add SMS Premium 1500 VA [networkupstools#1987] The UPGRADING note covers the behaviors that changed for existing users: the meaning of test.battery.start.quick, the delays sent by the shutdown commands, and the composition of ups.status. Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
…rkupstools#1987] Timed battery tests on an SMS Premium 1500 (line-interactive), with the durations read from the event log of the UPS: values of 10, 30 and 100 ran for 6, 18 and 59 seconds, so the unit is a hundredth of a minute. This matches the vendor software, whose "10 seconds" test sends 16 and which multiplies its values by 0.6 only for the on-line type (so that type counts in seconds). With the conversion, a request for 30 seconds ran for 30. Apply it to the test duration and to the shutdown delays of 'S' and 'R'. Only the test duration was measured; the shutdown delays are assumed to use the same unit. The restore delay of 'R' is passed through unchanged. Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
…delays [networkupstools#1987] The time unit of the delays depends on the UPS type, which is only known after a status poll, and "driver -k" runs upsdrv_shutdown() in a fresh instance that never polled. Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
…n battery [networkupstools#1987] At the first poll of an outage the battery level can still read 100, and the status was then reported as "floating". Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
… back [networkupstools#1987] The delay format and the reply validation were checked with one model and a protocol simulator, plus reply samples of two other models. Should a device which worked with earlier versions not cope with either change, these flags restore the earlier behavior without downgrading: the old parameter bytes for 'T', 'S' and 'R', and no checksum/terminator check. Both log a request to report the device. Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
…er time unit and fallback flags [networkupstools#1987] Say that the delays are given in seconds and converted to the time unit of the UPS, what was measured and what is assumed, and that the unit of the restore delay is not known. Document the "legacydelays" and "novalidate" flags and add them to the dictionary (the header count is as regenerated by "make spellcheck-sortdict"). Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
…store delay counts in minutes [networkupstools#1987] Measured on an SMS Premium 1500 VA: a restore delay of 1 brought the output back 63 s after the cut, 3 brought it back after 183 s, so the UPS counts this field in minutes while the shutdown delays count in 0.6 s units. The ondelay setting and ups.delay.start are now in seconds like the other delays, rounded up to whole minutes and never below one minute when sent (the vendor software never sends 0). Default 60. With mains absent the UPS switches itself off about a minute after the cut and re-energises a few seconds after mains returns, whatever the restore delay; noted in the man page. Developed with Claude Code (model Claude Fable 5.1). Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
diogot
force-pushed
the
sms_ser-premium-support
branch
from
September 22, 2026 14:25
d1fbe07 to
d64e5f2
Compare
This was referenced Sep 22, 2026
…orkupstools#3701] Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
|
Tested on an SMS Gamer 1500 VA ( Before (2.8.1 With this PR (1.06): At rest: Full outage, mains pulled for ~17 min, 4 secondaries + 1 local Also seen: Not tested yet: Two small things on this model:
|
|
✅ Build nut 2.8.5.5896-master completed (commit 030d8c6986 by @jimklimov)
|
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.
Rework of the
sms_serdriver (SMS Brazil single-phase protocol), developedagainst an SMS Premium 1500 VA (
PRM1500BiBiW, line-interactive, USB with abuilt-in Prolific PL2303 serial adapter). Related discussion: #1987.
What was wrong
SMS Manager III Support #1987) raise the bypass flag whenever their inverter runs.
ups.statuswas picked by precedence with bypass first, so a power outage was reported
as
BYPASSand never asOBorLB;upsmonnever reacted.reopened after a USB replug: the driver logged
Short read from UPSforever on a stale handle.
delay of 64 went out as
0x40FF,shutdown.returnsent four0xFFbytes, and the
test.battery.start.quick/.startnames were swappedrelative to their effect.
What this branch does (13 commits, each one functional change)
ups.statusbuilt from all flags:OL/OB, plusLB,RB,BOOST,and
CALwithups.test.resultduring a battery test.BYPASSis onlyreported for on-line models, decided from the topology byte of the status
reply, as the vendor software does.
LBis also raised while on batteryif the charge is at or below
battery.charge.low, when defined.port is closed and reopened by name, which handles a USB replug and the
UPS powering itself down and up.
offdelayandondelaysettings with writableups.delay.shutdown,ups.delay.startandups.delay.reboot; newtest.battery.start.deep(runs until the UPS reports low battery);
test.battery.start.quickisnow 10 seconds.
models count in 0.6 s units (measured: a 10 second test used to run for
6), on-line models in seconds. The restore delay of the shutdown command
counts in minutes (measured: 1 gave 63 s, 3 gave 183 s) and is rounded up
from the seconds given.
upsdrv_shutdown()queries the UPS type first, since the killpower pathruns as a fresh driver instance that never polled.
ups.mfr,ups.model,ups.type,output.voltage.nominalpublished;battery.charger.statusisdischargingwhenever on battery; decimalskept; frames hex-dumped at debug level 4.
legacydelays(old parameter bytes forT,S,R) andnovalidate(skip the reply check).
NEWS.adoc,UPGRADING.adoc(changed meaning oftest.battery.start.quickand of the delays; malformedrebootdelaynowfatal),
data/driver.list.in,docs/nut.dict.DRIVER_VERSIONbumpedto 1.06.
Tested on hardware (SMS Premium 1500 VA)
upsmon,upsschedand a Synology DSM client all react toOB/OL.unit of the restore delay,
shutdown.stopcancelling a pending shutdown,shutdown.returnwith and without mains (with mains the output returnsafter the restore delay; without it the UPS switches itself off about a
minute after the cut and returns a few seconds after mains is back), and
the killpower path (
sms_ser -k) in both cases, all with only a lamp onthe UPS output.
full drain;
test.battery.start.deep.down; a 14 hour soak run (10007 polls, no rejected reply, flat memory).
Proxmox host since 2026-09-22.
Tested on a simulator only
legacydelaysandnovalidateflags (byte for byte against thestock driver's frames).
<,>reply types) were not available at all; thecode paths for them keep the previous behaviour where nothing better is
known.
Asking for testers
Owners of other SMS models in #1987 will be asked to try the branch before a
merge (Gamer 1500 / 2000, Manager III, the author's original unit), in
particular for the raw replies at debug level 4 and for the effect of the
two flags. A NUT DDL dump for the Premium will follow in a separate PR.
Disclosure
Developed with Claude Code (model Claude Fable 5.1), with the author
directing the work, reviewing every change and running all hardware tests.
Each commit carries the same note.
Checklist
limitations stated
AsciiDoc
DRIVER_VERSIONbumped (1.06)docs/nut-names.txtdata/driver.list.inupdated (SMS Premium 1500 VA)byte by byte,
uint16_t/size_twhere due)upsdebugx()/upslogx()/fatalx()for progress and errorsmake distcheck-lightpassesNEWS.adocandUPGRADING.adocupdateddocs/acknowledgements.txt: not applicable (no vendor backing)docs/man/sms_ser.txtupdatedmake spellcheckpasses,docs/nut.dictupdated