2013-11-24 17:00:12 +02:00
/* nutdrv_qx_voltronic.c - Subdriver for Voltronic Power UPSes
*
* Copyright ( C )
* 2013 Daniele Pezzini < hyouko @ gmail . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# include "main.h"
# include "nutdrv_qx.h"
# include "nutdrv_qx_voltronic.h"
2015-04-30 16:53:36 +03:00
# define VOLTRONIC_VERSION "Voltronic 0.03"
2013-11-24 17:00:12 +02:00
/* Support functions */
static int voltronic_claim ( void ) ;
static void voltronic_makevartable ( void ) ;
static void voltronic_massive_unskip ( const int protocol ) ;
/* Range/enum functions */
static int voltronic_batt_low ( char * value , size_t len ) ;
static int voltronic_bypass_volt_max ( char * value , size_t len ) ;
static int voltronic_bypass_volt_min ( char * value , size_t len ) ;
static int voltronic_bypass_freq_max ( char * value , size_t len ) ;
static int voltronic_bypass_freq_min ( char * value , size_t len ) ;
static int voltronic_eco_freq_min ( char * value , size_t len ) ;
static int voltronic_eco_freq_max ( char * value , size_t len ) ;
/* Preprocess functions */
static int voltronic_process_setvar ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_process_command ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_capability ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_capability_set ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_capability_set_nonut ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_capability_reset ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_eco_volt ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_eco_volt_range ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_eco_freq ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_bypass ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_batt_numb ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_batt_runtime ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_protocol ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_fault ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_warning ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_mode ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_status ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_output_powerfactor ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_serial_numb ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_outlet ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_outlet_delay ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_outlet_delay_set ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_p31b ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_p31b_set ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_p31g ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_p31g_set ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_phase ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_phase_set ( item_t * item , char * value , size_t valuelen ) ;
static int voltronic_parallel ( item_t * item , char * value , size_t valuelen ) ;
/* Capability vars */
static char * bypass_alarm ,
* battery_alarm ,
* bypass_when_off ,
* alarm_control ,
* converter_mode ,
* eco_mode ,
* battery_open_status_check ,
* bypass_forbidding ,
* site_fault_detection ,
* advanced_eco_mode ,
* constant_phase_angle ,
* limited_runtime_on_battery ;
/* ups.conf settings */
static int max_bypass_volt ,
min_bypass_volt ,
battery_number ,
output_phase_angle ,
work_range_type ;
static double max_bypass_freq ,
min_bypass_freq ;
/* == Ranges/enums == */
/* Range for ups.delay.start */
static info_rw_t voltronic_r_ondelay [ ] = {
{ " 0 " , 0 } ,
{ " 599940 " , 0 } ,
{ " " , 0 }
} ;
/* Range for ups.delay.shutdown */
static info_rw_t voltronic_r_offdelay [ ] = {
{ " 12 " , 0 } ,
{ " 5940 " , 0 } ,
{ " " , 0 }
} ;
/* Enumlist for output phase angle */
static info_rw_t voltronic_e_phase [ ] = {
{ " 000 " , 0 } ,
{ " 120 " , 0 } ,
{ " 180 " , 0 } ,
{ " 240 " , 0 } ,
{ " " , 0 }
} ;
/* Range for battery low voltage */
static info_rw_t voltronic_r_batt_low [ ] = {
{ " 20 " , 0 } ,
{ " 24 " , voltronic_batt_low } ,
{ " 28 " , voltronic_batt_low } ,
{ " " , 0 }
} ;
/* Preprocess range value for battery low voltage */
static int voltronic_batt_low ( char * value , size_t len )
{
int val = strtol ( value , NULL , 10 ) ;
const char * ovn = dstate_getinfo ( " output.voltage.nominal " ) ,
* ocn = dstate_getinfo ( " output.current.nominal " ) ;
if ( ! ovn | | ! ocn ) {
upsdebugx ( 2 , " %s: unable to get the value of output voltage nominal/output current nominal " , __func__ ) ;
return - 1 ;
}
if ( ( strtol ( ovn , NULL , 10 ) * strtol ( ocn , NULL , 10 ) ) < 1000 ) {
if ( val = = 24 )
return 0 ;
else
return - 1 ;
} else {
if ( val = = 28 )
return 0 ;
else
return - 1 ;
}
}
/* Range for outlet.n.delay.shutdown */
static info_rw_t voltronic_r_outlet_delay [ ] = {
{ " 0 " , 0 } ,
{ " 59940 " , 0 } ,
{ " " , 0 }
} ;
/* Enumlist for device grid working range type */
static info_rw_t voltronic_e_work_range [ ] = {
{ " Appliance " , 0 } , /* 00 */
{ " UPS " , 0 } , /* 01 */
{ " " , 0 }
} ;
/* Enumlist for battery type */
static info_rw_t voltronic_e_batt_type [ ] = {
{ " Li " , 0 } , /* 00 */
{ " Flooded " , 0 } , /* 01 */
{ " AGM " , 0 } , /* 02 */
{ " " , 0 }
} ;
/* Range for number of battery packs */
static info_rw_t voltronic_r_batt_packs [ ] = {
{ " 1 " , 0 } ,
{ " 99 " , 0 } ,
{ " " , 0 }
} ;
/* Range for number of batteries */
static info_rw_t voltronic_r_batt_numb [ ] = {
{ " 1 " , 0 } ,
{ " 9 " , 0 } ,
{ " " , 0 }
} ;
/* Range for Bypass Mode maximum voltage */
static info_rw_t voltronic_r_bypass_volt_max [ ] = {
{ " 60 " , voltronic_bypass_volt_max } , /* P09 */
2015-04-30 16:53:36 +03:00
{ " 115 " , voltronic_bypass_volt_max } , /* P02/P03/P10/P13/P14/P99 ivn<200 */
2013-11-24 17:00:12 +02:00
{ " 120 " , voltronic_bypass_volt_max } , /* P01 ivn<200 */
{ " 132 " , voltronic_bypass_volt_max } , /* P99 ivn<200 */
2015-04-30 16:53:36 +03:00
{ " 138 " , voltronic_bypass_volt_max } , /* P02/P03/P10/P13/P14 ivn<200 */
2013-11-24 17:00:12 +02:00
{ " 140 " , voltronic_bypass_volt_max } , /* P01 ivn<200, P09 */
{ " 230 " , voltronic_bypass_volt_max } , /* P01 ivn>=200 */
2015-04-30 16:53:36 +03:00
{ " 231 " , voltronic_bypass_volt_max } , /* P02/P03/P10/P13/P14/P99 ivn>=200 */
2013-11-24 17:00:12 +02:00
{ " 261 " , voltronic_bypass_volt_max } , /* P99 ivn>=200 */
{ " 264 " , voltronic_bypass_volt_max } , /* P01 ivn>=200 */
2015-04-30 16:53:36 +03:00
{ " 276 " , voltronic_bypass_volt_max } , /* P02/P03/P10/P13/P14 ivn>=200 */
2013-11-24 17:00:12 +02:00
{ " " , 0 }
} ;
/* Preprocess range value for Bypass Mode maximum voltage */
static int voltronic_bypass_volt_max ( char * value , size_t len )
{
int protocol = strtol ( dstate_getinfo ( " ups.firmware.aux " ) + 1 , NULL , 10 ) ,
val = strtol ( value , NULL , 10 ) ,
ivn ;
const char * involtnom = dstate_getinfo ( " input.voltage.nominal " ) ;
if ( ! involtnom ) {
upsdebugx ( 2 , " %s: unable to get input.voltage.nominal " , __func__ ) ;
return - 1 ;
}
ivn = strtol ( involtnom , NULL , 10 ) ;
switch ( val )
{
case 60 : /* P09 */
if ( protocol = = 9 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 115 : /* P02/P03/P10/P13/P14/P99 ivn<200 */
2013-11-24 17:00:12 +02:00
if ( ivn > = 200 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 120 : /* P01 ivn<200 */
if ( ivn > = 200 )
return - 1 ;
if ( protocol = = 1 )
return 0 ;
break ;
case 132 : /* P99 ivn<200 */
if ( ivn > = 200 )
return - 1 ;
if ( protocol = = 99 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 138 : /* P02/P03/P10/P13/P14 ivn<200 */
2013-11-24 17:00:12 +02:00
if ( ivn > = 200 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 2 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 140 : /* P01 ivn<200, P09 */
if ( protocol = = 9 )
return 0 ;
if ( ivn > = 200 )
return - 1 ;
if ( protocol = = 1 )
return 0 ;
break ;
case 230 : /* P01 ivn>=200 */
if ( ivn < 200 )
return - 1 ;
if ( protocol = = 1 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 231 : /* P02/P03/P10/P13/P14/P99 ivn>=200 */
2013-11-24 17:00:12 +02:00
if ( ivn < 200 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 2 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 261 : /* P99 ivn>=200 */
if ( ivn < 200 )
return - 1 ;
if ( protocol = = 99 )
return 0 ;
break ;
case 264 : /* P01 ivn>=200 */
if ( ivn < 200 )
return - 1 ;
if ( protocol = = 1 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 276 : /* P02/P03/P10/P13/P14 ivn>=200 */
2013-11-24 17:00:12 +02:00
if ( ivn < 200 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
default :
upsdebugx ( 2 , " %s: unknown value (%s) " , __func__ , value ) ;
break ;
}
return - 1 ;
}
/* Range for Bypass Mode minimum voltage */
static info_rw_t voltronic_r_bypass_volt_min [ ] = {
{ " 50 " , voltronic_bypass_volt_min } , /* P99 ivn<200 */
2015-04-30 16:53:36 +03:00
{ " 55 " , voltronic_bypass_volt_min } , /* P02/P03/P10/P13/P14 ivn<200 */
2013-11-24 17:00:12 +02:00
{ " 60 " , voltronic_bypass_volt_min } , /* P09 */
{ " 85 " , voltronic_bypass_volt_min } , /* P01/P99 ivn<200 */
2015-04-30 16:53:36 +03:00
{ " 104 " , voltronic_bypass_volt_min } , /* P02/P03/P10/P13/P14 ivn<200 */
{ " 110 " , voltronic_bypass_volt_min } , /* P02/P03/P10/P13/P14 ivn>=200 */
2013-11-24 17:00:12 +02:00
{ " 115 " , voltronic_bypass_volt_min } , /* P01 ivn<200 */
{ " 140 " , voltronic_bypass_volt_min } , /* P09 */
{ " 149 " , voltronic_bypass_volt_min } , /* P99 ivn>=200 */
{ " 170 " , voltronic_bypass_volt_min } , /* P01 ivn>=200 */
2015-04-30 16:53:36 +03:00
{ " 209 " , voltronic_bypass_volt_min } , /* P02/P03/P10/P13/P14/P99 ivn>=200 */
2013-11-24 17:00:12 +02:00
{ " 220 " , voltronic_bypass_volt_min } , /* P01 ivn>=200 */
{ " " , 0 }
} ;
/* Preprocess range value for Bypass Mode minimum voltage */
static int voltronic_bypass_volt_min ( char * value , size_t len )
{
int protocol = strtol ( dstate_getinfo ( " ups.firmware.aux " ) + 1 , NULL , 10 ) ,
val = strtol ( value , NULL , 10 ) ,
ivn ;
const char * involtnom = dstate_getinfo ( " input.voltage.nominal " ) ;
if ( ! involtnom ) {
upsdebugx ( 2 , " %s: unable to get input.voltage.nominal " , __func__ ) ;
return - 1 ;
}
ivn = strtol ( involtnom , NULL , 10 ) ;
switch ( val )
{
case 50 : /* P99 ivn<200 */
if ( ivn > = 200 )
return - 1 ;
if ( protocol = = 99 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 55 : /* P02/P03/P10/P13/P14 ivn<200 */
2013-11-24 17:00:12 +02:00
if ( ivn > = 200 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 60 : /* P09 */
case 140 : /* P09 */
if ( protocol = = 9 )
return 0 ;
break ;
case 85 : /* P01/P99 ivn<200 */
if ( ivn > = 200 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 99 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 104 : /* P02/P03/P10/P13/P14 ivn<200 */
2013-11-24 17:00:12 +02:00
if ( ivn > = 200 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 110 : /* P02/P03/P10/P13/P14 ivn>=200 */
2013-11-24 17:00:12 +02:00
if ( ivn < 200 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 115 : /* P01 ivn<200 */
if ( ivn > = 200 )
return - 1 ;
if ( protocol = = 1 )
return 0 ;
break ;
case 149 : /* P99 ivn>=200 */
if ( ivn < 200 )
return - 1 ;
if ( protocol = = 99 )
return 0 ;
break ;
case 170 : /* P01 ivn>=200 */
if ( ivn < 200 )
return - 1 ;
if ( protocol = = 1 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 209 : /* P02/P03/P10/P13/P14/P99 ivn>=200 */
2013-11-24 17:00:12 +02:00
if ( ivn < 200 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 220 : /* P01 ivn>=200 */
if ( ivn < 200 )
return - 1 ;
if ( protocol = = 1 )
return 0 ;
break ;
default :
upsdebugx ( 2 , " %s: unknown value (%s) " , __func__ , value ) ;
break ;
}
return - 1 ;
}
/* Range for Bypass Mode maximum frequency */
static info_rw_t voltronic_r_bypass_freq_max [ ] = {
2015-04-30 16:53:36 +03:00
{ " 51.0 " , voltronic_bypass_freq_max } , /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==50.0 */
{ " 54.0 " , voltronic_bypass_freq_max } , /* P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
{ " 60.0 " , voltronic_bypass_freq_max } , /* P01/P09 ofn==50.0 */
2015-04-30 16:53:36 +03:00
{ " 61.0 " , voltronic_bypass_freq_max } , /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==60.0 */
{ " 64.0 " , voltronic_bypass_freq_max } , /* P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
{ " 70.0 " , voltronic_bypass_freq_max } , /* P01/P09 ofn==60.0 */
{ " " , 0 }
} ;
/* Preprocess range value for Bypass Mode maximum frequency */
static int voltronic_bypass_freq_max ( char * value , size_t len )
{
int protocol = strtol ( dstate_getinfo ( " ups.firmware.aux " ) + 1 , NULL , 10 ) ,
val = strtol ( value , NULL , 10 ) ;
double ofn ;
const char * outfreqnom = dstate_getinfo ( " output.frequency.nominal " ) ;
if ( ! outfreqnom ) {
upsdebugx ( 2 , " %s: unable to get output.frequency.nominal " , __func__ ) ;
return - 1 ;
}
ofn = strtod ( outfreqnom , NULL ) ;
switch ( val )
{
2015-04-30 16:53:36 +03:00
case 51 : /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 50.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 1 | | protocol = = 2 | | protocol = = 3 | | protocol = = 9 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 54 : /* P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 50.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 60 : /* P01/P09 ofn==50.0 */
if ( ofn ! = 50.0 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 9 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 61 : /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 60.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 1 | | protocol = = 2 | | protocol = = 3 | | protocol = = 9 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 64 : /* P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 60.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 70 : /* P01/P09 ofn==60.0 */
if ( ofn ! = 60.0 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 9 )
return 0 ;
break ;
default :
upsdebugx ( 2 , " %s: unknown value (%s) " , __func__ , value ) ;
break ;
}
return - 1 ;
}
/* Range for Bypass Mode minimum frequency */
static info_rw_t voltronic_r_bypass_freq_min [ ] = {
{ " 40.0 " , voltronic_bypass_freq_min } , /* P01/P09 ofn==50.0 */
2015-04-30 16:53:36 +03:00
{ " 46.0 " , voltronic_bypass_freq_min } , /* P02/P03/P10/P13/P14/P99 ofn==50.0 */
{ " 49.0 " , voltronic_bypass_freq_min } , /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
{ " 50.0 " , voltronic_bypass_freq_min } , /* P01/P09 ofn==60.0 */
2015-04-30 16:53:36 +03:00
{ " 56.0 " , voltronic_bypass_freq_min } , /* P02/P03/P10/P13/P14/P99 ofn==60.0 */
{ " 59.0 " , voltronic_bypass_freq_min } , /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
{ " " , 0 }
} ;
/* Preprocess range value for Bypass Mode minimum frequency */
static int voltronic_bypass_freq_min ( char * value , size_t len )
{
int protocol = strtol ( dstate_getinfo ( " ups.firmware.aux " ) + 1 , NULL , 10 ) ,
val = strtol ( value , NULL , 10 ) ;
double ofn ;
const char * outfreqnom = dstate_getinfo ( " output.frequency.nominal " ) ;
if ( ! outfreqnom ) {
upsdebugx ( 2 , " %s: unable to get output.frequency.nominal " , __func__ ) ;
return - 1 ;
}
ofn = strtod ( outfreqnom , NULL ) ;
switch ( val )
{
case 40 : /* P01/P09 ofn==50.0 */
if ( ofn ! = 50.0 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 9 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 46 : /* P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 50.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 49 : /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 50.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 1 | | protocol = = 2 | | protocol = = 3 | | protocol = = 9 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 50 : /* P01/P09 ofn==60.0 */
if ( ofn ! = 60.0 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 9 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 56 : /* P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 60.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 59 : /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 60.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 1 | | protocol = = 2 | | protocol = = 3 | | protocol = = 9 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
default :
upsdebugx ( 2 , " %s: unknown value (%s) " , __func__ , value ) ;
break ;
}
return - 1 ;
}
/* Range for Eco Mode maximum voltage: filled at runtime by voltronic_eco_volt */
static info_rw_t voltronic_r_eco_volt_max [ ] = {
{ " " , 0 } ,
{ " " , 0 } ,
{ " " , 0 }
} ;
/* Range for ECO Mode minimum voltage: filled at runtime by voltronic_eco_volt */
static info_rw_t voltronic_r_eco_volt_min [ ] = {
{ " " , 0 } ,
{ " " , 0 } ,
{ " " , 0 }
} ;
/* Range for ECO Mode minimum frequency */
static info_rw_t voltronic_r_eco_freq_min [ ] = {
{ " 40.0 " , voltronic_eco_freq_min } , /* P01/P09 ofn==50.0 */
2015-04-30 16:53:36 +03:00
{ " 46.0 " , voltronic_eco_freq_min } , /* P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
{ " 47.0 " , voltronic_eco_freq_min } , /* P01/P09 ofn==50.0 */
2015-04-30 16:53:36 +03:00
{ " 48.0 " , voltronic_eco_freq_min } , /* P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
{ " 50.0 " , voltronic_eco_freq_min } , /* P01/P09 ofn==60.0 */
2015-04-30 16:53:36 +03:00
{ " 56.0 " , voltronic_eco_freq_min } , /* P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
{ " 57.0 " , voltronic_eco_freq_min } , /* P01/P09 ofn==60.0 */
2015-04-30 16:53:36 +03:00
{ " 58.0 " , voltronic_eco_freq_min } , /* P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
{ " " , 0 }
} ;
/* Preprocess range value for ECO Mode minimum frequency */
static int voltronic_eco_freq_min ( char * value , size_t len )
{
int protocol = strtol ( dstate_getinfo ( " ups.firmware.aux " ) + 1 , NULL , 10 ) ,
val = strtol ( value , NULL , 10 ) ;
double ofn ;
const char * outfreqnom = dstate_getinfo ( " output.frequency.nominal " ) ;
if ( ! outfreqnom ) {
upsdebugx ( 2 , " %s: unable to get output.frequency.nominal " , __func__ ) ;
return - 1 ;
}
ofn = strtod ( outfreqnom , NULL ) ;
switch ( val )
{
case 40 : /* P01/P09 ofn==50.0 */
if ( ofn ! = 50.0 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 9 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 46 : /* P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 50.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 47 : /* P01/P09 ofn==50.0 */
if ( ofn ! = 50.0 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 9 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 48 : /* P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 50.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 50 : /* P01/P09 ofn==60.0 */
if ( ofn ! = 60.0 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 9 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 56 : /* P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 60.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 57 : /* P01/P09 ofn==60.0 */
if ( ofn ! = 60.0 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 9 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 58 : /* P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 60.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
default :
upsdebugx ( 2 , " %s: unknown value (%s) " , __func__ , value ) ;
break ;
}
return - 1 ;
}
/* Range for ECO Mode maximum frequency */
static info_rw_t voltronic_r_eco_freq_max [ ] = {
2015-04-30 16:53:36 +03:00
{ " 52.0 " , voltronic_eco_freq_max } , /* P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
{ " 53.0 " , voltronic_eco_freq_max } , /* P01/P09 ofn==50.0 */
2015-04-30 16:53:36 +03:00
{ " 54.0 " , voltronic_eco_freq_max } , /* P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
{ " 60.0 " , voltronic_eco_freq_max } , /* P01/P09 ofn==50.0 */
2015-04-30 16:53:36 +03:00
{ " 62.0 " , voltronic_eco_freq_max } , /* P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
{ " 63.0 " , voltronic_eco_freq_max } , /* P01/P09 ofn==60.0 */
2015-04-30 16:53:36 +03:00
{ " 64.0 " , voltronic_eco_freq_max } , /* P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
{ " 70.0 " , voltronic_eco_freq_max } , /* P01/P09 ofn==60.0 */
{ " " , 0 }
} ;
/* Preprocess range value for ECO Mode maximum frequency */
static int voltronic_eco_freq_max ( char * value , size_t len )
{
int protocol = strtol ( dstate_getinfo ( " ups.firmware.aux " ) + 1 , NULL , 10 ) ,
val = strtol ( value , NULL , 10 ) ;
double ofn ;
const char * outfreqnom = dstate_getinfo ( " output.frequency.nominal " ) ;
if ( ! outfreqnom ) {
upsdebugx ( 2 , " %s: unable to get output.frequency.nominal " , __func__ ) ;
return - 1 ;
}
ofn = strtod ( outfreqnom , NULL ) ;
switch ( val )
{
2015-04-30 16:53:36 +03:00
case 52 : /* P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 50.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 53 : /* P01/P09 ofn==50.0 */
if ( ofn ! = 50.0 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 9 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 54 : /* P02/P03/P10/P13/P14/P99 ofn==50.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 50.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 60 : /* P01/P09 ofn==50.0 */
if ( ofn ! = 50.0 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 9 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 62 : /* P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 60.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 63 : /* P01/P09 ofn==60.0 */
if ( ofn ! = 60.0 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 9 )
return 0 ;
break ;
2015-04-30 16:53:36 +03:00
case 64 : /* P02/P03/P10/P13/P14/P99 ofn==60.0 */
2013-11-24 17:00:12 +02:00
if ( ofn ! = 60.0 )
return - 1 ;
2015-04-30 16:53:36 +03:00
if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 )
2013-11-24 17:00:12 +02:00
return 0 ;
break ;
case 70 : /* P01/P09 ofn==60.0 */
if ( ofn ! = 60.0 )
return - 1 ;
if ( protocol = = 1 | | protocol = = 9 )
return 0 ;
break ;
default :
upsdebugx ( 2 , " %s: unknown value (%s) " , __func__ , value ) ;
break ;
}
return - 1 ;
}
/* Enumlist for UPS capabilities that have a NUT var */
static info_rw_t voltronic_e_cap [ ] = {
{ " no " , 0 } ,
{ " yes " , 0 } ,
{ " " , 0 }
} ;
/* Enumlist for NONUT capabilities */
static info_rw_t voltronic_e_cap_nonut [ ] = {
{ " enabled " , 0 } ,
{ " disabled " , 0 } ,
{ " " , 0 }
} ;
/* == qx2nut lookup table == */
static item_t voltronic_qx2nut [ ] = {
/* Query UPS for protocol
* > [ QPI \ r ]
* < [ ( PI00 \ r ]
* 012345
* 0
*/
2015-04-30 16:53:36 +03:00
{ " ups.firmware.aux " , 0 , NULL , " QPI \r " , " " , 6 , ' ( ' , " " , 1 , 4 , " %s " , QX_FLAG_STATIC , NULL , voltronic_protocol } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for ratings
* > [ QRI \ r ]
* < [ ( 230.0 004 024.0 50.0 \ r ]
* 01234567 89012345678901
* 0 1 2
*/
2015-04-30 16:53:36 +03:00
{ " output.voltage.nominal " , 0 , NULL , " QRI \r " , " " , 22 , ' ( ' , " " , 1 , 5 , " %.1f " , QX_FLAG_STATIC , NULL , NULL } ,
{ " output.current.nominal " , 0 , NULL , " QRI \r " , " " , 22 , ' ( ' , " " , 7 , 9 , " %.0f " , QX_FLAG_STATIC , NULL , NULL } ,
{ " battery.voltage.nominal " , 0 , NULL , " QRI \r " , " " , 22 , ' ( ' , " " , 11 , 15 , " %.1f " , QX_FLAG_SEMI_STATIC , NULL , NULL } , /* as *per battery pack*: the value will change when the number of batteries is changed (battery_number through BATNn) */
{ " output.frequency.nominal " , 0 , NULL , " QRI \r " , " " , 22 , ' ( ' , " " , 17 , 20 , " %.1f " , QX_FLAG_STATIC , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for ratings
* > [ QMD \ r ]
* < [ ( # # # # # # # OLHVT1K0 # # # 1000 80 1 / 1 230 230 02 12.0 \ r ] < - Some UPS may reply with spaces instead of hashes
* 01234567 8901234567890123456789012345678901234567
* 0 1 2 3 4
*/
2015-04-30 16:53:36 +03:00
{ " device.model " , 0 , NULL , " QMD \r " , " " , 48 , ' ( ' , " " , 1 , 15 , " %s " , QX_FLAG_STATIC | QX_FLAG_TRIM , NULL , NULL } ,
{ " ups.power.nominal " , 0 , NULL , " QMD \r " , " " , 48 , ' ( ' , " " , 17 , 23 , " %s " , QX_FLAG_STATIC | QX_FLAG_TRIM , NULL , NULL } ,
{ " output.powerfactor " , 0 , NULL , " QMD \r " , " " , 48 , ' ( ' , " " , 25 , 26 , " %.1f " , QX_FLAG_STATIC , NULL , voltronic_output_powerfactor } ,
{ " input.phases " , 0 , NULL , " QMD \r " , " " , 48 , ' ( ' , " " , 28 , 28 , " %.0f " , QX_FLAG_STATIC , NULL , NULL } ,
{ " output.phases " , 0 , NULL , " QMD \r " , " " , 48 , ' ( ' , " " , 30 , 30 , " %.0f " , QX_FLAG_STATIC , NULL , NULL } ,
{ " input.voltage.nominal " , 0 , NULL , " QMD \r " , " " , 48 , ' ( ' , " " , 32 , 34 , " %.1f " , QX_FLAG_STATIC , NULL , NULL } ,
{ " output.voltage.nominal " , 0 , NULL , " QMD \r " , " " , 48 , ' ( ' , " " , 36 , 38 , " %.1f " , QX_FLAG_STATIC , NULL , NULL } , /* redundant with value from QRI */
/* { "battery_number", ST_FLAG_RW, voltronic_r_batt_numb, "QMD\r", "", 48, '(', "", 40, 41, "%d", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT, NULL, voltronic_batt_numb }, */ /* redundant with value from QBV */
/* { "battery.voltage.nominal", 0, NULL, "QMD\r", "", 48, '(', "", 43, 46, "%.1f", QX_FLAG_STATIC, NULL, NULL }, */ /* as *per battery* vs *per pack* reported by QRI */
2013-11-24 17:00:12 +02:00
/* Query UPS for ratings
* > [ F \ r ]
* < [ # 220.0 000 024.0 50.0 \ r ]
* 01234567 89012345678901
* 0 1 2
*/
2015-04-30 16:53:36 +03:00
{ " input.voltage.nominal " , 0 , NULL , " F \r " , " " , 22 , ' # ' , " " , 1 , 5 , " %.1f " , QX_FLAG_STATIC , NULL , NULL } ,
{ " input.current.nominal " , 0 , NULL , " F \r " , " " , 22 , ' # ' , " " , 7 , 9 , " %.1f " , QX_FLAG_STATIC , NULL , NULL } ,
{ " battery.voltage.nominal " , 0 , NULL , " F \r " , " " , 22 , ' # ' , " " , 11 , 15 , " %.1f " , QX_FLAG_STATIC , NULL , NULL } ,
{ " input.frequency.nominal " , 0 , NULL , " F \r " , " " , 22 , ' # ' , " " , 17 , 20 , " %.1f " , QX_FLAG_STATIC , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for manufacturer
* > [ QMF \ r ]
* < [ ( # # # # # # # BOH \ r ] < - I don ' t know if it has a fixed length ( - > so min length = ( + \ r = 2 ) . Hashes may be replaced by spaces
* 01234567 8901
* 0 1
*/
2015-04-30 16:53:36 +03:00
{ " device.mfr " , 0 , NULL , " QMF \r " , " " , 2 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_STATIC | QX_FLAG_TRIM , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for firmware version
* > [ QVFW \ r ]
* < [ ( VERFW : 00322.02 \ r ]
* 01234567 89012345
* 0 1
*/
2015-04-30 16:53:36 +03:00
{ " ups.firmware " , 0 , NULL , " QVFW \r " , " " , 16 , ' ( ' , " " , 7 , 14 , " %s " , QX_FLAG_STATIC , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for serial number
* > [ QID \ r ]
* < [ ( 12345679012345 \ r ] < - As far as I know it hasn ' t a fixed length - > min length = ( + \ r = 2
* 01234567 89012345
* 0 1
*/
2015-04-30 16:53:36 +03:00
{ " device.serial " , 0 , NULL , " QID \r " , " " , 2 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_STATIC , NULL , voltronic_serial_numb } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for vendor infos
* > [ I \ r ]
* < [ # - - - - - - - - - - - - - - - - - - - VT12046Q \ r ]
* 01234567 8901234567890123456789012345678
* 0 1 2 3
*/
2015-04-30 16:53:36 +03:00
{ " device.mfr " , 0 , NULL , " I \r " , " " , 39 , ' # ' , " " , 1 , 15 , " %s " , QX_FLAG_STATIC | QX_FLAG_TRIM , NULL , NULL } ,
{ " device.model " , 0 , NULL , " I \r " , " " , 39 , ' # ' , " " , 17 , 26 , " %s " , QX_FLAG_STATIC | QX_FLAG_TRIM , NULL , NULL } ,
{ " ups.firmware " , 0 , NULL , " I \r " , " " , 39 , ' # ' , " " , 28 , 37 , " %s " , QX_FLAG_STATIC | QX_FLAG_TRIM , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for status
* > [ QGS \ r ]
* < [ ( 234.9 50.0 229.8 50.0 000.0 000 369.1 - - - . - 026.5 - - - . - 018.8 100000000001 \ r ]
* 01234567 89012345678901234567890123456789012345678901234567890123456789012345
* 0 1 2 3 4 5 6 7
*/
2015-04-30 16:53:36 +03:00
{ " input.voltage " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 1 , 5 , " %.1f " , 0 , NULL , NULL } ,
{ " input.frequency " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 7 , 10 , " %.1f " , 0 , NULL , NULL } ,
{ " output.voltage " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 12 , 16 , " %.1f " , 0 , NULL , NULL } ,
{ " output.frequency " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 18 , 21 , " %.1f " , 0 , NULL , NULL } ,
{ " output.current " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 23 , 27 , " %.1f " , 0 , NULL , NULL } ,
{ " ups.load " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 29 , 31 , " %.0f " , 0 , NULL , NULL } ,
/* { "unknown.1", 0, NULL, "QGS\r", "", 76, '(', "", 33, 37, "%.1f", 0, NULL, NULL }, */ /* Unknown */
/* { "unknown.2", 0, NULL, "QGS\r", "", 76, '(', "", 39, 43, "%.1f", 0, NULL, NULL }, */ /* Unknown */
{ " battery.voltage " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 45 , 49 , " %.2f " , 0 , NULL , NULL } ,
/* { "unknown.3", 0, NULL, "QGS\r", "", 76, '(', "", 51, 55, "%.1f", 0, NULL, NULL }, */ /* Unknown */
{ " ups.temperature " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 57 , 61 , " %.1f " , 0 , NULL , NULL } ,
{ " ups.type " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 63 , 64 , " %s " , QX_FLAG_SEMI_STATIC , NULL , voltronic_status } ,
{ " ups.status " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 65 , 65 , " %s " , QX_FLAG_QUICK_POLL , NULL , voltronic_status } , /* Utility Fail (Immediate) */
{ " ups.status " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 66 , 66 , " %s " , QX_FLAG_QUICK_POLL , NULL , voltronic_status } , /* Battery Low */
{ " ups.status " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 67 , 67 , " %s " , QX_FLAG_QUICK_POLL , NULL , voltronic_status } , /* Bypass/Boost or Buck Active */
{ " ups.alarm " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 67 , 67 , " %s " , 0 , NULL , voltronic_status } , /* Bypass/Boost or Buck Active */
{ " ups.alarm " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 68 , 68 , " %s " , 0 , NULL , voltronic_status } , /* UPS Fault */
/* { "unknown.4", 0, NULL, "QGS\r", "", 76, '(', "", 69, 69, "%s", 0, NULL, voltronic_status }, */ /* Unknown */
{ " ups.status " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 70 , 70 , " %s " , QX_FLAG_QUICK_POLL , NULL , voltronic_status } , /* Test in Progress */
{ " ups.status " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 71 , 71 , " %s " , QX_FLAG_QUICK_POLL , NULL , voltronic_status } , /* Shutdown Active */
{ " ups.beeper.status " , 0 , NULL , " QGS \r " , " " , 76 , ' ( ' , " " , 72 , 72 , " %s " , 0 , NULL , voltronic_status } , /* Beeper status - ups.beeper.status */
/* { "unknown.5", 0, NULL, "QGS\r", "", 76, '(', "", 73, 73, "%s", 0, NULL, voltronic_status }, */ /* Unknown */
/* { "unknown.6", 0, NULL, "QGS\r", "", 76, '(', "", 74, 74, "%s", 0, NULL, voltronic_status }, */ /* Unknown */
2013-11-24 17:00:12 +02:00
/* Query UPS for actual working mode
* > [ QMOD \ r ]
* < [ ( S \ r ]
* 012
* 0
*/
2015-04-30 16:53:36 +03:00
{ " ups.alarm " , 0 , NULL , " QMOD \r " , " " , 3 , ' ( ' , " " , 1 , 1 , " %s " , 0 , NULL , voltronic_mode } ,
{ " ups.status " , 0 , NULL , " QMOD \r " , " " , 3 , ' ( ' , " " , 1 , 1 , " %s " , 0 , NULL , voltronic_mode } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for faults and their type. Unskipped when a fault is found in 12bit flag of QGS, otherwise you'll get a fake reply.
* > [ QFS \ r ]
* < [ ( OK \ r ] < - No fault
* 0123
* 0
* < [ ( 14 212.1 50.0 005.6 49.9 006 010.6 343.8 - - - . - 026.2 021.8 01101100 \ r ] < - Fault type + Short status
* 01234567 8901234567890123456789012345678901234567890123456789012345678
* 0 1 2 3 4 5 6
*/
2015-04-30 16:53:36 +03:00
{ " ups.alarm " , 0 , NULL , " QFS \r " , " " , 4 , ' ( ' , " " , 1 , 2 , " %s " , QX_FLAG_SKIP , NULL , voltronic_fault } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for warnings and their type
* > [ QWS \ r ]
* < [ ( 0000000100000000000000000000000000000000000000000000000000000000 \ r ]
* 01234567 8901234567890123456789012345678901234567890123456789012345
* 0 1 2 3 4 5 6
*/
2015-04-30 16:53:36 +03:00
{ " ups.alarm " , 0 , NULL , " QWS \r " , " " , 66 , ' ( ' , " " , 1 , 64 , " %s " , 0 , NULL , voltronic_warning } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for actual infos about battery
* > [ QBV \ r ]
* < [ ( 026.5 02 01 06 8 255 \ r ]
* 01234567 8901234567890
* 0 1 2
*/
2015-04-30 16:53:36 +03:00
{ " battery.voltage " , 0 , NULL , " QBV \r " , " " , 21 , ' ( ' , " " , 1 , 5 , " %.2f " , 0 , NULL , NULL } ,
{ " battery_number " , ST_FLAG_RW , voltronic_r_batt_numb , " QBV \r " , " " , 21 , ' ( ' , " " , 7 , 9 , " %d " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT , NULL , voltronic_batt_numb } , /* Number of batteries that make a pack */
{ " battery.packs " , ST_FLAG_RW , voltronic_r_batt_packs , " QBV \r " , " " , 21 , ' ( ' , " " , 10 , 11 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE , NULL , NULL } , /* Number of battery packs in parallel */
{ " battery.charge " , 0 , NULL , " QBV \r " , " " , 21 , ' ( ' , " " , 13 , 15 , " %.0f " , 0 , NULL , NULL } ,
{ " battery.runtime " , 0 , NULL , " QBV \r " , " " , 21 , ' ( ' , " " , 17 , 19 , " %.0f " , 0 , NULL , voltronic_batt_runtime } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for last seen min/max load level
* > [ QLDL \ r ]
* < [ ( 021 023 \ r ] < - minimum load level - maximum load level
* 01234567 8
* 0
*/
2015-04-30 16:53:36 +03:00
{ " output.power.minimum.percent " , 0 , NULL , " QLDL \r " , " " , 9 , ' ( ' , " " , 1 , 3 , " %.0f " , 0 , NULL , NULL } ,
{ " output.power.maximum.percent " , 0 , NULL , " QLDL \r " , " " , 9 , ' ( ' , " " , 5 , 7 , " %.0f " , 0 , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for multi-phase voltages/frequencies
* > [ Q3 * * \ r ]
* < [ ( 123.4 123.4 123.4 123.4 123.4 123.4 \ r ] < - Q3PV
* < [ ( 123.4 123.4 123.4 123.4 123.4 123.4 \ r ] < - Q3OV
* < [ ( 123 123 123 \ r ] < - Q3PC
* < [ ( 123 123 123 \ r ] < - Q3OC
* < [ ( 123 123 123 \ r ] < - Q3LD
* < [ ( 123.4 123.4 123.4 \ r ] < - Q3YV - P09 protocol
* < [ ( 123.4 123.4 123.4 123.4 123.4 123.4 \ r ] < - Q3YV - P10 / P03 protocols
* 01234567 89012345678901234567890123456
* 0 1 2 3
*
* P09 = 2 - phase input / 2 - phase output
* Q3PV ( Input Voltage L1 | Input Voltage L2 | Input Voltage L3 | Input Voltage L1 - L2 | Input Voltage L1 - L3 | Input Voltage L2 - L3
* Q3OV ( Output Voltage L1 | Output Voltage L2 | Output Voltage L3 | Output Voltage L1 - L2 | Output Voltage L1 - L3 | Output Voltage L2 - L3
* Q3PC ( Input Current L1 | Input Current L2 | Input Current L3
* Q3OC ( Output Current L1 | Output Current L2 | Output Current L3
* Q3LD ( Output Load Level L1 | Output Load Level L2 | Output Load Level L3
* Q3YV ( Output Bypass Voltage L1 | Output Bypass Voltage L2 | Output Bypass Voltage L3
*
* P10 = 3 - phase input / 3 - phase output / P03 = 3 - phase input / 1 - phase output
* Q3PV ( Input Voltage L1 | Input Voltage L2 | Input Voltage L3 | Input Voltage L1 - L2 | Input Voltage L2 - L3 | Input Voltage L1 - L3
* Q3OV ( Output Voltage L1 | Output Voltage L2 | Output Voltage L3 | Output Voltage L1 - L2 | Output Voltage L2 - L3 | Output Voltage L1 - L3
* Q3PC ( Input Current L1 | Input Current L2 | Input Current L3
* Q3OC ( Output Current L1 | Output Current L2 | Output Current L3
* Q3LD ( Output Load Level L1 | Output Load Level L2 | Output Load Level L3
* Q3YV ( Output Bypass Voltage L1 | Output Bypass Voltage L2 | Output Bypass Voltage L3 | Output Bypass Voltage L1 - L2 | Output Bypass Voltage L2 - L3 | Output Bypass Voltage L1 - L3
*
*/
/* From Q3PV */
2015-04-30 16:53:36 +03:00
{ " input.L1-N.voltage " , 0 , NULL , " Q3PV \r " , " " , 37 , ' ( ' , " " , 1 , 5 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " input.L2-N.voltage " , 0 , NULL , " Q3PV \r " , " " , 37 , ' ( ' , " " , 7 , 11 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " input.L3-N.voltage " , 0 , NULL , " Q3PV \r " , " " , 37 , ' ( ' , " " , 13 , 17 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " input.L1-L2.voltage " , 0 , NULL , " Q3PV \r " , " " , 37 , ' ( ' , " " , 19 , 23 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " input.L2-L3.voltage " , 0 , NULL , " Q3PV \r " , " " , 37 , ' ( ' , " " , 25 , 29 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " input.L1-L3.voltage " , 0 , NULL , " Q3PV \r " , " " , 37 , ' ( ' , " " , 31 , 35 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
/* { "input.L1-L3.voltage", 0, NULL, "Q3PV\r", "", 37, '(', "", 25, 29, "%.1f", QX_FLAG_SKIP, NULL, NULL }, */ /* P09 */ /* Commented out because P09 should be two-phase input/output UPSes */
/* { "input.L2-L3.voltage", 0, NULL, "Q3PV\r", "", 37, '(', "", 31, 35, "%.1f", QX_FLAG_SKIP, NULL, NULL }, */ /* P09 */ /* Commented out because P09 should be two-phase input/output UPSes */
2013-11-24 17:00:12 +02:00
/* From Q3PC */
2015-04-30 16:53:36 +03:00
{ " input.L1.current " , 0 , NULL , " Q3PC \r " , " " , 13 , ' ( ' , " " , 1 , 3 , " %.0f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " input.L2.current " , 0 , NULL , " Q3PC \r " , " " , 13 , ' ( ' , " " , 5 , 7 , " %.0f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " input.L3.current " , 0 , NULL , " Q3PC \r " , " " , 13 , ' ( ' , " " , 9 , 11 , " %.0f " , QX_FLAG_SKIP , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* From Q3OV */
2015-04-30 16:53:36 +03:00
{ " output.L1-N.voltage " , 0 , NULL , " Q3OV \r " , " " , 37 , ' ( ' , " " , 1 , 5 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.L2-N.voltage " , 0 , NULL , " Q3OV \r " , " " , 37 , ' ( ' , " " , 7 , 11 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.L3-N.voltage " , 0 , NULL , " Q3OV \r " , " " , 37 , ' ( ' , " " , 13 , 17 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.L1-L2.voltage " , 0 , NULL , " Q3OV \r " , " " , 37 , ' ( ' , " " , 19 , 23 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.L2-L3.voltage " , 0 , NULL , " Q3OV \r " , " " , 37 , ' ( ' , " " , 25 , 29 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.L1-L3.voltage " , 0 , NULL , " Q3OV \r " , " " , 37 , ' ( ' , " " , 31 , 35 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
/* { "output.L1-L3.voltage", 0, NULL, "Q3OV\r", "", 37, '(', "", 25, 29, "%.1f", QX_FLAG_SKIP, NULL, NULL }, */ /* P09 */ /* Commented out because P09 should be two-phase input/output UPSes */
/* { "output.L2-L3.voltage", 0, NULL, "Q3OV\r", "", 37, '(', "", 31, 35, "%.1f", QX_FLAG_SKIP, NULL, NULL }, */ /* P09 */ /* Commented out because P09 should be two-phase input/output UPSes */
2013-11-24 17:00:12 +02:00
/* From Q3OC */
2015-04-30 16:53:36 +03:00
{ " output.L1.current " , 0 , NULL , " Q3OC \r " , " " , 13 , ' ( ' , " " , 1 , 3 , " %.0f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.L2.current " , 0 , NULL , " Q3OC \r " , " " , 13 , ' ( ' , " " , 5 , 7 , " %.0f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.L3.current " , 0 , NULL , " Q3OC \r " , " " , 13 , ' ( ' , " " , 9 , 11 , " %.0f " , QX_FLAG_SKIP , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* From Q3LD */
2015-04-30 16:53:36 +03:00
{ " output.L1.power.percent " , 0 , NULL , " Q3LD \r " , " " , 13 , ' ( ' , " " , 1 , 3 , " %.0f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.L2.power.percent " , 0 , NULL , " Q3LD \r " , " " , 13 , ' ( ' , " " , 5 , 7 , " %.0f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.L3.power.percent " , 0 , NULL , " Q3LD \r " , " " , 13 , ' ( ' , " " , 9 , 11 , " %.0f " , QX_FLAG_SKIP , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* From Q3YV */
2015-04-30 16:53:36 +03:00
{ " output.bypass.L1-N.voltage " , 0 , NULL , " Q3YV \r " , " " , 37 , ' ( ' , " " , 1 , 5 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.bypass.L2-N.voltage " , 0 , NULL , " Q3YV \r " , " " , 37 , ' ( ' , " " , 7 , 11 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.bypass.L3-N.voltage " , 0 , NULL , " Q3YV \r " , " " , 37 , ' ( ' , " " , 13 , 17 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.bypass.L1-N.voltage " , 0 , NULL , " Q3YV \r " , " " , 19 , ' ( ' , " " , 1 , 5 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } , /* P09 */
{ " output.bypass.L2-N.voltage " , 0 , NULL , " Q3YV \r " , " " , 19 , ' ( ' , " " , 7 , 11 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } , /* P09 */
/* { "output.bypass.L3-N.voltage", 0, NULL, "Q3YV\r", "", 19, '(', "", 13, 17, "%.1f", QX_FLAG_SKIP, NULL, NULL }, */ /* P09 */ /* Commented out because P09 should be two-phase input/output UPSes */
{ " output.bypass.L1-L2.voltage " , 0 , NULL , " Q3YV \r " , " " , 37 , ' ( ' , " " , 19 , 23 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.bypass.L2-L3.voltage " , 0 , NULL , " Q3YV \r " , " " , 37 , ' ( ' , " " , 25 , 29 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
{ " output.bypass.L1-L3.voltage " , 0 , NULL , " Q3YV \r " , " " , 37 , ' ( ' , " " , 31 , 35 , " %.1f " , QX_FLAG_SKIP , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for capability - total options available: 23; only those whom the UPS is capable of are reported as Enabled or Disabled
* > [ QFLAG \ r ]
* < [ ( EpashcDbroegfl \ r ]
* 01234567 89012345
* 0 1 * min length = ( + E + D + \ r = 4
*/
2015-04-30 16:53:36 +03:00
{ " ups.start.auto " , ST_FLAG_RW , voltronic_e_cap , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM , NULL , voltronic_capability } ,
{ " battery.protection " , ST_FLAG_RW , voltronic_e_cap , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM , NULL , voltronic_capability } ,
{ " battery.energysave " , ST_FLAG_RW , voltronic_e_cap , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM , NULL , voltronic_capability } ,
{ " ups.start.battery " , ST_FLAG_RW , voltronic_e_cap , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM , NULL , voltronic_capability } ,
{ " outlet.0.switchable " , ST_FLAG_RW , voltronic_e_cap , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM , NULL , voltronic_capability } ,
2013-11-24 17:00:12 +02:00
/* Not available in NUT */
2015-04-30 16:53:36 +03:00
{ " bypass_alarm " , 0 , NULL , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_capability } ,
{ " battery_alarm " , 0 , NULL , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_capability } ,
{ " bypass_when_off " , 0 , NULL , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_capability } ,
{ " alarm_control " , 0 , NULL , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_capability } ,
{ " converter_mode " , 0 , NULL , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_capability } ,
{ " eco_mode " , 0 , NULL , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_capability } ,
{ " battery_open_status_check " , 0 , NULL , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_capability } ,
{ " bypass_forbidding " , 0 , NULL , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_capability } ,
{ " site_fault_detection " , 0 , NULL , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_capability } ,
{ " advanced_eco_mode " , 0 , NULL , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_capability } ,
{ " constant_phase_angle " , 0 , NULL , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_capability } ,
{ " limited_runtime_on_battery " , 0 , NULL , " QFLAG \r " , " " , 4 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_capability } ,
2013-11-24 17:00:12 +02:00
/* Enable or Disable or Reset to safe default values capability options
* > [ PEX \ r ] > [ PDX \ r ] > [ PF \ r ]
* < [ ( ACK \ r ] < [ ( ACK \ r ] < [ ( ACK \ r ]
* 01234 01234 01234
* 0 0 0
*/
2015-04-30 16:53:36 +03:00
{ " ups.start.auto " , 0 , voltronic_e_cap , " P%sR \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_SKIP , NULL , voltronic_capability_set } ,
{ " battery.protection " , 0 , voltronic_e_cap , " P%sS \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_SKIP , NULL , voltronic_capability_set } ,
{ " battery.energysave " , 0 , voltronic_e_cap , " P%sG \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_SKIP , NULL , voltronic_capability_set } ,
{ " ups.start.battery " , 0 , voltronic_e_cap , " P%sC \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_SKIP , NULL , voltronic_capability_set } ,
{ " outlet.0.switchable " , 0 , voltronic_e_cap , " P%sJ \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_SKIP , NULL , voltronic_capability_set } ,
2013-11-24 17:00:12 +02:00
/* Not available in NUT */
2015-04-30 16:53:36 +03:00
{ " reset_to_default " , 0 , NULL , " PF \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_reset } ,
{ " bypass_alarm " , 0 , voltronic_e_cap_nonut , " P%sP \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_set_nonut } ,
{ " battery_alarm " , 0 , voltronic_e_cap_nonut , " P%sB \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_set_nonut } ,
{ " bypass_when_off " , 0 , voltronic_e_cap_nonut , " P%sO \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_set_nonut } ,
{ " alarm_control " , 0 , voltronic_e_cap_nonut , " P%sA \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_set_nonut } ,
{ " converter_mode " , 0 , voltronic_e_cap_nonut , " P%sV \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_set_nonut } ,
{ " eco_mode " , 0 , voltronic_e_cap_nonut , " P%sE \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_set_nonut } ,
{ " battery_open_status_check " , 0 , voltronic_e_cap_nonut , " P%sD \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_set_nonut } ,
{ " bypass_forbidding " , 0 , voltronic_e_cap_nonut , " P%sF \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_set_nonut } ,
{ " site_fault_detection " , 0 , voltronic_e_cap_nonut , " P%sL \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_set_nonut } ,
{ " advanced_eco_mode " , 0 , voltronic_e_cap_nonut , " P%sN \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_set_nonut } ,
{ " constant_phase_angle " , 0 , voltronic_e_cap_nonut , " P%sQ \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_set_nonut } ,
{ " limited_runtime_on_battery " , 0 , voltronic_e_cap_nonut , " P%sW \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_capability_set_nonut } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for programmable outlet (1-4) status
* > [ QSK1 \ r ]
* < [ ( 1 \ r ] < - if outlet is on - > ( 1 , if off - > ( 0 ; ( NAK - > outlet is not programmable
* 012
* 0
*/
2015-04-30 16:53:36 +03:00
{ " outlet.1.switchable " , 0 , NULL , " QSK1 \r " , " " , 3 , ' ( ' , " " , 1 , 1 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP , NULL , voltronic_outlet } ,
{ " outlet.1.status " , 0 , NULL , " QSK1 \r " , " " , 3 , ' ( ' , " " , 1 , 1 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP , NULL , voltronic_outlet } ,
{ " outlet.2.switchable " , 0 , NULL , " QSK2 \r " , " " , 3 , ' ( ' , " " , 1 , 1 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP , NULL , voltronic_outlet } ,
{ " outlet.2.status " , 0 , NULL , " QSK2 \r " , " " , 3 , ' ( ' , " " , 1 , 1 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP , NULL , voltronic_outlet } ,
{ " outlet.3.switchable " , 0 , NULL , " QSK3 \r " , " " , 3 , ' ( ' , " " , 1 , 1 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP , NULL , voltronic_outlet } ,
{ " outlet.3.status " , 0 , NULL , " QSK3 \r " , " " , 3 , ' ( ' , " " , 1 , 1 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP , NULL , voltronic_outlet } ,
{ " outlet.4.switchable " , 0 , NULL , " QSK4 \r " , " " , 3 , ' ( ' , " " , 1 , 1 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP , NULL , voltronic_outlet } ,
{ " outlet.4.status " , 0 , NULL , " QSK4 \r " , " " , 3 , ' ( ' , " " , 1 , 1 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP , NULL , voltronic_outlet } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for programmable outlet n (1-4) delay time before it shuts down the load when on battery mode
* > [ QSKT1 \ r ]
* < [ ( 00 8 \ r ] < - if delay time is set ( by PSK [ 1 - 4 ] n ) it ' ll report n ( minutes ) otherwise it ' ll report ( NAK ( also if outlet is not programmable )
* 01234
* 0
*/
2015-04-30 16:53:36 +03:00
{ " outlet.1.delay.shutdown " , ST_FLAG_RW , voltronic_r_outlet_delay , " QSKT1 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_outlet_delay } ,
{ " outlet.2.delay.shutdown " , ST_FLAG_RW , voltronic_r_outlet_delay , " QSKT2 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_outlet_delay } ,
{ " outlet.3.delay.shutdown " , ST_FLAG_RW , voltronic_r_outlet_delay , " QSKT3 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_outlet_delay } ,
{ " outlet.4.delay.shutdown " , ST_FLAG_RW , voltronic_r_outlet_delay , " QSKT4 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_outlet_delay } ,
2013-11-24 17:00:12 +02:00
/* Set delay time for programmable outlets
* > [ PSK1nnn \ r ] n = 0. .9
* < [ ( ACK \ r ]
* 01234
* 0
*/
2015-04-30 16:53:36 +03:00
{ " outlet.1.delay.shutdown " , 0 , voltronic_r_outlet_delay , " PSK1%03d \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_outlet_delay_set } ,
{ " outlet.2.delay.shutdown " , 0 , voltronic_r_outlet_delay , " PSK2%03d \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_outlet_delay_set } ,
{ " outlet.3.delay.shutdown " , 0 , voltronic_r_outlet_delay , " PSK3%03d \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_outlet_delay_set } ,
{ " outlet.4.delay.shutdown " , 0 , voltronic_r_outlet_delay , " PSK4%03d \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_outlet_delay_set } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for ECO Mode voltage limits
* > [ QHE \ r ]
* < [ ( 242 218 \ r ]
* 01234567 8
* 0
*/
2015-04-30 16:53:36 +03:00
{ " input.transfer.high " , ST_FLAG_RW , voltronic_r_eco_volt_max , " QHE \r " , " " , 9 , ' ( ' , " " , 1 , 3 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_eco_volt } ,
{ " input.transfer.low " , ST_FLAG_RW , voltronic_r_eco_volt_min , " QHE \r " , " " , 9 , ' ( ' , " " , 5 , 7 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_eco_volt } ,
{ " input.transfer.low.min " , 0 , NULL , " QHE \r " , " " , 9 , ' ( ' , " " , 5 , 7 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP , NULL , voltronic_eco_volt_range } ,
{ " input.transfer.low.max " , 0 , NULL , " QHE \r " , " " , 9 , ' ( ' , " " , 5 , 7 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP , NULL , voltronic_eco_volt_range } ,
{ " input.transfer.high.min " , 0 , NULL , " QHE \r " , " " , 9 , ' ( ' , " " , 1 , 3 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP , NULL , voltronic_eco_volt_range } ,
{ " input.transfer.high.max " , 0 , NULL , " QHE \r " , " " , 9 , ' ( ' , " " , 1 , 3 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP , NULL , voltronic_eco_volt_range } ,
2013-11-24 17:00:12 +02:00
/* Set ECO Mode voltage limits
* > [ HEHnnn \ r ] > [ HELnnn \ r ] n = 0. .9
* < [ ( ACK \ r ] < [ ( ACK \ r ]
* 01234 01234
* 0 0
*/
2015-04-30 16:53:36 +03:00
{ " input.transfer.high " , 0 , voltronic_r_eco_volt_max , " HEH%03.0f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_process_setvar } ,
{ " input.transfer.low " , 0 , voltronic_r_eco_volt_min , " HEL%03.0f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_process_setvar } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for ECO Mode frequency limits
* > [ QFRE \ r ]
* < [ ( 53.0 47.0 \ r ]
* 01234567 890
* 0 1
*/
2015-04-30 16:53:36 +03:00
{ " input.frequency.high " , ST_FLAG_RW , voltronic_r_eco_freq_max , " QFRE \r " , " " , 11 , ' ( ' , " " , 1 , 4 , " %.1f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_eco_freq } ,
{ " input.frequency.low " , ST_FLAG_RW , voltronic_r_eco_freq_min , " QFRE \r " , " " , 11 , ' ( ' , " " , 6 , 9 , " %.1f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_eco_freq } ,
2013-11-24 17:00:12 +02:00
/* Set ECO Mode frequency limits
* > [ FREHnn . n \ r ] > [ FRELnn . n \ r ] n = 0. .9
* < [ ( ACK \ r ] < [ ( ACK \ r ]
* 01234 01234
* 0 0
*/
2015-04-30 16:53:36 +03:00
{ " input.frequency.high " , 0 , voltronic_r_eco_freq_max , " FREH%04.1f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_process_setvar } ,
{ " input.frequency.low " , 0 , voltronic_r_eco_freq_min , " FREL%04.1f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP , NULL , voltronic_process_setvar } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for Bypass Mode voltage limits
* > [ QBYV \ r ]
* < [ ( 264 170 \ r ]
* 01234567 8
* 0
*/
2015-04-30 16:53:36 +03:00
{ " max_bypass_volt " , ST_FLAG_RW , voltronic_r_bypass_volt_max , " QBYV \r " , " " , 9 , ' ( ' , " " , 1 , 3 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_bypass } ,
{ " min_bypass_volt " , ST_FLAG_RW , voltronic_r_bypass_volt_min , " QBYV \r " , " " , 9 , ' ( ' , " " , 5 , 7 , " %.0f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_bypass } ,
2013-11-24 17:00:12 +02:00
/* Set Bypass Mode voltage limits
* > [ PHVnnn \ r ] > [ PLVnnn \ r ] n = 0. .9
* < [ ( ACK \ r ] < [ ( ACK \ r ]
* 01234 01234
* 0 0
*/
2015-04-30 16:53:36 +03:00
{ " max_bypass_volt " , 0 , voltronic_r_bypass_volt_max , " PHV%03.0f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_process_setvar } ,
{ " min_bypass_volt " , 0 , voltronic_r_bypass_volt_min , " PLV%03.0f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_process_setvar } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for Bypass Mode frequency limits
* > [ QBYF \ r ]
* < [ ( 53.0 47.0 \ r ]
* 01234567 890
* 0 1
*/
2015-04-30 16:53:36 +03:00
{ " max_bypass_freq " , ST_FLAG_RW , voltronic_r_bypass_freq_max , " QBYF \r " , " " , 11 , ' ( ' , " " , 1 , 4 , " %.1f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_bypass } ,
{ " min_bypass_freq " , ST_FLAG_RW , voltronic_r_bypass_freq_min , " QBYF \r " , " " , 11 , ' ( ' , " " , 6 , 9 , " %.1f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_bypass } ,
2013-11-24 17:00:12 +02:00
/* Set Bypass Mode frequency limits
* > [ PGFnn . n \ r ] > [ PSFnn . n \ r ] n = 0. .9
* < [ ( ACK \ r ] < [ ( ACK \ r ]
* 01234 01234
* 0 0
*/
2015-04-30 16:53:36 +03:00
{ " max_bypass_freq " , 0 , voltronic_r_bypass_freq_max , " PGF%04.1f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_process_setvar } ,
{ " min_bypass_freq " , 0 , voltronic_r_bypass_freq_min , " PSF%04.1f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_process_setvar } ,
2013-11-24 17:00:12 +02:00
/* Set number of batteries that make a pack to n (integer, 1-9). NOTE: changing the number of batteries will change the UPS's estimation on battery charge/runtime
* > [ BATNn \ r ]
* < [ ( ACK \ r ]
* 01234
* 0
*/
2015-04-30 16:53:36 +03:00
{ " battery_number " , 0 , voltronic_r_batt_numb , " BATN%1.0f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_NONUT , NULL , voltronic_process_setvar } ,
2013-11-24 17:00:12 +02:00
/* Set number of battery packs in parallel to n (integer, 01-99). NOTE: changing the number of battery packs will change the UPS's estimation on battery charge/runtime
* > [ BATGNn \ r ]
* < [ ( ACK \ r ]
* 01234
* 0
*/
2015-04-30 16:53:36 +03:00
{ " battery.packs " , 0 , voltronic_r_batt_packs , " BATGN%02.0f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE , NULL , voltronic_process_setvar } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for battery type (Only P31)
* > [ QBT \ r ]
* < [ ( 01 \ r ] < - 00 = " Li " , 01 = " Flooded " or 02 = " AGM "
* 0123
* 0
*/
2015-04-30 16:53:36 +03:00
{ " battery.type " , ST_FLAG_RW , voltronic_e_batt_type , " QBT \r " , " " , 4 , ' ( ' , " " , 1 , 2 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM | QX_FLAG_SKIP , NULL , voltronic_p31b } ,
2013-11-24 17:00:12 +02:00
/* Set battery type (Only P31)
* > [ PBTnn \ r ] nn = 00 / 01 / 02
* < [ ( ACK \ r ]
* 01234
* 0
*/
2015-04-30 16:53:36 +03:00
{ " battery.type " , 0 , voltronic_e_batt_type , " PBT%02.0f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_SKIP , NULL , voltronic_p31b_set } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for device grid working range (Only P31)
* > [ QGR \ r ]
* < [ ( 01 \ r ] < - 00 = Appliance , 01 = UPS
* 0123
* 0
*/
2015-04-30 16:53:36 +03:00
{ " work_range_type " , ST_FLAG_RW , voltronic_e_work_range , " QGR \r " , " " , 4 , ' ( ' , " " , 1 , 2 , " %s " , QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_p31g } ,
2013-11-24 17:00:12 +02:00
/* Set device grid working range type (Only P31)
* > [ PBTnn \ r ] nn = 00 / 01
* < [ ( ACK \ r ]
* 01234
* 0
*/
2015-04-30 16:53:36 +03:00
{ " work_range_type " , 0 , voltronic_e_work_range , " PGR%02.0f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_p31g_set } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for battery low voltage
* > [ RE0 \ r ]
* < [ # 20 \ r ]
* 012
* 0
*/
2015-04-30 16:53:36 +03:00
{ " battery.voltage.low " , ST_FLAG_RW , voltronic_r_batt_low , " RE0 \r " , " " , 3 , ' # ' , " " , 1 , 2 , " %.1f " , QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* Set voltage for battery low to n (integer, 20..24/20..28). NOTE: changing the battery low voltage will change the UPS's estimation on battery charge/runtime
* > [ W0En \ r ]
* < [ ( ACK \ r ]
* 01234
* 0
*/
2015-04-30 16:53:36 +03:00
{ " battery.voltage.low " , 0 , voltronic_r_batt_low , " W0E%02.0f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_RANGE , NULL , voltronic_process_setvar } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for Phase Angle
* > [ QPD \ r ]
* < [ ( 000 120 \ r ] < - Input Phase Angle - Output Phase Angle
* 01234567 8
* 0
*/
2015-04-30 16:53:36 +03:00
{ " input_phase_angle " , 0 , NULL , " QPD \r " , " " , 9 , ' ( ' , " " , 1 , 3 , " %03d " , QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT , NULL , voltronic_phase } ,
{ " output_phase_angle " , ST_FLAG_RW , voltronic_e_phase , " QPD \r " , " " , 9 , ' ( ' , " " , 5 , 7 , " %03d " , QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM | QX_FLAG_NONUT , NULL , voltronic_phase } ,
2013-11-24 17:00:12 +02:00
/* Set output phase angle
* > [ PPDn \ r ] n = ( 000 , 120 , 180 or 240 )
* < [ ( ACK \ r ]
* 01234
* 0
*/
2015-04-30 16:53:36 +03:00
{ " output_phase_angle " , 0 , voltronic_e_phase , " PPD%03.0f \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , voltronic_phase_set } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for master/slave for a system of UPSes in parallel
* > [ QPAR \ r ]
* < [ ( 001 \ r ] < - 001 for master UPS , 002 and 003 for slave UPSes
* 01234
* 0
*/
2015-04-30 16:53:36 +03:00
{ " voltronic_parallel " , 0 , NULL , " QPAR \r " , " " , 5 , ' ( ' , " " , 1 , 3 , " %s " , QX_FLAG_STATIC | QX_FLAG_NONUT , NULL , voltronic_parallel } ,
2013-11-24 17:00:12 +02:00
/* Query UPS for ??
* > [ QBDR \ r ]
* < [ ( 1234 \ r ] < - unknown reply - My UPS ( NAK at me
* 012345
* 0
*/
2015-04-30 16:53:36 +03:00
{ " unknown.7 " , 0 , NULL , " QBDR \r " , " " , 5 , ' ( ' , " " , 1 , 0 , " %s " , QX_FLAG_STATIC | QX_FLAG_NONUT | QX_FLAG_SKIP , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* Instant commands */
2015-04-30 16:53:36 +03:00
{ " load.off " , 0 , NULL , " SOFF \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD , NULL , NULL } ,
{ " load.on " , 0 , NULL , " SON \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
2015-04-30 16:53:36 +03:00
{ " shutdown.return " , 0 , NULL , " S%s \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD , NULL , voltronic_process_command } ,
{ " shutdown.stayoff " , 0 , NULL , " S%sR0000 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD , NULL , voltronic_process_command } ,
{ " shutdown.stop " , 0 , NULL , " CS \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
2015-04-30 16:53:36 +03:00
{ " test.battery.start " , 0 , NULL , " T%s \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD , NULL , voltronic_process_command } ,
{ " test.battery.start.deep " , 0 , NULL , " TL \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD , NULL , NULL } ,
{ " test.battery.start.quick " , 0 , NULL , " T \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD , NULL , NULL } ,
{ " test.battery.stop " , 0 , NULL , " CT \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
2015-04-30 16:53:36 +03:00
{ " beeper.toggle " , 0 , NULL , " BZ%s \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD , NULL , voltronic_process_command } ,
2013-11-24 17:00:12 +02:00
/* Enable/disable beeper: unskipped if the UPS can control alarm (capability) */
2015-04-30 16:53:36 +03:00
{ " beeper.enable " , 0 , NULL , " PEA \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD | QX_FLAG_SKIP , NULL , NULL } ,
{ " beeper.disable " , 0 , NULL , " PDA \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD | QX_FLAG_SKIP , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* Outlet control: unskipped if the outlets are manageable */
2015-04-30 16:53:36 +03:00
{ " outlet.1.load.off " , 0 , NULL , " SKOFF1 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD | QX_FLAG_SKIP , NULL , NULL } ,
{ " outlet.1.load.on " , 0 , NULL , " SKON1 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD | QX_FLAG_SKIP , NULL , NULL } ,
{ " outlet.2.load.off " , 0 , NULL , " SKOFF2 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD | QX_FLAG_SKIP , NULL , NULL } ,
{ " outlet.2.load.on " , 0 , NULL , " SKON2 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD | QX_FLAG_SKIP , NULL , NULL } ,
{ " outlet.3.load.off " , 0 , NULL , " SKOFF3 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD | QX_FLAG_SKIP , NULL , NULL } ,
{ " outlet.3.load.on " , 0 , NULL , " SKON3 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD | QX_FLAG_SKIP , NULL , NULL } ,
{ " outlet.4.load.off " , 0 , NULL , " SKOFF4 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD | QX_FLAG_SKIP , NULL , NULL } ,
{ " outlet.4.load.on " , 0 , NULL , " SKON4 \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD | QX_FLAG_SKIP , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* Bypass: unskipped if the UPS is capable of ECO Mode */
2015-04-30 16:53:36 +03:00
{ " bypass.start " , 0 , NULL , " PEE \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD | QX_FLAG_SKIP , NULL , NULL } ,
{ " bypass.stop " , 0 , NULL , " PDE \r " , " " , 5 , ' ( ' , " " , 1 , 3 , NULL , QX_FLAG_CMD | QX_FLAG_SKIP , NULL , NULL } ,
2013-11-24 17:00:12 +02:00
/* Server-side settable vars */
2015-04-30 16:53:36 +03:00
{ " ups.delay.start " , ST_FLAG_RW , voltronic_r_ondelay , NULL , " " , 0 , 0 , " " , 0 , 0 , DEFAULT_ONDELAY , QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE , NULL , voltronic_process_setvar } ,
{ " ups.delay.shutdown " , ST_FLAG_RW , voltronic_r_offdelay , NULL , " " , 0 , 0 , " " , 0 , 0 , DEFAULT_OFFDELAY , QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE , NULL , voltronic_process_setvar } ,
2013-11-24 17:00:12 +02:00
/* End of structure. */
2015-04-30 16:53:36 +03:00
{ NULL , 0 , NULL , NULL , " " , 0 , 0 , " " , 0 , 0 , NULL , 0 , NULL , NULL }
2013-11-24 17:00:12 +02:00
} ;
/* == Testing table == */
# ifdef TESTING
static testing_t voltronic_testing [ ] = {
2015-04-30 16:53:36 +03:00
{ " QGS \r " , " (234.9 50.0 229.8 50.0 000.0 00A 369.1 ---.- 026.5 ---.- 018.8 100000000001 \r " , - 1 } ,
{ " QPI \r " , " (PI01 \r " , - 1 } ,
{ " QRI \r " , " (230.0 004 024.0 50.0 \r " , - 1 } ,
{ " QMF \r " , " (#####VOLTRONIC \r " , - 1 } ,
{ " I \r " , " #------------- ------ VT12046Q \r " , - 1 } ,
{ " F \r " , " #220.0 000 024.0 50.0 \r " , - 1 } ,
{ " QMD \r " , " (#######OLHVT1K0 ###1000 80 2/2 230 230 02 12.0 \r " , - 1 } ,
{ " QFS \r " , " (14 212.1 50.0 005.6 49.9 006 010.6 343.8 ---.- 026.2 021.8 01101100 \r " , - 1 } ,
{ " QMOD \r " , " (S \r " , - 1 } ,
{ " QVFW \r " , " (VERFW:00322.02 \r " , - 1 } ,
{ " QID \r " , " (685653211455 \r " , - 1 } ,
{ " QBV \r " , " (026.5 02 01 068 255 \r " , - 1 } ,
{ " QFLAG \r " , " (EpashcjDbroegfl \r " , - 1 } ,
{ " QWS \r " , " (0000000000000000000000000000000000000000000000000000000001000001 \r " , - 1 } ,
{ " QHE \r " , " (242 218 \r " , - 1 } ,
{ " QBYV \r " , " (264 170 \r " , - 1 } ,
{ " QBYF \r " , " (53.0 47.0 \r " , - 1 } ,
{ " QSK1 \r " , " (1 \r " , - 1 } ,
{ " QSK2 \r " , " (0 \r " , - 1 } ,
{ " QSK3 \r " , " (1 \r " , - 1 } ,
{ " QSK4 \r " , " (NAK \r " , - 1 } ,
{ " QSKT1 \r " , " (008 \r " , - 1 } ,
{ " QSKT2 \r " , " (012 \r " , - 1 } ,
{ " QSKT3 \r " , " (NAK \r " , - 1 } ,
{ " QSKT4 \r " , " (007 \r " , - 1 } ,
{ " RE0 \r " , " #20 \r " , - 1 } ,
{ " W0E24 \r " , " (ACK \r " , - 1 } ,
{ " PF \r " , " (ACK \r " , - 1 } ,
{ " PEA \r " , " (ACK \r " , - 1 } ,
{ " PDR \r " , " (NAK \r " , - 1 } ,
{ " HEH250 \r " , " (ACK \r " , - 1 } ,
{ " HEL210 \r " , " (ACK \r " , - 1 } ,
{ " PHV260 \r " , " (NAK \r " , - 1 } ,
{ " PLV190 \r " , " (ACK \r " , - 1 } ,
{ " PGF51.0 \r " , " (NAK \r " , - 1 } ,
{ " PSF47.5 \r " , " (ACK \r " , - 1 } ,
{ " BATN2 \r " , " (ACK \r " , - 1 } ,
{ " BATGN04 \r " , " (ACK \r " , - 1 } ,
{ " QBT \r " , " (01 \r " , - 1 } ,
{ " PBT02 \r " , " (ACK \r " , - 1 } ,
{ " QGR \r " , " (00 \r " , - 1 } ,
{ " PGR01 \r " , " (ACK \r " , - 1 } ,
{ " PSK1008 \r " , " (ACK \r " , - 1 } ,
{ " PSK3987 \r " , " (ACK \r " , - 1 } ,
{ " PSK2009 \r " , " (ACK \r " , - 1 } ,
{ " PSK4012 \r " , " (ACK \r " , - 1 } ,
{ " Q3PV \r " , " (123.4 456.4 789.4 012.4 323.4 223.4 \r " , - 1 } ,
{ " Q3OV \r " , " (253.4 163.4 023.4 143.4 103.4 523.4 \r " , - 1 } ,
{ " Q3OC \r " , " (109 069 023 \r " , - 1 } ,
{ " Q3LD \r " , " (005 033 089 \r " , - 1 } ,
{ " Q3YV \r " , " (303.4 245.4 126.4 222.4 293.4 321.4 \r " , - 1 } ,
{ " Q3PC \r " , " (002 023 051 \r " , - 1 } ,
{ " SOFF \r " , " (NAK \r " , - 1 } ,
{ " SON \r " , " (ACK \r " , - 1 } ,
{ " T \r " , " (NAK \r " , - 1 } ,
{ " TL \r " , " (ACK \r " , - 1 } ,
{ " CS \r " , " (ACK \r " , - 1 } ,
{ " CT \r " , " (NAK \r " , - 1 } ,
{ " BZOFF \r " , " (ACK \r " , - 1 } ,
{ " BZON \r " , " (ACK \r " , - 1 } ,
{ " S.3R0002 \r " , " (ACK \r " , - 1 } ,
{ " S02R0024 \r " , " (NAK \r " , - 1 } ,
{ " S.5 \r " , " (ACK \r " , - 1 } ,
{ " T.3 \r " , " (ACK \r " , - 1 } ,
{ " T02 \r " , " (NAK \r " , - 1 } ,
{ " SKON1 \r " , " (ACK \r " , - 1 } ,
{ " SKOFF1 \r " , " (NAK \r " , - 1 } ,
{ " SKON2 \r " , " (ACK \r " , - 1 } ,
{ " SKOFF2 \r " , " (ACK \r " , - 1 } ,
{ " SKON3 \r " , " (NAK \r " , - 1 } ,
{ " SKOFF3 \r " , " (ACK \r " , - 1 } ,
{ " SKON4 \r " , " (NAK \r " , - 1 } ,
{ " SKOFF4 \r " , " (NAK \r " , - 1 } ,
{ " QPAR \r " , " (003 \r " , - 1 } ,
{ " QPD \r " , " (000 240 \r " , - 1 } ,
{ " PPD120 \r " , " (ACK \r " , - 1 } ,
{ " QLDL \r " , " (005 080 \r " , - 1 } ,
{ " QBDR \r " , " (1234 \r " , - 1 } ,
{ " QFRE \r " , " (50.0 00.0 \r " , - 1 } ,
{ " FREH54.0 \r " , " (ACK \r " , - 1 } ,
{ " FREL47.0 \r " , " (ACK \r " , - 1 } ,
{ " PEP \r " , " (ACK \r " , - 1 } ,
{ " PDP \r " , " (ACK \r " , - 1 } ,
{ " PEB \r " , " (ACK \r " , - 1 } ,
{ " PDB \r " , " (ACK \r " , - 1 } ,
{ " PER \r " , " (NAK \r " , - 1 } ,
{ " PDR \r " , " (NAK \r " , - 1 } ,
{ " PEO \r " , " (ACK \r " , - 1 } ,
{ " PDO \r " , " (ACK \r " , - 1 } ,
{ " PEA \r " , " (ACK \r " , - 1 } ,
{ " PDA \r " , " (ACK \r " , - 1 } ,
{ " PES \r " , " (ACK \r " , - 1 } ,
{ " PDS \r " , " (ACK \r " , - 1 } ,
{ " PEV \r " , " (ACK \r " , - 1 } ,
{ " PDV \r " , " (ACK \r " , - 1 } ,
{ " PEE \r " , " (ACK \r " , - 1 } ,
{ " PDE \r " , " (ACK \r " , - 1 } ,
{ " PEG \r " , " (ACK \r " , - 1 } ,
{ " PDG \r " , " (NAK \r " , - 1 } ,
{ " PED \r " , " (ACK \r " , - 1 } ,
{ " PDD \r " , " (ACK \r " , - 1 } ,
{ " PEC \r " , " (ACK \r " , - 1 } ,
{ " PDC \r " , " (NAK \r " , - 1 } ,
{ " PEF \r " , " (NAK \r " , - 1 } ,
{ " PDF \r " , " (ACK \r " , - 1 } ,
{ " PEJ \r " , " (NAK \r " , - 1 } ,
{ " PDJ \r " , " (ACK \r " , - 1 } ,
{ " PEL \r " , " (ACK \r " , - 1 } ,
{ " PDL \r " , " (ACK \r " , - 1 } ,
{ " PEN \r " , " (ACK \r " , - 1 } ,
{ " PDN \r " , " (ACK \r " , - 1 } ,
{ " PEQ \r " , " (ACK \r " , - 1 } ,
{ " PDQ \r " , " (ACK \r " , - 1 } ,
{ " PEW \r " , " (NAK \r " , - 1 } ,
{ " PDW \r " , " (ACK \r " , - 1 } ,
2013-11-24 17:00:12 +02:00
{ NULL }
} ;
# endif /* TESTING */
/* == Support functions == */
/* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. */
static int voltronic_claim ( void )
{
/* We need at least QGS and QPI to run this subdriver */
item_t * item = find_nut_info ( " input.voltage " , 0 , 0 ) ;
/* Don't know what happened */
if ( ! item )
return 0 ;
/* No reply/Unable to get value */
if ( qx_process ( item , NULL ) )
return 0 ;
/* Unable to process value */
if ( ups_infoval_set ( item ) ! = 1 )
return 0 ;
/* UPS Protocol */
item = find_nut_info ( " ups.firmware.aux " , 0 , 0 ) ;
/* Don't know what happened */
if ( ! item ) {
dstate_delinfo ( " input.voltage " ) ;
return 0 ;
}
/* No reply/Unable to get value */
if ( qx_process ( item , NULL ) ) {
dstate_delinfo ( " input.voltage " ) ;
return 0 ;
}
/* Unable to process value/Protocol out of range */
if ( ups_infoval_set ( item ) ! = 1 ) {
dstate_delinfo ( " input.voltage " ) ;
return 0 ;
}
return 1 ;
}
/* Subdriver-specific flags/vars */
static void voltronic_makevartable ( void )
{
/* Capability vars */
addvar ( VAR_FLAG , " reset_to_default " , " Reset capability options and their limits to safe default values " ) ;
addvar ( VAR_VALUE , " bypass_alarm " , " Alarm (BEEP!) at Bypass Mode [enabled/disabled] " ) ;
addvar ( VAR_VALUE , " battery_alarm " , " Alarm (BEEP!) at Battery Mode [enabled/disabled] " ) ;
addvar ( VAR_VALUE , " bypass_when_off " , " Bypass when the UPS is Off [enabled/disabled] " ) ;
addvar ( VAR_VALUE , " alarm_control " , " Alarm (BEEP!) Control [enabled/disabled] " ) ;
addvar ( VAR_VALUE , " converter_mode " , " Converter Mode [enabled/disabled] " ) ;
addvar ( VAR_VALUE , " eco_mode " , " ECO Mode [enabled/disabled] " ) ;
addvar ( VAR_VALUE , " battery_open_status_check " , " Battery Open Status Check [enabled/disabled] " ) ;
addvar ( VAR_VALUE , " bypass_forbidding " , " Bypass not allowed (Bypass Forbidding) [enabled/disabled] " ) ;
addvar ( VAR_VALUE , " site_fault_detection " , " Site fault detection [enabled/disabled] " ) ;
addvar ( VAR_VALUE , " advanced_eco_mode " , " Advanced ECO Mode [enabled/disabled] " ) ;
addvar ( VAR_VALUE , " constant_phase_angle " , " Constant Phase Angle Function (Output and input phase angles are not equal) [enabled/disabled] " ) ;
addvar ( VAR_VALUE , " limited_runtime_on_battery " , " Limited runtime on battery mode [enabled/disabled] " ) ;
/* Bypass Mode frequency/voltage limits */
addvar ( VAR_VALUE , " max_bypass_volt " , " Maximum voltage for Bypass Mode " ) ;
addvar ( VAR_VALUE , " min_bypass_volt " , " Minimum voltage for Bypass Mode " ) ;
addvar ( VAR_VALUE , " max_bypass_freq " , " Maximum frequency for Bypass Mode " ) ;
addvar ( VAR_VALUE , " min_bypass_freq " , " Minimum frequency for Bypass Mode " ) ;
/* Device grid working range type for P31 UPSes */
addvar ( VAR_VALUE , " work_range_type " , " Device grid working range for P31 UPSes [Appliance/UPS] " ) ;
/* Output phase angle */
addvar ( VAR_VALUE , " output_phase_angle " , " Change output phase angle to the provided value [000, 120, 180, 240]° " ) ;
/* Number of batteries */
addvar ( VAR_VALUE , " battery_number " , " Set number of batteries that make a pack to n (integer, 1-9) " ) ;
/* For testing purposes */
addvar ( VAR_FLAG , " testing " , " If invoked the driver will exec also commands that still need testing " ) ;
}
/* Unskip vars according to protocol used by the UPS */
static void voltronic_massive_unskip ( const int protocol )
{
item_t * item ;
for ( item = voltronic_qx2nut ; item - > info_type ! = NULL ; item + + ) {
if ( ! item - > command )
continue ;
if ( /* == Multiphase UPSes == */
/* P09 */
( protocol = = 9 & & (
/* (!strcasecmp(item->info_type, "input.L1-L3.voltage") && item->from == 25) || */ /* Not unskipped because P09 should be 2-phase input/output */
/* (!strcasecmp(item->info_type, "input.L2-L3.voltage") && item->from == 31) || */ /* Not unskipped because P09 should be 2-phase input/output */
/* (!strcasecmp(item->info_type, "output.L1-L3.voltage") && item->from == 25) || */ /* Not unskipped because P09 should be 2-phase input/output */
/* (!strcasecmp(item->info_type, "output.L2-L3.voltage") && item->from == 31) || */ /* Not unskipped because P09 should be 2-phase input/output */
( ! strcasecmp ( item - > info_type , " output.bypass.L1-N.voltage " ) & & item - > answer_len = = 19 ) | |
( ! strcasecmp ( item - > info_type , " output.bypass.L2-N.voltage " ) & & item - > answer_len = = 19 ) /* ||
( ! strcasecmp ( item - > info_type , " output.bypass.L3-N.voltage " ) & & item - > answer_len = = 19 ) */ /* Not unskipped because P09 should be 2-phase input/output */
) ) | |
/* P10 */
( protocol = = 10 & & (
! strcasecmp ( item - > info_type , " output.L3-N.voltage " ) | |
( ! strcasecmp ( item - > info_type , " output.L2-L3.voltage " ) & & item - > from = = 25 ) | |
( ! strcasecmp ( item - > info_type , " output.L1-L3.voltage " ) & & item - > from = = 31 ) | |
( ! strcasecmp ( item - > info_type , " output.bypass.L1-N.voltage " ) & & item - > answer_len = = 37 ) | |
( ! strcasecmp ( item - > info_type , " output.bypass.L2-N.voltage " ) & & item - > answer_len = = 37 ) | |
( ! strcasecmp ( item - > info_type , " output.bypass.L3-N.voltage " ) & & item - > answer_len = = 37 ) | |
! strcasecmp ( item - > info_type , " output.bypass.L1-L2.voltage " ) | |
! strcasecmp ( item - > info_type , " output.bypass.L2-L3.voltage " ) | |
! strcasecmp ( item - > info_type , " output.bypass.L1-L3.voltage " ) | |
! strcasecmp ( item - > info_type , " output.L3.current " ) | |
! strcasecmp ( item - > info_type , " output.L3.power.percent " )
) ) | |
/* P09-P10 */
( ( protocol = = 9 | | protocol = = 10 ) & & (
! strcasecmp ( item - > info_type , " output.L1-N.voltage " ) | |
! strcasecmp ( item - > info_type , " output.L2-N.voltage " ) | | /*
! strcasecmp ( item - > info_type , " output.L3-N.voltage " ) | | */ /* Not unskipped because P09 should be 2-phase input/output */
! strcasecmp ( item - > info_type , " output.L1-L2.voltage " ) | |
! strcasecmp ( item - > info_type , " output.L1.current " ) | |
! strcasecmp ( item - > info_type , " output.L2.current " ) | | /*
! strcasecmp ( item - > info_type , " output.L3.current " ) | | */ /* Not unskipped because P09 should be 2-phase input/output */
! strcasecmp ( item - > info_type , " output.L1.power.percent " ) | |
! strcasecmp ( item - > info_type , " output.L2.power.percent " ) /* ||
! strcasecmp ( item - > info_type , " output.L3.power.percent " ) */ /* Not unskipped because P09 should be 2-phase input/output */
) ) | |
/* P03-P09-P10 */
( ( protocol = = 3 | | protocol = = 9 | | protocol = = 10 ) & & (
! strcasecmp ( item - > info_type , " input.L1-N.voltage " ) | |
! strcasecmp ( item - > info_type , " input.L2-N.voltage " ) | | /*
! strcasecmp ( item - > info_type , " input.L3-N.voltage " ) | | */ /* Not unskipped because P09 should be 2-phase input/output */
! strcasecmp ( item - > info_type , " input.L1-L2.voltage " ) | |
! strcasecmp ( item - > info_type , " input.L1.current " ) | |
! strcasecmp ( item - > info_type , " input.L2.current " ) /* ||
! strcasecmp ( item - > info_type , " input.L3.current " ) */ /* Not unskipped because P09 should be 2-phase input/output */
) ) | |
/* P03-P10 */
( ( protocol = = 3 | | protocol = = 10 ) & & (
! strcasecmp ( item - > info_type , " input.L3-N.voltage " ) | |
( ! strcasecmp ( item - > info_type , " input.L2-L3.voltage " ) & & item - > from = = 25 ) | |
( ! strcasecmp ( item - > info_type , " input.L1-L3.voltage " ) & & item - > from = = 31 ) | |
! strcasecmp ( item - > info_type , " input.L3.current " )
) ) | |
/* == P31 battery type/device grid working range == */
( protocol = = 31 & & (
! strcasecmp ( item - > info_type , " battery.type " ) | |
( ! strcasecmp ( item - > info_type , " work_range_type " ) & & ! ( item - > qxflags & QX_FLAG_SETVAR ) ) | |
( ! strcasecmp ( item - > info_type , " work_range_type " ) & & ( item - > qxflags & QX_FLAG_SETVAR ) & & getval ( item - > info_type ) )
) ) | |
/* == ByPass limits: all but P00/P08/P31 == */
( protocol ! = 0 & & protocol ! = 8 & & protocol ! = 31 & & (
( ! strcasecmp ( item - > info_type , " max_bypass_volt " ) & & ! ( item - > qxflags & QX_FLAG_SETVAR ) ) | |
( ! strcasecmp ( item - > info_type , " min_bypass_volt " ) & & ! ( item - > qxflags & QX_FLAG_SETVAR ) ) | |
( ! strcasecmp ( item - > info_type , " max_bypass_freq " ) & & ! ( item - > qxflags & QX_FLAG_SETVAR ) ) | |
( ! strcasecmp ( item - > info_type , " min_bypass_freq " ) & & ! ( item - > qxflags & QX_FLAG_SETVAR ) )
) ) | |
/* == Reset capabilities options to safe default values == */
( ! strcasecmp ( item - > info_type , " reset_to_default " ) & & testvar ( " reset_to_default " ) ) | |
/* == QBDR (unknown) == */
( ! strcasecmp ( item - > info_type , " unknown.7 " ) & & testvar ( " testing " ) )
) {
item - > qxflags & = ~ QX_FLAG_SKIP ;
}
}
}
/* == Preprocess functions == */
/* *SETVAR(/NONUT)* Preprocess setvars */
static int voltronic_process_setvar ( item_t * item , char * value , size_t valuelen )
{
if ( ! strlen ( value ) ) {
upsdebugx ( 2 , " %s: value not given for %s " , __func__ , item - > info_type ) ;
return - 1 ;
}
double val = strtod ( value , NULL ) ;
if ( ! strcasecmp ( item - > info_type , " ups.delay.start " ) ) {
/* Truncate to minute */
val - = ( ( int ) val % 60 ) ;
snprintf ( value , valuelen , " %.0f " , val ) ;
return 0 ;
} else if ( ! strcasecmp ( item - > info_type , " ups.delay.shutdown " ) ) {
/* Truncate to nearest setable value */
if ( val < 60 ) {
val - = ( ( int ) val % 6 ) ;
} else {
val - = ( ( int ) val % 60 ) ;
}
snprintf ( value , valuelen , " %.0f " , val ) ;
return 0 ;
} else if ( ! strcasecmp ( item - > info_type , " max_bypass_freq " ) ) {
if ( val = = max_bypass_freq ) {
upslogx ( LOG_INFO , " %s is already set to %.1f " , item - > info_type , val ) ;
return - 1 ;
}
} else if ( ! strcasecmp ( item - > info_type , " min_bypass_freq " ) ) {
if ( val = = min_bypass_freq ) {
upslogx ( LOG_INFO , " %s is already set to %.1f " , item - > info_type , val ) ;
return - 1 ;
}
} else if ( ! strcasecmp ( item - > info_type , " max_bypass_volt " ) ) {
if ( val = = max_bypass_volt ) {
upslogx ( LOG_INFO , " %s is already set to %.0f " , item - > info_type , val ) ;
return - 1 ;
}
} else if ( ! strcasecmp ( item - > info_type , " min_bypass_volt " ) ) {
if ( val = = min_bypass_volt ) {
upslogx ( LOG_INFO , " %s is already set to %.0f " , item - > info_type , val ) ;
return - 1 ;
}
} else if ( ! strcasecmp ( item - > info_type , " battery_number " ) ) {
if ( val = = battery_number ) {
upslogx ( LOG_INFO , " %s is already set to %.0f " , item - > info_type , val ) ;
return - 1 ;
}
}
snprintf ( value , valuelen , item - > command , val ) ;
return 0 ;
}
/* *CMD* Preprocess instant commands */
static int voltronic_process_command ( item_t * item , char * value , size_t valuelen )
{
char buf [ SMALLBUF ] = " " ;
if ( ! strcasecmp ( item - > info_type , " shutdown.return " ) ) {
/* Sn: Shutdown after n minutes and then turn on when mains is back
* SnRm : Shutdown after n minutes and then turn on after m minutes
* Accepted values for n : .2 - > .9 , 01 - > 99
* Accepted values for m : 0001 - > 9999 */
int offdelay = strtol ( dstate_getinfo ( " ups.delay.shutdown " ) , NULL , 10 ) ,
ondelay = strtol ( dstate_getinfo ( " ups.delay.start " ) , NULL , 10 ) / 60 ;
if ( ondelay = = 0 ) {
if ( offdelay < 60 ) {
snprintf ( buf , sizeof ( buf ) , " .%d " , offdelay / 6 ) ;
} else {
snprintf ( buf , sizeof ( buf ) , " %02d " , offdelay / 60 ) ;
}
} else if ( offdelay < 60 ) {
snprintf ( buf , sizeof ( buf ) , " .%dR%04d " , offdelay / 6 , ondelay ) ;
} else {
snprintf ( buf , sizeof ( buf ) , " %02dR%04d " , offdelay / 60 , ondelay ) ;
}
} else if ( ! strcasecmp ( item - > info_type , " shutdown.stayoff " ) ) {
/* SnR0000
* Shutdown after n minutes and stay off
* Accepted values for n : .2 - > .9 , 01 - > 99 */
int offdelay = strtol ( dstate_getinfo ( " ups.delay.shutdown " ) , NULL , 10 ) ;
if ( offdelay < 60 ) {
snprintf ( buf , sizeof ( buf ) , " .%d " , offdelay / 6 ) ;
} else {
snprintf ( buf , sizeof ( buf ) , " %02d " , offdelay / 60 ) ;
}
} else if ( ! strcasecmp ( item - > info_type , " test.battery.start " ) ) {
/* Accepted values for test time: .2 -> .9 (.2=12sec ..), 01 -> 99 (minutes)
* - > you have to invoke test . battery . start + number of seconds [ 12. .5940 ] */
int delay ;
if ( strlen ( value ) ! = strspn ( value , " 0123456789 " ) ) {
upslogx ( LOG_ERR , " %s: non numerical value [%s] " , item - > info_type , value ) ;
return - 1 ;
}
delay = strlen ( value ) > 0 ? strtol ( value , NULL , 10 ) : 600 ;
if ( ( delay < 12 ) | | ( delay > 5940 ) ) {
upslogx ( LOG_ERR , " %s: battery test time '%d' out of range [12..5940] seconds " , item - > info_type , delay ) ;
return - 1 ;
}
/* test time < 1 minute */
if ( delay < 60 ) {
delay = delay / 6 ;
snprintf ( buf , sizeof ( buf ) , " .%d " , delay ) ;
/* test time > 1 minute */
} else {
delay = delay / 60 ;
snprintf ( buf , sizeof ( buf ) , " %02d " , delay ) ;
}
} else if ( ! strcasecmp ( item - > info_type , " beeper.toggle " ) ) {
const char * beeper_status = dstate_getinfo ( " ups.beeper.status " ) ;
/* If the UPS is beeping then we can call BZOFF; if we previously set BZOFF we can call BZON, provided that the beeper is not disabled */
/* The UPS can disable/enable alarm (from UPS capability) */
if ( alarm_control ) {
if ( ! strcmp ( beeper_status , " enabled " ) ) {
snprintf ( buf , sizeof ( buf ) , " OFF " ) ;
} else if ( ! strcmp ( beeper_status , " muted " ) ) {
snprintf ( buf , sizeof ( buf ) , " ON " ) ;
/* Beeper disabled */
} else {
upslogx ( LOG_INFO , " The beeper is already disabled " ) ;
return - 1 ;
}
/* The UPS can't disable/enable alarm (from UPS capability) */
} else {
if ( ! strcmp ( beeper_status , " enabled " ) ) {
snprintf ( buf , sizeof ( buf ) , " OFF " ) ;
} else if ( ! strcmp ( beeper_status , " disabled " ) ) {
snprintf ( buf , sizeof ( buf ) , " ON " ) ;
}
}
} else {
/* Don't know what happened */
return - 1 ;
}
snprintf ( value , valuelen , item - > command , buf ) ;
return 0 ;
}
/* UPS capabilities */
static int voltronic_capability ( item_t * item , char * value , size_t valuelen )
{
char rawval [ SMALLBUF ] , * enabled , * disabled , * val = NULL , * saveptr = NULL ;
item_t * unskip ;
snprintf ( rawval , sizeof ( rawval ) , " %s " , item - > value ) ;
enabled = strtok_r ( rawval + 1 , " D " , & saveptr ) ;
disabled = strtok_r ( NULL , " \0 " , & saveptr ) ;
if ( ! enabled & & ! disabled ) {
upsdebugx ( 2 , " %s: parsing failed " , __func__ ) ;
return - 1 ;
}
enabled = enabled ? enabled : " " ;
disabled = disabled ? disabled : " " ;
/* NONUT items */
if ( ! strcasecmp ( item - > info_type , " bypass_alarm " ) ) {
if ( strchr ( enabled , ' p ' ) ) {
val = bypass_alarm = " enabled " ;
} else if ( strchr ( disabled , ' p ' ) ) {
val = bypass_alarm = " disabled " ;
}
} else if ( ! strcasecmp ( item - > info_type , " battery_alarm " ) ) {
if ( strchr ( enabled , ' b ' ) ) {
val = battery_alarm = " enabled " ;
} else if ( strchr ( disabled , ' b ' ) ) {
val = battery_alarm = " disabled " ;
}
} else if ( ! strcasecmp ( item - > info_type , " bypass_when_off " ) ) {
if ( strchr ( enabled , ' o ' ) ) {
val = bypass_when_off = " enabled " ;
} else if ( strchr ( disabled , ' o ' ) ) {
val = bypass_when_off = " disabled " ;
}
} else if ( ! strcasecmp ( item - > info_type , " alarm_control " ) ) {
if ( strchr ( item - > value , ' a ' ) ) {
if ( strchr ( enabled , ' a ' ) ) {
const char * beeper = dstate_getinfo ( " ups.beeper.status " ) ;
val = alarm_control = " enabled " ;
if ( ! beeper | | strcmp ( beeper , " muted " ) ) {
dstate_setinfo ( " ups.beeper.status " , " enabled " ) ;
}
} else if ( strchr ( disabled , ' a ' ) ) {
val = alarm_control = " disabled " ;
dstate_setinfo ( " ups.beeper.status " , " disabled " ) ;
}
/* Unskip beeper.{enable,disable} instcmds */
unskip = find_nut_info ( " beeper.enable " , QX_FLAG_CMD , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
unskip = find_nut_info ( " beeper.disable " , QX_FLAG_CMD , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
}
} else if ( ! strcasecmp ( item - > info_type , " converter_mode " ) ) {
if ( strchr ( enabled , ' v ' ) ) {
val = converter_mode = " enabled " ;
} else if ( strchr ( disabled , ' v ' ) ) {
val = converter_mode = " disabled " ;
}
} else if ( ! strcasecmp ( item - > info_type , " eco_mode " ) ) {
if ( strchr ( item - > value , ' e ' ) ) {
if ( strchr ( enabled , ' e ' ) ) {
val = eco_mode = " enabled " ;
} else if ( strchr ( disabled , ' e ' ) ) {
val = eco_mode = " disabled " ;
}
/* Unskip bypass.{start,stop} instcmds */
unskip = find_nut_info ( " bypass.start " , QX_FLAG_CMD , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
unskip = find_nut_info ( " bypass.stop " , QX_FLAG_CMD , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
/* Unskip input.transfer.{high,low} */
unskip = find_nut_info ( " input.transfer.high " , QX_FLAG_SEMI_STATIC , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
unskip = find_nut_info ( " input.transfer.low " , QX_FLAG_SEMI_STATIC , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
/* Unskip input.frequency.{high,low} */
unskip = find_nut_info ( " input.frequency.high " , QX_FLAG_SEMI_STATIC , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
unskip = find_nut_info ( " input.frequency.low " , QX_FLAG_SEMI_STATIC , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
}
} else if ( ! strcasecmp ( item - > info_type , " battery_open_status_check " ) ) {
if ( strchr ( enabled , ' d ' ) ) {
val = battery_open_status_check = " enabled " ;
} else if ( strchr ( disabled , ' d ' ) ) {
val = battery_open_status_check = " disabled " ;
}
} else if ( ! strcasecmp ( item - > info_type , " bypass_forbidding " ) ) {
if ( strchr ( enabled , ' f ' ) ) {
val = bypass_forbidding = " enabled " ;
} else if ( strchr ( disabled , ' f ' ) ) {
val = bypass_forbidding = " disabled " ;
}
} else if ( ! strcasecmp ( item - > info_type , " site_fault_detection " ) ) {
if ( strchr ( enabled , ' l ' ) ) {
val = site_fault_detection = " enabled " ;
} else if ( strchr ( disabled , ' l ' ) ) {
val = site_fault_detection = " disabled " ;
}
} else if ( ! strcasecmp ( item - > info_type , " advanced_eco_mode " ) ) {
if ( strchr ( enabled , ' n ' ) ) {
val = advanced_eco_mode = " enabled " ;
} else if ( strchr ( disabled , ' n ' ) ) {
val = advanced_eco_mode = " disabled " ;
}
} else if ( ! strcasecmp ( item - > info_type , " constant_phase_angle " ) ) {
if ( strchr ( enabled , ' q ' ) ) {
val = constant_phase_angle = " enabled " ;
} else if ( strchr ( disabled , ' q ' ) ) {
val = constant_phase_angle = " disabled " ;
}
} else if ( ! strcasecmp ( item - > info_type , " limited_runtime_on_battery " ) ) {
if ( strchr ( enabled , ' w ' ) ) {
val = limited_runtime_on_battery = " enabled " ;
} else if ( strchr ( disabled , ' w ' ) ) {
val = limited_runtime_on_battery = " disabled " ;
}
/* } else if (!strcasecmp(item->info_type, "")) {
if ( strchr ( enabled , ' h ' ) ) { unknown / unused
} else if ( strchr ( disabled , ' h ' ) ) { }
} else if ( ! strcasecmp ( item - > info_type , " " ) ) {
if ( strchr ( enabled , ' t ' ) ) { unknown / unused
} else if ( strchr ( disabled , ' t ' ) ) { }
} else if ( ! strcasecmp ( item - > info_type , " " ) ) {
if ( strchr ( enabled , ' k ' ) ) { unknown / unused
} else if ( strchr ( disabled , ' k ' ) ) { }
} else if ( ! strcasecmp ( item - > info_type , " " ) ) {
if ( strchr ( enabled , ' i ' ) ) { unknown / unused
} else if ( strchr ( disabled , ' i ' ) ) { }
} else if ( ! strcasecmp ( item - > info_type , " " ) ) {
if ( strchr ( enabled , ' m ' ) ) { unknown / unused
} else if ( strchr ( disabled , ' m ' ) ) { }
} else if ( ! strcasecmp ( item - > info_type , " " ) ) {
if ( strchr ( enabled , ' z ' ) ) { unknown / unused
} else if ( strchr ( disabled , ' z ' ) ) { }
*/
/* Items with a NUT variable */
} else if ( ! strcasecmp ( item - > info_type , " ups.start.auto " ) ) {
if ( strchr ( enabled , ' r ' ) ) {
val = " yes " ;
} else if ( strchr ( disabled , ' r ' ) ) {
val = " no " ;
}
} else if ( ! strcasecmp ( item - > info_type , " battery.protection " ) ) {
if ( strchr ( enabled , ' s ' ) ) {
val = " yes " ;
} else if ( strchr ( disabled , ' s ' ) ) {
val = " no " ;
}
} else if ( ! strcasecmp ( item - > info_type , " battery.energysave " ) ) {
if ( strchr ( enabled , ' g ' ) ) {
val = " yes " ;
} else if ( strchr ( disabled , ' g ' ) ) {
val = " no " ;
}
} else if ( ! strcasecmp ( item - > info_type , " ups.start.battery " ) ) {
if ( strchr ( enabled , ' c ' ) ) {
val = " yes " ;
} else if ( strchr ( disabled , ' c ' ) ) {
val = " no " ;
}
} else if ( ! strcasecmp ( item - > info_type , " outlet.0.switchable " ) ) {
if ( strchr ( enabled , ' j ' ) ) {
int i ;
char buf [ SMALLBUF ] ;
val = " yes " ;
/* Unskip outlet.n.{switchable,status} */
for ( i = 1 ; i < = 4 ; i + + ) {
snprintf ( buf , sizeof ( buf ) , " outlet.%d.switchable " , i ) ;
unskip = find_nut_info ( buf , 0 , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
snprintf ( buf , sizeof ( buf ) , " outlet.%d.status " , i ) ;
unskip = find_nut_info ( buf , 0 , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
}
} else if ( strchr ( disabled , ' j ' ) ) {
val = " no " ;
}
}
/* UPS doesn't have that capability */
if ( ! val )
return - 1 ;
snprintf ( value , valuelen , item - > dfl , val ) ;
/* This item doesn't have a NUT var and we were not asked by the user to change its value */
if ( ( item - > qxflags & QX_FLAG_NONUT ) & & ! getval ( item - > info_type ) )
return 0 ;
/* Unskip setvar */
unskip = find_nut_info ( item - > info_type , QX_FLAG_SETVAR , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
return 0 ;
}
/* *SETVAR* Set UPS capability options */
static int voltronic_capability_set ( item_t * item , char * value , size_t valuelen )
{
if ( ! strcasecmp ( value , " yes " ) ) {
snprintf ( value , valuelen , item - > command , " E " ) ;
return 0 ;
}
if ( ! strcasecmp ( value , " no " ) ) {
snprintf ( value , valuelen , item - > command , " D " ) ;
return 0 ;
}
/* At this point value should have been already checked against enum so this shouldn't happen.. however.. */
upslogx ( LOG_ERR , " %s: given value [%s] is not acceptable. Enter either 'yes' or 'no'. " , item - > info_type , value ) ;
return - 1 ;
}
/* *SETVAR/NONUT* Change UPS capability according to user configuration in ups.conf */
static int voltronic_capability_set_nonut ( item_t * item , char * value , size_t valuelen )
{
const char * match = NULL ;
int i ;
const struct {
const char * type ; /* Name of the option */
const char * match ; /* Value reported by the UPS */
} capability [ ] = {
{ " bypass_alarm " , bypass_alarm } ,
{ " battery_alarm " , battery_alarm } ,
{ " bypass_when_off " , bypass_when_off } ,
{ " alarm_control " , alarm_control } ,
{ " converter_mode " , converter_mode } ,
{ " eco_mode " , eco_mode } ,
{ " battery_open_status_check " , battery_open_status_check } ,
{ " bypass_forbidding " , bypass_forbidding } ,
{ " site_fault_detection " , site_fault_detection } ,
{ " advanced_eco_mode " , advanced_eco_mode } ,
{ " constant_phase_angle " , constant_phase_angle } ,
{ " limited_runtime_on_battery " , limited_runtime_on_battery } ,
{ NULL }
} ;
for ( i = 0 ; capability [ i ] . type ; i + + ) {
if ( strcasecmp ( item - > info_type , capability [ i ] . type ) )
continue ;
match = capability [ i ] . match ;
break ;
}
/* UPS doesn't have that capability */
if ( ! match )
return - 1 ;
/* At this point value should have been already checked by nutdrv_qx's own setvar so this shouldn't happen.. however.. */
if ( ! strcasecmp ( value , match ) ) {
upslogx ( LOG_INFO , " %s is already %s " , item - > info_type , match ) ;
return - 1 ;
}
if ( ! strcasecmp ( value , " disabled " ) ) {
snprintf ( value , valuelen , item - > command , " D " ) ;
} else if ( ! strcasecmp ( value , " enabled " ) ) {
snprintf ( value , valuelen , item - > command , " E " ) ;
} else {
/* At this point value should have been already checked against enum so this shouldn't happen.. however.. */
upslogx ( LOG_ERR , " %s: [%s] is not within acceptable values [enabled/disabled] " , item - > info_type , value ) ;
return - 1 ;
}
return 0 ;
}
/* *SETVAR/NONUT* Reset capability options and their limits to safe default values */
static int voltronic_capability_reset ( item_t * item , char * value , size_t valuelen )
{
/* Nothing to do */
if ( ! testvar ( " reset_to_default " ) )
return - 1 ;
/* UPS capability options can be reset only when the UPS is in 'Standby Mode' (=OFF) (from QMOD) */
if ( ! ( qx_status ( ) & STATUS ( OFF ) ) ) {
upslogx ( LOG_ERR , " %s: UPS capability options can be reset only when the UPS is in Standby Mode (i.e. ups.status = 'OFF'). " , item - > info_type ) ;
return - 1 ;
}
snprintf ( value , valuelen , " %s " , item - > command ) ;
return 0 ;
}
/* Voltage limits for ECO Mode */
static int voltronic_eco_volt ( item_t * item , char * value , size_t valuelen )
{
const int protocol = strtol ( dstate_getinfo ( " ups.firmware.aux " ) + 1 , NULL , 10 ) ;
int ovn ;
const char * outvoltnom ;
char buf [ SMALLBUF ] ;
item_t * unskip ;
/* Range of accepted values for maximum voltage for ECO Mode */
struct {
int lower ; /* Lower limit */
int upper ; /* Upper limit */
} max ;
/* Range of accepted values for minimum voltage for ECO Mode */
struct {
int lower ; /* Lower limit */
int upper ; /* Upper limit */
} min ;
if ( strspn ( item - > value , " 0123456789 . " ) ! = strlen ( item - > value ) ) {
upsdebugx ( 2 , " %s: non numerical value [%s: %s] " , __func__ , item - > info_type , item - > value ) ;
return - 1 ;
}
snprintf ( value , valuelen , item - > dfl , strtod ( item - > value , NULL ) ) ;
outvoltnom = dstate_getinfo ( " output.voltage.nominal " ) ;
/* Since query for ratings (QRI) is not mandatory to run this driver, skip next steps if we can't get the value of output voltage nominal */
if ( ! outvoltnom ) {
upsdebugx ( 2 , " %s: unable to get output voltage nominal " , __func__ ) ;
/* We return 0 since we have the value and all's ok: simply we can't set its range so we won't unskip SETVAR item and .{min,max} */
return 0 ;
}
ovn = strtol ( outvoltnom , NULL , 10 ) ;
/* For P01/P09 */
if ( protocol = = 1 | | protocol = = 9 ) {
if ( ovn > = 200 ) {
min . lower = ovn - 24 ;
min . upper = ovn - 7 ;
max . lower = ovn + 7 ;
max . upper = ovn + 24 ;
} else {
min . lower = ovn - 12 ;
min . upper = ovn - 3 ;
max . lower = ovn + 3 ;
max . upper = ovn + 12 ;
}
2015-04-30 16:53:36 +03:00
/* For P02/P03/P10/P13/P14/P99 */
} else if ( protocol = = 2 | | protocol = = 3 | | protocol = = 10 | | protocol = = 13 | | protocol = = 14 | | protocol = = 99 ) {
2013-11-24 17:00:12 +02:00
if ( ovn > = 200 ) {
min . lower = ovn - 24 ;
min . upper = ovn - 11 ;
max . lower = ovn + 11 ;
max . upper = ovn + 24 ;
} else {
min . lower = ovn - 12 ;
min . upper = ovn - 5 ;
max . lower = ovn + 5 ;
max . upper = ovn + 12 ;
}
/* ECO mode not supported */
} else {
upsdebugx ( 2 , " %s: the UPS doesn't seem to support ECO Mode " , __func__ ) ;
/* We return 0 since we have the value and all's ok: simply we can't set its range so we won't unskip SETVAR item and .{min,max} */
return 0 ;
}
if ( ! strcasecmp ( item - > info_type , " input.transfer.high " ) ) {
/* Fill voltronic_r_eco_volt_max */
snprintf ( item - > info_rw [ 0 ] . value , sizeof ( item - > info_rw [ 0 ] . value ) , " %d " , max . lower ) ;
snprintf ( item - > info_rw [ 1 ] . value , sizeof ( item - > info_rw [ 1 ] . value ) , " %d " , max . upper ) ;
} else if ( ! strcasecmp ( item - > info_type , " input.transfer.low " ) ) {
/* Fill voltronic_r_eco_volt_min */
snprintf ( item - > info_rw [ 0 ] . value , sizeof ( item - > info_rw [ 0 ] . value ) , " %d " , min . lower ) ;
snprintf ( item - > info_rw [ 1 ] . value , sizeof ( item - > info_rw [ 1 ] . value ) , " %d " , min . upper ) ;
}
/* Unskip input.transfer.{high,low}.{min,max} */
snprintf ( buf , sizeof ( buf ) , " %s.min " , item - > info_type ) ;
unskip = find_nut_info ( buf , QX_FLAG_SEMI_STATIC , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
snprintf ( buf , sizeof ( buf ) , " %s.max " , item - > info_type ) ;
unskip = find_nut_info ( buf , QX_FLAG_SEMI_STATIC , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
/* Unskip input.transfer.{high,low} setvar */
unskip = find_nut_info ( item - > info_type , QX_FLAG_SETVAR , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
return 0 ;
}
/* Voltage limits for ECO Mode (max, min) */
static int voltronic_eco_volt_range ( item_t * item , char * value , size_t valuelen )
{
char * buf ;
int i ;
item_t * from ;
if ( ! strcasecmp ( item - > info_type , " input.transfer.low.min " ) ) {
buf = " input.transfer.low " ;
i = 0 ;
} else if ( ! strcasecmp ( item - > info_type , " input.transfer.low.max " ) ) {
buf = " input.transfer.low " ;
i = 1 ;
} else if ( ! strcasecmp ( item - > info_type , " input.transfer.high.min " ) ) {
buf = " input.transfer.high " ;
i = 0 ;
} else if ( ! strcasecmp ( item - > info_type , " input.transfer.high.max " ) ) {
buf = " input.transfer.high " ;
i = 1 ;
} else {
/* Don't know what happened */
return - 1 ;
}
from = find_nut_info ( buf , QX_FLAG_SEMI_STATIC , 0 ) ;
/* Don't know what happened */
if ( ! from )
return - 1 ;
/* Value is set at runtime by voltronic_eco_volt, so if it's still unset something went wrong */
if ( ! strlen ( from - > info_rw [ i ] . value ) )
return - 1 ;
snprintf ( value , valuelen , " %s " , from - > info_rw [ i ] . value ) ;
return 0 ;
}
/* Frequency limits for ECO Mode */
static int voltronic_eco_freq ( item_t * item , char * value , size_t valuelen )
{
item_t * unskip ;
if ( strspn ( item - > value , " 0123456789 . " ) ! = strlen ( item - > value ) ) {
upsdebugx ( 2 , " %s: non numerical value [%s: %s] " , __func__ , item - > info_type , item - > value ) ;
return - 1 ;
}
snprintf ( value , valuelen , item - > dfl , strtod ( item - > value , NULL ) ) ;
/* Unskip input.transfer.{high,low} setvar */
unskip = find_nut_info ( item - > info_type , QX_FLAG_SETVAR , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
return 0 ;
}
/* *NONUT* Voltage/frequency limits for Bypass Mode */
static int voltronic_bypass ( item_t * item , char * value , size_t valuelen )
{
item_t * unskip ;
double val ;
if ( strspn ( item - > value , " 0123456789 . " ) ! = strlen ( item - > value ) ) {
upsdebugx ( 2 , " %s: non numerical value [%s: %s] " , __func__ , item - > info_type , item - > value ) ;
return - 1 ;
}
if ( ! strcasecmp ( item - > info_type , " max_bypass_volt " ) ) {
val = max_bypass_volt = strtol ( item - > value , NULL , 10 ) ;
} else if ( ! strcasecmp ( item - > info_type , " min_bypass_volt " ) ) {
val = min_bypass_volt = strtol ( item - > value , NULL , 10 ) ;
} else if ( ! strcasecmp ( item - > info_type , " max_bypass_freq " ) ) {
val = max_bypass_freq = strtod ( item - > value , NULL ) ;
} else if ( ! strcasecmp ( item - > info_type , " min_bypass_freq " ) ) {
val = min_bypass_freq = strtod ( item - > value , NULL ) ;
} else {
/* Don't know what happened */
return - 1 ;
}
snprintf ( value , valuelen , item - > dfl , val ) ;
/* No user-provided value to change.. */
if ( ! getval ( item - > info_type ) )
return 0 ;
/* Unskip {min,max}_bypass_volt setvar */
unskip = find_nut_info ( item - > info_type , QX_FLAG_SETVAR , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
return 0 ;
}
/* *NONUT* Number of batteries */
static int voltronic_batt_numb ( item_t * item , char * value , size_t valuelen )
{
item_t * unskip ;
if ( strspn ( item - > value , " 0123456789 . " ) ! = strlen ( item - > value ) ) {
upsdebugx ( 2 , " %s: non numerical value [%s: %s] " , __func__ , item - > info_type , item - > value ) ;
return - 1 ;
}
battery_number = strtol ( item - > value , NULL , 10 ) ;
snprintf ( value , valuelen , item - > dfl , battery_number ) ;
/* No user-provided value to change.. */
if ( ! getval ( item - > info_type ) )
return 0 ;
/* Unskip battery_number setvar */
unskip = find_nut_info ( " battery_number " , QX_FLAG_SETVAR , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
return 0 ;
}
/* Battery runtime */
static int voltronic_batt_runtime ( item_t * item , char * value , size_t valuelen )
{
double runtime ;
if ( strspn ( item - > value , " 0123456789 . " ) ! = strlen ( item - > value ) ) {
upsdebugx ( 2 , " %s: non numerical value [%s: %s] " , __func__ , item - > info_type , item - > value ) ;
return - 1 ;
}
/* Battery runtime is reported by the UPS in minutes, NUT expects seconds */
runtime = strtod ( item - > value , NULL ) * 60 ;
snprintf ( value , valuelen , item - > dfl , runtime ) ;
return 0 ;
}
/* Protocol used by the UPS */
static int voltronic_protocol ( item_t * item , char * value , size_t valuelen )
{
int protocol ;
if ( strncasecmp ( item - > value , " PI " , 2 ) ) {
upsdebugx ( 2 , " %s: invalid start characters [%.2s] " , __func__ , item - > value ) ;
return - 1 ;
}
/* Here we exclude non numerical value and other non accepted protocols (hence the restricted comparison target) */
if ( strspn ( item - > value + 2 , " 0123489 " ) ! = strlen ( item - > value + 2 ) ) {
upslogx ( LOG_ERR , " Protocol [%s] is not supported by this driver " , item - > value ) ;
return - 1 ;
}
protocol = strtol ( item - > value + 2 , NULL , 10 ) ;
switch ( protocol )
{
case 0 :
case 1 :
case 2 :
case 3 :
case 8 :
case 9 :
case 10 :
2015-04-30 16:53:36 +03:00
case 13 :
2013-11-24 17:00:12 +02:00
case 14 :
case 31 :
case 99 :
break ;
default :
upslogx ( LOG_ERR , " Protocol [PI%02d] is not supported by this driver " , protocol ) ;
return - 1 ;
}
snprintf ( value , valuelen , " P%02d " , protocol ) ;
/* Unskip vars according to protocol */
voltronic_massive_unskip ( protocol ) ;
return 0 ;
}
/* Fault reported by the UPS:
* When the UPS is queried for status ( QGS ) , if it reports a fault ( 6 th bit of 12 bit flag of the reply to QGS set to 1 ) , the driver unskips the QFS item in qx2nut array : this function processes the reply to QFS query */
static int voltronic_fault ( item_t * item , char * value , size_t valuelen )
{
int protocol = strtol ( dstate_getinfo ( " ups.firmware.aux " ) + 1 , NULL , 10 ) ;
char alarm [ SMALLBUF ] ;
upslogx ( LOG_INFO , " Checking for faults.. " ) ;
if ( ! strcasecmp ( item - > value , " OK " ) ) {
snprintf ( value , valuelen , item - > dfl , " No fault found " ) ;
upslogx ( LOG_INFO , " %s " , value ) ;
item - > qxflags | = QX_FLAG_SKIP ;
return 0 ;
}
if ( ( strspn ( item - > value , " 0123456789ABC " ) ! = 2 ) | | ( ( item - > value [ 0 ] ! = ' 1 ' ) & & ( strspn ( item - > value + 1 , " 0123456789 " ) ! = 1 ) ) ) {
snprintf ( alarm , sizeof ( alarm ) , " Unknown fault [%s] " , item - > value ) ;
/* P31 UPSes */
} else if ( protocol = = 31 ) {
if ( strpbrk ( item - > value + 1 , " ABC " ) ) {
snprintf ( alarm , sizeof ( alarm ) , " Unknown fault [%s] " , item - > value ) ;
} else {
switch ( strtol ( item - > value , NULL , 10 ) )
{
case 1 :
strcpy ( alarm , " Fan failure. " ) ;
break ;
case 2 :
strcpy ( alarm , " Over temperature fault. " ) ;
break ;
case 3 :
strcpy ( alarm , " Battery voltage is too high. " ) ;
break ;
case 4 :
strcpy ( alarm , " Battery voltage too low. " ) ;
break ;
case 5 :
strcpy ( alarm , " Inverter relay short-circuited. " ) ;
break ;
case 6 :
strcpy ( alarm , " Inverter voltage over maximum value. " ) ;
break ;
case 7 :
strcpy ( alarm , " Overload fault. " ) ;
update_status ( " OVER " ) ;
break ;
case 8 :
strcpy ( alarm , " Bus voltage exceeds its upper limit. " ) ;
break ;
case 9 :
strcpy ( alarm , " Bus soft start fail. " ) ;
break ;
case 10 :
strcpy ( alarm , " Unknown fault [Fault code: 10] " ) ;
break ;
case 51 :
strcpy ( alarm , " Over current fault. " ) ;
break ;
case 52 :
strcpy ( alarm , " Bus voltage below its under limit. " ) ;
break ;
case 53 :
strcpy ( alarm , " Inverter soft start fail. " ) ;
break ;
case 54 :
strcpy ( alarm , " Self test fail. " ) ;
break ;
case 55 :
strcpy ( alarm , " Output DC voltage exceeds its upper limit. " ) ;
break ;
case 56 :
strcpy ( alarm , " Battery open fault. " ) ;
break ;
case 57 :
strcpy ( alarm , " Current sensor fault. " ) ;
break ;
case 58 :
strcpy ( alarm , " Battery short. " ) ;
break ;
case 59 :
strcpy ( alarm , " Inverter voltage below its lower limit. " ) ;
break ;
default :
snprintf ( alarm , sizeof ( alarm ) , " Unknown fault [%s] " , item - > value ) ;
break ;
}
}
/* All other UPSes */
} else {
switch ( strtol ( item - > value , NULL , 10 ) )
{
case 1 :
switch ( item - > value [ 1 ] )
{
case ' A ' :
strcpy ( alarm , " L1 inverter negative power out of acceptable range. " ) ;
break ;
case ' B ' :
strcpy ( alarm , " L2 inverter negative power out of acceptable range. " ) ;
break ;
case ' C ' :
strcpy ( alarm , " L3 inverter negative power out of acceptable range. " ) ;
break ;
default :
strcpy ( alarm , " Bus voltage not within default setting. " ) ;
break ;
}
break ;
case 2 :
strcpy ( alarm , " Bus voltage over maximum value. " ) ;
break ;
case 3 :
strcpy ( alarm , " Bus voltage below minimum value. " ) ;
break ;
case 4 :
strcpy ( alarm , " Bus voltage differences out of acceptable range. " ) ;
break ;
case 5 :
strcpy ( alarm , " Bus voltage of slope rate drops too fast. " ) ;
break ;
case 6 :
strcpy ( alarm , " Over current in PFC input inductor. " ) ;
break ;
case 11 :
strcpy ( alarm , " Inverter voltage not within default setting. " ) ;
break ;
case 12 :
strcpy ( alarm , " Inverter voltage over maximum value. " ) ;
break ;
case 13 :
strcpy ( alarm , " Inverter voltage below minimum value. " ) ;
break ;
case 14 :
strcpy ( alarm , " Inverter short-circuited. " ) ;
break ;
case 15 :
strcpy ( alarm , " L2 phase inverter short-circuited. " ) ;
break ;
case 16 :
strcpy ( alarm , " L3 phase inverter short-circuited. " ) ;
break ;
case 17 :
strcpy ( alarm , " L1L2 inverter short-circuited. " ) ;
break ;
case 18 :
strcpy ( alarm , " L2L3 inverter short-circuited. " ) ;
break ;
case 19 :
strcpy ( alarm , " L3L1 inverter short-circuited. " ) ;
break ;
case 21 :
strcpy ( alarm , " Battery SCR short-circuited. " ) ;
break ;
case 22 :
strcpy ( alarm , " Line SCR short-circuited. " ) ;
break ;
case 23 :
strcpy ( alarm , " Inverter relay open fault. " ) ;
break ;
case 24 :
strcpy ( alarm , " Inverter relay short-circuited. " ) ;
break ;
case 25 :
strcpy ( alarm , " Input and output wires oppositely connected. " ) ;
break ;
case 26 :
strcpy ( alarm , " Battery oppositely connected. " ) ;
break ;
case 27 :
strcpy ( alarm , " Battery voltage is too high. " ) ;
break ;
case 28 :
strcpy ( alarm , " Battery voltage too low. " ) ;
break ;
case 29 :
strcpy ( alarm , " Failure for battery fuse being open-circuited. " ) ;
break ;
case 31 :
strcpy ( alarm , " CAN-bus communication fault. " ) ;
break ;
case 32 :
strcpy ( alarm , " Host signal circuit fault. " ) ;
break ;
case 33 :
strcpy ( alarm , " Synchronous signal circuit fault. " ) ;
break ;
case 34 :
strcpy ( alarm , " Synchronous pulse signal circuit fault. " ) ;
break ;
case 35 :
strcpy ( alarm , " Parallel cable disconnected. " ) ;
break ;
case 36 :
strcpy ( alarm , " Load unbalanced. " ) ;
break ;
case 41 :
strcpy ( alarm , " Over temperature fault. " ) ;
break ;
case 42 :
strcpy ( alarm , " Communication failure between CPUs in control board. " ) ;
break ;
case 43 :
strcpy ( alarm , " Overload fault. " ) ;
update_status ( " OVER " ) ;
break ;
case 44 :
strcpy ( alarm , " Fan failure. " ) ;
break ;
case 45 :
strcpy ( alarm , " Charger failure. " ) ;
break ;
case 46 :
strcpy ( alarm , " Model fault. " ) ;
break ;
case 47 :
strcpy ( alarm , " MCU communication fault. " ) ;
break ;
default :
snprintf ( alarm , sizeof ( alarm ) , " Unknown fault [%s] " , item - > value ) ;
break ;
}
}
snprintf ( value , valuelen , item - > dfl , alarm ) ;
upslogx ( LOG_INFO , " Fault found: %s " , alarm ) ;
item - > qxflags | = QX_FLAG_SKIP ;
return 0 ;
}
/* Warnings reported by the UPS */
static int voltronic_warning ( item_t * item , char * value , size_t valuelen )
{
char warn [ SMALLBUF ] = " " , unk [ SMALLBUF ] = " " , bitwarns [ SMALLBUF ] = " " , warns [ 4096 ] = " " ;
int i ;
if ( strspn ( item - > value , " 01 " ) ! = strlen ( item - > value ) ) {
upsdebugx ( 2 , " %s: invalid reply from the UPS [%s] " , __func__ , item - > value ) ;
return - 1 ;
}
/* No warnings */
if ( strspn ( item - > value , " 0 " ) = = strlen ( item - > value ) ) {
return 0 ;
}
snprintf ( value , valuelen , " UPS warnings: " ) ;
for ( i = 0 ; i < ( int ) strlen ( item - > value ) ; i + + ) {
int u = 0 ;
if ( item - > value [ i ] = = ' 1 ' ) {
switch ( i )
{
case 0 :
strcpy ( warn , " Battery disconnected. " ) ;
break ;
case 1 :
strcpy ( warn , " Neutral not connected. " ) ;
break ;
case 2 :
strcpy ( warn , " Site fault. " ) ;
break ;
case 3 :
strcpy ( warn , " Phase sequence incorrect. " ) ;
break ;
case 4 :
strcpy ( warn , " Phase sequence incorrect in bypass. " ) ;
break ;
case 5 :
strcpy ( warn , " Input frequency unstable in bypass. " ) ;
break ;
case 6 :
strcpy ( warn , " Battery overcharged. " ) ;
break ;
case 7 :
strcpy ( warn , " Low battery. " ) ;
update_status ( " LB " ) ;
break ;
case 8 :
strcpy ( warn , " Overload alarm. " ) ;
update_status ( " OVER " ) ;
break ;
case 9 :
strcpy ( warn , " Fan alarm. " ) ;
break ;
case 10 :
strcpy ( warn , " EPO enabled. " ) ;
break ;
case 11 :
strcpy ( warn , " Unable to turn on UPS. " ) ;
break ;
case 12 :
strcpy ( warn , " Over temperature alarm. " ) ;
break ;
case 13 :
strcpy ( warn , " Charger alarm. " ) ;
break ;
case 14 :
strcpy ( warn , " Remote auto shutdown. " ) ;
break ;
case 15 :
strcpy ( warn , " L1 input fuse not working. " ) ;
break ;
case 16 :
strcpy ( warn , " L2 input fuse not working. " ) ;
break ;
case 17 :
strcpy ( warn , " L3 input fuse not working. " ) ;
break ;
case 18 :
strcpy ( warn , " Positive PFC abnormal in L1. " ) ;
break ;
case 19 :
strcpy ( warn , " Negative PFC abnormal in L1. " ) ;
break ;
case 20 :
strcpy ( warn , " Positive PFC abnormal in L2. " ) ;
break ;
case 21 :
strcpy ( warn , " Negative PFC abnormal in L2. " ) ;
break ;
case 22 :
strcpy ( warn , " Positive PFC abnormal in L3. " ) ;
break ;
case 23 :
strcpy ( warn , " Negative PFC abnormal in L3. " ) ;
break ;
case 24 :
strcpy ( warn , " Abnormal in CAN-bus communication. " ) ;
break ;
case 25 :
strcpy ( warn , " Abnormal in synchronous signal circuit. " ) ;
break ;
case 26 :
strcpy ( warn , " Abnormal in synchronous pulse signal circuit. " ) ;
break ;
case 27 :
strcpy ( warn , " Abnormal in host signal circuit. " ) ;
break ;
case 28 :
strcpy ( warn , " Male connector of parallel cable not connected well. " ) ;
break ;
case 29 :
strcpy ( warn , " Female connector of parallel cable not connected well. " ) ;
break ;
case 30 :
strcpy ( warn , " Parallel cable not connected well. " ) ;
break ;
case 31 :
strcpy ( warn , " Battery connection not consistent in parallel systems. " ) ;
break ;
case 32 :
strcpy ( warn , " AC connection not consistent in parallel systems. " ) ;
break ;
case 33 :
strcpy ( warn , " Bypass connection not consistent in parallel systems. " ) ;
break ;
case 34 :
strcpy ( warn , " UPS model types not consistent in parallel systems. " ) ;
break ;
case 35 :
strcpy ( warn , " Capacity of UPSes not consistent in parallel systems. " ) ;
break ;
case 36 :
strcpy ( warn , " Auto restart setting not consistent in parallel systems. " ) ;
break ;
case 37 :
strcpy ( warn , " Battery cell over charge. " ) ;
break ;
case 38 :
strcpy ( warn , " Battery protection setting not consistent in parallel systems. " ) ;
break ;
case 39 :
strcpy ( warn , " Battery detection setting not consistent in parallel systems. " ) ;
break ;
case 40 :
strcpy ( warn , " Bypass not allowed setting not consistent in parallel systems. " ) ;
break ;
case 41 :
strcpy ( warn , " Converter setting not consistent in parallel systems. " ) ;
break ;
case 42 :
strcpy ( warn , " High loss point for frequency in bypass mode not consistent in parallel systems. " ) ;
break ;
case 43 :
strcpy ( warn , " Low loss point for frequency in bypass mode not consistent in parallel systems. " ) ;
break ;
case 44 :
strcpy ( warn , " High loss point for voltage in bypass mode not consistent in parallel systems. " ) ;
break ;
case 45 :
strcpy ( warn , " Low loss point for voltage in bypass mode not consistent in parallel systems. " ) ;
break ;
case 46 :
strcpy ( warn , " High loss point for frequency in AC mode not consistent in parallel systems. " ) ;
break ;
case 47 :
strcpy ( warn , " Low loss point for frequency in AC mode not consistent in parallel systems. " ) ;
break ;
case 48 :
strcpy ( warn , " High loss point for voltage in AC mode not consistent in parallel systems. " ) ;
break ;
case 49 :
strcpy ( warn , " Low loss point for voltage in AC mode not consistent in parallel systems. " ) ;
break ;
case 50 :
strcpy ( warn , " Warning for locking in bypass mode after 3 consecutive overloads within 30 min. " ) ;
break ;
case 51 :
strcpy ( warn , " Warning for three-phase AC input current unbalance. " ) ;
break ;
case 52 :
strcpy ( warn , " Warning for a three-phase input current unbalance detected in battery mode. " ) ;
break ;
case 53 :
strcpy ( warn , " Warning for Inverter inter-current unbalance. " ) ;
break ;
case 54 :
strcpy ( warn , " Programmable outlets cut off pre-alarm. " ) ;
break ;
case 55 :
strcpy ( warn , " Warning for Battery replace. " ) ;
update_status ( " RB " ) ;
break ;
case 56 :
strcpy ( warn , " Abnormal warning on input phase angle. " ) ;
break ;
case 57 :
strcpy ( warn , " Warning!! Cover of maintain switch is open. " ) ;
break ;
case 61 :
strcpy ( warn , " EEPROM operation error. " ) ;
break ;
default :
snprintf ( warn , sizeof ( warn ) , " Unknown warning from UPS [bit: #%02d] " , i + 1 ) ;
u + + ;
break ;
}
upslogx ( LOG_INFO , " Warning from UPS: %s " , warn ) ;
if ( u ) { /* Unknown warnings */
snprintfcat ( unk , sizeof ( unk ) , " , #%02d " , i + 1 ) ;
} else { /* Known warnings */
if ( strlen ( warns ) > 0 ) {
/* For too long warnings (total) */
snprintfcat ( bitwarns , sizeof ( bitwarns ) , " , #%02d " , i + 1 ) ;
/* For warnings (total) not too long */
snprintfcat ( warns , sizeof ( warns ) , " %s " , warn ) ;
} else {
snprintf ( bitwarns , sizeof ( bitwarns ) , " Known (see log or manual) [bit: #%02d " , i + 1 ) ;
snprintf ( warns , sizeof ( warns ) , " %s " , warn ) ;
}
}
}
}
/* There's some known warning, at least */
if ( strlen ( warns ) > 0 ) {
/* We have both known and unknown warnings */
if ( strlen ( unk ) > 0 ) {
/* Appending unknown ones to known ones; removing leading comma from unk - 'explicit' */
snprintfcat ( warns , sizeof ( warns ) , " Unknown warnings [bit:%s] " , unk + 1 ) ;
/* Appending unknown ones to known ones; removing leading comma from unk - 'cryptic' */
snprintfcat ( bitwarns , sizeof ( bitwarns ) , " ]; Unknown warnings [bit:%s] " , unk + 1 ) ;
/* We have only known warnings */
} else {
snprintfcat ( bitwarns , sizeof ( bitwarns ) , " ] " ) ;
}
/* We have only unknown warnings */
} else if ( strlen ( unk ) > 0 ) {
/* Removing leading comma from unk */
snprintf ( warns , sizeof ( warns ) , " Unknown warnings [bit:%s] " , unk + 1 ) ;
strcpy ( bitwarns , warns ) ;
} else {
/* Don't know what happened */
upsdebugx ( 2 , " %s: failed to process warnings " , __func__ ) ;
return - 1 ;
}
/* If grand total of warnings doesn't exceed value of alarm (=ST_MAX_VALUE_LEN) minus some space (32) for other alarms.. */
if ( ( ST_MAX_VALUE_LEN - 32 ) > strlen ( warns ) ) {
/* ..then be explicit.. */
snprintfcat ( value , valuelen , " %s " , warns ) ;
/* ..otherwise.. */
} else {
/* ..be cryptic */
snprintfcat ( value , valuelen , " %s " , bitwarns ) ;
}
return 0 ;
}
/* Working mode reported by the UPS */
static int voltronic_mode ( item_t * item , char * value , size_t valuelen )
{
char * status = NULL , * alarm = NULL ;
switch ( item - > value [ 0 ] )
{
case ' P ' :
alarm = " UPS is going ON " ;
break ;
case ' S ' :
status = " OFF " ;
break ;
case ' Y ' :
status = " BYPASS " ;
break ;
case ' L ' :
status = " OL " ;
break ;
case ' B ' :
status = " !OL " ;
break ;
case ' T ' :
status = " CAL " ;
break ;
case ' F ' :
alarm = " Fault reported by UPS. " ;
break ;
case ' E ' :
alarm = " UPS is in ECO Mode. " ;
break ;
case ' C ' :
alarm = " UPS is in Converter Mode. " ;
break ;
case ' D ' :
alarm = " UPS is shutting down! " ;
status = " FSD " ;
break ;
default :
upsdebugx ( 2 , " %s: invalid reply from the UPS [%s] " , __func__ , item - > value ) ;
return - 1 ;
}
if ( alarm & & ! strcasecmp ( item - > info_type , " ups.alarm " ) ) {
snprintf ( value , valuelen , item - > dfl , alarm ) ;
} else if ( status & & ! strcasecmp ( item - > info_type , " ups.status " ) ) {
snprintf ( value , valuelen , item - > dfl , status ) ;
}
return 0 ;
}
/* Process status bits */
static int voltronic_status ( item_t * item , char * value , size_t valuelen )
{
char * val = " " ;
if ( strspn ( item - > value , " 01 " ) ! = strlen ( item - > value ) ) {
upsdebugx ( 3 , " %s: unexpected value %s@%d->%s " , __func__ , item - > value , item - > from , item - > value ) ;
return - 1 ;
}
switch ( item - > from )
{
case 63 : /* UPS Type - ups.type */
{
int type = strtol ( item - > value , NULL , 10 ) ;
if ( ! type ) /* 00 -> Offline */
val = " offline " ;
else if ( type = = 1 ) /* 01 -> Line-interactive */
val = " line-interactive " ;
else if ( type = = 10 ) /* 10 -> Online */
val = " online " ;
else {
upsdebugx ( 2 , " %s: invalid type [%s: %s] " , __func__ , item - > info_type , item - > value ) ;
return - 1 ;
}
}
break ;
case 65 : /* Utility Fail (Immediate) - ups.status */
if ( item - > value [ 0 ] = = ' 1 ' )
val = " !OL " ;
else
val = " OL " ;
break ;
case 66 : /* Battery Low - ups.status */
if ( item - > value [ 0 ] = = ' 1 ' )
val = " LB " ;
else
val = " !LB " ;
break ;
case 67 : /* Bypass/Boost or Buck Active - ups.{status,alarm} */
if ( item - > value [ 0 ] = = ' 1 ' ) {
double vi , vo ;
vi = strtod ( dstate_getinfo ( " input.voltage " ) , NULL ) ;
vo = strtod ( dstate_getinfo ( " output.voltage " ) , NULL ) ;
if ( vo < 0.5 * vi ) {
upsdebugx ( 2 , " %s: output voltage too low " , __func__ ) ;
return - 1 ;
}
if ( vo < 0.95 * vi ) {
val = " TRIM " ;
} else if ( vo < 1.05 * vi ) {
int prot = strtol ( dstate_getinfo ( " ups.firmware.aux " ) + 1 , NULL , 10 ) ;
if ( ! prot | | prot = = 8 ) { /* ups.alarm */
if ( ! strcasecmp ( item - > info_type , " ups.alarm " ) )
val = " UPS is in AVR Mode. " ;
} else { /* ups.status */
if ( ! strcasecmp ( item - > info_type , " ups.status " ) )
val = " BYPASS " ;
}
} else if ( vo < 1.5 * vi ) {
val = " BOOST " ;
} else {
upsdebugx ( 2 , " %s: output voltage too high " , __func__ ) ;
return - 1 ;
}
}
break ;
case 68 : /* UPS Fault - ups.alarm */
if ( item - > value [ 0 ] = = 1 ) {
item_t * faultitem ;
for ( faultitem = voltronic_qx2nut ; faultitem - > info_type ! = NULL ; faultitem + + ) {
if ( ! faultitem - > command )
continue ;
if ( ! strcasecmp ( faultitem - > command , " QFS \r " ) ) {
faultitem - > qxflags & = ~ QX_FLAG_SKIP ;
break ;
}
}
val = " UPS Fault! " ;
}
break ;
/* case 69: */ /* unknown */
/* break;*/
case 70 : /* Test in Progress - ups.status */
if ( item - > value [ 0 ] = = ' 1 ' )
val = " CAL " ;
else
val = " !CAL " ;
break ;
case 71 : /* Shutdown Active - ups.status */
if ( item - > value [ 0 ] = = ' 1 ' )
val = " FSD " ;
else
val = " !FSD " ;
break ;
case 72 : /* Beeper status - ups.beeper.status */
/* The UPS has the ability to enable/disable the alarm (from UPS capability) */
if ( alarm_control ) {
const char * beeper = dstate_getinfo ( " ups.beeper.status " ) ;
if ( ! beeper | | strcasecmp ( beeper , " disabled " ) ) {
if ( item - > value [ 0 ] = = ' 0 ' ) /* Beeper On */
val = " enabled " ;
else
val = " muted " ;
}
/* The UPS lacks the ability to enable/disable the alarm (from UPS capability) */
} else {
if ( item - > value [ 0 ] = = ' 0 ' ) /* Beeper On */
val = " enabled " ;
else
val = " disabled " ;
}
break ;
/* case 73: */ /* unknown */
/* break;*/
/* case 74: */ /* unknown */
/* break;*/
default :
/* Don't know what happened */
return - 1 ;
}
snprintf ( value , valuelen , " %s " , val ) ;
return 0 ;
}
/* Output power factor */
static int voltronic_output_powerfactor ( item_t * item , char * value , size_t valuelen )
{
double opf ;
if ( strspn ( item - > value , " 0123456789 . " ) ! = strlen ( item - > value ) ) {
upsdebugx ( 2 , " %s: non numerical value [%s: %s] " , __func__ , item - > info_type , item - > value ) ;
return - 1 ;
}
/* UPS report a value expressed in % so -> output.powerfactor*100 e.g. opf = 0,8 -> ups = 80 */
opf = strtod ( item - > value , NULL ) * 0.01 ;
snprintf ( value , valuelen , item - > dfl , opf ) ;
return 0 ;
}
/* UPS serial number */
static int voltronic_serial_numb ( item_t * item , char * value , size_t valuelen )
{
/* If the UPS report a 00..0 serial we'll log it but we won't store it in device.serial */
if ( strspn ( item - > value , " 0 " ) = = strlen ( item - > value ) ) {
upslogx ( LOG_INFO , " %s: UPS reported a non-significant serial [%s] " , item - > info_type , item - > value ) ;
return - 1 ;
}
snprintf ( value , valuelen , item - > dfl , item - > value ) ;
return 0 ;
}
/* Outlet status */
static int voltronic_outlet ( item_t * item , char * value , size_t valuelen )
{
const char * status , * switchable ;
char number = item - > info_type [ 7 ] ,
buf [ SMALLBUF ] ;
item_t * outlet_item ;
switch ( item - > value [ 0 ] )
{
case ' 1 ' :
switchable = " yes " ;
status = " on " ;
break ;
case ' 0 ' :
switchable = " yes " ;
status = " off " ;
break ;
default :
upsdebugx ( 2 , " %s: invalid reply from the UPS [%s: %s] " , __func__ , item - > info_type , item - > value ) ;
return - 1 ;
}
if ( strstr ( item - > info_type , " switchable " ) ) {
snprintf ( value , valuelen , item - > dfl , switchable ) ;
} else if ( strstr ( item - > info_type , " status " ) ) {
snprintf ( value , valuelen , item - > dfl , status ) ;
} else {
/* Don't know what happened */
return - 1 ;
}
/* Unskip outlet.n.delay.shutdown */
snprintf ( buf , sizeof ( buf ) , " outlet.%c.delay.shutdown " , number ) ;
outlet_item = find_nut_info ( buf , QX_FLAG_SEMI_STATIC , 0 ) ;
/* Don't know what happened*/
if ( ! outlet_item )
return - 1 ;
outlet_item - > qxflags & = ~ QX_FLAG_SKIP ;
/* Unskip outlet.n.load.on */
snprintf ( buf , sizeof ( buf ) , " outlet.%c.load.on " , number ) ;
outlet_item = find_nut_info ( buf , QX_FLAG_CMD , 0 ) ;
/* Don't know what happened*/
if ( ! outlet_item )
return - 1 ;
outlet_item - > qxflags & = ~ QX_FLAG_SKIP ;
/* Unskip outlet.n.load.off */
snprintf ( buf , sizeof ( buf ) , " outlet.%c.load.off " , number ) ;
outlet_item = find_nut_info ( buf , QX_FLAG_CMD , 0 ) ;
/* Don't know what happened*/
if ( ! outlet_item )
return - 1 ;
outlet_item - > qxflags & = ~ QX_FLAG_SKIP ;
return 0 ;
}
/* Outlet delay time */
static int voltronic_outlet_delay ( item_t * item , char * value , size_t valuelen )
{
char number = item - > info_type [ 7 ] ,
buf [ SMALLBUF ] ;
double val ;
item_t * setvar_item ;
if ( strspn ( item - > value , " 0123456789 . " ) ! = strlen ( item - > value ) ) {
upsdebugx ( 2 , " %s: non numerical value [%s: %s] " , __func__ , item - > info_type , item - > value ) ;
return - 1 ;
}
/* UPS reports minutes, NUT expects seconds */
val = strtod ( item - > value , NULL ) * 60 ;
snprintf ( value , valuelen , item - > dfl , val ) ;
/* Unskip outlet.n.delay.shutdown setvar */
snprintf ( buf , sizeof ( buf ) , " outlet.%c.delay.shutdown " , number ) ;
setvar_item = find_nut_info ( buf , QX_FLAG_SETVAR , 0 ) ;
/* Don't know what happened*/
if ( ! setvar_item )
return - 1 ;
setvar_item - > qxflags & = ~ QX_FLAG_SKIP ;
return 0 ;
}
/* *SETVAR* Outlet delay time */
static int voltronic_outlet_delay_set ( item_t * item , char * value , size_t valuelen )
{
int delay = strtol ( value , NULL , 10 ) ;
/* From seconds to minute */
delay = delay / 60 ;
snprintf ( value , valuelen , item - > command , delay ) ;
return 0 ;
}
/* Type of battery */
static int voltronic_p31b ( item_t * item , char * value , size_t valuelen )
{
int val ;
if ( ( item - > value [ 0 ] ! = ' 0 ' ) | | ( strspn ( item - > value + 1 , " 012 " ) ! = 1 ) ) {
upsdebugx ( 2 , " %s: invalid battery type reported by the UPS [%s] " , __func__ , item - > value ) ;
return - 1 ;
}
val = strtol ( item - > value , NULL , 10 ) ;
snprintf ( value , valuelen , item - > dfl , item - > info_rw [ val ] . value ) ;
return 0 ;
}
/* *SETVAR* Type of battery */
static int voltronic_p31b_set ( item_t * item , char * value , size_t valuelen )
{
int i ;
for ( i = 0 ; strlen ( item - > info_rw [ i ] . value ) > 0 ; i + + ) {
if ( ! strcasecmp ( item - > info_rw [ i ] . value , value ) )
break ;
}
/* At this point value should already be checked against enum so this shouldn't happen.. however.. */
if ( i > = ( int ) ( sizeof ( item - > info_rw ) / sizeof ( item - > info_rw [ 0 ] ) ) ) {
upslogx ( LOG_ERR , " %s: value [%s] out of range " , item - > info_type , value ) ;
return - 1 ;
}
snprintf ( value , valuelen , " %d " , i ) ;
return voltronic_process_setvar ( item , value , valuelen ) ;
}
/* *NONUT* Actual device grid working range type for P31 UPSes */
static int voltronic_p31g ( item_t * item , char * value , size_t valuelen )
{
int val ;
if ( ( item - > value [ 0 ] ! = ' 0 ' ) | | ( strspn ( item - > value + 1 , " 01 " ) ! = 1 ) ) {
upsdebugx ( 2 , " %s: invalid device grid working range reported by the UPS [%s] " , __func__ , item - > value ) ;
return - 1 ;
}
val = strtol ( item - > value , NULL , 10 ) ;
snprintf ( value , valuelen , item - > dfl , item - > info_rw [ val ] . value ) ;
work_range_type = val ;
return 0 ;
}
/* *SETVAR/NONUT* Device grid working range type for P31 UPSes */
static int voltronic_p31g_set ( item_t * item , char * value , size_t valuelen )
{
int i ;
for ( i = 0 ; strlen ( item - > info_rw [ i ] . value ) > 0 ; i + + ) {
if ( ! strcasecmp ( item - > info_rw [ i ] . value , value ) )
break ;
}
/* At this point value should have been already checked against enum so this shouldn't happen.. however.. */
if ( i > = ( int ) ( sizeof ( item - > info_rw ) / sizeof ( item - > info_rw [ 0 ] ) ) ) {
upslogx ( LOG_ERR , " %s: value [%s] out of range " , item - > info_type , value ) ;
return - 1 ;
}
if ( i = = work_range_type ) {
upslogx ( LOG_INFO , " %s is already set to %s " , item - > info_type , item - > info_rw [ i ] . value ) ;
return - 1 ;
}
snprintf ( value , valuelen , " %d " , i ) ;
return voltronic_process_setvar ( item , value , valuelen ) ;
}
/* *NONUT* UPS actual input/output phase angles */
static int voltronic_phase ( item_t * item , char * value , size_t valuelen )
{
int angle ;
if ( strspn ( item - > value , " 0123456789 . " ) ! = strlen ( item - > value ) ) {
upsdebugx ( 2 , " %s: non numerical value [%s: %s] " , __func__ , item - > info_type , item - > value ) ;
return - 1 ;
}
angle = strtol ( item - > value , NULL , 10 ) ;
if ( ! strcasecmp ( item - > info_type , " output_phase_angle " ) ) {
output_phase_angle = angle ;
/* User-provided value to change.. */
if ( getval ( item - > info_type ) ) {
item_t * unskip ;
/* Unskip output_phase_angle setvar */
unskip = find_nut_info ( item - > info_type , QX_FLAG_SETVAR , 0 ) ;
/* Don't know what happened */
if ( ! unskip )
return - 1 ;
unskip - > qxflags & = ~ QX_FLAG_SKIP ;
}
}
snprintf ( value , valuelen , item - > dfl , angle ) ;
return 0 ;
}
/* *SETVAR/NONUT* Output phase angle */
static int voltronic_phase_set ( item_t * item , char * value , size_t valuelen )
{
int i ;
for ( i = 0 ; strlen ( item - > info_rw [ i ] . value ) > 0 ; i + + ) {
if ( ! strcasecmp ( item - > info_rw [ i ] . value , value ) )
break ;
}
/* At this point value should have been already checked against enum so this shouldn't happen.. however.. */
if ( i > = ( int ) ( sizeof ( item - > info_rw ) / sizeof ( item - > info_rw [ 0 ] ) ) ) {
upslogx ( LOG_ERR , " %s: value [%s] out of range " , item - > info_type , value ) ;
return - 1 ;
}
if ( strtol ( item - > info_rw [ i ] . value , NULL , 10 ) = = output_phase_angle ) {
upslogx ( LOG_INFO , " %s is already set to %s " , item - > info_type , item - > info_rw [ i ] . value ) ;
return - 1 ;
}
snprintf ( value , valuelen , " %d " , i ) ;
return voltronic_process_setvar ( item , value , valuelen ) ;
}
/* *NONUT* UPS is master/slave in a system of UPSes in parallel */
static int voltronic_parallel ( item_t * item , char * value , size_t valuelen )
{
char * type ;
if ( strlen ( item - > value ) ! = strspn ( item - > value , " 0123456789 " ) ) {
upsdebugx ( 2 , " %s: non numerical value [%s: %s] " , __func__ , item - > info_type , item - > value ) ;
return - 1 ;
}
/* 001 for master UPS, 002 and 003 for slave UPSes */
switch ( strtol ( item - > value , NULL , 10 ) )
{
case 1 :
type = " master " ;
break ;
case 2 :
case 3 :
type = " slave " ;
break ;
default :
upsdebugx ( 2 , " %s: invalid reply from the UPS [%s] " , __func__ , item - > value ) ;
return - 1 ;
}
snprintf ( value , valuelen , " This UPS is *%s* in a system of UPSes in parallel " , type ) ;
return 0 ;
}
/* == Subdriver interface == */
subdriver_t voltronic_subdriver = {
VOLTRONIC_VERSION ,
voltronic_claim ,
voltronic_qx2nut ,
NULL ,
NULL ,
voltronic_makevartable ,
" ACK " ,
" (NAK \r " ,
# ifdef TESTING
voltronic_testing ,
# endif /* TESTING */
} ;