[svn r15] implemented some more stuff trunk svn.15

Fri, 12 Feb 2010 16:21:48 +0100

author
mbayer
date
Fri, 12 Feb 2010 16:21:48 +0100
branch
trunk
changeset 13
51e97053dca5
parent 12
e012ecd1e612
child 14
bd1361d7e7fe

[svn r15] implemented some more stuff

README file | annotate | diff | comparison | revisions
http/header.inc file | annotate | diff | comparison | revisions
http/maintenance.tmpl file | annotate | diff | comparison | revisions
http/settings.tmpl file | annotate | diff | comparison | revisions
http/status.tmpl file | annotate | diff | comparison | revisions
structures.py file | annotate | diff | comparison | revisions
tools.py file | annotate | diff | comparison | revisions
victrond.py file | annotate | diff | comparison | revisions
--- a/README	Fri Feb 12 12:36:37 2010 +0100
+++ b/README	Fri Feb 12 16:21:48 2010 +0100
@@ -1,10 +1,18 @@
 Licensed under GPL V3
 
-This is the alpha version - do not use it in productive environments
+This is the currently the beta version - use it at your own risk in productive environments
 
 TODO:
-    Initiate battery calibration
     create a full xmlrpc interface (should i do???)
+    
+    add a graphical UPS Status panel
+    bugfix admin authentication!
+    modify selftest to be checked in main loop (do not wait for completion after init test)
+    
+    invoke the shutdown script, when on battery
+	shutdown after x seconds
+	shutdown when <est runtime
+	shutdown when battery low
 
 requires:
     rrdtool
--- a/http/header.inc	Fri Feb 12 12:36:37 2010 +0100
+++ b/http/header.inc	Fri Feb 12 16:21:48 2010 +0100
@@ -1,6 +1,6 @@
 	<HTML>
 	    <HEAD>
-		<TITLE>[GE:DigitalEnergy / IMV Victron] NetPro UPS maintenance</TITLE>
+		<TITLE>GE/IMV/Victron NetPro UPS maintenance</TITLE>
 		<STYLE TYPE="text/css">
 		    table { width:100% }
 		    td    { border: thin solid grey; }
@@ -35,7 +35,6 @@
     <UL class="menu">
 	<li><a href="status.tmpl">UPS Status</a></li>
 	<li><a href="graphs.tmpl">System Graphs</a></li>
-	<li><a href="settings.tmpl">UPS Settings</a></li>
 	<li><a href="maintenance.tmpl">UPS Maintenance</a></li>
     </UL>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/http/maintenance.tmpl	Fri Feb 12 16:21:48 2010 +0100
