2828#include "nut_stdint.h"
2929
3030#define DRIVER_NAME "Opti-UPS driver"
31- #define DRIVER_VERSION "1.03 "
31+ #define DRIVER_VERSION "1.04 "
3232
3333/* driver description structure */
3434upsdrv_info_t upsdrv_info = {
@@ -83,7 +83,8 @@ static char _buf[256];
8383static int optimodel = 0 ;
8484enum {
8585 OPTIMODEL_DEFAULT = 0 ,
86- OPTIMODEL_ZINTO = 1
86+ OPTIMODEL_ZINTO = 1 ,
87+ OPTIMODEL_PS = 2
8788};
8889
8990
@@ -123,6 +124,19 @@ static ezfill_t _pollv_zinto[] = {
123124 { "BT" , "ups.temperature" , 0 },
124125};
125126
127+ /* When on a 220-2400V mains supply, the NV and OV commands return 115V values. FV
128+ * returns a value that matches the DIP switch settings for 120/240V models, so
129+ * it can be used to scale the valus from NV and OV.
130+ *
131+ * I suspect this will be the case for other Opti-UPS models, but as I can only
132+ * test with a PS-1440RM at 230V the change is only applied to PowerSeries models.
133+ */
134+ static ezfill_t _pollv_ps [] = {
135+ { "OL" , "ups.load" , 1.0 },
136+ { "FF" , "input.frequency" , 0.1 },
137+ { "BT" , "ups.temperature" , 0 },
138+ };
139+
126140/* model "IO" is parsed differently in upsdrv_initinfo() */
127141static ezfill_t _initv [] = {
128142 { "IM" , "ups.mfr" , 0 },
@@ -347,6 +361,13 @@ void upsdrv_initinfo(void)
347361 optiquery ( "ON" );
348362 }
349363
364+ /* Autodetect an Opti-UPS PS series */
365+ r = optiquery ( "IO" );
366+ if ( r > 0 && !strncasecmp (_buf , "PS-" , 3 ) )
367+ {
368+ optimodel = OPTIMODEL_PS ;
369+ }
370+
350371 optifill ( _initv , sizeof (_initv )/sizeof (_initv [0 ]) );
351372
352373 /* Parse out model into longer string -- is this really USEFUL??? */
@@ -463,6 +484,29 @@ void upsdrv_updateinfo(void)
463484 /* read some easy settings */
464485 if ( optimodel == OPTIMODEL_ZINTO )
465486 optifill ( _pollv_zinto , sizeof (_pollv_zinto )/sizeof (_pollv_zinto [0 ]) );
487+ else if ( optimodel == OPTIMODEL_PS ) {
488+ short inV , outV , fV ;
489+
490+ optifill ( _pollv_ps , sizeof (_pollv_ps )/sizeof (_pollv_ps [0 ]) );
491+
492+ r = optiquery ( "NV" );
493+ str_to_short ( _buf , & inV , 10 );
494+ r = optiquery ( "OV" );
495+ str_to_short ( _buf , & outV , 10 );
496+
497+ r = optiquery ( "FV" );
498+ if ( r >= 1 )
499+ {
500+ str_to_short ( _buf , & fV , 10 );
501+ if ( fV > 180 )
502+ {
503+ inV = inV * 2 ;
504+ outV = outV * 2 ;
505+ }
506+ }
507+ dstate_setinfo ( "input.voltage" , "%d" , inV );
508+ dstate_setinfo ( "output.voltage" , "%d" , outV );
509+ }
466510 else
467511 optifill ( _pollv , sizeof (_pollv )/sizeof (_pollv [0 ]) );
468512
@@ -475,8 +519,16 @@ void upsdrv_updateinfo(void)
475519 float p , v = strtol ( _buf , NULL , 10 ) / 10.0 ;
476520 dstate_setinfo ("battery.voltage" , "%.1f" , v );
477521
478- /* battery voltage range: 10.4 - 13.0 VDC */
479- p = ((v - 10.4 ) / 2.6 ) * 100.0 ;
522+ if (v > 20 )
523+ {
524+ /* battery voltage range: 20.8 - 26.0 VDC */
525+ p = ((v - 20.8 ) / 5.2 ) * 100.0 ;
526+ }
527+ else
528+ {
529+ /* battery voltage range: 10.4 - 13.0 VDC */
530+ p = ((v - 10.4 ) / 2.6 ) * 100.0 ;
531+ }
480532 if ( p > 100.0 )
481533 p = 100.0 ;
482534 dstate_setinfo ("battery.charge" , "%.1f" , p );
0 commit comments