Beremiz_service.py
changeset 368 86ecd8374dae
parent 362 181231bf275f
child 369 bd54d41a7573
equal deleted inserted replaced
367:a76ee5307bb7 368:86ecd8374dae
    32            -i        - ip of interface to bind to (x.x.x.x)
    32            -i        - ip of interface to bind to (x.x.x.x)
    33            -p        - port number
    33            -p        - port number
    34            -h        - print this help text and quit
    34            -h        - print this help text and quit
    35            -a        - autostart PLC (0:disable 1:enable)
    35            -a        - autostart PLC (0:disable 1:enable)
    36            -x        - enable/disable wxTaskbarIcon (0:disable 1:enable)
    36            -x        - enable/disable wxTaskbarIcon (0:disable 1:enable)
       
    37            -t        - enable/disable Twisted web interface (0:disable 1:enable)
    37            
    38            
    38            working_dir - directory where are stored PLC files
    39            working_dir - directory where are stored PLC files
    39 """%sys.argv[0]
    40 """%sys.argv[0]
    40 
    41 
    41 try:
    42 try:
    42     opts, argv = getopt.getopt(sys.argv[1:], "i:p:n:x:a:h")
    43     opts, argv = getopt.getopt(sys.argv[1:], "i:p:n:x:t:a:h")
    43 except getopt.GetoptError, err:
    44 except getopt.GetoptError, err:
    44     # print help information and exit:
    45     # print help information and exit:
    45     print str(err) # will print something like "option -a not recognized"
    46     print str(err) # will print something like "option -a not recognized"
    46     usage()
    47     usage()
    47     sys.exit(2)
    48     sys.exit(2)
    54      "win32":"USERNAME",
    55      "win32":"USERNAME",
    55      }.get(sys.platform, "USER")]
    56      }.get(sys.platform, "USER")]
    56 autostart = False
    57 autostart = False
    57 enablewx = True
    58 enablewx = True
    58 havewx = False
    59 havewx = False
       
    60 enabletwisted = True
       
    61 havetwisted = False
    59 
    62 
    60 for o, a in opts:
    63 for o, a in opts:
    61     if o == "-h":
    64     if o == "-h":
    62         usage()
    65         usage()
    63         sys.exit()
    66         sys.exit()
    69         port = int(a)
    72         port = int(a)
    70     elif o == "-n":
    73     elif o == "-n":
    71         name = a
    74         name = a
    72     elif o == "-x":
    75     elif o == "-x":
    73         enablewx = int(a)
    76         enablewx = int(a)
       
    77     elif o == "-t":
       
    78         enabletwisted = int(a)
    74     elif o == "-a":
    79     elif o == "-a":
    75         autostart = int(a)
    80         autostart = int(a)
    76     else:
    81     else:
    77         usage()
    82         usage()
    78         sys.exit()
    83         sys.exit()
   424 
   429 
   425 def default_evaluator(callable, *args, **kwargs):
   430 def default_evaluator(callable, *args, **kwargs):
   426     return callable(*args,**kwargs)
   431     return callable(*args,**kwargs)
   427 
   432 
   428 class Server():
   433 class Server():
   429     def __init__(self, name, ip, port, workdir, argv, autostart=False, statuschange=None, evaluator=default_evaluator):
   434     def __init__(self, name, ip, port, workdir, argv, autostart=False, statuschange=None, evaluator=default_evaluator, website=None):
   430         self.continueloop = True
   435         self.continueloop = True
   431         self.daemon = None
   436         self.daemon = None
   432         self.name = name
   437         self.name = name
   433         self.ip = ip
   438         self.ip = ip
   434         self.port = port
   439         self.port = port
   437         self.plcobj = None
   442         self.plcobj = None
   438         self.servicepublisher = None
   443         self.servicepublisher = None
   439         self.autostart = autostart
   444         self.autostart = autostart
   440         self.statuschange = statuschange
   445         self.statuschange = statuschange
   441         self.evaluator = evaluator
   446         self.evaluator = evaluator
       
   447         self.website = website
   442     
   448     
   443     def Loop(self):
   449     def Loop(self):
   444         while self.continueloop:
   450         while self.continueloop:
   445             self.Start()
   451             self.Start()
   446         
   452         
   452         self.Stop()
   458         self.Stop()
   453 
   459 
   454     def Start(self):
   460     def Start(self):
   455         pyro.initServer()
   461         pyro.initServer()
   456         self.daemon=pyro.Daemon(host=self.ip, port=self.port)
   462         self.daemon=pyro.Daemon(host=self.ip, port=self.port)
   457         self.plcobj = PLCObject(self.workdir, self.daemon, self.argv, self.statuschange, self.evaluator)
   463         self.plcobj = PLCObject(self.workdir, self.daemon, self.argv, self.statuschange, self.evaluator, self.website)
   458         uri = self.daemon.connect(self.plcobj,"PLCObject")
   464         uri = self.daemon.connect(self.plcobj,"PLCObject")
   459     
   465     
   460         print "The daemon runs on port :",self.port
   466         print "The daemon runs on port :",self.port
   461         print "The object's uri is :",uri
   467         print "The object's uri is :",uri
   462         print "The working directory :",self.workdir
   468         print "The working directory :",self.workdir
   479         self.plcobj.StopPLC()
   485         self.plcobj.StopPLC()
   480         if self.servicepublisher is not None:
   486         if self.servicepublisher is not None:
   481             self.servicepublisher.UnRegisterService()
   487             self.servicepublisher.UnRegisterService()
   482             del self.servicepublisher
   488             del self.servicepublisher
   483         self.daemon.shutdown(True)
   489         self.daemon.shutdown(True)
   484         
   490 
       
   491 if enabletwisted:
       
   492     try:
       
   493         if havewx:
       
   494             from twisted.internet import wxreactor
       
   495             wxreactor.install()
       
   496         from twisted.internet import reactor, task
       
   497         from twisted.python import log, util
       
   498         from nevow import rend, appserver, inevow, tags, loaders, athena
       
   499         from nevow.page import renderer
       
   500         
       
   501         havetwisted = True
       
   502     except:
       
   503         havetwisted = False
       
   504 
       
   505 if havetwisted:
       
   506     
       
   507     xhtml_header = '''<?xml version="1.0" encoding="utf-8"?>
       
   508 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
       
   509 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
       
   510 '''
       
   511 
       
   512     
       
   513     class DefaultPLCStartedHMI(athena.LiveElement):
       
   514         docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[                                    
       
   515                                              tags.h1["PLC IS NOW STARTED"],
       
   516                                              ])
       
   517     class PLCStoppedHMI(athena.LiveElement):
       
   518         docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
       
   519                                              tags.h1["PLC IS STOPPED"]
       
   520                                              ])
       
   521     
       
   522     class MainPage(athena.LiveElement):
       
   523         jsClass = u"WebInterface.PLC"
       
   524         docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
       
   525                                                         tags.div(id='content')[                         
       
   526                                                         tags.div(render = tags.directive('PLCElement')),
       
   527                                                         ]])
       
   528         
       
   529         def __init__(self, *a, **kw):
       
   530             athena.LiveElement.__init__(self, *a, **kw)
       
   531             self.pcl_state = False
       
   532             self.HMI = None
       
   533             self.resetPLCStartedHMI()
       
   534         
       
   535         def setPLCState(self, state):
       
   536             self.pcl_state = state
       
   537             if self.HMI is not None:
       
   538                 self.callRemote('updateHMI')
       
   539         
       
   540         def setPLCStartedHMI(self, hmi):
       
   541             self.PLCStartedHMIClass = hmi
       
   542         
       
   543         def resetPLCStartedHMI(self):
       
   544             self.PLCStartedHMIClass = DefaultPLCStartedHMI
       
   545         
       
   546         def getHMI(self):
       
   547             return self.HMI
       
   548         
       
   549         def HMIexec(self, function, *args, **kwargs):
       
   550             if self.HMI is not None:
       
   551                 getattr(self.HMI, function, lambda:None)(*args, **kwargs)
       
   552         athena.expose(executeOnHMI)
       
   553         
       
   554         def resetHMI(self):
       
   555             self.HMI = None
       
   556         
       
   557         def PLCElement(self, ctx, data):
       
   558             return self.getPLCElement()
       
   559         renderer(PLCElement)
       
   560         
       
   561         def getPLCElement(self):
       
   562             self.detachFragmentChildren()
       
   563             if self.pcl_state:
       
   564                 f = self.PLCStartedHMIClass()
       
   565             else:
       
   566                 f = PLCStoppedHMI()
       
   567             self.HMI = f
       
   568             f.setFragmentParent(self)
       
   569             return f
       
   570         athena.expose(getPLCElement)
       
   571 
       
   572         def detachFragmentChildren(self):
       
   573             for child in self.liveFragmentChildren[:]:
       
   574                 child.detach()
       
   575         
       
   576     class WebInterface(athena.LivePage):
       
   577 
       
   578         docFactory = loaders.stan([tags.raw(xhtml_header),
       
   579                                    tags.html(xmlns="http://www.w3.org/1999/xhtml")[
       
   580                                        tags.head(render=tags.directive('liveglue')),
       
   581                                        tags.body[
       
   582                                            tags.div[
       
   583                                                    tags.div( render = tags.directive( "MainPage" ))
       
   584                                                    ]]]])
       
   585         MainPage = MainPage()
       
   586 
       
   587         def __init__(self, plcState=False, *a, **kw):
       
   588             super(WebInterface, self).__init__(*a, **kw)
       
   589             self.jsModules.mapping[u'WebInterface'] = util.sibpath(__file__, 'webinterface.js')
       
   590             self.plcState = plcState
       
   591             self.MainPage.setPLCState(plcState)
       
   592 
       
   593         def getHMI(self):
       
   594             return self.MainPage.getHMI()
       
   595         
       
   596         def LoadHMI(self, plc, jsmodules):
       
   597             for name, path in jsmodules.iteritems():
       
   598                 self.jsModules.mapping[name] = os.path.join(WorkingDir, path)
       
   599             self.MainPage.setPLCStarted(plc)
       
   600         
       
   601         def UnLoadHMI(self):
       
   602             self.MainPage.resetPLCStartedHMI()
       
   603         
       
   604         def PLCStarted(self):
       
   605             self.plcState = True
       
   606             self.MainPage.setPLCState(True)
       
   607         
       
   608         def PLCStopped(self):
       
   609             self.plcState = False
       
   610             self.MainPage.setPLCState(False)
       
   611             
       
   612         def renderHTTP(self, ctx):
       
   613             """
       
   614             Force content type to fit with SVG
       
   615             """
       
   616             req = inevow.IRequest(ctx)
       
   617             req.setHeader('Content-type', 'application/xhtml+xml')
       
   618             return super(WebInterface, self).renderHTTP(ctx)
       
   619 
       
   620         def render_MainPage(self, ctx, data):
       
   621             f = self.MainPage
       
   622             f.setFragmentParent(self)
       
   623             return ctx.tag[f]
       
   624 
       
   625         def child_(self, ctx):
       
   626             self.MainPage.detachFragmentChildren()
       
   627             return WebInterface(plcState=self.plcState)
       
   628             
       
   629         def beforeRender(self, ctx):
       
   630             d = self.notifyOnDisconnect()
       
   631             d.addErrback(self.disconnected)
       
   632         
       
   633         def disconnected(self, reason):
       
   634             self.MainPage.resetHMI()
       
   635             #print reason
       
   636             #print "We will be called back when the client disconnects"
       
   637     
       
   638     if havewx:
       
   639         reactor.registerWxApp(app)
       
   640     res = WebInterface()
       
   641     site = appserver.NevowSite(res)
       
   642     reactor.listenTCP(8009, site)
       
   643 else:
       
   644     res = None
   485 
   645 
   486 if havewx:
   646 if havewx:
   487     from threading import Semaphore
   647     from threading import Semaphore
   488     wx_eval_lock = Semaphore(0)
   648     wx_eval_lock = Semaphore(0)
   489     mythread = currentThread()
   649     mythread = currentThread()
   508         else:
   668         else:
   509             wx.CallAfter(wx_evaluator,callable,*args,**kwargs)
   669             wx.CallAfter(wx_evaluator,callable,*args,**kwargs)
   510             wx_eval_lock.acquire()
   670             wx_eval_lock.acquire()
   511         return eval_res
   671         return eval_res
   512 
   672 
   513     pyroserver = Server(name, ip, port, WorkingDir, argv, autostart, statuschange, evaluator)
   673     pyroserver = Server(name, ip, port, WorkingDir, argv, autostart, statuschange, evaluator, res)
   514     taskbar_instance = BeremizTaskBarIcon(pyroserver)
   674     taskbar_instance = BeremizTaskBarIcon(pyroserver)
   515     
   675     
   516     pyro_thread=Thread(target=pyroserver.Loop)
   676     pyro_thread=Thread(target=pyroserver.Loop)
   517     pyro_thread.start()
   677     pyro_thread.start()
       
   678 else:
       
   679     pyroserver = Server(name, ip, port, WorkingDir, argv, autostart, website=res)
       
   680 
       
   681 if havetwisted:
       
   682     reactor.run()
       
   683 elif havewx:
   518     app.MainLoop()
   684     app.MainLoop()
   519 else:
   685 else:
   520     pyroserver = Server(name, ip, port, WorkingDir, argv, autostart)
       
   521     pyroserver.Loop()
   686     pyroserver.Loop()