nut icon indicating copy to clipboard operation
nut copied to clipboard

override.battery.packs doesn't work to adjust reported battery voltage

Open baerenwaldfreund opened this issue 4 years ago • 52 comments

I spent a lot of time reactivating my old UPS: Online Xanto S700 (build before 2012). But now it almost works. But I still have a small error.

The parameter 'override.battery.packs' doesn't work. Incorrect battery voltage is still reported.

Here the output:

upsc ups@localhost

Init SSL without certificate database battery.charge: 100 battery.packs: 12 battery.runtime: 2400 battery.voltage: 2.27 battery.voltage.high: 26.00 battery.voltage.low: 22.00 battery.voltage.nominal: 24.00 device.mfr: Online-UPS device.model: Xanto S700 device.type: ups driver.name: nutdrv_qx driver.parameter.chargetime: 43200 driver.parameter.idleload: 10 driver.parameter.pollfreq: 5 driver.parameter.pollinterval: 2 driver.parameter.port: /dev/ttyUSB0 driver.parameter.protocol: q1 driver.parameter.runtimecal: 240,100,720,50 driver.parameter.synchronous: no driver.version: 2.7.4 driver.version.data: Q1 0.07 driver.version.internal: 0.28 input.frequency: 50.0 input.voltage: 243.8 input.voltage.fault: 243.8 output.voltage: 230.0 ups.beeper.status: disabled ups.delay.shutdown: 30 ups.delay.start: 180 ups.load: 0 ups.mfr: Online-UPS ups.model: Xanto S700 ups.status: OL ups.temperature: 25.0 ups.type: online

The batterie voltage is 2.27V. So I hoped the parameter 'override.battery.packs=12' will help. But it doesn't work. The reported voltage is still 2.27V.

Here is my ups.conf:

[ups] driver = nutdrv_qx port = "/dev/ttyUSB0" desc = "Online Xanto S700" protocol = q1 override.battery.packs = 12 default.battery.voltage.nominal = 24.00 default.battery.voltage.low = 22.00 default.battery.voltage.high = 26.00 runtimecal = 240,100,720,50 chargetime = 43200 idleload = 10 pollfreq = 5 default.ups.mfr = "Online-UPS" default.ups.model = "Xanto S700"

What can I do to ensure that the correct voltage is displayed?

baerenwaldfreund avatar Feb 09 '22 17:02 baerenwaldfreund

I am not sure how that value's override would impact voltage. I believe it is for tracking the hardware composition of (larger) UPSes - how many independent batteries it has, if some can be diagnosed and replaced separately: https://github.com/networkupstools/nut/blob/master/docs/nut-names.txt#L450

Beside that, the issue title is misleading: according to the data screenshot in your post, battery.packs: 12 is in fact applied :)

jimklimov avatar Feb 10 '22 11:02 jimklimov

Also, just in case: are you able to measure the actual battery voltage with an electric meter?

Is the battery as old as the UPS or did you replace it - their lifetime is in a few years' range at best, so a 10 years old battery is probably dead and the voltage reading may be in fact correct ;)

jimklimov avatar Feb 10 '22 11:02 jimklimov

thx for your reply.

The two batteries are new. I replaced the batteries a few weeks ago. The voltage should be 2x12V=24V (nominal voltage). I measured the open circuit voltage at 27,2V.

The original software of my UPS shows the right voltage: 27,24V. So the problem is in the nut-software.

Here the description of this parameter:

 override.battery.packs = value

    Some devices report a part of the total battery voltage.

    For instance, if battery.voltage.nominal is 24 V, but it reports a battery.voltage
of around 2 V, the number of battery.packs to correct this reading would be 12.
The driver will attempt to detect this automatically, but if this fails somehow,
you may want to override this value.

per https://networkupstools.org/docs/man/nutdrv_qx.html

So it should work. But it doesn't work :-(

I found another thread about this: https://github.com/networkupstools/nut/issues/1039

But I can't find a solution.

Any ideas?

baerenwaldfreund avatar Feb 10 '22 15:02 baerenwaldfreund

I also have the same issue reported by the user. My NUT is returning Battery.voltage 225.00 and when viewing the UPS panel or measuring through a voltmeter, I get 216 Volts. I performed tests with blazer_ser and nutdrv_qx but got the same results.

Has anyone found a solution?

