788 lines
32 KiB
C
788 lines
32 KiB
C
/* ever-hid.c - subdriver to monitor EVER USB/HID devices with NUT
|
|
*
|
|
* Copyright (C)
|
|
* 2003 - 2012 Arnaud Quette <ArnaudQuette@Eaton.com>
|
|
* 2005 - 2006 Peter Selinger <selinger@users.sourceforge.net>
|
|
* 2008 - 2009 Arjen de Korte <adkorte-guest@alioth.debian.org>
|
|
* 2013 Charles Lepple <clepple+nut@gmail.com>
|
|
* 2017 EVER Power Systems [https://ever.eu/]
|
|
* 2020 - 2022 Jim Klimov <jimklimov+nut@gmail.com>
|
|
*
|
|
* Note: this subdriver was initially generated as a "stub" by the
|
|
* gen-usbhid-subdriver script. It must be customized.
|
|
*
|
|
* 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 "config.h" /* must be first */
|
|
|
|
#include "usbhid-ups.h"
|
|
#include "ever-hid.h"
|
|
#include "main.h" /* for getval() */
|
|
#include "usb-common.h"
|
|
|
|
#define EVER_HID_VERSION "Ever HID 0.1"
|
|
/* FIXME: experimental flag to be put in upsdrv_info */
|
|
|
|
/* Ever */
|
|
#define EVER_VENDORID 0x2e51
|
|
|
|
/* ST Microelectronics */
|
|
#define STMICRO_VENDORID 0x0483
|
|
|
|
/* USB IDs device table */
|
|
static usb_device_id_t ever_usb_device_table[] = {
|
|
|
|
{ USB_DEVICE(STMICRO_VENDORID, 0xa113), NULL },
|
|
{ USB_DEVICE(EVER_VENDORID, 0xffff), NULL},
|
|
{ USB_DEVICE(EVER_VENDORID, 0x0000), NULL},
|
|
|
|
/* Terminating entry */
|
|
{ 0, 0, NULL }
|
|
};
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Vendor-specific usage table */
|
|
/* --------------------------------------------------------------- */
|
|
|
|
static const char *ever_format_hardware_fun(double value)
|
|
{
|
|
/*TODO - add exception handling for v1.0b0B */
|
|
const char* hard_rev[27] = {"0", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
|
|
static char model[10];
|
|
snprintf(model, sizeof(model), "rev.%sv%02u",
|
|
(&hard_rev[ ((unsigned int)value & 0xFF00)>>8 ])[0],
|
|
(unsigned int)value & 0xFF );
|
|
return model;
|
|
}
|
|
|
|
static const char *ever_format_version_fun(double value)
|
|
{
|
|
/*upsdebugx(1, "UPS ups_firmware_conversion_fun VALUE: %d", (long)value ); */
|
|
static char model[10];
|
|
snprintf(model, sizeof(model), "v%X.%Xb%02d",
|
|
((unsigned int)value & 0xF000)>>12,
|
|
((unsigned int)value & 0xF00)>>8,
|
|
((int)value & 0xFF) );
|
|
return model;
|
|
}
|
|
|
|
static const char *ever_mac_address_fun(double value)
|
|
{
|
|
NUT_UNUSED_VARIABLE(value);
|
|
|
|
int mac_adress_report_id = 210;
|
|
int len = reportbuf->len[mac_adress_report_id];
|
|
const void *buf = reportbuf->data[mac_adress_report_id];
|
|
|
|
static char line[100];
|
|
line[0] = '\0';
|
|
int n = 0; /* number of characters currently in line */
|
|
int i; /* number of bytes output from buffer */
|
|
|
|
/* skip first elemnt which is a report id */
|
|
for (i = 1; i < len; i++) {
|
|
n = snprintfcat(line, sizeof(line), n ? ":%02x" : "%02x",
|
|
((unsigned char *)buf)[i]);
|
|
}
|
|
|
|
return line;
|
|
}
|
|
|
|
static const char *ever_ip_address_fun(double value)
|
|
{
|
|
NUT_UNUSED_VARIABLE(value);
|
|
|
|
static int report_counter = 1;
|
|
int report_id = 211;
|
|
|
|
if(report_counter == 1)
|
|
report_id = 211; /* notification dest ip */
|
|
else if(report_counter == 2)
|
|
report_id = 230; /* ip address */
|
|
else if(report_counter == 3)
|
|
report_id = 231; /* network mask */
|
|
else if(report_counter == 4)
|
|
report_id = 232; /* default gateway */
|
|
|
|
report_counter== 4 ? report_counter=1 : report_counter++;
|
|
|
|
int len = reportbuf->len[report_id];
|
|
const void *buf = reportbuf->data[report_id];
|
|
|
|
static char line[100];
|
|
line[0] = '\0';
|
|
int n = 0; /* number of characters currently in line */
|
|
int i; /* number of bytes output from buffer */
|
|
|
|
/*skip first element which is a report id */
|
|
for (i = 1; i < len; i++)
|
|
{
|
|
n = snprintfcat(line, sizeof(line), n ? ".%d" : "%d",
|
|
((unsigned char *)buf)[i]);
|
|
}
|
|
|
|
return line;
|
|
}
|
|
|
|
static const char *ever_packets_fun(double value)
|
|
{
|
|
NUT_UNUSED_VARIABLE(value);
|
|
|
|
static int report_counter = 1;
|
|
int report_id = 215;
|
|
|
|
if(report_counter == 1 )
|
|
report_id = 215;
|
|
else if(report_counter == 2 )
|
|
report_id = 216;
|
|
else if(report_counter == 3 )
|
|
report_id = 217;
|
|
else if(report_counter == 4 )
|
|
report_id = 218;
|
|
|
|
report_counter== 4 ? report_counter=1 : report_counter++;
|
|
|
|
int len = reportbuf->len[report_id];
|
|
const unsigned char *buf = reportbuf->data[report_id];
|
|
|
|
static char line[100];
|
|
line[0] = '\0';
|
|
|
|
/*skip first elemnt which is a report id */
|
|
|
|
if(len < 5)
|
|
return "";
|
|
|
|
int res = (int)buf[1];
|
|
res |= (int)buf[2] << 8;
|
|
res |= (int)buf[3] << 16;
|
|
res |= (int)buf[4] << 24;
|
|
|
|
snprintf(line, sizeof(line), "%d", res);
|
|
return line;
|
|
|
|
}
|
|
|
|
static const char* ever_workmode_fun(double value)
|
|
{
|
|
NUT_UNUSED_VARIABLE(value);
|
|
|
|
int workmode_report_id = 74;
|
|
int workmode = -1;
|
|
const unsigned char *buf = reportbuf->data[workmode_report_id];
|
|
|
|
static char line[100];
|
|
line[0] = '\0';
|
|
|
|
/*skip first element which is a report id */
|
|
snprintfcat(line, sizeof(line), "%d", buf[1]);
|
|
|
|
workmode = atoi(line);
|
|
|
|
switch(workmode)
|
|
{
|
|
case 1:
|
|
return "UNKNOWN";
|
|
|
|
case 2:
|
|
return "STOP";
|
|
|
|
case 4:
|
|
return "ONLINE";
|
|
|
|
case 8:
|
|
return "ONBATTERY";
|
|
|
|
case 16:
|
|
return "WATCH";
|
|
|
|
case 32:
|
|
return "WAITING";
|
|
|
|
case 64:
|
|
return "EMERGENCY";
|
|
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
}
|
|
|
|
static const char* ever_messages_fun(double value)
|
|
{
|
|
NUT_UNUSED_VARIABLE(value);
|
|
|
|
int messages_report_id = 75;
|
|
const unsigned char *buf = reportbuf->data[messages_report_id];
|
|
|
|
static char line[200];
|
|
line[0] = '\0';
|
|
|
|
/*skip first element which is a report id */
|
|
int messages = (int)buf[1];
|
|
messages |= (int)buf[2] << 8;
|
|
|
|
int n = 0; /* number of characters currently in line */
|
|
|
|
/* duplicate of ups.status: OB LB */
|
|
/*
|
|
if(messages & 0x01)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "OVERLOAD");
|
|
if(messages & 0x02)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "BATTERY_LOW");
|
|
*/
|
|
if(messages & 0x04)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "BOOST");
|
|
if(messages & 0x08)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "BUCK");
|
|
if(messages & 0x10)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "BOOST_BLOCKED");
|
|
if(messages & 0x20)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "BUCK_BLOCKED");
|
|
if(messages & 0x40)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "CHARGING");
|
|
if(messages & 0x80)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "FAN_ON");
|
|
if(messages & 0x100)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "EPO_BLOCKED");
|
|
if(messages & 0x200)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "NEED_REPLACMENT");
|
|
if(messages & 0x400 || messages & 0x800)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "OVERHEAT");
|
|
if(messages & 0x1000)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "WAITING_FOR_MIN_CHARGE");
|
|
if(messages & 0x2000)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "MAINS_OUT_OF_RANGE");
|
|
return line;
|
|
}
|
|
|
|
static const char* ever_alarms_fun(double value)
|
|
{
|
|
NUT_UNUSED_VARIABLE(value);
|
|
|
|
int alarms_report_id = 76;
|
|
|
|
const unsigned char *buf = reportbuf->data[alarms_report_id];
|
|
|
|
static char line[200];
|
|
line[0] = '\0';
|
|
|
|
/*skip first element which is a report id */
|
|
int alarms = (int)buf[1];
|
|
alarms |= (int)buf[2] << 8;
|
|
|
|
int n = 0; /* number of characters currently in line */
|
|
|
|
if(alarms & 0x01)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "OVERLOAD");
|
|
if(alarms & 0x02)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "SHORT-CIRCUIT");
|
|
if(alarms & 0x04 || alarms & 0x08)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "OVERHEAT");
|
|
if(alarms & 0x10)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "EPO");
|
|
if(alarms & 0x20)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "INERNAL_ERROR");
|
|
if(alarms & 0x40)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "REVERSE_POWER_SUPPLY");
|
|
if(alarms & 0x80)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "NO_INETERNAL_COMM");
|
|
if(alarms & 0x100)
|
|
n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "CRITICAL_BATT_VOLTAGE");
|
|
|
|
return line;
|
|
}
|
|
|
|
static const char* ever_on_off_fun(double value)
|
|
{
|
|
NUT_UNUSED_VARIABLE(value);
|
|
|
|
int workmode_report_id = 74;
|
|
int workmode = -1;
|
|
const unsigned char *buf = reportbuf->data[workmode_report_id];
|
|
|
|
static char line[100];
|
|
line[0] = '\0';
|
|
|
|
/*skip first element which is a report id */
|
|
snprintfcat(line, sizeof(line), "%d", buf[1]);
|
|
|
|
workmode = atoi(line);
|
|
|
|
if(workmode != 0x04 && workmode != 0x08)
|
|
return "off";
|
|
|
|
return "!off";
|
|
}
|
|
|
|
static info_lkp_t ever_format_hardware[] = {
|
|
{ 0, NULL, ever_format_hardware_fun, NULL },
|
|
{ 0, NULL, NULL, NULL }
|
|
};
|
|
|
|
static info_lkp_t ever_format_version[] = {
|
|
{ 0, NULL, ever_format_version_fun, NULL },
|
|
{ 0, NULL, NULL, NULL }
|
|
};
|
|
|
|
static info_lkp_t ever_mac_address[] = {
|
|
{ 0, NULL, ever_mac_address_fun, NULL },
|
|
{ 0, NULL, NULL, NULL }
|
|
};
|
|
|
|
static info_lkp_t ever_ip_address[] = {
|
|
{ 0, NULL, ever_ip_address_fun, NULL },
|
|
{ 0, NULL, NULL, NULL }
|
|
};
|
|
|
|
static info_lkp_t ever_packets[] = {
|
|
{ 0, NULL, ever_packets_fun, NULL },
|
|
{ 0, NULL, NULL, NULL }
|
|
};
|
|
|
|
static info_lkp_t ever_workmode[] = {
|
|
{ 0, NULL, ever_workmode_fun, NULL },
|
|
{ 0, NULL, NULL, NULL }
|
|
};
|
|
|
|
static info_lkp_t ever_messages[] = {
|
|
{ 0, NULL, ever_messages_fun, NULL },
|
|
{ 0, NULL, NULL, NULL }
|
|
};
|
|
|
|
static info_lkp_t ever_alarms[] = {
|
|
{ 0, NULL, ever_alarms_fun, NULL },
|
|
{ 0, NULL, NULL, NULL }
|
|
};
|
|
|
|
static info_lkp_t ever_on_off_info[] = {
|
|
{ 0, NULL, ever_on_off_fun, NULL },
|
|
{ 0, NULL, NULL, NULL }
|
|
};
|
|
|
|
|
|
/* EVER usage table */
|
|
static usage_lkp_t ever_usage_lkp[] = {
|
|
{ "EVER1", 0x00000000 },
|
|
{ "EVER2", 0xff000000 },
|
|
{ "EVER3", 0xff000001 },
|
|
{ "EVER4", 0xff000002 },
|
|
{ "EVER5", 0xff000003 },
|
|
{ "EVER6", 0xff000004 },
|
|
{ "EVER7", 0xff000005 },
|
|
{ "EVER8", 0xff000006 },
|
|
{ "EVER9", 0xff000007 },
|
|
{ "EVER10", 0xff000008 },
|
|
{ "EVER11", 0xff000009 },
|
|
{ "EVER12", 0xff000010 },
|
|
{ "EVER13", 0xff000011 },
|
|
{ "EVER14", 0xff000012 },
|
|
{ "EVER15", 0xff000013 },
|
|
{ "EVER16", 0xff000014 },
|
|
{ "EVER17", 0xff000015 },
|
|
{ "EVER18", 0xff000016 },
|
|
{ "EVER19", 0xff000017 },
|
|
{ "EVER20", 0xff000018 },
|
|
{ "EVER21", 0xff000019 },
|
|
{ "EVER22", 0xff00001a },
|
|
{ "EVER23", 0xff00001b },
|
|
{ "EVER24", 0xff00001c },
|
|
{ "EVER25", 0xff00001d },
|
|
{ "EVER26", 0xff00001e },
|
|
{ "EVER27", 0xff00001f },
|
|
{ "EVER28", 0xff000020 },
|
|
{ "EVER29", 0xff000021 },
|
|
{ "EVER30", 0xff000022 },
|
|
{ "EVER31", 0xff000023 },
|
|
{ "EVER32", 0xff000030 },
|
|
{ "EVER33", 0xff000031 },
|
|
{ "EVER34", 0xff000032 },
|
|
{ "EVER35", 0xff000033 },
|
|
{ "EVER36", 0xff000034 },
|
|
{ "EVER37", 0xff000035 },
|
|
{ "EVER38", 0xff000036 },
|
|
{ "EVER39", 0xff000037 },
|
|
{ "EVER40", 0xff000038 },
|
|
{ "EVER41", 0xff000039 },
|
|
{ "EVER42", 0xff000040 },
|
|
{ "EVER43", 0xff000041 },
|
|
{ "EVER44", 0xff000042 },
|
|
{ "EVER45", 0xff000043 },
|
|
{ "EVER46", 0xff000044 },
|
|
{ "EVER47", 0xff000045 },
|
|
{ "EVER48", 0xff000046 },
|
|
{ "EVER49", 0xff000050 },
|
|
{ "EVER50", 0xff000051 },
|
|
{ "EVER51", 0xff000052 },
|
|
{ "EVER52", 0xff000053 },
|
|
{ "EVER53", 0xff000054 },
|
|
{ "EVER54", 0xff000060 },
|
|
{ "EVER55", 0xff000061 },
|
|
{ "EVER56", 0xff000062 },
|
|
{ "EVER57", 0xff000063 },
|
|
{ "EVER58", 0xff000064 },
|
|
{ "EVER59", 0xff000066 },
|
|
{ "EVER60", 0xff000067 },
|
|
{ "EVER61", 0xff000068 },
|
|
{ "EVER62", 0xff000069 },
|
|
{ "EVER63", 0xff00006a },
|
|
{ "EVER64", 0xff00006b },
|
|
{ "EVER65", 0xff00006c },
|
|
{ "EVER66", 0xff00006d },
|
|
{ "EVER67", 0xff00006e },
|
|
{ "EVER68", 0xff00006f },
|
|
{ "EVER69", 0xff000070 },
|
|
{ "EVER70", 0xff000071 },
|
|
{ "EVER71", 0xff000072 },
|
|
{ "EVER72", 0xff000073 },
|
|
{ "EVER73", 0xff000074 },
|
|
{ "EVER74", 0xff000075 },
|
|
{ "EVER75", 0xff000076 },
|
|
{ "EVER76", 0xff000077 },
|
|
{ "EVER77", 0xff000078 },
|
|
{ "EVER78", 0xff000079 },
|
|
{ "EVER79", 0xff00007a },
|
|
{ "EVER80", 0xff00007b },
|
|
{ "EVER81", 0xff00007c },
|
|
{ "EVER82", 0xff00007d },
|
|
{ "EVER83", 0xff00007e },
|
|
{ "EVER84", 0xff00007f },
|
|
{ "EVER85", 0xff000080 },
|
|
{ "EVER86", 0xff000081 },
|
|
{ "EVER87", 0xff000082 },
|
|
{ "EVER88", 0xff000083 },
|
|
{ "EVER89", 0xff000084 },
|
|
{ "EVER90", 0xff000085 },
|
|
{ "EVER91", 0xff000086 },
|
|
{ "EVER92", 0xff000087 },
|
|
{ "EVER93", 0xff000088 },
|
|
{ "EVER94", 0xff000089 },
|
|
{ "EVER95", 0xff00008a },
|
|
{ "EVER96", 0xff00008b },
|
|
{ "EVER97", 0xff000090 },
|
|
{ "EVER98", 0xff000091 },
|
|
{ "EVER99", 0xff000092 },
|
|
{ "EVER100", 0xff000093 },
|
|
{ "EVER101", 0xff000094 },
|
|
{ "EVER102", 0xff000095 },
|
|
{ "EVER103", 0xff000096 },
|
|
{ "EVER104", 0xff000097 },
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
static usage_tables_t ever_utab[] = {
|
|
ever_usage_lkp,
|
|
hid_usage_lkp,
|
|
NULL,
|
|
};
|
|
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* HID2NUT lookup table */
|
|
/* --------------------------------------------------------------- */
|
|
|
|
static hid_info_t ever_hid2nut[] = {
|
|
|
|
/* Note: fields marked with "experimental." prefix were proposed without
|
|
* an exact match vs. docs/nut-names.txt definitions. PRs are welcome to
|
|
* analyze and map those values into standard NUT variable names, or to
|
|
* raise discussion on mailing lists and define new names via consensus.
|
|
* There is a lot of interesting info listed below.
|
|
*
|
|
* Note: mappings that were applied below (as committed 2022-02-09) may
|
|
* be wrong and are based mostly on cursory reading of original names.
|
|
* In particular, not sure if the skipped "id.*" fields were identifiers
|
|
* or some "internal device" etc.
|
|
*/
|
|
|
|
/* experimental: "NUT variable names" do not currently have
|
|
* any battery.*id data points: */
|
|
{ "experimental.battery.batteryid", 0, 0, "UPS.BatterySystem.Battery.BatteryID", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.battery.systemid", 0, 0, "UPS.BatterySystem.BatterySystemID", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.battery.chargerid", 0, 0, "UPS.BatterySystem.Charger.ChargerID", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.battery.input_flowid", 0, 0, "UPS.BatterySystem.Input.FlowID", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.battery.input_id", 0, 0, "UPS.BatterySystem.Input.InputID", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.battery.output_flowid", 0, 0, "UPS.BatterySystem.Output.FlowID", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.battery.output_id", 0, 0, "UPS.BatterySystem.Output.OutputID", NULL, "%.0f", 0, NULL },
|
|
|
|
/* experimental: "NUT variable names" do not currently have
|
|
* any id (nor version) data points for FW/HW of components: */
|
|
/* not implemented*/
|
|
/* { "experimental.id.ups_type", 0, 0, "UPS.EVER1.EVER12", NULL, "%s", 0, ever_format_model }, */
|
|
{ "experimental.id.firmware_version_inverter", 0, 0, "UPS.EVER1.EVER13", NULL, "%s", 0, ever_format_version },
|
|
{ "experimental.id.firmware_version_interfaces", 0, 0, "UPS.EVER1.EVER14", NULL, "%s", 0, ever_format_version },
|
|
{ "experimental.id.hardware_version", 0, 0, "UPS.EVER1.EVER15", NULL, "%s", 0, ever_format_hardware },
|
|
{ "experimental.id.protocol_version_inverter", 0, 0, "UPS.EVER1.EVER16", NULL, "%s", 0, ever_format_version },
|
|
{ "experimental.id.protocol_version_interfaces", 0, 0, "UPS.EVER1.EVER17", NULL, "%s", 0, ever_format_version },
|
|
|
|
/* WAS: "experimental.inverter_info.heatsink_temperature" */
|
|
{ "ups.temperature", 0, 0, "UPS.EVER1.EVER42", NULL, "%s", 0, kelvin_celsius_conversion },
|
|
/* WAS: "experimental.inverter_info.battery_temperature" */
|
|
{ "battery.temperature", 0, 0, "UPS.EVER1.EVER43", NULL, "%s", 0, kelvin_celsius_conversion },
|
|
/* WAS: "experimental.ups_info.output_powerfactor" */
|
|
{ "powerfactor", 0, 0, "UPS.EVER1.EVER44", NULL, "%.0f", 0, NULL },
|
|
|
|
/* experimental: Should these be HU_TYPE_CMD entries?
|
|
* Or are they really settings? */
|
|
{ "experimental.control.ups_on", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER45.EVER46", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.control.clear_fault", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER45.EVER47", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.control.clear_battery_fault", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER45.EVER48", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.control.epo_blocked", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER49.EVER50", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.control.green_mode", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER49.EVER51", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.control.button_sound", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER49.EVER52", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.control.audible_alarm", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER49.EVER53", NULL, "%.0f", 0, NULL },
|
|
|
|
/* WAS: "experimental.config.output_voltage" */
|
|
{ "output.voltage", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.EVER1.EVER54", NULL, "%.0f", 0, NULL },
|
|
|
|
/* not implemented*/
|
|
/*
|
|
{ "experimental.config.min_output_voltage", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.EVER1.EVER55", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.config.max_output_voltage", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.EVER1.EVER56", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.config.min_output_frequency", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER57", NULL, "%.1f", 0, NULL },
|
|
{ "experimental.config.max_output_frequency", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER58", NULL, "%.1f", 0, NULL },
|
|
*/
|
|
/* experimental: what units is this counted in?
|
|
* is "ups.load.high" a suitable mapping here? or "battery.voltage.high"?
|
|
*/
|
|
{ "experimental.config.overload_clearance_threshold", ST_FLAG_RW | ST_FLAG_STRING, 2, "UPS.EVER1.EVER59", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.config.stb_charge", ST_FLAG_RW | ST_FLAG_STRING, 2, "UPS.EVER1.EVER60", NULL, "%.0f", 0, NULL },
|
|
/* WAS: "experimental.config.number_of_ebms"
|
|
* Should this be a string? rw?
|
|
*/
|
|
{ "battery.packs.external", ST_FLAG_RW | ST_FLAG_STRING, 1, "UPS.EVER1.EVER61", NULL, "%.0f", 0, NULL },
|
|
|
|
{ "experimental.statistics.mains_loss_counter", 0, 0, "UPS.EVER1.EVER62", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.statistics.lowering_AVR_trigger_counter", 0, 0, "UPS.EVER1.EVER63", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.statistics.rising_AVR_trigger_counter", 0, 0, "UPS.EVER1.EVER64", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.statistics.overload_counter", 0, 0, "UPS.EVER1.EVER65", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.statistics.short_circuit_counter", 0, 0, "UPS.EVER1.EVER66", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.statistics.discharge_counter", 0, 0, "UPS.EVER1.EVER67", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.statistics.overheat_counter", 0, 0, "UPS.EVER1.EVER68", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.statistics.mains_operation_time", 0, 0, "UPS.EVER1.EVER69", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.statistics.autonomous_operation_time", 0, 0, "UPS.EVER1.EVER70", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.statistics.overload_operation_time", 0, 0, "UPS.EVER1.EVER71", NULL, "%.0f", 0, NULL },
|
|
|
|
{ "experimental.networkcard.mac_address", 0, 0, "UPS.EVER1.EVER72", NULL, "%s", 0, ever_mac_address },
|
|
{ "experimental.networkcard.notification_destination_ip", 0, 0, "UPS.EVER1.EVER73", NULL, "%s", 0, ever_ip_address },
|
|
{ "experimental.networkcard.send_packets", 0, 0, "UPS.EVER1.EVER77", NULL, "%s", 0, ever_packets },
|
|
{ "experimental.networkcard.received_packets", 0, 0, "UPS.EVER1.EVER78", NULL, "%s", 0, ever_packets },
|
|
{ "experimental.networkcard.send_packets_err", 0, 0, "UPS.EVER1.EVER79", NULL, "%s", 0, ever_packets },
|
|
{ "experimental.networkcard.received_packets_err", 0, 0, "UPS.EVER1.EVER80", NULL, "%s", 0, ever_packets },
|
|
{ "experimental.networkcard.config_dhcp_enabled", 0, 0, "UPS.EVER1.EVER85.EVER86", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.networkcard.config_ethernet_enabled", 0, 0, "UPS.EVER1.EVER85.EVER87", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.networkcard.config_http_enabled", 0, 0, "UPS.EVER1.EVER85.EVER88", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.networkcard.config_snmp_enabled", 0, 0, "UPS.EVER1.EVER85.EVER89", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.networkcard.config_snmp_trap_enabled", 0, 0, "UPS.EVER1.EVER85.EVER90", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.networkcard.config_readonly", 0, 0, "UPS.EVER1.EVER85.EVER91", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.networkcard.config_restart_eth", 0, 0, "UPS.EVER1.EVER85.EVER96", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.networkcard.ip_address", 0, 0, "UPS.EVER1.EVER93", NULL, "%s", 0, ever_ip_address },
|
|
{ "experimental.networkcard.network_mask", 0, 0, "UPS.EVER1.EVER94", NULL, "%s", 0, ever_ip_address },
|
|
{ "experimental.networkcard.default_gateway", 0, 0, "UPS.EVER1.EVER95", NULL, "%s", 0, ever_ip_address },
|
|
|
|
/* WAS: "experimental.id.config_active_power" */
|
|
{ "ups.realpower.nominal", 0, 0, "UPS.Flow.ConfigActivePower", NULL, "%.0f", 0, NULL },
|
|
/* WAS: "experimental.id.config_apparent_power"
|
|
* Other HID subdrivers use "ups.power.nominal" mostly (often HU_FLAG_STATIC);
|
|
* once of each: "ups.realpower.nominal", "ups.realpower".
|
|
* Is this even a run-time value or a hardware property?
|
|
*/
|
|
{ "ups.power.nominal", 0, 0, "UPS.Flow.ConfigApparentPower", NULL, "%.0f", 0, NULL },
|
|
|
|
/* WAS: "experimental.ups.config_frequency"
|
|
* Here and next: is this about input or output?..
|
|
* Other drivers have "input.frequency.nominal" on numbered Flows
|
|
* As a "nominal", should it be HU_FLAG_SEMI_STATIC or HU_FLAG_STATIC maybe?
|
|
* Note there are non-nominal values in "powerconverter" below,
|
|
* so the questions here may be somewhat irrelevant...
|
|
*/
|
|
{ "output.frequency.nominal", 0, 0, "UPS.Flow.ConfigFrequency", NULL, "%.0f", 0, NULL },
|
|
/* WAS: "experimental.ups.config_voltage" */
|
|
{ "output.voltage.nominal", 0, 0, "UPS.Flow.ConfigVoltage", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.ups.flow_id", 0, 0, "UPS.Flow.FlowID", NULL, "%.0f", 0, NULL },
|
|
|
|
/* NOTE: NUT variable names define "outlet.n.*" names for numbering all
|
|
* separately manageable outlets; the numberless value (or outlet.0.*)
|
|
* is reserved to represent common properties of all outlets, if there
|
|
* are more than one outlet (group).
|
|
* Mapping below arbitrarily assigns n=1 but really this should be tied
|
|
* to actual outlet counts (see %i mappings in other drivers).
|
|
*/
|
|
/* WAS: experimental.outlet.outlet_id */
|
|
{ "outlet.1.id", 0, 0, "UPS.OutletSystem.Outlet.OutletID", NULL, "%.0f", 0, NULL },
|
|
/* WAS: */
|
|
{ "experimental.outlet.1.present", 0, 0, "UPS.OutletSystem.Outlet.PresentStatus.Present", NULL, "%.0f", 0, yes_no_info },
|
|
{ "outlet.1.switchable", 0, 0, "UPS.OutletSystem.Outlet.PresentStatus.Switchable", NULL, "%.0f", 0, yes_no_info },
|
|
/* WAS: experimental.outlet.switch_on_off */
|
|
{ "outlet.1.status", 0, 0, "UPS.OutletSystem.Outlet.PresentStatus.SwitchOn/Off", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.outlet.1.undefined", 0, 0, "UPS.OutletSystem.Outlet.PresentStatus.Undefined", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.outlet.1.system_id", 0, 0, "UPS.OutletSystem.OutletSystemID", NULL, "%.0f", 0, NULL },
|
|
/* experimental: Should these be HU_TYPE_CMD entries?
|
|
* Or are they really settings? */
|
|
{ "experimental.outlet.1.switch_off_control", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.OutletSystem.Outlet.SwitchOffControl", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.outlet.1.switch_on_control", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.OutletSystem.Outlet.SwitchOnControl", NULL, "%.0f", 0, NULL },
|
|
|
|
{ "experimental.powerconverter.input_flow_id", 0, 0, "UPS.PowerConverter.Input.FlowID", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powerconverter.input_frequency */
|
|
{ "input.frequency", 0, 0, "UPS.PowerConverter.Input.Frequency", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.powerconverter.input_id", 0, 0, "UPS.PowerConverter.Input.InputID", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powerconverter.input_voltage */
|
|
{ "input.voltage", 0, 0, "UPS.PowerConverter.Input.Voltage", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powerconverter.output_active_power */
|
|
{ "ups.realpower", 0, 0, "UPS.PowerConverter.Output.ActivePower", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powerconverter.output_apparent_power */
|
|
{ "ups.power", 0, 0, "UPS.PowerConverter.Output.ApparentPower", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powerconverter.output_current */
|
|
{ "output.current", 0, 0, "UPS.PowerConverter.Output.Current", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.powerconverter.output_flowid", 0, 0, "UPS.PowerConverter.Output.FlowID", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powerconverter.output_frequency */
|
|
{ "output.frequency", 0, 0, "UPS.PowerConverter.Output.Frequency", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.powerconverter.output_id", 0, 0, "UPS.PowerConverter.Output.OutputID", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powerconverter.output_percent_load
|
|
* Note: several original readings map into "ups.load", first served wins
|
|
*/
|
|
{ "ups.load", 0, 0, "UPS.PowerConverter.Output.PercentLoad", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powerconverter.output_voltage */
|
|
{ "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.powerconverter.powerconverterid", 0, 0, "UPS.PowerConverter.PowerConverterID", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.powersummary.capacity_granularity_1", 0, 0, "UPS.PowerSummary.CapacityGranularity1", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.powersummary.capacity_granularity_2", 0, 0, "UPS.PowerSummary.CapacityGranularity2", NULL, "%.0f", 0, NULL },
|
|
/* WAS: */
|
|
{ "experimental.powersummary.capacity_mode", 0, 0, "UPS.PowerSummary.CapacityMode", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powersummary.delay_before_shutdown */
|
|
{ "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL },
|
|
/* WAS: experimental.powersummary.design_capacity */
|
|
{ "battery.capacity", 0, 0, "UPS.PowerSummary.DesignCapacity", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.powersummary.flow_id", 0, 0, "UPS.PowerSummary.FlowID", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powersummary.full_charge_capacity */
|
|
{ "battery.capacity", 0, 0, "UPS.PowerSummary.FullChargeCapacity", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powersummary.idevice_chemistry */
|
|
{ "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powersummary.percent_load
|
|
* Note: several original readings map into "ups.load", first served wins
|
|
*/
|
|
{ "ups.load", 0, 0, "UPS.PowerSummary.PercentLoad", NULL, "%.0f", 0, NULL },
|
|
{ "experimental.powersummary.rechargeable", 0, 0, "UPS.PowerSummary.Rechargeable", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powersummary.remaining_capacity */
|
|
{ "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powersummary.remaining_time_limit */
|
|
{ "battery.runtime.low", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powersummary.run_time_to_empty */
|
|
{ "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powersummary.voltage */
|
|
{ "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%.0f", 0, NULL },
|
|
/* WAS: experimental.powersummary.delay_before_shutdown */
|
|
{ "ups.timer.shutdown", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL },
|
|
|
|
/* not implemented*/
|
|
/* { "unmapped.ups.powersummary.powersummaryid", 0, 0, "UPS.PowerSummary.PowerSummaryID", NULL, "%.0f", 0, NULL }, */
|
|
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info },
|
|
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.AwaitingPower", NULL, NULL, HU_FLAG_QUICK_POLL, awaitingpower_info },
|
|
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BatteryPresent", NULL, NULL, 0, nobattery_info },
|
|
|
|
/* not implemented*/
|
|
/* { "experimental.ups.presentstatus.belowremainingcapacitylimit", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, "%.0f", 0, NULL }, */
|
|
/* { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Boost", NULL, NULL, 0, boost_info }, */
|
|
/* { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Buck", NULL, NULL, 0, trim_info }, */
|
|
/* { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, */
|
|
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.CommunicationLost", NULL, NULL, 0, commfault_info },
|
|
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info },
|
|
/* not implemented*/
|
|
/* { "experimental.ups.powersummary.presentstatus.good", 0, 0, "UPS.PowerSummary.PresentStatus.Good", NULL, "%.0f", 0, NULL }, */
|
|
/* { "experimental.ups.powersummary.presentstatus.internalfailure", 0, 0, "UPS.PowerSummary.PresentStatus.InternalFailure", NULL, "%.0f", 0, NULL }, */
|
|
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info },
|
|
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, NULL, HU_FLAG_QUICK_POLL, overload_info },
|
|
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.OverTemperature", NULL, NULL, 0, overheat_info },
|
|
/* not implemented*/
|
|
/* { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.RemainingTimeLimitExpired", NULL, NULL, 0, lowbatt_info }, */
|
|
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, shutdownimm_info },
|
|
|
|
{ "BOOL", 0, 0, "UPS.EVER1.EVER18.EVER19", NULL, NULL, 0, overload_info },
|
|
{ "BOOL", 0, 0, "UPS.EVER1.EVER18.EVER20", NULL, NULL, 0, lowbatt_info },
|
|
{ "BOOL", 0, 0, "UPS.EVER1.EVER18.EVER21", NULL, NULL, 0, boost_info },
|
|
{ "BOOL", 0, 0, "UPS.EVER1.EVER18.EVER22", NULL, NULL, 0, trim_info },
|
|
{ "BOOL", 0, 0, "UPS.EVER1.EVER18.EVER25", NULL, NULL, 0, charging_info },
|
|
{ "BOOL", 0, 0, "UPS.EVER1.EVER18.EVER28", NULL, NULL, 0, replacebatt_info },
|
|
{ "BOOL", 0, 0, "UPS.EVER1.EVER32.EVER33", NULL, NULL, 0, overload_info },
|
|
{ "BOOL", 0, 0, "UPS.EVER1.EVER32.EVER40", NULL, "%.0f", 0, commfault_info },
|
|
{ "BOOL", 0, 0, "UPS.EVER1.EVER97.EVER102", NULL, "%s", 0, ever_on_off_info },
|
|
|
|
/* ever workmodes, messages & alarms */
|
|
{ "experimental.status.workmode", 0, 0, "UPS.EVER1.EVER97.EVER98", NULL, "%s", 0, ever_workmode },
|
|
{ "experimental.status.messages", 0, 0, "UPS.EVER1.EVER18.EVER28", NULL, NULL, 0, ever_messages },
|
|
{ "experimental.status.alarms", 0, 0, "UPS.EVER1.EVER32.EVER33", NULL, NULL, 0, ever_alarms },
|
|
|
|
/* instant commands */
|
|
/* experimental: With the same fields here, are the commands different?
|
|
* Per NUT command names, should be: documented load.off stays off, like
|
|
* shutdown.stayoff, but shutdown.return may return if wall power comes back!
|
|
* In many drivers, similar command with "-1" instead of DEFAULT_OFFDELAY
|
|
* serves as a shutdown.stop (to abort a pending shutdown).
|
|
*/
|
|
{ "load.off.delay", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL },
|
|
{ "shutdown.return", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL },
|
|
|
|
/* end of structure. */
|
|
{ NULL, 0, 0, NULL, NULL, NULL, 0, NULL }
|
|
};
|
|
|
|
static const char *ever_format_model(HIDDevice_t *hd) {
|
|
return hd->Product;
|
|
}
|
|
|
|
static const char *ever_format_mfr(HIDDevice_t *hd) {
|
|
return hd->Vendor ? hd->Vendor : "Ever";
|
|
}
|
|
|
|
static const char *ever_format_serial(HIDDevice_t *hd) {
|
|
return hd->Serial;
|
|
}
|
|
|
|
/* this function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. */
|
|
static int ever_claim(HIDDevice_t *hd)
|
|
{
|
|
int status = is_usb_device_supported(ever_usb_device_table, hd);
|
|
|
|
switch (status)
|
|
{
|
|
case POSSIBLY_SUPPORTED:
|
|
/* by default, reject, unless the productid option is given */
|
|
if (getval("productid")) {
|
|
return 1;
|
|
}
|
|
possibly_supported("Ever", hd);
|
|
return 0;
|
|
|
|
case SUPPORTED:
|
|
return 1;
|
|
|
|
case NOT_SUPPORTED:
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
subdriver_t ever_subdriver = {
|
|
EVER_HID_VERSION,
|
|
ever_claim,
|
|
ever_utab,
|
|
ever_hid2nut,
|
|
ever_format_model,
|
|
ever_format_mfr,
|
|
ever_format_serial,
|
|
fix_report_desc,
|
|
};
|