@@ -0,0 +1,122 @@
+		<form action="setSettings.py" name="settings" method="post">
+		<table>
+		    <tr>
+			<td colspan="3">Device settings</td>
+		    </tr>
+		    <tr>
+			<td>NoLoad Shutdown</td>	<td>[SNoLoad_en]</td>
+			<td>
+			    <select name="SNoLoad_en">
+				<option value="#">Don't change</option>
+				<option value="4">Enable</option>
+				<option value="0">Disable</option>
+			    </select>
+			</td>    	
+		    </tr>
+		    <tr>
+			<td>Bypass enabled</td>		<td>[SByPass_en]</td>
+			<td>
+			    <select name="SByPass_en">
+				<option value="#">Don't change</option>
+				<option value="2">Enable</option>
+				<option value="0">Disable</option>
+			    </select>
+			</td>    	
+		    </tr>
+		    <tr>
+			<td>Alarm buzzer</td>		<td>[SBuzzerTxt]</td>
+			<td>
+			    <select name="SBuzzer">
+				<option value="#">Don't change</option>
+				<option value="1">Disable</option>
+				<option value="2">Enable</option>
+				<option value="3">Mute</option>
+			    </select>
+			</td>    	
+			
+		    </tr>
+		    <tr>
+			<td>Output Voltage</td>		<td>[SOVolt] V</td>
+			<td>
+			    <select name="SOVolt">
+				<option value="#">Don't change</option>
+				<option value="220">220 V</option>
+				<option value="230">230 V</option>
+				<option value="240">240 V</option>
+			    </select>
+			</td>
+		    </tr>
+		    <tr>
+			<td>Output Frequency</td>	<td>[SOFreq] Hz</td>
+			<td>
+			    <select name="SOFreq">
+				<option value="#">Don't change</option>
+				<option value="500">50 Hz</option>
+				<option value="600">60 Hz</option>
+			    </select>
+			</td>
+		    </tr>
+		    <tr>
+			<td>Battery Capacity</td>	<td>[SBCapa] Ah</td>
+			<td>
+			    <input name="SBCapa" SIZE="5" VALUE="[SBCapa]">
+			</td>    
+		    </tr>
+		    <tr>
+			<td>Auto-Restart</td>		<td>[SAutorestart_en]</td>
+			<td>
+			    <select name="SAutorestart_en">
+				<option value="#">Don't change</option>
+				<option value="1">Enable</option>
+				<option value="2">Disable</option>
+			    </select>
+			</td>    	
+		    </tr>
+		</table>
+		
+		<input type="button" value="Save &amp; Activate settings" onClick="javascript:submit_yesno('settings','Some settings may be vulnerable to attached hardware. Activate settings now?')">
+		
+
+		</form>
+
+
+<p />
+<b> Perform self-tests: </b>
+
+		<form action="selfTest.py" name="selftest" method="post">
+			Run self-test:
+			    <select name="test">
+				<option value="0">Stop any running test</option>
+				<option value="1">System Test</option>
+				<option value="2">Quick battery test</option>
+				<option value="4">ByPass Test (maybe unsupported)</option>
+				<option value="3">Battery calibration (maybe unsupported)</option>
+			    </select>
+
+		<input type="button" value="OK" onClick="javascript:submit_yesno('selftest','Are you sure to perform the operation?')">
+
+		</form>
+
+
+<p />
+<b> Control the UPS Device (be careful): </b>
+
+		<form action="setDeviceState.py" name="devicestate" method="post">
+			Set Device state:
+			    <select name="vCa">
+				<option value="1">Output only</option>
+				<option value="2" selected>System</option>
+			    </select>
+			    to
+			    <select name="cmd">
+				<option value="#">Don't change</option>
+				<option value="vCc">ON</option>
+				<option value="vCb">OFF</option>
+			    </select>
+			    after delay of
+			    <input name="delay" size="3" value="2" />
+			    seconds
+
+		<input type="button" value="OK" onClick="javascript:submit_yesno('devicestate','Are you sure to perform the operation?')">
+
+		</form>
--- a/http/settings.tmpl	Fri Feb 12 12:36:37 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-		<form action="setSettings.py" name="settings" method="post">
-		<table>
-		    <tr>
-			<td colspan="3">Device settings</td>
-		    </tr>
-		    <tr>
-			<td>NoLoad Shutdown</td>	<td>[SNoLoad_en]</td>
-			<td>
-			    <select name="SNoLoad_en">
-				<option value="#">Don't change</option>
-				<option value="4">Enable</option>
-				<option value="0">Disable</option>
-			    </select>
-			</td>    	
-		    </tr>
-		    <tr>
-			<td>Bypass enabled</td>		<td>[SByPass_en]</td>
-			<td>
-			    <select name="SByPass_en">
-				<option value="#">Don't change</option>
-				<option value="2">Enable</option>
-				<option value="0">Disable</option>
-			    </select>
-			</td>    	
-		    </tr>
-		    <tr>
-			<td>Alarm buzzer</td>		<td>[SBuzzerTxt]</td>
-			<td>
-			    <select name="SBuzzer">
-				<option value="#">Don't change</option>
-				<option value="1">Disable</option>
-				<option value="2">Enable</option>
-				<option value="3">Mute</option>
-			    </select>
-			</td>    	
-			
-		    </tr>
-		    <tr>
-			<td>Output Voltage</td>		<td>[SOVolt] V</td>
-			<td>
-			    <select name="SOVolt">
-				<option value="#">Don't change</option>
-				<option value="220">220 V</option>
-				<option value="230">230 V</option>
-				<option value="240">240 V</option>
-			    </select>
-			</td>
-		    </tr>
-		    <tr>
-			<td>Output Frequency</td>	<td>[SOFreq] Hz</td>
-			<td>
-			    <select name="SOFreq">
-				<option value="#">Don't change</option>
-				<option value="500">50 Hz</option>
-				<option value="600">60 Hz</option>
-			    </select>
-			</td>
-		    </tr>
-		    <tr>
-			<td>Battery Capacity</td>	<td>[SBCapa] Ah</td>
-			<td>
-			    <input name="SBCapa" SIZE="5" VALUE="[SBCapa]">
-			</td>    
-		    </tr>
-		    <tr>
-			<td>Auto-Restart</td>		<td>[SAutorestart_en]</td>
-			<td>
-			    <select name="SAutorestart_en">
-				<option value="#">Don't change</option>
-				<option value="1">Enable</option>
-				<option value="2">Disable</option>
-			    </select>
-			</td>    	
-		    </tr>
-		</table>
-		
-		<input type="button" value="Save &amp; Activate settings" onClick="javascript:submit_yesno('settings','Some settings may be vulnerable to attached hardware. Activate settings now?')">
-		
-
-		</form>
-
-
-<br />
-<input class="btn" type="button" value="Perform a general system test" onClick="window.open('SystemTest.py','_self')" />
-<br />
-<input class="btn" type="button" value="Perform a quick battery test" onClick="window.open('BatteryTest.py','_self')" />
-<br />
-<input class="btn" type="button" value="Perform a long battery test" onClick="if (confirm('Warning, this will run on batteries until _battery-low_ reached. Continue?')) {window.open('BatteryCalibration.py','_self')}" />
-<br />
-<input class="btn" type="button" value="Stop any running test" onClick="window.open('StopTest.py','_self')" />
-
-<p />
-Control the UPS Device (be careful):
-
-<br />
-<input class="btn_switch" type="button" value="System OFF" onClick="if (confirm('Are you REALLY Sure?')) window.open('System_Off.py','_self')" />
-<input class="btn_switch" type="button" value="System ON" onClick="if (confirm('Are you REALLY Sure?')) window.open('System_On.py','_self')" />
-
-<br />
-<input class="btn_switch" type="button" value="Output OFF" onClick="if (confirm('Are you REALLY Sure?')) window.open('Output_Off.py','_self')" />
-<input class="btn_switch" type="button" value="Output ON" onClick="if (confirm('Are you REALLY Sure?')) window.open('Output_On.py','_self')" />
--- a/http/status.tmpl	Fri Feb 12 12:36:37 2010 +0100
+++ b/http/status.tmpl	Fri Feb 12 16:21:48 2010 +0100
@@ -38,9 +38,6 @@
 			<td>NoLoad Shutdown</td>	<td>[SNoLoad_en]</td>
 		    </tr>
 		    <tr>
