Skip to content

Commit

Permalink
Fix Liebert firmware (incorrect exponents)
Browse files Browse the repository at this point in the history
There are at least two Liebert firmware types which both report
a VID:PID of 10af:0001. The newer ones tend not to have the Belkin
broken Usage Pages (and therefore use standard HID PDC paths) but they
have incorrect exponents for some fields. This patch fixes the values
for the latter implementation

Author: Charles Lepple <clepple+nut@gmail.com>

Fossil-ID: SVN r3607
  • Loading branch information
aquette committed May 21, 2012
1 parent dd84a11 commit 207fed2
Showing 1 changed file with 145 additions and 7 deletions.
152 changes: 145 additions & 7 deletions drivers/belkin-hid.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* belkin-hid.h - data to monitor Belkin UPS Systems USB/HID devices with NUT
/* belkin-hid.c - data to monitor Belkin UPS Systems USB/HID devices with NUT
*
* Copyright (C)
* 2003 - 2008 Arnaud Quette <arnaud.quette@free.fr>
* 2005 Peter Selinger <selinger@users.sourceforge.net>
* 2011 Charles Lepple <clepple+nut@gmail>
*
* Sponsored by MGE UPS SYSTEMS <http://www.mgeups.com>
*
Expand All @@ -28,13 +29,18 @@
#include "belkin-hid.h"
#include "usb-common.h"

#define BELKIN_HID_VERSION "Belkin HID 0.12"
#define BELKIN_HID_VERSION "Belkin HID 0.15"

/* Belkin */
#define BELKIN_VENDORID 0x050d

/* Liebert */
#define LIEBERT_VENDORID 0x10af
/* Note that there are at least two Liebert firmware types which both report
* a VID:PID of 10af:0001. The newer ones tend not to have the Belkin broken
* Usage Pages (and therefore use standard HID PDC paths) but they have
* incorrect exponents for some fields.
*/