NOTE: Nobreate TS Shara TS SYAL 10 KVa connected via serial to USB converter.

ups@ups:~$ upsc tsshara01 Init SSL without certificate database battery.charge: 100 battery.voltage: 225.00 battery.voltage.high: 221 battery.voltage.low: 166.40 battery.voltage.nominal: 192.0 device.mfr: device.model: 11-06K device.type: ups driver.name: blazer_ser driver.parameter.pollinterval: 2 driver.parameter.port: /dev/ttyUSB0 driver.parameter.synchronous: no driver.version: 2.7.4 driver.version.internal: 1.57 input.current.nominal: 47.0 input.frequency: 59.9 input.frequency.nominal: 60 input.voltage: 122.5 input.voltage.fault: 32.9 input.voltage.nominal: 127 output.voltage: 126.9 ups.beeper.status: enabled ups.delay.shutdown: 30 ups.delay.start: 180 ups.firmware: 11.001.011 ups.load: 36 ups.mfr: ups.model: 11-06K ups.status: OL ups.temperature: 25.0 ups.type: online

EmersonHeiderich avatar May 17 '22 16:05 EmersonHeiderich

Facing same problem with Powerman Online 1000 Plus (USB connection): (battery.packs are changed, but voltage still around 2V)

[ 1194.166542] usb 1-8: new low-speed USB device number 3 using xhci_hcd [ 1194.182429] usb 1-8: New USB device found, idVendor=0001, idProduct=0000 [ 1194.182434] usb 1-8: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [ 1194.182460] usb 1-8: Product: MEC0003 [ 1194.182463] usb 1-8: Manufacturer: MEC [ 1194.183546] usb 1-8: ep 0x81 - rounding interval to 64 microframes, ep desc says 80 microframes [ 1194.728180] generic-usb 0003:0001:0000.0001: hiddev0,hidraw0: USB HID v1.00 Device [MEC MEC0003] on usb-0000:00:14.0-8/input0

$upsc ups0@localhost battery.charge: 100 battery.packs: 12 battery.voltage: 2.25 battery.voltage.high: 26.00 battery.voltage.low: 20.80 battery.voltage.nominal: 24 device.type: ups driver.name: nutdrv_qx driver.parameter.pollfreq: 30 driver.parameter.pollinterval: 2 driver.parameter.port: auto driver.parameter.synchronous: no driver.version: 2.7.4 driver.version.data: Megatec 0.06 driver.version.internal: 0.28 input.current.nominal: 4.0 input.frequency: 50.0 input.frequency.nominal: 50 input.voltage: 235.4 input.voltage.fault: 120.0 input.voltage.nominal: 220 output.voltage: 235.3 ups.beeper.status: enabled ups.delay.shutdown: 30 ups.delay.start: 180 ups.firmware: V009B002D= ups.load: 31 ups.productid: 0000 ups.status: OL BYPASS ups.temperature: 27.0 ups.type: online ups.vendorid: 0001

anphsw avatar Jun 08 '22 06:06 anphsw

Tried blazer_usb with with same override.battery.packs value - it shows actual voltage, so maybe bug in nutdrv_qx only. $upsc ups0@localhost battery.charge: 100 battery.packs: 12 battery.voltage: 27.0 battery.voltage.high: 26.0 battery.voltage.low: 20.8 battery.voltage.nominal: 24.0 device.mfr: device.model: device.type: ups driver.name: blazer_usb driver.parameter.pollinterval: 2 driver.parameter.port: auto driver.parameter.synchronous: no driver.version: 2.7.4 driver.version.internal: 0.12 input.current.nominal: 4.0 input.frequency: 50.0 input.frequency.nominal: 50 input.voltage: 235.8 input.voltage.fault: 120.0 input.voltage.nominal: 220 output.voltage: 235.7 ups.beeper.status: enabled ups.delay.shutdown: 30 ups.delay.start: 180 ups.firmware: V009B002D= ups.load: 31 ups.mfr: ups.model: ups.productid: 0000 ups.status: OL BYPASS ups.temperature: 27.0 ups.type: online ups.vendorid: 0001

anphsw avatar Jun 08 '22 07:06 anphsw

Just in case - might also be a bug in 2.7.4 release that was long ago. With 2.8.0 finally published this year, are you in position to check if it (or current git head) fares better?

jimklimov avatar Jun 09 '22 13:06 jimklimov

