diff --git a/NEWS.adoc b/NEWS.adoc index de559cf130..b640d8f1d0 100644 --- a/NEWS.adoc +++ b/NEWS.adoc @@ -228,6 +228,14 @@ as part of https://github.com/networkupstools/nut/issues/1410 solution. - The `bestfortress` driver shutdown handling was fixed to use a non-trivial default timeout [#1820] + - The `optiups` driver only gave accurate voltage information with 120VAC + models and assumed a 12V battery when calculating capacity. There is + a protocol command that gives a (fixed) voltage which correlates with + the voltage selection DIP switches on the back of the UPS, taking into + account whether it is a 120 or 240VAC model. Likewise, now the battery + capacity fix is applied globally, based on whether or not the battery + voltage is greater than 20V. [#2089] + - GPIO drivers [#1855]: * Added a new category of drivers, using GPIO interface to locally connected devices (currently limited to 2018+ Linux libgpiod, but its architecture diff --git a/data/driver.list.in b/data/driver.list.in index ac613778c6..d1eb3951e2 100644 --- a/data/driver.list.in +++ b/data/driver.list.in @@ -925,6 +925,7 @@ "Opti-UPS" "ups" "1" "PowerES" "420E" "optiups" "Opti-UPS" "ups" "1" "VS 575C" "type=OPTI" "powercom" "Opti-UPS" "ups" "1" "Power Series" "PS1500E" "blazer_usb" +"Opti-UPS" "ups" "1" "Power Series" "PS1440RM" "optiups" "Orvaldi Power Protection" "ups" "2" "various" "not 400 or 600" "blazer_ser" "Orvaldi Power Protection" "ups" "2" "750 / 900SP" "USB" "blazer_usb" diff --git a/drivers/optiups.c b/drivers/optiups.c index eddd94e173..35f1005361 100644 --- a/drivers/optiups.c +++ b/drivers/optiups.c @@ -28,7 +28,7 @@ #include "nut_stdint.h" #define DRIVER_NAME "Opti-UPS driver" -#define DRIVER_VERSION "1.03" +#define DRIVER_VERSION "1.04" /* driver description structure */ upsdrv_info_t upsdrv_info = { @@ -83,7 +83,8 @@ static char _buf[256]; static int optimodel = 0; enum { OPTIMODEL_DEFAULT = 0, - OPTIMODEL_ZINTO = 1 + OPTIMODEL_ZINTO = 1, + OPTIMODEL_PS = 2 }; @@ -123,6 +124,19 @@ static ezfill_t _pollv_zinto[] = { { "BT", "ups.temperature", 0 }, }; +/* When on a 220-2400V mains supply, the NV and OV commands return 115V values. FV + * returns a value that matches the DIP switch settings for 120/240V models, so + * it can be used to scale the valus from NV and OV. + * + * I suspect this will be the case for other Opti-UPS models, but as I can only + * test with a PS-1440RM at 230V the change is only applied to PowerSeries models. + */ +static ezfill_t _pollv_ps[] = { + { "OL", "ups.load", 1.0 }, + { "FF", "input.frequency", 0.1 }, + { "BT", "ups.temperature", 0 }, +}; + /* model "IO" is parsed differently in upsdrv_initinfo() */ static ezfill_t _initv[] = { { "IM", "ups.mfr", 0 }, @@ -347,6 +361,13 @@ void upsdrv_initinfo(void) optiquery( "ON" ); } + /* Autodetect an Opti-UPS PS series */ + r = optiquery( "IO" ); + if ( r > 0 && !strncasecmp(_buf, "PS-", 3) ) + { + optimodel = OPTIMODEL_PS; + } + optifill( _initv, sizeof(_initv)/sizeof(_initv[0]) ); /* Parse out model into longer string -- is this really USEFUL??? */ @@ -463,6 +484,29 @@ void upsdrv_updateinfo(void) /* read some easy settings */ if ( optimodel == OPTIMODEL_ZINTO ) optifill( _pollv_zinto, sizeof(_pollv_zinto)/sizeof(_pollv_zinto[0]) ); + else if ( optimodel == OPTIMODEL_PS ) { + short inV, outV, fV; + + optifill( _pollv_ps, sizeof(_pollv_ps)/sizeof(_pollv_ps[0]) ); + + r = optiquery( "NV" ); + str_to_short ( _buf, &inV, 10 ); + r = optiquery( "OV" ); + str_to_short ( _buf, &outV, 10 ); + + r = optiquery( "FV" ); + if ( r >= 1 ) + { + str_to_short ( _buf, &fV, 10 ); + if ( fV > 180 ) + { + inV = inV * 2; + outV = outV * 2; + } + } + dstate_setinfo( "input.voltage", "%d", inV ); + dstate_setinfo( "output.voltage", "%d", outV ); + } else optifill( _pollv, sizeof(_pollv)/sizeof(_pollv[0]) ); @@ -475,8 +519,16 @@ void upsdrv_updateinfo(void) float p, v = strtol( _buf, NULL, 10 ) / 10.0; dstate_setinfo("battery.voltage", "%.1f", v ); - /* battery voltage range: 10.4 - 13.0 VDC */ - p = ((v - 10.4) / 2.6) * 100.0; + if (v > 20) + { + /* battery voltage range: 20.8 - 26.0 VDC */ + p = ((v - 20.8) / 5.2) * 100.0; + } + else + { + /* battery voltage range: 10.4 - 13.0 VDC */ + p = ((v - 10.4) / 2.6) * 100.0; + } if ( p > 100.0 ) p = 100.0; dstate_setinfo("battery.charge", "%.1f", p );