Changeset 655 for pvMail


Ignore:
Timestamp:
Nov 25, 2011 2:54:42 PM (14 years ago)
Author:
jemian
Message:

CLI version is ready for regular testing, GUI version not started

Location:
pvMail
Files:
1 deleted
6 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified pvMail/.pydevproject

    r91 r655  
    66<path>/pvMail/src</path>
    77</pydev_pathproperty>
    8 <pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.5</pydev_property>
     8<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
    99<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
    1010</pydev_project>
  • pvMail/src

    • Property svn:ignore set to

  • TabularUnified pvMail/src/ca_utils/pvMail.py

    r654 r655  
    384384            # Get email addresses set by user
    385385            emailWidgets = (self.eEmail1, self.eEmail2, self.eEmail3)
    386             who = [self.widgetGet(w).strip() for w in emailWidgets]
     386            who = [self.widgetGet(w).strip() for w in emailWidgets]
    387387
    388388            TrigPV = str(self.widgetGet(self.eTrig))
     
    425425                    # popen is deprecated since Python 2.6
    426426                    # use subprocess module instead
    427                     cmd = fmt[arch] % ( subject, recipient )
    428                     self.setStatus(cmd)
    429                     #print cmd
     427                    cmd = fmt[arch] % ( subject, recipient )
     428                    self.setStatus(cmd)
     429                    #print cmd
    430430                    os.popen(cmd)
    431                     self.setStatus("To: " + recipient)
     431                    self.setStatus("To: " + recipient)
    432432                    time.sleep(0.2)
    433433       
  • pvMail/src/pyEpics

    • Property svn:ignore set to
      pvMail.log
      pvMail_email.txt

  • TabularUnified pvMail/src/pyEpics/pvMail.py

    r654 r655  
    4545    05.09.07  kag  Initial alpha version.  Needs testing.
    4646    2009-12-02 prj: converted to use wxPython (no Tkinter or Pmw)
    47     2011-11-23 prj: converted to use PyEpics and combined GUI and CLI
     47    2011-11-23 prj: complete rewrite using PyEpics and combined GUI and CLI
    4848   
    4949:requires: EPICS system (http://www.aps.anl.gov/epics)
     
    5454'''
    5555
     56
     57import argparse
    5658import datetime
    5759import epics
     
    6264import subprocess
    6365import sys
    64 
    65 
    66 __version__ = "3.0a"
     66import time
     67
     68
     69__version__ = "3.0a." + "$Rev$".split(" ")[1]
    6770__svnid__ = "$Id$"
     71__description__ = "Watch an EPICS PV. Send email when it changes from 0 to 1."
    6872LOG_FILE = "pvMail.log"
     73MESSAGE_FILE = "pvmail_email.txt"
     74RETRY_INTERVAL_S = 0.2
     75CHECKPOINT_INTERVAL_S = 5.0
    6976
    7077
     
    7986        self.message = "default message"
    8087        self.subject = "pvMail.py"
    81         self.triggerPV = "pvMail:trigger"
    82         self.messagePV = "pvMail:message"
    83         self.email_list = "prjemian@gmail.com"
    84         self.message_file = "/tmp/pvmail_email.txt"
     88        self.triggerPV = ""
     89        self.messagePV = ""
     90        self.message_file = MESSAGE_FILE
    8591        self.recipients = []
    86         self.sender = "jemian@anl.gov"
     92        self.old_value = None
     93        self.monitoredPVs = []
     94   
     95    def basicChecks(self):
     96        '''
     97        check for valid inputs,
     98        raise exceptions as discovered,
     99        otherwise no return result
     100        '''
     101        if len(self.recipients) == 0:
     102            msg = "need at least one email address for list of recipients"
     103            raise RuntimeWarning, msg
     104        fmt = "could not connect to %s PV: %s"
     105        parts = {'message': self.messagePV,
     106                 'trigger': self.triggerPV}
     107        for name, pv in parts.items():
     108            if len(pv) == 0:
     109                raise RuntimeWarning, "no name for the %s PV" % name
     110            if self.testConnect(pv, timeout=0.5) is False:
     111                raise RuntimeWarning, fmt % (name, pv)
     112       
     113    def testConnect(self, pvname, timeout=5.0):
     114        '''
     115        create PV,
     116        wait for connection,
     117        return connection state (True | False)
     118       
     119        adapted from PyEpics __createPV() method
     120        '''
     121        logger("test connect with %s" % pvname)
     122        retry_interval_s = 0.0001
     123        start_time = time.time()
     124        thispv = epics.PV(pvname)
     125        thispv.connect()
     126        while not thispv.connected:
     127            time.sleep(retry_interval_s)
     128            epics.ca.poll()
     129            if time.time()-start_time > timeout:
     130                break
     131        return thispv.connected
     132   
     133    def doStart(self):
     134        '''start watching for triggers'''
     135        logger("doStart")
     136        if len(self.monitoredPVs) == 0:
     137            self.basicChecks()
     138            epics.camonitor(self.messagePV, callback=self.receiveMessageMonitor)
     139            epics.camonitor(self.triggerPV, callback=self.receiveTriggerMonitor)
     140            # What happens if either self.messagePV or self.triggerPV
     141            # are changed after self.doStart() is called?
     142            # Keep a local list of what was initiated.
     143            self.monitoredPVs.append(self.messagePV)
     144            self.monitoredPVs.append(self.triggerPV)
     145   
     146    def doStop(self):
     147        '''stop watching for triggers'''
     148        logger("doStop")
     149        for pv in self.monitoredPVs:
     150            epics.camonitor_clear(pv)   # no problem if pv was not monitored
     151        self.monitoredPVs = []
     152   
     153    def doRestart(self):
     154        '''restart watching for triggers'''
     155        self.doStop()
     156        self.doStart()
     157   
     158    def receiveMessageMonitor(self, value, **kw):
     159        '''respond to EPICS CA monitors on message PV'''
     160        logger("%s = %s" % (self.messagePV, value))
     161        self.message = value
     162   
     163    def receiveTriggerMonitor(self, value, **kw):
     164        '''respond to EPICS CA monitors on trigger PV'''
     165        logger("%s = %s" % (self.triggerPV, value))
     166        if self.old_value == 0:
     167            if value == 1:
     168                # Cannot use this definition:
     169                #     self.trigger = (value == 1)
     170                # since the trigger PV just may transition back
     171                # to zero before self.doMessageTrigger() runs.
     172                self.trigger = True
     173        self.old_value = value
    87174   
    88175    def doMessageTrigger(self):
    89176        '''this routine initiates sending the message'''
     177        logger("doMessageTrigger")
    90178        self.trigger = False        # triggered event received
    91         if (len(self.messagePV) > 0
    92            and len(self.triggerPV) > 0
    93            and len(self.recipients) > 0):
     179        try:
     180            self.basicChecks()
    94181            self.message = epics.caget(self.messagePV)
    95182            self.subject = "pvMail.py: " + epics.caget(self.triggerPV)
    96183            sendMail(self.subject, self.message, self.recipients)
     184        except:
     185            logger(sys.exc_info()[1])
    97186   
    98187    def addMessageTail(self):
     
    111200        sends a test message, used for development only
    112201        '''
     202        logger("send_test_message")
    113203        self.recipients = ["prjemian@gmail.com"]
    114204        self.message = "this is a test\n\n" + self.addMessageTail()
    115205        self.subject = "pvMail development test"
    116206        sendMail(self.subject, self.message, self.recipients)
     207
    117208
    118209def sendMail(subject, message, recipients):
     
    139230        # popen is deprecated since Python 2.6
    140231        # use subprocess module instead
     232       
     233        # THIS DOES NOT WORK CORRECTLY! 
     234        #sends mail to /tmp/pvmail_message.txt with no message
    141235        #args = shlex.split(cmd)
    142         #subprocess.call(args)  # THIS DOES NOT WORK CORRECTLY!  sends mail to /tmp/pvmail_message.txt with no message
     236        #subprocess.call(args) 
    143237
    144238
     
    157251
    158252
    159 if __name__ == '__main__':
    160     '''only run the tool from the command line'''
     253def basicStartTest():
     254    '''simple test of the PvMail class'''
    161255    logging.basicConfig(filename=LOG_FILE,level=logging.INFO)
    162256    logger("startup")
    163257    pvm = PvMail()
     258    pvm.recipients = ['prjemian@gmail.com']
     259    pvm.triggerPV = "pvMail:trigger"
     260    pvm.messagePV = "pvMail:message"
     261    retry_interval_s = 0.05
     262    end_time = time.time() + 60
     263    report_time = time.time() + 5.0
     264    pvm.doStart()
     265    while time.time() < end_time:
     266        if time.time() > report_time:
     267            report_time = time.time() + 5.0
     268            logger("time remaining: %.1f seconds ..." % (end_time - time.time()))
     269        time.sleep(retry_interval_s)
     270    pvm.doStop()
     271
     272
     273def basicMailTest():
     274    '''simple test sending mail using the PvMail class'''
     275    pvm = PvMail()
    164276    pvm.send_test_message()
     277
     278
     279def cli(results):
     280    '''
     281    command-line interface to the PvMail class
     282   
     283    :param obj results: default parameters from argparse, see chooser()
     284    '''
     285    logging.basicConfig(filename=results.log_file, level=logging.INFO)
     286    logger("startup")
     287
     288    pvm = PvMail()
     289    pvm.triggerPV = results.trigger_PV
     290    pvm.messagePV = results.message_PV
     291    pvm.recipients = results.email_addresses.strip().split(" ")
     292    pvm.message_file = results.message_file
     293    checkpoint_time = time.time() + results.logging_interval
     294    pvm.doStart()
     295    while True:     # endless loop, kill with ^C or equal
     296        if time.time() > checkpoint_time:
     297            checkpoint_time = time.time() + results.logging_interval
     298            logger("checkpoint")
     299        time.sleep(results.sleep_duration)
     300    pvm.doStop()        # this will never be called
     301
     302
     303def gui(results):
     304    '''
     305    graphical user interface to the PvMail class
     306   
     307    :param obj results: default parameters from argparse, see chooser()
     308    '''
     309    logging.basicConfig(filename=results.log_file,level=logging.INFO)
     310    logger("startup")
     311
     312    pvm = PvMail()
     313    pvm.message_file = results.message_file
     314    # TODO: tba
     315
     316
     317def chooser():
     318    '''parse command-line and choose which interface to use'''
     319    parser = argparse.ArgumentParser(description=__description__)
     320
     321    parser.add_argument('trigger_PV', action='store',
     322                        help="EPICS trigger PV name", default="")
     323
     324    parser.add_argument('message_PV', action='store',
     325                        help="EPICS message PV name", default="")
     326
     327    parser.add_argument('email_addresses', action='store',
     328                        help="email address(es), comma-separated if more than one",
     329                        default="")
     330
     331    parser.add_argument('-l', action='store', dest='log_file',
     332                        help="for logging program progress and comments",
     333                        default=LOG_FILE)
     334
     335    parser.add_argument('-f', action='store', dest='message_file',
     336                        help="temporary file for email message",
     337                        default=MESSAGE_FILE)
     338
     339    parser.add_argument('-i', action='store', dest='logging_interval',
     340                        type=float,
     341                        help="checkpoint reporting interval (s) in log file",
     342                        default=CHECKPOINT_INTERVAL_S)
     343
     344    parser.add_argument('-r', action='store', dest='sleep_duration',
     345                        type=float,
     346                        help="sleep duration (s) in main event loop",
     347                        default=RETRY_INTERVAL_S)
     348
     349    parser.add_argument('--gui', action='store_true', default=False,
     350                        dest='interface',
     351                        help='Use the graphical rather than command-line interface')
     352
     353    parser.add_argument('--version', action='version', version=__version__)
     354
     355    results = parser.parse_args()
     356    print "trigger PV       = " + results.trigger_PV
     357    print "message PV       = " + results.message_PV
     358    print "email list       = " + str(results.email_addresses.strip().split(","))
     359    print "log file         = " + results.log_file
     360    print "message file     = " + results.message_file
     361    print "logging interval = " + str( results.logging_interval )
     362    print "sleep duration   = " + str( results.sleep_duration )
     363    print "interface        = " + {False: 'command-line', True: 'GUI'}[results.interface]
     364    {False: cli, True: gui}[results.interface](results)     # call the interface
     365
     366
     367if __name__ == '__main__':
     368    #  ./pvMail.py  pvMail:trigger pvMail:message prjemian@gmail.com,jemian@anl.gov
     369    chooser()
  • TabularUnified pvMail/src/pyEpics/test.db

    r654 r655  
    1010
    1111#  /APSshare/epics/base-3.14.12.1/bin/linux-x86-el5-debug/softIoc -d test.db
    12 #  camonitor pvMail:{trigger,message}
     12#
     13#  IOC:     softIoc -d test.db
     14#  client:  camonitor pvMail:{trigger,message}
    1315
    1416record(bo, "pvMail:trigger")
Note: See TracChangeset for help on using the changeset viewer.