[Nut-upsdev] New snmp-ups subdriver for Huawei

Stuart Henderson
2015-03-26T01:21:51Z

Hi, the diff inline below adds a new subdriver for snmp-ups to support
Huawei UPS, based on an observed walk from a UPS5000-E with a few bits
filled in from the MIBs (copy at http://junkpile.org/HUAWEI_UPS_MIB/).
Sample output from upsc follows the diff.

cheers,
Stuart


diff --git a/data/driver.list.in b/data/driver.list.in
index a0e82fb..fac3d5a 100644
--- a/data/driver.list.in
+++ b/data/driver.list.in
@@ -417,6 +417,8 @@
 "HP"	"ups"	"4"	"Various (SNMP mode)"
"HP UPS Management Module "	"snmp-ups"
 "HP"	"pdu"	"1"	"HP3488 Switch/Control
Unit"	""	"powerman-pdu (experimental)"

+"Huawei"	"ups"	"4"	"UPS5000-E"
""	"snmp-ups"
+
 "IBM"	"pdu"	"1"	"Blade Center Management
Module"	"15 outlets"	"powerman-pdu (experimental)"

 "ICS"	"pdu"	"1"	"8064 Ethernet Relay
Interface"	"16 outlets"	"powerman-pdu (experimental)"
diff --git a/docs/man/snmp-ups.txt b/docs/man/snmp-ups.txt
index 3ec3a52..eba7638 100644
--- a/docs/man/snmp-ups.txt
+++ b/docs/man/snmp-ups.txt
@@ -50,6 +50,9 @@ HP/Compaq AF401A management card, perhaps others
 *cyberpower*::
 Cyberpower RMCARD201. Should also support RMCARD100 (net version), RMCARD202
and RMCARD301

+*huawei*::
+Huawei UPS5000-E, perhaps others
+
 EXTRA ARGUMENTS
 ---------------

diff --git a/docs/snmp-subdrivers.txt b/docs/snmp-subdrivers.txt
index d717b96..9f36986 100644
--- a/docs/snmp-subdrivers.txt
+++ b/docs/snmp-subdrivers.txt
@@ -218,6 +218,7 @@ subdrivers are written.:
 - netvision-mib.c/h
 - powerware-mib.c/h
 - raritan-pdu-mib.c
+- huawei-mib.c/h

 To help you, above each entry in <LDRIVER>-mib.c, there is a comment that
 displays the textual OID name. For example, the following entry:
diff --git a/drivers/Makefile.am b/drivers/Makefile.am
index bf36319..d8cc127 100644
--- a/drivers/Makefile.am
+++ b/drivers/Makefile.am
@@ -199,8 +199,7 @@ mge_shut_LDADD = $(LDADD)
 # SNMP
 snmp_ups_SOURCES = snmp-ups.c apc-mib.c baytech-mib.c compaq-mib.c eaton-mib.c
\
  ietf-mib.c mge-mib.c netvision-mib.c powerware-mib.c raritan-pdu-mib.c \
- bestpower-mib.c cyberpower-mib.c delta_ups-mib.c \
- xppc-mib.c
+ bestpower-mib.c cyberpower-mib.c delta_ups-mib.c xppc-mib.c huawei-mib.c
 snmp_ups_LDADD = $(LDADD_DRIVERS) $(LIBNETSNMP_LIBS)

 # NEON XML/HTTP
@@ -264,7 +263,7 @@ dist_noinst_HEADERS = apc-mib.h apc-hid.h baytech-mib.h
bcmxcp.h	\
  delta_ups-mib.h nutdrv_qx.h nutdrv_qx_bestups.h nutdrv_qx_blazer-common.h
nutdrv_qx_mecer.h	\
  nutdrv_qx_megatec.h nutdrv_qx_megatec-old.h nutdrv_qx_mustek.h nutdrv_qx_q1.h
\
  nutdrv_qx_voltronic.h nutdrv_qx_voltronic-qs.h nutdrv_qx_voltronic-qs-hex.h
nutdrv_qx_zinto.h \
- xppc-mib.h
+ xppc-mib.h huawei-mib.h

 # Define a dummy library so that Automake builds rules for the
 # corresponding object files.  This library is not actually built,
diff --git a/drivers/huawei-mib.c b/drivers/huawei-mib.c
new file mode 100644
index 0000000..b5922a4
--- /dev/null
+++ b/drivers/huawei-mib.c
@@ -0,0 +1,234 @@
+/* huawei-mib.c - subdriver to monitor Huawei SNMP devices with NUT
+ *
+ *  Copyright (C)
+ *  2011 - 2012	Arnaud Quette <arnaud.quette at free.fr>
+ *  2015	Stuart Henderson <stu at spacehopper.org>
+ *
+ *  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 "huawei-mib.h"
+
+#define HUAWEI_MIB_VERSION  "0.1"
+
+#define HUAWEI_SYSOID       ".1.3.6.1.4.1.8072.3.2.10"
+#define HUAWEI_UPSMIB       ".1.3.6.1.4.1.2011"
+
+/* To create a value lookup structure (as needed on the 2nd line of the example
+ * below), use the following kind of declaration, outside of the present
snmp_info_t[]:
+ * static info_lkp_t onbatt_info[] = {
+ * 	{ 1, "OB" },
+ * 	{ 2, "OL" },
+ * 	{ 0, "NULL" }
+ * };
+ */
+
+static info_lkp_t supplymethod_info[] = {
+	{ 1, "" },		/* no supply */
+	{ 2, "OL BYPASS" },
+	{ 3, "OL" },
+	{ 4, "OB" },
+	{ 5, "" },		/* combined */
+	{ 6, "OL ECO" },
+	{ 7, "OB ECO" },
+	{ 0, "NULL" }
+};
+
+static info_lkp_t battstate_info[] = {
+	{ 1, "" },		/* not connected */
+	{ 2, "" },		/* not charging or discharging */
+	{ 3, "" },		/* hibernation */
+	{ 4, "" },		/* float */
+	{ 5, "CHRG" },		/* equalized charging */
+	{ 6, "DISCHRG" },
+	{ 0, "NULL" }
+};
+
+static info_lkp_t phase_info[] = {
+	{ 1, "1" },
+	{ 2, "3" },
+	{ 0, "NULL" }
+};
+
+static info_lkp_t voltrating_info[] = {
+	{ 1, "200" },
+	{ 2, "208" },
+	{ 3, "220" },
+	{ 4, "380" },
+	{ 5, "400" },
+	{ 6, "415" },
+	{ 7, "480" },
+	{ 8, "600" },
+	{ 9, "690" },
+	{ 0, "NULL" }
+};
+
+static info_lkp_t freqrating_info[] = {
+	{ 1, "50" },
+	{ 2, "60" },
+	{ 0, "NULL" }
+};
+
+static info_lkp_t pwrrating_info[] = {
+	{ 1, "80000" },
+	{ 2, "100000" },
+	{ 3, "120000" },
+	{ 4, "160000" },
+	{ 5, "200000" },
+	{ 6, "30000" },
+	{ 7, "40000" },
+	{ 8, "60000" },
+	{ 9, "2400000" },
+	{ 10, "2500000" },
+	{ 11, "2800000" },
+	{ 12, "3000000" },
+	{ 0, "NULL" }
+};
+
+static info_lkp_t ietf_test_result_info[] = {
+	{ 1, "done and passed" },
+	{ 2, "done and warning" },
+	{ 3, "done and error" },
+	{ 4, "aborted" },
+	{ 5, "in progress" },
+	{ 6, "no test initiated" },
+	{ 0, "NULL" }
+};
+
+
+/* HUAWEI Snmp2NUT lookup table */
+static snmp_info_t huawei_mib[] = {
+
+	/* Data format:
+	 * { info_type, info_flags, info_len, OID, dfl, flags, oid2info, setvar },
+	 *
+	 *	info_type:	NUT INFO_ or CMD_ element name
+	 *	info_flags:	flags to set in addinfo
+	 *	info_len:	length of strings if STR
+	 *				cmd value if CMD, multiplier otherwise
+	 *	OID: SNMP OID or NULL
+	 *	dfl: default value
+	 *	flags: snmp-ups internal flags (FIXME: ...)
+	 *	oid2info: lookup table between OID and NUT values
+	 *	setvar: variable to set for SU_FLAG_SETINT
+	 *
+	 * Example:
+	 * { "input.voltage", 0, 0.1,
".1.3.6.1.4.1.705.1.6.2.1.2.1", "", SU_INPUT_1, NULL },
+	 * { "ups.status", ST_FLAG_STRING, SU_INFOSIZE,
".1.3.6.1.4.1.705.1.7.3.0", "", SU_FLAG_OK | SU_STATUS_BATT,
onbatt_info },
+	 *
+	 * To create a value lookup structure (as needed on the 2nd line), use the
+	 * following kind of declaration, outside of the present snmp_info_t[]:
+	 * static info_lkp_t onbatt_info[] = {
+	 * 	{ 1, "OB" },
+	 * 	{ 2, "OL" },
+	 * 	{ 0, "NULL" }
+	 * };
+	 */
+
+	/* UPS page */
+
+	{ "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "Huawei",
SU_FLAG_ABSENT | SU_FLAG_OK, NULL },
+	{ "ups.model", ST_FLAG_STRING, SU_INFOSIZE,
".1.3.6.1.4.1.2011.6.174.1.2.100.1.2.1", "Generic SNMP UPS",
SU_FLAG_STATIC | SU_FLAG_OK, NULL },
+	{ "ups.id", ST_FLAG_STRING, SU_INFOSIZE,
".1.3.6.1.4.1.2011.6.174.1.1.1.2.0", NULL, SU_FLAG_STATIC |
SU_FLAG_OK, NULL },
+
+	{ "ups.time", 0, 1, ".1.3.6.1.4.1.2011.6.174.1.11.1.0",
NULL, SU_FLAG_OK, NULL }, /* seconds since epoch */
+
+	{ "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE,
".1.3.6.1.4.1.2011.6.174.1.2.100.1.3.1", NULL, SU_FLAG_STATIC |
SU_FLAG_OK, NULL },
+	{ "ups.serial", ST_FLAG_STRING, SU_INFOSIZE,
".1.3.6.1.4.1.2011.6.174.1.2.100.1.5.1", NULL, SU_FLAG_STATIC |
SU_FLAG_OK, NULL },
+
+	{ "ups.status", 0, 1,
".1.3.6.1.4.1.2011.6.174.1.2.101.1.1.1", NULL, SU_FLAG_OK,
supplymethod_info },
+	{ "ups.status", 0, 1,
".1.3.6.1.4.1.2011.6.174.1.2.101.1.3.1", NULL, SU_STATUS_BATT |
SU_FLAG_OK, battstate_info },
+
+	{ "ups.test.result", ST_FLAG_STRING, SU_INFOSIZE,
".1.3.6.1.2.1.33.1.7.3.0", "", 0, ietf_test_result_info },
+
+
+	/* Input page */
+
+	/* hwUpsCtrlInputStandard listed in MIB but not present on tested UPS5000-E */
+	{ "input.phases", ST_FLAG_STRING, SU_INFOSIZE,
".1.3.6.1.4.1.2011.6.174.1.102.100.1.8", "3", SU_FLAG_ABSENT
| SU_FLAG_OK, phase_info },
+
+	{ "input.L1-N.voltage", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.3.100.1.1.1", NULL, SU_FLAG_OK, NULL },
+	{ "input.L2-N.voltage", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.3.100.1.2.1", NULL, SU_FLAG_OK, NULL },
+	{ "input.L3-N.voltage", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.3.100.1.3.1", NULL, SU_FLAG_OK, NULL },
+
+	{ "input.frequency", 0, 0.01,
".1.3.6.1.4.1.2011.6.174.1.3.100.1.4.1", NULL, SU_FLAG_OK, NULL },
+
+	{ "input.L1.current", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.3.100.1.5.1", NULL, SU_FLAG_OK, NULL },
+	{ "input.L2.current", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.3.100.1.6.1", NULL, SU_FLAG_OK, NULL },
+	{ "input.L3.current", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.3.100.1.7.1", NULL, SU_FLAG_OK, NULL },
+
+	{ "input.L1.powerfactor", 0, 0.01,
".1.3.6.1.4.1.2011.6.174.1.3.100.1.8.1", NULL, SU_FLAG_OK, NULL },
+	{ "input.L2.powerfactor", 0, 0.01,
".1.3.6.1.4.1.2011.6.174.1.3.100.1.9.1", NULL, SU_FLAG_OK, NULL },
+	{ "input.L3.powerfactor", 0, 0.01,
".1.3.6.1.4.1.2011.6.174.1.3.100.1.10.1", NULL, SU_FLAG_OK, NULL },
+
+	{ "input.bypass.L1-N.voltage", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.5.100.1.1.1", NULL, SU_FLAG_OK, NULL },
+	{ "input.bypass.L2-N.voltage", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.5.100.1.2.1", NULL, SU_FLAG_OK, NULL },
+	{ "input.bypass.L3-N.voltage", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.5.100.1.3.1", NULL, SU_FLAG_OK, NULL },
+
+	{ "input.bypass.frequency", 0, 0.01,
".1.3.6.1.4.1.2011.6.174.1.5.100.1.4.1", NULL, SU_FLAG_OK, NULL },
+
+
+	/* Output page */
+
+	/* hwUpsCtrlOutputStandard listed in MIB but not present on tested UPS5000-E
*/
+	{ "output.phases", ST_FLAG_STRING, SU_INFOSIZE,
".1.3.6.1.4.1.2011.6.174.1.102.100.1.9", "3", SU_FLAG_ABSENT
| SU_FLAG_OK, phase_info },
+
+	{ "output.L1-N.voltage", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.1.1", NULL, SU_FLAG_OK, NULL },
+	{ "output.L2-N.voltage", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.2.1", NULL, SU_FLAG_OK, NULL },
+	{ "output.L3-N.voltage", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.3.1", NULL, SU_FLAG_OK, NULL },
+
+	{ "output.L1.current", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.4.1", NULL, SU_FLAG_OK, NULL },
+	{ "output.L2.current", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.5.1", NULL, SU_FLAG_OK, NULL },
+	{ "output.L3.current", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.6.1", NULL, SU_FLAG_OK, NULL },
+
+	{ "output.frequency", 0, 0.01,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.7.1", NULL, SU_FLAG_OK, NULL },
+
+	{ "output.L1.realpower", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.8.1", NULL, SU_FLAG_OK, NULL },
+	{ "output.L1.realpower", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.9.1", NULL, SU_FLAG_OK, NULL },
+	{ "output.L1.realpower", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.10.1", NULL, SU_FLAG_OK, NULL },
+
+	{ "output.L1.power", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.11.1", NULL, SU_FLAG_OK, NULL },
+	{ "output.L2.power", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.12.1", NULL, SU_FLAG_OK, NULL },
+	{ "output.L3.power", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.13.1", NULL, SU_FLAG_OK, NULL },
+
+	{ "output.L1.power.percent", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.14.1", NULL, SU_FLAG_OK, NULL },
+	{ "output.L2.power.percent", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.15.1", NULL, SU_FLAG_OK, NULL },
+	{ "output.L3.power.percent", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.16.1", NULL, SU_FLAG_OK, NULL },
+
+	{ "output.voltage.nominal", ST_FLAG_STRING, SU_INFOSIZE,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.17.1", NULL, SU_FLAG_STATIC |
SU_FLAG_OK, voltrating_info },
+	{ "output.frequency.nominal", ST_FLAG_STRING, SU_INFOSIZE,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.18.1", NULL, SU_FLAG_STATIC |
SU_FLAG_OK, freqrating_info },
+	{ "output.power.nominal", ST_FLAG_STRING, SU_INFOSIZE,
".1.3.6.1.4.1.2011.6.174.1.2.100.1.6.1", NULL, SU_FLAG_STATIC |
SU_FLAG_OK, pwrrating_info },
+
+	{ "output.L1.powerfactor", 0, 0.01,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.19.1", NULL, SU_FLAG_OK, NULL },
+	{ "output.L2.powerfactor", 0, 0.01,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.20.1", NULL, SU_FLAG_OK, NULL },
+	{ "output.L2.powerfactor", 0, 0.01,
".1.3.6.1.4.1.2011.6.174.1.4.100.1.21.1", NULL, SU_FLAG_OK, NULL },
+
+
+	/* Battery page */
+
+	{ "battery.voltage", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.6.100.1.1.1", NULL, SU_FLAG_OK, NULL },
+	{ "battery.current", 0, 0.1,
".1.3.6.1.4.1.2011.6.174.1.6.100.1.2.1", NULL, SU_FLAG_OK, NULL },
+	{ "battery.charge", 0, 1,
".1.3.6.1.4.1.2011.6.174.1.6.100.1.3.1", NULL, SU_FLAG_OK, NULL },
+	{ "battery.runtime", 0, 1,
".1.3.6.1.4.1.2011.6.174.1.6.100.1.4.1", NULL, SU_FLAG_OK, NULL },
+
+
+	/* { "unmapped.hwUpsBattTest", 0, 1,
".1.3.6.1.4.1.2011.6.174.1.103.101.1.6.1", NULL, SU_FLAG_OK, NULL },
*/
+
+
+	/* end of structure. */
+	{ NULL, 0, 0, NULL, NULL, 0, NULL }
+};
+
+mib2nut_info_t	huawei = { "huawei", HUAWEI_MIB_VERSION, NULL, NULL,
huawei_mib, HUAWEI_SYSOID };
diff --git a/drivers/huawei-mib.h b/drivers/huawei-mib.h
new file mode 100644
index 0000000..326a71e
--- /dev/null
+++ b/drivers/huawei-mib.h
@@ -0,0 +1,9 @@
+#ifndef HUAWEI_MIB_H
+#define HUAWEI_MIB_H
+
+#include "main.h"
+#include "snmp-ups.h"
+
+extern mib2nut_info_t huawei;
+
+#endif /* HUAWEI_MIB_H */
diff --git a/drivers/snmp-ups.c b/drivers/snmp-ups.c
index e99615d..5b48f8a 100644
--- a/drivers/snmp-ups.c
+++ b/drivers/snmp-ups.c
@@ -48,6 +48,7 @@
 #include "bestpower-mib.h"
 #include "cyberpower-mib.h"
 #include "delta_ups-mib.h"
+#include "huawei-mib.h"
 #include "ietf-mib.h"
 #include "xppc-mib.h"

@@ -72,7 +73,8 @@ static mib2nut_info_t *mib2nut[] = {
 	&bestpower,
 	&cyberpower,
 	&delta_ups,
-        &xppc,
+	&xppc,
+	&huawei,
 	/*
 	 * Prepend vendor specific MIB mappings before IETF, so that
 	 * if a device supports both IETF and vendor specific MIB,
@@ -100,7 +102,7 @@ const char *mibvers;
 static void disable_transfer_oids(void);

 #define DRIVER_NAME	"Generic SNMP UPS driver"
-#define DRIVER_VERSION		"0.72"
+#define DRIVER_VERSION		"0.73"

 /* driver description structure */
 upsdrv_info_t	upsdrv_info = {


Sample output:

battery.charge: 99.00
battery.current: 0.10
battery.runtime: 13740.00
battery.voltage: 536.80
device.mfr: Huawei
device.model: UPS5000-E
device.serial: 2102310NYJ10EA000006
device.type: ups
driver.name: snmp-ups
driver.parameter.pollinterval: 2
driver.parameter.port: 192.168.44.2
driver.parameter.secLevel: authNoPriv
driver.parameter.snmp_version: v3
driver.version: 2.7.2
driver.version.data: huawei MIB 0.1
driver.version.internal: 0.73
input.bypass.frequency: 49.96
input.bypass.L1-N.voltage: 246.70
input.bypass.L2-N.voltage: 249.60
input.bypass.L3-N.voltage: 244.20
input.frequency: 49.96
input.L1-N.voltage: 247.60
input.L1.current: 7.60
input.L1.powerfactor: 0.94
input.L2-N.voltage: 249.60
input.L2.current: 7.90
input.L2.powerfactor: 0.94
input.L3-N.voltage: 244.00
input.L3.current: 8.60
input.L3.powerfactor: 0.95
input.phases: 3
output.frequency: 49.99
output.frequency.nominal: 50
output.L1-N.voltage: 238.30
output.L1.current: 13.90
output.L1.power: 3.30
output.L1.power.percent: 24.80
output.L1.powerfactor: 0.99
output.L1.realpower: 0.00
output.L2-N.voltage: 240.70
output.L2.current: 3.30
output.L2.power: 0.80
output.L2.power.percent: 5.90
output.L2.powerfactor: 0.00
output.L3-N.voltage: 241.30
output.L3.current: 0.00
output.L3.power: 0.00
output.L3.power.percent: 0.00
output.phases: 3
output.power.nominal: 40000
output.voltage.nominal: 400
ups.firmware: V100R001C10SPC600
ups.id: UPS5000-E
ups.mfr: Huawei
ups.model: UPS5000-E
ups.serial: 2102310NYJ10EA000006
ups.status: OL
ups.test.result: no test initiated
ups.time: 1427332224.00