I think there is a bug in nutdrv_qx, switched from blazer_usb and lost battery charge info additionally

mateuszdrab avatar Aug 22 '22 18:08 mateuszdrab

FWIW, I can confirm with latest git head the bug in nutdrv_qx persists. Tested on ABB Powervalue with usb

Network UPS Tools - Generic Q* USB/Serial driver 0.32 (2.8.0-5-g9cb8de681)
USB communication driver (libusb 1.0) 0.43
battery.charge: 0
battery.voltage: 2.28
battery.voltage.high: 26.00
battery.voltage.low: 20.80
battery.voltage.nominal: 24.0
device.model: WPHVR1K0
device.type: ups
driver.name: nutdrv_qx
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.productid: 5161
driver.parameter.synchronous: auto
driver.parameter.vendorid: 0665
driver.version: 2.8.0-5-g9cb8de681
driver.version.data: Megatec 0.06
driver.version.internal: 0.32
driver.version.usb: libusb-1.0.26 (API: 0x1000109)
input.current.nominal: 4.0
input.frequency: 50.0
input.frequency.nominal: 50
input.voltage: 238.9
input.voltage.fault: 238.4
input.voltage.nominal: 240
output.voltage: 238.7
ups.beeper.status: enabled
ups.delay.shutdown: 30
ups.delay.start: 180
ups.firmware: 02724.08
ups.load: 17
ups.productid: 5161
ups.status: OL BYPASS
ups.temperature: 24.9
ups.type: online
ups.vendorid: 0665

y0g33 avatar Aug 31 '22 06:08 y0g33

Just to clarify: https://github.com/networkupstools/nut/commit/9cb8de681 is not "latest git head" but the April release of NUT v2.8.0. Some bugs were fixed since then, though I don't remember anyone addressing this one.

One thing that comes to mind regards the change from libusb-0.1 to 1.0 - might be some issue in that lib or use of it?.. Can you build and test in-place (install not required) current NUT against libusb-0.1.x to rule that out?

jimklimov avatar Aug 31 '22 19:08 jimklimov

Also by IDs in the last post, I think the subdriver should be cypress?

jimklimov avatar Aug 31 '22 19:08 jimklimov

Found the error, was using old build config rules. After fixing the config, still no dice :-(.

battery.charge: 100
battery.voltage: 2.28
battery.voltage.high: 26.00
battery.voltage.low: 20.80
battery.voltage.nominal: 24.0
device.model: WPHVR1K0
device.type: ups
driver.name: nutdrv_qx
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.productid: 5161
driver.parameter.subdriver: cypress
driver.parameter.synchronous: auto
driver.parameter.vendorid: 0665
driver.version: 2.8.0-497-g532bada82
driver.version.data: Megatec 0.06
driver.version.internal: 0.32
driver.version.usb: libusb-1.0.26 (API: 0x1000109)
input.current.nominal: 4.0
input.frequency: 50.0
input.frequency.nominal: 50
input.voltage: 240.8
input.voltage.fault: 240.6
input.voltage.nominal: 240
output.voltage: 240.7
ups.beeper.status: enabled
ups.delay.shutdown: 30
ups.delay.start: 180
ups.firmware: 02724.08
ups.load: 19
ups.productid: 5161
ups.status: OL BYPASS
ups.temperature: 23.0
ups.type: online
ups.vendorid: 0665

As requested here is an output when compiled with libusb-0.1.

battery.charge: 100
battery.voltage: 2.28
battery.voltage.high: 26.00
battery.voltage.low: 20.80
battery.voltage.nominal: 24.0
device.model: WPHVR1K0
device.type: ups
driver.name: nutdrv_qx
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.productid: 5161
driver.parameter.subdriver: cypress
driver.parameter.synchronous: auto
driver.parameter.vendorid: 0665
driver.version: 2.8.0-497-g532bada82
driver.version.data: Megatec 0.06
driver.version.internal: 0.32
driver.version.usb: libusb-0.1 (or compat)
input.current.nominal: 4.0
input.frequency: 50.0
input.frequency.nominal: 50
input.voltage: 238.8
input.voltage.fault: 239.6
input.voltage.nominal: 240
output.voltage: 238.8
ups.beeper.status: enabled
ups.delay.shutdown: 30
ups.delay.start: 180
ups.firmware: 02724.08
ups.load: 18
ups.productid: 5161
ups.status: OL BYPASS
ups.temperature: 22.9
ups.type: online
ups.vendorid: 0665

y0g33 avatar Sep 01 '22 06:09 y0g33

Scribbling some notes here, to juggle for "differential diagnostics, people!" :)

  • blazer_ser returns IMHO strange results - battery (pack) yielding 216V? (or 225V for that matter... wondering if there is some rounding error with the maths and int-float conversions involved)
    • To me, the hundreds of Volts are suspicious on batteries, if that is not a rack-sized stack of UPS with expansion cabinets... but if the original software, or panel, or Voltmeter confirm that... so be it
    • "216 vs 225" needs a closer look at maths done in code. Note that part of NUT release v2.8.0 there was a large effort to fix compilation warnings, including revision of numeric type conversion and casting. It would be helpful to check if current codebase also mis-reports that reading, or fixed it "inadvertently" (and only delve further if not fixed). Notably, some casting from floating-point to integer types in the middle of calculations chain could cause effective rounding, and errors of that could aggregate in overall result.
  • blazer_usb seems to work as people expect it to, at least for NUT v2.7.4 codebase
  • nutdrv_qx seems to NOT work as people expect it to, regardless of NUT v2.7.4 of v2.8.0+ codebase and libusb0/1 backend, so at least not a regression of v2.8.0
  • some of the nutdrv_qx reports did not include a battery.packs reading so I suppose those reporters did not set the override parameter