-			<td>Bypass enabled</td>		<td>[SByPass_en]</td>
-		    </tr>
-		    <tr>
 			<td>Alarm buzzer</td>		<td>[SBuzzerTxt]</td>
 		    </tr>
 		    <tr>
@@ -55,18 +52,27 @@
 		    <tr>
 			<td>Auto-Restart</td>		<td>[SAutorestart_en]</td>
 		    </tr>
+		    <tr>
+			<td>Bypass enabled</td>		<td>[SByPass_en]</td>
+		    </tr>
+		    <tr>
+			<td>Input Transfer Voltage</td>		<td>[SIVLow] - [SIVHigh] V</td>
+		    </tr>
 		</table>
 
 		<table>
 		    <tr>
-			<th  width="50%">Programmed shutdown</th>
+			<th  width="50%">Scheduled Info</th>
 		    </tr>
 		    <tr>
-			<td>Shutdown progress</td>		<td>[SShutdown_delay] sec</td>
+			<td>Shutdown progress</td>		<td>[SShutdown_delay] sec <a href="cancelShutdown.py">cancel</a></td>
 		    </tr>
 		    <tr>
 			<td>Shutdown Type</td>		<td>[Shutdown_typeTxt]</td>
 		    </tr>
+		    <tr>
+			<td>SelfTest Status</td>	<td>[TestStatusTxt] ([TestResult])</td>
+		    </tr>
 		    
 		</table>
 	</div>
