Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

HskSqlGuiReceiver.py

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 

Generated on Fri Jul 21 13:26:30 2006 for LATTE R04-12-00 by doxygen 1.4.3