00001 #!/usr/local/bin/python 00002 # 00003 # Copyright 2004 00004 # by 00005 # The Board of Trustees of the 00006 # Leland Stanford Junior University. 00007 # All rights reserved. 00008 # 00009 00010 __facility__ = "Online" 00011 __abstract__ = "GLAST LAT Housekeeping server infrastructure" 00012 __author__ = "Jim Panetta <panetta@slac.stanford.edu> SLAC - GLAST I&T" 00013 __date__ = "07/28/04" 00014 __version__ = "$Revision: 1.7 $" 00015 __release__ = "$Name: R04-12-00 $" 00016 __credits__ = "SLAC" 00017 00018 import LATTE.copyright_SLAC 00019 00020 # from LATTE.monitoring.HskReceiver import HskCfgTextReceiver 00021 from LATTE.client.gOptions import Options 00022 from LATTE.monitoring.HskSqlInterface import HskSqlReceiver 00023 00024 import logging 00025 import sys 00026 import time 00027 import qt 00028 from sihippo import Observer 00029 import sihippo 00030 import MySQLdb 00031 00032 second = 1 00033 minute = 60 * second 00034 hour = minute * 60 00035 day = hour * 24 00036 era = 10**9 00037 00038 timeFmt = '%H:%M:%S' 00039 dataFile = None 00040 timeDepth = 2*hour 00041 00042 sqlDatabase = None 00043 dataSource = None 00044 00045 class QtReceiver(qt.QObject, HskSqlReceiver): 00046 00047 class TrendUpdateEvent(qt.QCustomEvent): 00048 def __init__(self,trendMap): 00049 qt.QCustomEvent.__init__(self,qt.QEvent.MaxUser-20) 00050 self.trendMap = trendMap 00051 00052 def __init__(self, sqlDB, timeDepth, trendList): 00053 HskSqlReceiver.__init__(self, sqlDB, timeDepth, trendList) 00054 qt.QObject.__init__(self) 00055 00056 def process(self,trendMap): 00057 qt.QApplication.postEvent(self,QtReceiver.TrendUpdateEvent(trendMap)) 00058 00059 def customEvent(self,event): 00060 self.emit(qt.PYSIGNAL('TrendUpdate(trendMap)'),(event.trendMap,)) 00061 00062 00063 00064 class TrendPlotter(qt.QWidget): 00065 def __init__(self, keyList, depth, *args): 00066 qt.QWidget.__init__(self,*args) 00067 00068 self.__ntuples = {} 00069 self.__plots = {} 00070 self.__views = {} 00071 self.__gen = {} 00072 self.__defaultDepth = depth # assuming 1 hz data rate 00073 self.__defaultLabels = ['Time',''] 00074 00075 self.__dynamic = True 00076 self.__keyList = keyList 00077 00078 self.grid = qt.QGridLayout(self,3,2) 00079 self.grid.setAutoAdd(1) 00080 self.true = True 00081 00082 def isDynamic(self): 00083 return self.__dynamic 00084 def setDynamic(self,bool): 00085 self.__dynamic=bool 00086 00087 def addPlot(self, key): 00088 labels = self.__defaultLabels 00089 depth = self.__defaultDepth 00090 name = self.__keyList[key] 00091 00092 # Create the Circular buffer to store the data 00093 ntc = sihippo.NTupleController.instance() 00094 nt = ntc.createCircularBuffer(labels) 00095 nt.reserve(depth) 00096 nt.setTitle(name) 00097 nt.setName(name) 00098 00099 # Create the Plot 00100 dc = sihippo.DisplayController.instance() 00101 plot = dc.createDisplay('XY Plot', nt, labels) 00102 # plot = dc.createDisplay('Strip Chart',nt,labels) 00103 00104 # kludge so that the range is initialized, and autoscales when we need. 00105 plot.setRange('x',0,1) 00106 plot.setAutoRanging('x',True) 00107 00108 # Add the time axis observer 00109 gen = TimeAxisGen() 00110 gen.setPlotter(plot, key) 00111 plot.addObserver(gen) 00112 00113 # Add the plot to the screen 00114 view = sihippo.QtViewWidget(self) 00115 view.setPlotter(plot) 00116 view.setDoubleBuffering(1) 00117 view.resize(200,100) 00118 view.setMinimumSize(qt.QSize(100,50)) 00119 # self.grid.addWidget(view) 00120 view.show() 00121 00122 # Maintain a reference to the created objects to prevent garbage collection 00123 self.__ntuples[key] = nt 00124 self.__plots[key] = plot 00125 self.__views[key] = view 00126 self.__gen[key] = gen 00127 00128 def update(self, trendMap): 00129 # if not self.true: return 00130 self.true=False 00131 # trendMap has timestamp, val1, val2, val3... 00132 timeStamp = trendMap['TimeStamp'] 00133 for key in trendMap: 00134 if key == 'TimeStamp': continue 00135 if key not in self.__views.keys() and self.__dynamic: 00136 self.addPlot(key) 00137 if key not in self.__views.keys(): 00138 return 00139 x=timeStamp 00140 y=trendMap[key] 00141 if y is None: 00142 continue 00143 self.__ntuples[key].addRow([x,y]) 00144 00145 class TimeAxisGen ( Observer ) : 00146 __labelFmt = '%Y/%m/%d' 00147 __tickFmt = '%H:%M' 00148 __dayFmt = '%m/%d %H:%M' 00149 __stepSet = [ 1*second, 5*second, 10*second, 30*second, 00150 1*minute, 2*minute, 5*minute, 10*minute, 15*minute, 20*minute, 30*minute, 00151 1*hour, 2*hour, 6*hour, 12*hour, 00152 1*day, 2*day, 7*day, 30*day, 90*day, 180*day, 364*day, 00153 era] 00154 00155 def setPlotter ( self, plotter, name ) : 00156 self.plotter = plotter 00157 self.name = name 00158 self.__goodStep = 0 00159 00160 def update ( self, obs ) : 00161 # return 00162 lowTime = self.plotter.getLowRangeOnX() 00163 highTime = self.plotter.getHighRangeOnX() 00164 00165 if ((highTime - lowTime)/TimeAxisGen.__stepSet[self.__goodStep]) < 1: 00166 # print "reset of goodStep", self.name, self.__goodStep , highTime, lowTime, ((highTime - lowTime)/TimeAxisGen.__stepSet[self.__goodStep]) 00167 self.__goodStep -= 1 00168 if ((highTime - lowTime)/TimeAxisGen.__stepSet[self.__goodStep]) > 6: 00169 # print self.name, highTime, lowTime, ((highTime - lowTime)/TimeAxisGen.__stepSet[self.__goodStep]) 00170 step = 0 00171 while ((highTime - lowTime)/TimeAxisGen.__stepSet[step]) > 5: 00172 # print "step:", step 00173 step += 1 00174 self.__goodStep = step 00175 step = TimeAxisGen.__stepSet[self.__goodStep] 00176 if step < 1*day: 00177 tickFmt = TimeAxisGen.__tickFmt 00178 else: 00179 tickFmt = TimeAxisGen.__dayFmt 00180 00181 lowTick = lowTime - (lowTime % step) + step 00182 values = [] 00183 values.append( lowTick ) 00184 00185 labels = [] 00186 labels.append( time.strftime(tickFmt, time.localtime(lowTick)) ) 00187 tick = lowTick 00188 tick += step 00189 while tick < highTime: 00190 values.append ( tick ) 00191 labels.append ( time.strftime(tickFmt, time.localtime(tick)) ) 00192 tick += step 00193 00194 self.plotter.setAutoTicksOnX( False ) 00195 self.plotter.setTicksOnX( values, labels ) 00196 00197 # REALLY REALLY don't do this: 00198 # setLabel calls "notifyObservers", which brings us back here... 00199 # xlabel = time.strftime(TimeAxisGen.__labelFmt, time.localtime(highTime)) 00200 # self.plotter.setLabel( 'x', xlabel ) 00201 00202 def memget(): 00203 import win32pdh 00204 hq = win32pdh.OpenQuery() 00205 # ch = win32pdh.AddCounter(hq, "\\\\gitow1\\Process(python)\\Private Bytes") 00206 ch = win32pdh.AddCounter(hq, "\\\\gitow1\\Process(python#1)\\Private Bytes") 00207 win32pdh.CollectQueryData(hq) 00208 type, val =win32pdh.GetFormattedCounterValue(ch,win32pdh.PDH_FMT_LONG) 00209 return val 00210 00211 def startup(): 00212 # print memget() 00213 logging.basicConfig() 00214 logging.root.setLevel(logging.DEBUG) 00215 00216 def startQT(sqlDB, timeDepth, keyList, source): 00217 import sys 00218 00219 app=qt.QApplication(sys.argv) 00220 r=QtReceiver(sqlDB, timeDepth, keyList.keys()) 00221 r.setSource(source) 00222 00223 gui=TrendPlotter(keyList, timeDepth/5) 00224 gui.connect(r,qt.PYSIGNAL('TrendUpdate(trendMap)'),gui.update) 00225 00226 app.connect(app,qt.SIGNAL("lastWindowClosed()"), 00227 app,qt.SLOT("quit()")) 00228 00229 app.setMainWidget(gui) 00230 gui.show() 00231 00232 r.setReceiving(1) 00233 app.exec_loop() 00234 r.shutdown() 00235 00236 00237 def configParse(configFile): 00238 global sqlDatabase, dataSource 00239 from ConfigParser import ConfigParser 00240 parser = ConfigParser() 00241 parser.read(configFile) 00242 00243 # test the config for required parameters 00244 cSect = parser.sections() 00245 if "database" not in cSect: 00246 msg = 'Config file %s is missing required section: %s' % ( configFile, "database" ) 00247 raise KeyError, msg 00248 00249 if parser.get('database', 'type') != 'sql': 00250 msg = 'HskSqlGuiReceiver requires a connection to an SQL database.\nPlease check your config file' 00251 raise KeyError, msg 00252 00253 host = parser.get('database', 'host') 00254 user = parser.get('database', 'user') 00255 sqlDatabase = MySQLdb.connect(host=host, db='itosdb', user=user) 00256 00257 dataSource = parser.getint('database', 'machineid') 00258 00259 00260 def usage(): 00261 return """ 00262 00263 HskGuiReceiver Usage: 00264 00265 Mandatory options: 00266 --config specify the configuration file to read 00267 00268 Optional options: 00269 --timeDepth define the time depth of the housekeeping plots. Default is 2 hours. 00270 Units are in seconds 00271 --keyFile define the file of variables to plot 00272 Note: keyFile format is "KEY : Plot title" 00273 00274 Example: 00275 $ HskGuiReceiver --dataFile c:\TEMP\lat-elf11.dat --timeDepth 3600 --keyFile keys.dat 00276 00277 """ 00278 00279 00280 if __name__ == '__main__': 00281 startup() 00282 00283 # Options, first list mandatory, second list optional 00284 options = Options(['config'], ['timeDepth', 'keyFile']) 00285 try: 00286 options.parse() 00287 except Exception, msg: 00288 options.usage() 00289 raise Exception, msg 00290 00291 if options.timeDepth is not None: 00292 timeDepth = int(options.timeDepth) 00293 else: 00294 timeDepth = 2*hour 00295 00296 if options.keyFile is not None: 00297 keyFile = options.keyFile 00298 from HskReceiver import parseKeyFile 00299 keyList = parseKeyFile(keyFile) 00300 else: # really really basic set of histos. 00301 keyList = {'LHKADAB33V' :'AEM DAQ board 3.3 V', 00302 'LHKAEMFR11T' :'AEM Free board 11 Temp', 00303 'LHKADABTEMP' :'AEM DAQ board Temp', 00304 'LHKAEMFR11V1' :'AEM Free 11 HV 1', 00305 'LHKAEMFR11V2' :'AEM Free 11 HV 2', 00306 'LHKAEMFR11VD' :'AEM Free 11 VDD', 00307 } 00308 00309 configParse(options.config) 00310 00311 startQT(sqlDatabase.cursor(), timeDepth, keyList, dataSource) 00312