--- a/structures.py	Fri Feb 12 12:36:37 2010 +0100
+++ b/structures.py	Fri Feb 12 16:21:48 2010 +0100
@@ -34,29 +34,40 @@
  2: "Complete system"
 }
 
+# vTr?
+TStatusTexts = {
+ 1: "Okay",
+ 2: "Warning",
+ 3: "Error",
+ 4: "Aborted",
+ 5: "In Progress",
+ 6: "No test initiated"
+}
+
+# vTd? -> test_result + 3 (?)
+
 def testBit(int_type, offset):
     mask = 1 << offset
     return(int_type & mask)
 
 def getEventText(Event):
     # convert the given events bitmask to a readable string
-
     if Event < 0:
 	return "N/A (lost comm)"
     if Event == 0:
-	return "Normal Operation"
+	return "Normal operation"
 
     # build a list of set bits
     s = ""
 
     if testBit(Event, 0):
-	s = s + ", Change Battery"
+	s = s + ", Replace Battery"
 
     if testBit(Event, 1):
 	s = s + ", Bad Input"
 
     if testBit(Event, 2):
-	s = s + ", 2?"
+	s = s + ", Low Battery"
 
     if testBit(Event, 3):
 	s = s + ", 3?"
@@ -71,7 +82,7 @@
 	s = s + ", 6?"
 
     if testBit(Event, 7):
-	s = s + ", 7?"
+	s = s + ", Overload"
 
     if testBit(Event, 8):
 	s = s + ", 8?"
@@ -83,16 +94,16 @@
 	s = s + ", 10?"
 
     if testBit(Event, 11):
-	s = s + ", 11?"
+	s = s + ", Shutdown timer active"
 
     if testBit(Event, 12):
 	s = s + ", 12?"
 
     if testBit(Event, 13):
-	s = s + ", Output Off"
+	s = s + ", System off"
 
     if testBit(Event, 14):
-	s = s + ", System Off"
+	s = s + ", Stand-By"
 
     if testBit(Event, 15):
 	s = s + ", 15?"
@@ -113,12 +124,12 @@
 	s = s + ", 20?"
 
     if testBit(Event, 21):
-	s = s + ", 21?"
+	s = s + ", Waiting for shutdown"
 
     if testBit(Event, 22):
 	s = s + ", 22?"
 
     if testBit(Event, 23):
-	s = s + ", Test Running"
+	s = s + ", Selftest running"
 
     return s[2:]
\ No newline at end of file
--- a/tools.py	Fri Feb 12 12:36:37 2010 +0100
+++ b/tools.py	Fri Feb 12 16:21:48 2010 +0100
@@ -2,6 +2,9 @@
 import rrdtool
 import math
 import time
+from config import *
+
+
 
 def rrd_check():
     # values are placed every 10 seconds!
--- a/victrond.py	Fri Feb 12 12:36:37 2010 +0100
+++ b/victrond.py	Fri Feb 12 16:21:48 2010 +0100
@@ -85,7 +85,9 @@
 	if s2.find("!") > -1:
 	    print "UPS Attention received!"
 	    self.attention = True
-	    return -1
+	    time.sleep(0.5)
+	    # hopefully that we dont receive endless "!", we do a recursive call :)
+	    return self.query(cmd,is_command)
 
 	if len(s)>len(cmd):
 	    ret = s[len(cmd):]
@@ -116,11 +118,15 @@
 	self.query('vCC5424107',1);
 	vZ2C = int(self.query('vZ2c'))
 	buzzer = int(self.query("vFh"))
+
 	vCa = int(self.query("vCa"))