Also:

  • the "override" and "default" parameters are not reflected in the "driver.*" collection complicating the investigation

I think there is a bug in nutdrv_qx, switched from blazer_usb and lost battery charge info additionally

  • They are different drivers with shared heritage, possibly not all mapping tables are in sync. And/or different subdriver or protocol settings were used - not enough detail in this message.
  • UPDATE: Per code analysis added below, these two issues may be related - seems charge is only calculated in some conditions if not reported by device directly. Although I think the intent was to provide it always - either natively from device reports, or guesstimated.

Noting similar code paths that deal with battery packs variables in blazer and nutdrv_qx drivers:

  • qx_initbattery() tries to guess battery.packs if not specified by config (or not learned from explicit data walk):
    • https://github.com/networkupstools/nut/blob/4e3d0ecceac4cc6ad7d61df8f1676ecf6c7e4035/drivers/nutdrv_qx.c#L320-L359
    • The bug might be here, in if (!dstate_getinfo("battery.charge") || !dstate_getinfo("battery.runtime")) { lots of init } clause at the start of the function -- at least for the original post, both dstate values are available so the driver never sets batt.packs it seems (and battery.voltage.high/low/nom for that matter):
      • https://github.com/networkupstools/nut/blob/4e3d0ecceac4cc6ad7d61df8f1676ecf6c7e4035/drivers/nutdrv_qx.c#L278-L283
    • Looking at that if clause, it seems that by original design (very original - from initial commit https://github.com/networkupstools/nut/commit/dee3620a1876e4c760628787f9ad1ec3ba2e3ba2 of the driver a decade ago), if the device initially reports its charge and runtime on its own, we do not guesstimate them from voltages and amounts of batteries; arguably per that intention these should not have been reported at all.
    • Maybe it makes sense to restructure this bit to do actually set values we have read from device or override config regardless of whether we have practical use for them. @clepple @aquette @zykh - WDYT?
    • Notably blazer_initbattery() is not so shielded from the start: https://github.com/networkupstools/nut/blob/4e3d0ecceac4cc6ad7d61df8f1676ecf6c7e4035/drivers/blazer.c#L602-L610
  • Equivalent bit of logic in blazer to set up batt.packs (apparently from battery.voltage.nominal) is:
    • https://github.com/networkupstools/nut/blob/4e3d0ecceac4cc6ad7d61df8f1676ecf6c7e4035/drivers/blazer.c#L133-L167
  • qx_ups_walk() part which deals with battery.voltage (and estimates battery.charge) is enabled by runtimecal option for some more complicated time-sliding logic to consider battery.packs, otherwise falls back to qx_battery() for linear approximation if the option is not set:
    • https://github.com/networkupstools/nut/blob/4e3d0ecceac4cc6ad7d61df8f1676ecf6c7e4035/drivers/nutdrv_qx.c#L3739-L3823
  • blazer_battery() and qx_battery():
    • https://github.com/networkupstools/nut/blob/4e3d0ecceac4cc6ad7d61df8f1676ecf6c7e4035/drivers/blazer.c#L89-L114
    • https://github.com/networkupstools/nut/blob/4e3d0ecceac4cc6ad7d61df8f1676ecf6c7e4035/drivers/nutdrv_qx.c#L225-L255

jimklimov avatar Sep 06 '22 13:09 jimklimov

Can you try building and running the driver from https://github.com/jimklimov/nut/tree/issue-1279 (source of PR #1652) to check if it behaves better? So far just making educated guesses...

jimklimov avatar Sep 06 '22 13:09 jimklimov

I get compile time errors when I try to build issue-1279. This does not happen with the master-branch

Build system is RPI3 running ArchLinux.

libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I../include -I../include -isystem /usr/local/include -g -O2 -Wno-reserved-identifier -Wno-unknown-warning-option -std=gnu99 -Wno-system-headers -Wall -Wextra -Wsign-compare -pedantic -Wno-error -MT strptime.lo -MD -MP -MF .deps/strptime.Tpo -c strptime.c  -fPIC -DPIC -o .libs/strptime.o
strptime.c:59:25: error: expected ';' before 'uint64_t'
   59 | typedef unsigned __int64 uint64_t;
      |                         ^~~~~~~~~
      |                         ;
strptime.c:59:1: warning: useless type name in empty declaration
   59 | typedef unsigned __int64 uint64_t;
      | ^~~~~~~
strptime.c: In function 'strptime':
strptime.c:389:25: warning: implicit declaration of function '_tzset'; did you mean 'tzset'? [-Wimplicit-function-declaration]
  389 |                         _tzset();
      |                         ^~~~~~
      |                         tzset
At top level:
cc1: note: unrecognized command-line option '-Wno-unknown-warning-option' may have been intended to silence earlier diagnostics
cc1: note: unrecognized command-line option '-Wno-reserved-identifier' may have been intended to silence earlier diagnostics
make[1]: *** [Makefile:603: strptime.lo] Error 1
make[1]: Leaving directory '/home/alarm/scratch/nut/nut/common'
make: *** [Makefile:507: all] Error 2

y0g33 avatar Sep 12 '22 23:09 y0g33

That's odd... errors per se seem familiar from recent discussion on more building stacks for Windows. This file is a fallback for platforms that lack strptime() in their libc, lifted from BSD and not much chiseled since it happened to work well for the one platform and toolkit it was then intended for practically.

The primary problem here is that it got built at all. The function should just be in standard Linux/glibc. And it should be similar in current master that got built well...

If you have that workspace still around, can you check in config.log - search for strptime and see what it could complain about when checking for build environment's capabilities? Any compiler error (space rays hitting RAM, low disk space, antivirus, etc.) that end up in a failed check cause an autotools decision that the method is not available.

So is it something random, due to build machine constraints, or something NUT recipes and other code can address?

Do the two codebases you tried differ in configure.ac or m4/* files? Maybe some existing fix was not backported from master to issue branches?..

jimklimov avatar Sep 13 '22 06:09 jimklimov

Also wondering if something important for the test happens reproducibly e.g. due to 32-bit ARM (right?)

jimklimov avatar Sep 13 '22 06:09 jimklimov

It is a 64 bit system

output snippet from config.log

 $ ./configure --enable-NIT

## --------- ##
## Platform. ##
## --------- ##

uname -m = aarch64
uname -r = 5.15.61-4-rpi-ARCH
uname -s = Linux
uname -v = #1 SMP PREEMPT Thu Sep 1 13:34:10 MDT 2022

To the untrained eye only thing that stands out is when configure exits.

target_vendor='unknown'
udevdir=''
configure: caught signal 2
configure: exit 1

y0g33 avatar Sep 13 '22 06:09 y0g33

The signal 2 would be Ctrl+C... Did the configure script complete? It should end with a printout of major features and CFLAGS, with a 0 exit-code.

jimklimov avatar Sep 13 '22 07:09 jimklimov

Also, did you ./autogen.sh it after changing branches?

jimklimov avatar Sep 13 '22 07:09 jimklimov

My bad. I did run "./autogen.sh".

These are the steps I undertook to build.

git clone --branch issue-1279  https://github.com/jimklimov/nut.git

cd nut

./autogen.sh

./configure

make

This time I have outputs from config.log to work with.

configure:13072: $? = 0
configure:13085: result: yes
configure:13103: checking for strptime(s1,s2,tm)
configure:13177: gcc -o conftest -isystem /usr/local/include -g -O2 -Wno-reserved-identifier -Wno-unknown-warning-option -std=gnu99   conftest.c  >&5
conftest.c: In function 'main':
conftest.c:141:11: error: storage size of 'tm' isn't known
  141 | struct tm tm;
      |           ^~
conftest.c:143:11: warning: implicit declaration of function 'strptime' [-Wimplicit-function-declaration]
  143 | char *p = strptime(date, "%m/%d/%Y", &tm);
      |           ^~~~~~~~
At top level:
cc1: note: unrecognized command-line option '-Wno-unknown-warning-option' may have been intended to silence earlier diagnostics
cc1: note: unrecognized command-line option '-Wno-reserved-identifier' may have been intended to silence earlier diagnostics
configure:13177: $? = 1
configure: program exited with status 1
configure: failed program was:
| /* confdefs.h */

y0g33 avatar Sep 13 '22 08:09 y0g33

Can you please grep -R strptime /usr/{,*/}include/ to check if it is there?

Possibly the test in configure.ac slacks off and only tests with one of include <time.h> or include <sys/time.h>?.. (on most systems nowadays both exist and picking one suffices) In that case it should get encumbered with #if HAVE_TIME_H etc. like in include/timehead.h I guess.

jimklimov avatar Sep 13 '22 16:09 jimklimov

Here is the requested output:

grep -R strptime /usr/{,*/}include/
/usr/include/isc/tm.h:isc_tm_strptime(const char *buf, const char *fmt, struct tm *tm);
/usr/include/time.h:extern char *strptime (const char *__restrict __s,
/usr/include/time.h:extern char *strptime_l (const char *__restrict __s,
/usr/include/c++/12.1.0/bits/locale_facets_nonio.tcc:  // Expand a strptime format string and parse it.  E.g., do_get_date() may
/usr/include/c++/12.1.0/bits/locale_facets_nonio.h:       *  specified for strftime(3)/strptime(3).  The actual parsing

y0g33 avatar Sep 14 '22 04:09 y0g33

Probably looking after the lines

configure: failed program was:
| /* confdefs.h */

you'd see a wall of text with generated tested source, including the macros about TIME headers the script found so far. But looking at the test code now, it should at least #include <time.h> as the fallback.

So then it seems like some systems thing why it does not serve the definitions. On my Debian Linux under hand, time.h includes bits/types/struct_tm.h (for target-dependent definitions) and only declares strptime if __USE_XOPEN is defined, which gets set in features.h if _GNU_SOURCE is defined among other ways to get it.

Your build does include -std=gnu99 so I'd expect that to be implicitly requested, but try running ./configure CFLAGS='-D_GNU_SOURCE=1' explicitly, to see if that rectifies things?

jimklimov avatar Sep 14 '22 09:09 jimklimov

Cheers @y0g33 : I've got an Arch Linux container running now, and reproduced your issue. Hopefully the shuffle from #1659 above would fix it for you (did for me, and ./ci_build.sh passed except for integration tests with Python). New gcc-12 and clang-14 offered some new warnings FWIW (but that is a separate matter for another day)...

Until that gets tested and merged, you can try to git pull --all ; git cherry-pick ffc2023 in your workspace, and rerun the build (including autogen).

UPDATE: That PR was merged, so issue-1279 branch was updated to include current NUT master plus the proposed fix.

jimklimov avatar Sep 14 '22 16:09 jimklimov

Thanks @jimklimov : Now the build did complete. Still no dice with override battery packs 😞.

battery.charge: 100
battery.packs: 12
battery.voltage: 2.28
battery.voltage.high: 26.00
battery.voltage.low: 20.80
battery.voltage.nominal: 24.0
device.model: WPHVR1K0
device.type: ups
driver.name: nutdrv_qx
driver.parameter.override.battery.packs: 12
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.productid: 5161
driver.parameter.subdriver: cypress
driver.parameter.synchronous: auto
driver.parameter.vendorid: 0665
driver.version: Windows-v2.8.0-alpha3-805-g65ed37042
driver.version.data: Megatec 0.06
driver.version.internal: 0.32
driver.version.usb: libusb-1.0.26 (API: 0x1000109)
input.current.nominal: 4.0
input.frequency: 50.0
input.frequency.nominal: 50
input.voltage: 239.7
input.voltage.fault: 239.5
input.voltage.nominal: 240
output.voltage: 239.7
ups.beeper.status: enabled
ups.delay.shutdown: 30
ups.delay.start: 180
ups.firmware: 02724.08
ups.load: 17
ups.productid: 5161
ups.status: OL
ups.temperature: 23.2
ups.type: online
ups.vendorid: 0665

y0g33 avatar Sep 15 '22 02:09 y0g33

Thanks for the report. At least, the part about reporting driver.parameter.override.* worked, and the parameter did set battery.packs.

Curiously, all previous reports stated ups.status: OL BYPASS but the latest one is ups.status: OL - do you know if that is a physically valid change (some maintenance works on the device at that time? anything in its own log if there is one?) or a change in the driver behavior (there were some CPS-related fixes since NUT v2.8.0 release, though ones I think of were IIRC for USB HID models).

As for battery.voltage not being further adjusted, I'm a bit of at a crossroads.

On one hand, this currently functions as designed: With the code analysis above in mind (as well as differences in some of these regards between nutdrv_qx and blazer* drivers), it seems that previous authors deemed this bit of info only useful as one of the factors in fallback estimation of battery charge and remaining battery.runtime (notably not seen produced in your case). At least, it also seems that for existing code having one of those values is reason to not bother about fixing up battery.voltage (I'd expect both of them to be required-served to avoid fallbacks, but oh well for the moment). Your device does serve at least a battery.charge: 100 hence fallback (or parts of it peppered around the codebase) is avoided, and so the "useless" adjustment from reported voltage of a single average(?) battery pack in your device's case to the summary voltage of all packs together as "the battery" (value in 24V range in your case) is also not done as it does not impact the charge/runtime fallback calculation which is not done because served.

On another hand, curious people like you do want a known reasonable voltage for "battery" overall. I wonder if it is reasonable to either introduce a new configuration option to be explicit about the requested adjustment, or to imply it by presence of the override.battery.packs setting, or "guess" by checking if the current battery.voltage is in the correct ballpark (between low/high if known, possibly via another override) or otherwise if the current battery.voltage times battery.packs is in that ballpark -- and if yes, adjust. I suppose an explicit option would be prudent to clearly either multiply or not - as the battery might discharge and get out of the ballpark during an outage, causing weird "adjusted" readings as the numbers for decision cross the border.

  • I do not know offhand if there are devices, at least those with Megatec Q* protocols, which natively report complete battery voltage or all report that of one cell/pack.

Yet another matter is the lack of battery.runtime reading in your case (and also some other reports above), which does not seem to be "guesstimated" instead either. This fallback might only be triggered by runtimecal driver option however, which is missing in your config.

jimklimov avatar Sep 18 '22 17:09 jimklimov

Can you start the driver with higher debug level? In case of current NUT codebase (e.g. with the PR build you have) it may be as easy as specifying debug_min = 2 among driver options and restarting the driver (comment it away later).

I wonder if either there on driver's stderr (or in driver systemd unit journal, etc.) or in system log at INFO level, you'd see messages from https://github.com/networkupstools/nut/blob/bce0bff55f89fce06da3330e7ced07e4d906f28e/drivers/nutdrv_qx.c#L399 and below. Overall, if the driver initialization does recognize lack of battery.runtime served by device in your case, so whether it would prepare the fallback handling at all (and how - successfully or not for different components it looks at)?

My current guess is that it might have tried even initially, with "standard" driver, but failed to guess battery.packs because 2.28 * 12 = 27.36 which is outside the 20.80 .. 26.00 range your device reports... or driver guesses as a fork around 24.0 if only the nominal voltage is known from device (it logs "No values for battery high/low voltages" and "Using 'guesstimation' (low: %f, high: %f)!" then). Maybe yours does not have 12 packs, etc? Possibly disconnecting the battery assembly and checking with a voltmeter (or just looking at its printed label spec, indentations on casing, etc.) could be usefully informative. Are there two assemblies of 12V each?

jimklimov avatar Sep 18 '22 17:09 jimklimov

Please find my answers to your queries.

Curiously, all previous reports stated ups.status: OL BYPASS but the latest one is ups.status: OL - do you know if that > is a physically valid change (some maintenance works on the device at that time? anything in its own log if there is one?) or a change in the driver behavior (there were some CPS-related fixes since NUT v2.8.0 release, though ones I think of were IIRC for USB HID models).

As the UPS is new. I was running some tests, The changes you see are intended change.

OL BYPASS -- was the Eco mode tests. OL -- It is running in production.

battery.voltage

Please note the low and high voltage values reported are guess estimated I have checked it at the Panel (random times) -- It does report 27.[2-6]0 as floating voltage Multimeter tests will follow soon.

battery.charge: 0

It could be that I provided output minus battery pack option from my initial testing

Battery

UPS uses 2x 12V (6 Cells per Unit) https://www.csb-battery.com.tw/english/01_product/02_detail.php?fid=17&pid=113

  • Spec sheet reported Floating Voltage matches with what I see at the panel

Runtimecal / battery.runtime

I have the values for Battery runtime. Please see the output below. I have observed it takes upto a minute (anecdotal) before I can see battery runtime

battery.charge: 100
battery.packs: 12
battery.runtime: 2400
battery.voltage: 2.26
battery.voltage.high: 26.00
battery.voltage.low: 20.80
battery.voltage.nominal: 24.0
device.model: WPHVR1K0
device.type: ups
driver.name: nutdrv_qx
driver.parameter.override.battery.packs: 12
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.productid: 5161
driver.parameter.runtimecal: 240,100,360,75,1200,50,1380,25
driver.parameter.subdriver: cypress
driver.parameter.synchronous: auto
driver.parameter.vendorid: 0665
driver.version: Windows-v2.8.0-alpha3-805-g65ed37042
driver.version.data: Megatec 0.06
driver.version.internal: 0.32
driver.version.usb: libusb-1.0.26 (API: 0x1000109)
input.current.nominal: 4.0
input.frequency: 50.0
input.frequency.nominal: 50
input.voltage: 241.8
input.voltage.fault: 242.1
input.voltage.nominal: 240
output.voltage: 239.7
ups.beeper.status: enabled
ups.delay.shutdown: 30
ups.delay.start: 180
ups.firmware: 02724.08
ups.load: 18
ups.productid: 5161
ups.status: OL
ups.temperature: 31.0
ups.type: online
ups.vendorid: 0665

y0g33 avatar Sep 19 '22 05:09 y0g33

Thanks for the confirmations and details! Especially that battery.runtime does eventually appear (it possibly takes a "full walk" of the device, or several?, for the driver to notice it does not have a native reading so it calculates one).

"Down and down went Alice into the rabbit hole..." - I can't actually find dstate_setinfo.*"battery.voltage" matches in QX-related drivers, neither nutdrv_qx nor blazer_usb. Some other (unrelated) drivers do have explicit assignments for the reading. A few nutdrv_qx subdrivers however have processing hooks, namely:

drivers/nutdrv_qx_ablerex.c:    { "battery.voltage",            0,      NULL,   "Q1\r", "",     47,     '(',    "",    28,                                                                                        31,      "%.2f", 0,      NULL,   NULL,   ablerex_battery },

=> lots of complicated if-then decisions

drivers/nutdrv_qx_masterguard.c:        { "battery.voltage",            0,      NULL,   "Q3\r", "",     71,     '(',   "",                                                                                        31,      35,     "%.1f", 0,                      NULL,   NULL,   masterguard_battvolt },

=> snprintf(value, valuelen, "%.2f", masterguard_my_numcells * s);

drivers/nutdrv_qx_voltronic-qs-hex.c:   { "battery.voltage",            0,      NULL,   "QS\r", "",     47,     '#',   "",                                                                                        32,      36,     "%.2f", 0,      NULL,   voltronic_qs_hex_preprocess_qs_answer,  voltronic_qs_hex_battery_voltage },

=> snprintf(value, valuelen, item->dfl, (val1 * val2) / 510.0);
=> but that one may be further complicated as a non-plaintext protocol dialect

Again, it seems like by default the packs count (times device-reported single pack voltage) was supposed to impact charge/runtime guesses but not to feed back into battery.voltage itself. Maybe a separate name for one of those is needed, to be clear...

jimklimov avatar Sep 19 '22 07:09 jimklimov