[Nut-upsdev] Patch for optiups to support Zinto D from ONLINE
USV-Systeme AG
Matthias Goebl
lists-nut at m.goebl.net
Sun Nov 26 14:35:00 CET 2006
Hi Arnaud,
Hi Scott,
Hi list,
Here is a patch to support the Zinto D from ONLINE USV-Systeme AG.
I already sent a version to Russell Kroll (2006-04-09), without no response
and I cannot find support for Zinto in svn until now.
I found a discussion on this list about the Xanto from ONLINE, but the Zinto
seems to use different commands.
The commands are quite similar to those for Opti-UPS, so I decided not to fork,
but to patch optiups. Where I found differences, I added if(testvar(OPTI_ZINTO)).
As soon as someone adds another device with similar commands, one could decide
how to differentiate within the driver (where to use select-case).
What do you think?
Yours,
Matthias
-------------- next part --------------
Index: data/driver.list
===================================================================
--- data/driver.list (revision 606)
+++ data/driver.list (working copy)
@@ -318,6 +318,7 @@
"Oneac" "EG/ON Series" "advanced interface" "oneac"
"Online" "P-Series" "" "genericups upstype=14"
+"Online" "Zinto D" "" "optiups zinto=1"
"OnLite" "AQUA" "50" "megatec"
Index: man/optiups.8
===================================================================
--- man/optiups.8 (revision 606)
+++ man/optiups.8 (working copy)
@@ -52,6 +52,12 @@
nut should power down the system soon after you pull the plug. When you are done
testing, you should remove this flag.
+.IP "zinto"
+
+Set this flag if your UPS is a Zinto D (or similar) from ONLINE USV-Systeme AG
+(www.online-ups.com). The commands are quite similar to those for Opti-UPS,
+but there are minor differences. The UPS has an additional switchable outlet.
+
.SH BUGS
On the 420E, ups.serial and ups.temperature are unsupported features. This
Index: drivers/optiups.c
===================================================================
--- drivers/optiups.c (revision 606)
+++ drivers/optiups.c (working copy)
@@ -3,6 +3,9 @@
Copyright (C) 1999 Russell Kroll <rkroll at exploits.org>
Copyright (C) 2006 Scott Heavner [Use my alioth acct: sheavner]
+ Support for Zinto D from ONLINE USV (only minor differences to OptiSafe UPS)
+ added by Matthias Goebl <matthias.goebl at goebl.net>
+
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
@@ -50,6 +53,7 @@
#define OPTI_MINPOLL "status_only"
#define OPTI_FAKELOW "fake_lowbatt"
#define OPTI_NOWARN_NOIMP "nowarn_noimp"
+#define OPTI_ZINTO "zinto"
/* All serial commands put their response in the same buffer space */
static char _buf[256];
@@ -79,6 +83,14 @@
{ "FF", "input.frequency", 0.1 },
{ "BT", "ups.temperature" },
};
+static ezfill _pollv_zinto[] = {
+ { "NV", "input.voltage", 2.0 },
+ { "OL", "ups.load", 1.0 },
+ { "OV", "output.voltage", 2.0 },
+ { "OF", "output.frequency", 0.1 },
+ { "NF", "input.frequency", 0.1 },
+ { "BT", "ups.temperature" },
+};
/* model "IO" is parsed differently in upsdrv_initinfo() */
static ezfill _initv[] = {
@@ -105,6 +117,10 @@
r=-2;
upsdebugx(1, "READ: <unsupported command>");
}
+ if ( _buf[0] == 0x06 )
+ {
+ upsdebugx(2, "READ: <command done>");
+ }
else
{
upsdebugx(2, "READ: \"%s\"", _buf );
@@ -125,6 +141,7 @@
{
upsdebugx(2, "SEND: \"%s\"", cmd );
ser_send( upsfd, cmd );
+ if ( testvar(OPTI_ZINTO) ) ser_send( upsfd, "\r\n" );
return optireadline();
}
@@ -179,12 +196,26 @@
{
/* You do realize this will kill power to ourself. Would probably only
* be useful for killing power for a slave computer */
+ if ( testvar(OPTI_ZINTO) )
+ {
+ optiquery( "Ct1" );
+ optiquery( "Cs0000000" );
+ sleep(2);
+ return STAT_INSTCMD_HANDLED;
+ }
optiquery( "Ct0" );
optiquery( "Cs00000000" );
return STAT_INSTCMD_HANDLED;
}
else if (!strcasecmp(cmdname, "load.on"))
{
+ if ( testvar(OPTI_ZINTO) )
+ {
+ optiquery( "Ct1" );
+ optiquery( "Cu0000000" );
+ sleep(2);
+ return STAT_INSTCMD_HANDLED;
+ }
optiquery( "Ct0" );
optiquery( "Cu00000000" );
return STAT_INSTCMD_HANDLED;
@@ -193,6 +224,13 @@
{
/* This shuts down the UPS. When the power returns to the UPS,
* it will power back up in its default state. */
+ if ( testvar(OPTI_ZINTO) )
+ {
+ optiquery( "Ct1" );
+ optiquery( "Cu0000010" );
+ optiquery( "Cs0000001" );
+ return STAT_INSTCMD_HANDLED;
+ }
optiquery( "Ct1" );
optiquery( "Cs00000010" );
return STAT_INSTCMD_HANDLED;
@@ -202,6 +240,12 @@
/* This actually stays off as long as the batteries hold,
* if the line power comes back before the batteries die,
* the UPS will never powerup its output stage!!! */
+ if ( testvar(OPTI_ZINTO) )
+ {
+ optiquery( "Ct1" );
+ optiquery( "Cs0000001" );
+ return STAT_INSTCMD_HANDLED;
+ }
optiquery( "Ct0" );
optiquery( "Cs00000010" );
return STAT_INSTCMD_HANDLED;
@@ -217,11 +261,52 @@
return STAT_INSTCMD_UNKNOWN;
}
+/* Handle variable setting */
+static int setvar(const char *varname, const char *val)
+{
+ int status;
+ if (sscanf(val, "%d", &status) != 1) {
+ return STAT_SET_UNKNOWN;
+ }
+
+ if (strcasecmp(varname, "outlet.1.switch") == 0) {
+ status = status==1 ? 1 : 0;
+ dstate_setinfo( "outlet.1.switch", "%d", status);
+ optiquery(status ? "Oi11" : "Oi10");
+ dstate_dataok();
+ return STAT_SET_HANDLED;
+ }
+
+ return STAT_SET_UNKNOWN;
+}
+
void upsdrv_initinfo(void)
{
int r;
+ if ( testvar(OPTI_ZINTO) )
+ {
+ /* If UPS is off, switch it on first */
+ /* Online-UPS send only "2" when off, without "\r\n" */
+ /* Therefore without power we cannot identify the ups */
+ if ( optiquery( "AG" ) < 1 )
+ {
+ ser_send( upsfd, "AG\r\n" );
+ r = ser_get_char(upsfd, &_buf[0], 1, 0);
+ if ( r == 1 && _buf[0] == '2' )
+ {
+ upslogx( LOG_WARNING, "ups was off, switched on" );
+ optiquery( "Ct1" );
+ optiquery( "Cu0000000" );
+ sleep(12);
+ }
+ }
+ optiquery( "Om11" );
+ optiquery( "Om21" );
+ optiquery( "ON" );
+ }
+
dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
optifill( _initv, sizeof(_initv)/sizeof(_initv[0]) );
@@ -248,15 +333,45 @@
dstate_addcmd("test.failure.start");
dstate_addcmd("load.off");
dstate_addcmd("load.on");
- dstate_addcmd("shutdown.stop");
+ if( !testvar(OPTI_ZINTO) )
+ dstate_addcmd("shutdown.stop");
dstate_addcmd("shutdown.return");
dstate_addcmd("shutdown.stayoff");
upsh.instcmd = instcmd;
+
+ if ( testvar(OPTI_ZINTO) )
+ {
+ dstate_setinfo("outlet.0.desc", "%s", "Main Outlet 1+2");
+ dstate_setinfo("outlet.1.desc", "%s", "Switchable Outlet 3+4");
+ dstate_setinfo("outlet.0.id", "%d", 1);
+ dstate_setinfo("outlet.1.id", "%d", 2);
+ dstate_setinfo("outlet.0.switchable", "%d", 0);
+ dstate_setinfo("outlet.1.switchable", "%d", 1);
+ dstate_setinfo("outlet.1.switch", "%d", 1);
+ dstate_setflags("outlet.1.switch", ST_FLAG_RW | ST_FLAG_STRING);
+ dstate_setaux("outlet.1.switch", 1);
+ upsh.setvar = setvar;
+ }
}
void upsdrv_updateinfo(void)
{
int r = optiquery( "AG" );
+
+ /* Online-UPS send only "2" when off, without "\r\n" */
+ if ( r < 1 && testvar(OPTI_ZINTO) )
+ {
+ ser_send( upsfd, "AG\r\n" );
+ r = ser_get_char(upsfd, &_buf[0], 1, 0);
+ if ( r == 1 && _buf[0] == '2' )
+ {
+ status_init();
+ status_set("OFF");
+ status_commit();
+ return;
+ }
+ }
+
if ( r < 1 )
{
upslogx(LOG_ERR, "can't retrieve ups status" );
@@ -289,7 +404,10 @@
return;
/* read some easy settings */
- optifill( _pollv, sizeof(_pollv)/sizeof(_pollv[0]) );
+ if ( testvar(OPTI_ZINTO) )
+ optifill( _pollv_zinto, sizeof(_pollv_zinto)/sizeof(_pollv_zinto[0]) );
+ else
+ optifill( _pollv, sizeof(_pollv)/sizeof(_pollv[0]) );
/* Battery voltage is harder */
r = optiquery( "BV" );
@@ -330,6 +448,24 @@
* turn off ups if on battery */
optiquery( "Ct1" );
+ /* What happens, if the power comes back *after* reading the ups status and
+ * before the shutdown command? For "Online-UPS Zinto D" *always* asking for
+ * "shutdown shortly and power-up later" works perfectly, because it forces
+ * a power cycle, even for the named race condition.*/
+ * For Opti-UPS I have no information, so I didn't dare to change it.
+ * BTW, Zinto expects only 7 digits after Cu/Cs.
+ * (Matthias Goebl)
+ */
+ if ( testvar(OPTI_ZINTO) )
+ {
+ /* On line power: Power up in 60 seconds (30 seconds after the following shutdown) */
+ /* On battery: Power up when the line power returns */
+ optiquery( "Cu0000060" );
+ /* Shutdown in 30 seconds */
+ optiquery( "Cs0000030" );
+ return;
+ }
+
/* Just cycling power, schedule output stage to come back on in 60 seconds */
if ( !(s&OPTISBIT_ON_BATTERY_POWER) )
optiquery( "Cu00000600" );
@@ -349,6 +485,7 @@
addvar(VAR_FLAG, OPTI_MINPOLL, "Only poll for critical status variables");
addvar(VAR_FLAG, OPTI_FAKELOW, "Fake a low battery status" );
addvar(VAR_FLAG, OPTI_NOWARN_NOIMP, "Supress warnings of unsupported commands");
+ addvar(VAR_FLAG, OPTI_ZINTO, "UPS is a Zinto D from ONLINE UPS");
}
void upsdrv_banner(void)
More information about the Nut-upsdev
mailing list