+
         self.settings = {
 	"SNoLoad_en":((vZ2C & 4)==4),
 	"SByPass_en":((vZ2C & 2)==2),
 	"SModemNumber":self.query("vZ0d"),
+	"SIVLow":self.query("vFi"),
+	"SIVHigh":self.query("vFj"),
 	"SBuzzer":buzzer,
 	"SBuzzerTxt":BuzzerTexts.get(buzzer,"Unknown: "+str(buzzer)),
 	"SOVolt":int(self.query("vFc")), # 220, 230, 240
@@ -129,7 +135,6 @@
 	"SReceptacle_count":int(self.query("vCn")),
 	"SReceptacle_en":self.query("vC0f")=="1",
 	"SAutorestart_en":self.query("vCe")=="1",
-	"SShutdown_delay":int(self.query("vCb")),
 	"Shutdown_type":vCa,
 	"Shutdown_typeTxt":ShutdownTypeTexts.get(vCa,"Unknown: "+str(vCa))
 	}
@@ -137,16 +142,31 @@
 	if LOG_DEBUG == True:
 	    print "Settings: "+repr(self.settings)+"\n"
 
-    def func_StopTest(self):
+# ===========================================================
+# SELF-TESTS
+# ===========================================================
+
+    def func_selfTest(self):
+	global form
+	if form["test"].value == "1":
+	    return self._SystemTest()
+	if form["test"].value == "2":
+	    return self._BatteryTest()
+	if form["test"].value == "3":
+	    return self._BatteryCalibration()
+	if form["test"].value == "4":
+	    return self._BypassTest()
+	return self._StopTest()
+	
+    def _StopTest(self):
 	self._wait_comm_free()
 	self.comm_free = False
 	time.sleep(0.5)
 	s = self.query("vTi2",1)
 	self.comm_free = True
-	mail_deliver(NOTICE_EMAIL,"Selftest Stopped","Admin: Stopped current running selftest")
 	return "Stopped any running test (returned "+s+")"
 
-    def func_SystemTest(self):
+    def _SystemTest(self):
 	self._wait_comm_free()
 	self.comm_free = False
 	time.sleep(0.5)
@@ -181,7 +201,7 @@
 	mail_deliver(NOTICE_EMAIL,"Selftest completed",s)
 	return s
 
-    def func_BatteryTest(self):
+    def _BatteryTest(self):
 	self._wait_comm_free()
 	self.comm_free = False
 	time.sleep(0.5)
@@ -215,10 +235,103 @@
 
 	return s
 
-    def func_BatteryCalibration(self):
-	s = "Sorry, this test isn't implemented yet."
+    def _BatteryCalibration(self):
+	self._wait_comm_free()
+	self.comm_free = False
+	time.sleep(0.5)
+	self.query("vTi2",1) # stop running test
+	time.sleep(0.5)
+	self.query("vTi5",1) # initiate  battery calibration
+
+	s = "Battery calibration started...<br />\n";
+	s = s+"Warning: This will deplete your batteries (ups will not switch off). UPS will recharge the batteries after this test.<br />\n";
+
+	self.comm_free = True
+
+	mail_deliver(NOTICE_EMAIL,"Battery calibration",s)
 	return s
 