/* USB IDs device table */
static usb_device_id_t belkin_usb_device_table[] = {
Expand Down Expand Up @@ -64,6 +70,123 @@ static usb_device_id_t belkin_usb_device_table[] = {
{ -1, -1, NULL }
};

static const char *liebert_online_fun(double value);
static const char *liebert_discharging_fun(double value);
static const char *liebert_charging_fun(double value);
static const char *liebert_lowbatt_fun(double value);
static const char *liebert_replacebatt_fun(double value);
static const char *liebert_shutdownimm_fun(double value);
static const char *liebert_config_voltage_fun(double value);
static const char *liebert_line_voltage_fun(double value);

static info_lkp_t liebert_online_info[] = {
{ 0, NULL, liebert_online_fun }
};

static info_lkp_t liebert_discharging_info[] = {
{ 0, NULL, liebert_discharging_fun }
};

static info_lkp_t liebert_charging_info[] = {
{ 0, NULL, liebert_charging_fun }
};

static info_lkp_t liebert_lowbatt_info[] = {
{ 0, NULL, liebert_lowbatt_fun }
};

static info_lkp_t liebert_replacebatt_info[] = {
{ 0, NULL, liebert_replacebatt_fun }
};

static info_lkp_t liebert_shutdownimm_info[] = {
{ 0, NULL, liebert_shutdownimm_fun }
};

static info_lkp_t liebert_config_voltage_info[] = {
{ 0, NULL, liebert_config_voltage_fun },
};

static info_lkp_t liebert_line_voltage_info[] = {
{ 0, NULL, liebert_line_voltage_fun },
};

static double liebert_config_voltage_mult = 1.0;
static double liebert_line_voltage_mult = 1.0;
static char liebert_conversion_buf[10];

/* These lookup functions also cover the 1e-7 factor which seems to be due to a
* broken report descriptor in certain Liebert units.
*/
static const char *liebert_online_fun(double value)
{
return value ? "online" : "!online";
}

static const char *liebert_discharging_fun(double value)
{
return value ? "dischrg" : "!dischrg";
}

static const char *liebert_charging_fun(double value)
{
return value ? "chrg" : "!chrg";
}

static const char *liebert_lowbatt_fun(double value)
{
return value ? "lowbatt" : "!lowbatt";
}

static const char *liebert_replacebatt_fun(double value)
{
return value ? "replacebatt" : "!replacebatt";
}

static const char *liebert_shutdownimm_fun(double value)
{
return value ? "shutdownimm" : "!shutdownimm";
}

/*! Apply heuristics to Liebert ConfigVoltage for correction of other values.
* Logic is weird since the ConfigVoltage item comes after InputVoltage and
* OutputVoltage.
*/
static const char *liebert_config_voltage_fun(double value)
{
if( value < 1 ) {
if( abs(value - 1e-7) < 1e-9 ) {
liebert_config_voltage_mult = 1e8;
liebert_line_voltage_mult = 1e7; /* stomp this in case input voltage was low */
upsdebugx(2, "ConfigVoltage = %g -> assuming correction factor = %g",
value, liebert_config_voltage_mult);
} else {
upslogx(LOG_NOTICE, "ConfigVoltage exponent looks wrong, but not correcting.");
}
}

snprintf(liebert_conversion_buf, sizeof(liebert_conversion_buf), "%.1f",
value * liebert_config_voltage_mult);
return liebert_conversion_buf;
}

static const char *liebert_line_voltage_fun(double value)
{
if( value < 1 ) {
if( abs(value - 1e-7) < 1e-9 ) {
liebert_line_voltage_mult = 1e7;
upsdebugx(2, "Input/OutputVoltage = %g -> assuming correction factor = %g",
value, liebert_line_voltage_mult);
} else {
upslogx(LOG_NOTICE, "LineVoltage exponent looks wrong, but not correcting.");
}
}

snprintf(liebert_conversion_buf, sizeof(liebert_conversion_buf), "%.1f",
value * liebert_line_voltage_mult);
return liebert_conversion_buf;
}

/* some conversion functions specific to Belkin */

/* returns statically allocated string - must not use it again before
Expand Down Expand Up @@ -338,12 +461,27 @@ static hid_info_t belkin_hid2nut[] = {
{ "ups.serial", 0, 0, "UPS.PowerSummary.iSerialNumber", NULL, "%s", 0, stringid_conversion },
{ "ups.test.result", 0, 0, "UPS.BELKINControls.BELKINTest", NULL, "%s", 0, belkin_test_info },
{ "ups.type", 0, 0, "UPS.BELKINDevice.BELKINUPSType", NULL, "%s", 0, belkin_upstype_conversion },

/* Liebert PSA: */
{ "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, /* why .broken above? */
{ "input.frequency", 0, 0, "UPS.Input.Frequency", NULL, "%s", 0, divide_by_10_conversion },
{ "input.voltage", 0, 0, "UPS.Input.Voltage", NULL, "%s", 0, liebert_line_voltage_info },
{ "output.voltage", 0, 0, "UPS.Output.Voltage", NULL, "%s", 0, liebert_line_voltage_info },
/* You would think these next two would be off by the same factor. You'd be wrong. */
{ "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%s", 0, liebert_line_voltage_info },
{ "battery.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%s", HU_FLAG_STATIC, liebert_config_voltage_info },
{ "ups.load", 0, 0, "UPS.Output.PercentLoad", NULL, "%.0f", 0, NULL },
/* status */
{ "BOOL", 0, 0, "UPS.PowerSummary.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info },
{ "BOOL", 0, 0, "UPS.PowerSummary.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info },
{ "BOOL", 0, 0, "UPS.PowerSummary.ShutdownImminent", NULL, NULL, 0, shutdownimm_info },
{ "BOOL", 0, 0, "UPS.PowerSummary.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info },
{ "BOOL", 0, 0, "UPS.PowerSummary.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_discharging_info }, /* might not need to be liebert_* version */
{ "BOOL", 0, 0, "UPS.PowerSummary.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_charging_info },
{ "BOOL", 0, 0, "UPS.PowerSummary.ShutdownImminent", NULL, NULL, 0, liebert_shutdownimm_info },
{ "BOOL", 0, 0, "UPS.PowerSummary.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_online_info },
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_discharging_info },
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_charging_info },
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, liebert_shutdownimm_info },
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_online_info },
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_replacebatt_info },
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_lowbatt_info },

/* { "BOOL", 0, 0, "UPS.PowerSummary.BelowRemainingCapacityLimit", NULL, "%s", 0, lowbatt_info }, broken! */
{ "BOOL", 0, 0, "UPS.BELKINStatus.BELKINPowerStatus", NULL, NULL, 0, belkin_overload_conversion },
{ "BOOL", 0, 0, "UPS.BELKINStatus.BELKINPowerStatus", NULL, NULL, 0, belkin_overheat_conversion },
Expand Down

0 comments on commit 207fed2

Please sign in to comment.