+    def _BypassTest(self):
+	self._wait_comm_free()
+	self.comm_free = False
+	time.sleep(0.5)
+	self.query("vTi2",1) # stop running test
+	time.sleep(0.5)
+	self.query("vTi101",1) # initiate bypass test
+
+	start = time.time()
+	s = "Bypass Test started...<br />\n";
+	r = self.query("vAa")
+	time.sleep(0.5)
+	r = self.query("vAa")
+	while r == "8388608":
+	    time.sleep(1) # wait for test to complete
+	    r = self.query("vAa")
+	s = s + "Finished after " + str(int(time.time()-start)) + " seconds<br />\n"
+
+	# now look for the status
+	self.query("vTr")
+	time.sleep(0.5)
+	self.query("vTr")
+	time.sleep(0.5)
+	if self.query("vTr") == "1":
+	    s = s + "<font color='green'>TEST SUCCESS</font>"
+	else:
+	    s = s + "<font color='red'>TEST FAILURE</font>"
+
+	self.comm_free = True
+
+	mail_deliver(NOTICE_EMAIL,"Selftest completed",s)
+
+	return s
+
+
+# ===========================================================
+# DEVICE-CONTROL
+# ===========================================================
+    def func_setDeviceState(self):
+	self._wait_comm_free()
+	self.comm_free = False
+	time.sleep(0.5)
+
+	global form
+	s = ""
+
+	delay = form["delay"].value
+	vCa = form["vCa"].value
+	cmd = form["cmd"].value
+	if  int(delay) < 2:
+	    s = s + "I do not accept this delay, minimum delay of 2 seconds set!<br />\n"
+	    delay = "2"
+
+	s = s + "Setting Shutdown type = vCa" +vCa+ "<br />\n"
+	self.query("vCa"+vCa, 1)
+
+	if cmd == "vCb":
+	    s = s+"Shutdown initiated, delay = "+delay+" seconds<br />\n"
+	if cmd == "vCc":
+	    s = s+"Startup initiated, delay = "+delay+" seconds<br />\n"
+
+	if cmd != "#":
+	    s = s+"Performing Set-System state command: "+cmd+delay + "<br />\n"
+	    self.query(cmd+delay, 1)
+	
+
+	self.comm_free = True
+	mail_deliver(NOTICE_EMAIL,"Device state change",s)
+	return s
+
+    def func_cancelShutdown(self):
+	self._wait_comm_free()
+	self.comm_free = False
+	time.sleep(0.5)
+	self.query("vCb-1", 1)
+	self.comm_free = True
+	s = "Programmed shutdown was cancelled"
+	mail_deliver(NOTICE_EMAIL,"Shutdown cancelled",s)
+	return s
+
+# ===========================================================
 
     def func_setSettings(self):
 	self._wait_comm_free()
@@ -253,7 +366,7 @@
 
 		if val != "#":
 		    cmd = cmd+val
-		    s = s+field+": cmd='"+cmd+"' <br>"
+		    s = s+field+": cmd='"+cmd+"' <br />\n"
 		    self.query(cmd,1)
 	    
 	# get vZ2c setting bits
@@ -279,7 +392,7 @@
 		vZ2c = (vZ2c | 2)
 	    
 	    if (vZ2c_old != vZ2c):
-		s = s+"<br>Setting general bitmask (NoLoad/Bypass) -> bitmask old/new: "+str(vZ2c_old)+"/"+str(vZ2c)
+		s = s+"\n<br />Setting general bitmask (NoLoad/Bypass) -> bitmask old/new: "+str(vZ2c_old)+"/"+str(vZ2c)
 		self.query("vZ2c"+str(vZ2c),1)
 
 	self.comm_free = True
@@ -288,17 +401,20 @@
 
 	if s == "":
 	    s = "Nothing changed!"
+	else:
+	    mail_deliver(NOTICE_EMAIL,"Device settings changed",s)
+
 
 	s = "Activating modified settings in UPS hardware...<hr />" + s
-	s = s+"<hr />--&gt;&gt; <a href='settings.tmpl'>back to settings page</a>"
+	s = s+"<hr />--&gt;&gt; <a href='maintenance.tmpl'>back to maintenance page</a>"
 
 	return s
 	
 
     def _getEventStatus(self):
-	self.Event = self.query("vAa")
+	Event = self.query("vAa")
 	try:
-	    dummy = int(self.Event)
+	    self.Event = int(Event)
 	except:
 	    self.Event = "-1"
 
@@ -329,6 +445,8 @@
 	if self.attention == False:
 	    self._getEventStatus
 
+	tstatus = int(self.query("vTr"))
+
 	self.values = {
 	"IBad":int(self.query("vIB")),
 	"IFreq":float(self.query("vI0f"))/10,
@@ -356,7 +474,11 @@
 	"BypassP":int(self.query("vP0P")),
 	"Efficiency":eff,
 	"SysPwr":syspwr,
-	"SysStatus": getEventText(self.Event)
+	"SysStatus": getEventText(self.Event),
+	"SShutdown_delay":int(self.query("vCb")),
+	"TestStatus":tstatus,
+	"TestStatusTxt":TStatusTexts.get(tstatus,"Unknown: "+str(tstatus)),
+	"TestResult":self.query("vTd")
 	}
 	self.comm_free = True
 	if LOG_DEBUG == True:

mercurial