Beremiz_service.py
changeset 1438 19ebe96b41c0
parent 1437 04177743b066
child 1439 a68cd4253259
equal deleted inserted replaced
1437:04177743b066 1438:19ebe96b41c0
   338     except Exception:
   338     except Exception:
   339         res=(None, sys.exc_info())
   339         res=(None, sys.exc_info())
   340     return res
   340     return res
   341 
   341 
   342 class Server():
   342 class Server():
   343     def __init__(self, servicename, ip_addr, port, workdir, argv, autostart=False, statuschange=None, evaluator=default_evaluator, website=None):
   343     def __init__(self, servicename, ip_addr, port,
       
   344                  workdir, argv, autostart=False,
       
   345                  statuschange=None, evaluator=default_evaluator,
       
   346                  website=None):
   344         self.continueloop = True
   347         self.continueloop = True
   345         self.daemon = None
   348         self.daemon = None
   346         self.servicename = servicename
   349         self.servicename = servicename
   347         self.ip_addr = ip_addr
   350         self.ip_addr = ip_addr
   348         self.port = port
   351         self.port = port
   369         self.Stop()
   372         self.Stop()
   370 
   373 
   371     def Start(self):
   374     def Start(self):
   372         pyro.initServer()
   375         pyro.initServer()
   373         self.daemon=pyro.Daemon(host=self.ip_addr, port=self.port)
   376         self.daemon=pyro.Daemon(host=self.ip_addr, port=self.port)
   374         self.plcobj = PLCObject(self.workdir, self.daemon, self.argv, self.statuschange, self.evaluator, self.website)
   377         self.plcobj = PLCObject(self.workdir, self.daemon, self.argv,
       
   378                                 self.statuschange, self.evaluator,
       
   379                                 self.website)
   375         uri = self.daemon.connect(self.plcobj,"PLCObject")
   380         uri = self.daemon.connect(self.plcobj,"PLCObject")
   376 
   381 
   377         print "Pyro port :",self.port
   382         print "Pyro port :",self.port
   378         print "Pyro object's uri :",uri
   383         print "Pyro object's uri :",uri
   379         print "Current working directory :",self.workdir
   384         print "Current working directory :",self.workdir
   410         try:
   415         try:
   411             from threading import Thread, currentThread
   416             from threading import Thread, currentThread
   412             if havewx:
   417             if havewx:
   413                 from twisted.internet import wxreactor
   418                 from twisted.internet import wxreactor
   414                 wxreactor.install()
   419                 wxreactor.install()
   415             from twisted.internet import reactor, task
   420             from twisted.internet import reactor
   416             from twisted.python import log, util
       
   417             from nevow import rend, appserver, inevow, tags, loaders, athena
       
   418             from nevow.page import renderer
       
   419 
   421 
   420             havetwisted = True
   422             havetwisted = True
   421         except:
   423         except:
   422             print "Twisted unavailable !"
   424             print "Twisted unavailable."
   423             havetwisted = False
   425             havetwisted = False
   424 
   426 
       
   427 pyruntimevars = {}
       
   428 statuschange = []
       
   429 registerserverto = []
       
   430 
   425 if havetwisted:
   431 if havetwisted:
   426 
       
   427     xhtml_header = '''<?xml version="1.0" encoding="utf-8"?>
       
   428 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
       
   429 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
       
   430 '''
       
   431 
       
   432     class PLCHMI(athena.LiveElement):
       
   433 
       
   434         initialised = False
       
   435 
       
   436         def HMIinitialised(self, result):
       
   437             self.initialised = True
       
   438 
       
   439         def HMIinitialisation(self):
       
   440             self.HMIinitialised(None)
       
   441 
       
   442     class DefaultPLCStartedHMI(PLCHMI):
       
   443         docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
       
   444                                              tags.h1["PLC IS NOW STARTED"],
       
   445                                              ])
       
   446 
       
   447     class PLCStoppedHMI(PLCHMI):
       
   448         docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
       
   449                                              tags.h1["PLC IS STOPPED"],
       
   450                                              ])
       
   451 
       
   452     class MainPage(athena.LiveElement):
       
   453         jsClass = u"WebInterface.PLC"
       
   454         docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
       
   455                                                         tags.div(id='content')[
       
   456                                                         tags.div(render = tags.directive('PLCElement')),
       
   457                                                         ]])
       
   458 
       
   459         def __init__(self, *a, **kw):
       
   460             athena.LiveElement.__init__(self, *a, **kw)
       
   461             self.pcl_state = False
       
   462             self.HMI = None
       
   463             self.resetPLCStartedHMI()
       
   464 
       
   465         def setPLCState(self, state):
       
   466             self.pcl_state = state
       
   467             if self.HMI is not None:
       
   468                 self.callRemote('updateHMI')
       
   469 
       
   470         def setPLCStartedHMI(self, hmi):
       
   471             self.PLCStartedHMIClass = hmi
       
   472 
       
   473         def resetPLCStartedHMI(self):
       
   474             self.PLCStartedHMIClass = DefaultPLCStartedHMI
       
   475 
       
   476         def getHMI(self):
       
   477             return self.HMI
       
   478 
       
   479         def HMIexec(self, function, *args, **kwargs):
       
   480             if self.HMI is not None:
       
   481                 getattr(self.HMI, function, lambda:None)(*args, **kwargs)
       
   482         athena.expose(HMIexec)
       
   483 
       
   484         def resetHMI(self):
       
   485             self.HMI = None
       
   486 
       
   487         def PLCElement(self, ctx, data):
       
   488             return self.getPLCElement()
       
   489         renderer(PLCElement)
       
   490 
       
   491         def getPLCElement(self):
       
   492             self.detachFragmentChildren()
       
   493             if self.pcl_state:
       
   494                 f = self.PLCStartedHMIClass()
       
   495             else:
       
   496                 f = PLCStoppedHMI()
       
   497             f.setFragmentParent(self)
       
   498             self.HMI = f
       
   499             return f
       
   500         athena.expose(getPLCElement)
       
   501 
       
   502         def detachFragmentChildren(self):
       
   503             for child in self.liveFragmentChildren[:]:
       
   504                 child.detach()
       
   505 
       
   506     class WebInterface(athena.LivePage):
       
   507 
       
   508         docFactory = loaders.stan([tags.raw(xhtml_header),
       
   509                                    tags.html(xmlns="http://www.w3.org/1999/xhtml")[
       
   510                                        tags.head(render=tags.directive('liveglue')),
       
   511                                        tags.body[
       
   512                                            tags.div[
       
   513                                                    tags.div( render = tags.directive( "MainPage" ))
       
   514                                                    ]]]])
       
   515         MainPage = MainPage()
       
   516         PLCHMI = PLCHMI
       
   517 
       
   518         def __init__(self, plcState=False, *a, **kw):
       
   519             super(WebInterface, self).__init__(*a, **kw)
       
   520             self.jsModules.mapping[u'WebInterface'] = util.sibpath(__file__, os.path.join('runtime', 'webinterface.js'))
       
   521             self.plcState = plcState
       
   522             self.MainPage.setPLCState(plcState)
       
   523 
       
   524         def getHMI(self):
       
   525             return self.MainPage.getHMI()
       
   526 
       
   527         def LoadHMI(self, hmi, jsmodules):
       
   528             for name, path in jsmodules.iteritems():
       
   529                 self.jsModules.mapping[name] = os.path.join(WorkingDir, path)
       
   530             self.MainPage.setPLCStartedHMI(hmi)
       
   531 
       
   532         def UnLoadHMI(self):
       
   533             self.MainPage.resetPLCStartedHMI()
       
   534 
       
   535         def PLCStarted(self):
       
   536             self.plcState = True
       
   537             self.MainPage.setPLCState(True)
       
   538 
       
   539         def PLCStopped(self):
       
   540             self.plcState = False
       
   541             self.MainPage.setPLCState(False)
       
   542 
       
   543         def renderHTTP(self, ctx):
       
   544             """
       
   545             Force content type to fit with SVG
       
   546             """
       
   547             req = inevow.IRequest(ctx)
       
   548             req.setHeader('Content-type', 'application/xhtml+xml')
       
   549             return super(WebInterface, self).renderHTTP(ctx)
       
   550 
       
   551         def render_MainPage(self, ctx, data):
       
   552             f = self.MainPage
       
   553             f.setFragmentParent(self)
       
   554             return ctx.tag[f]
       
   555 
       
   556         def child_(self, ctx):
       
   557             self.MainPage.detachFragmentChildren()
       
   558             return WebInterface(plcState=self.plcState)
       
   559 
       
   560         def beforeRender(self, ctx):
       
   561             d = self.notifyOnDisconnect()
       
   562             d.addErrback(self.disconnected)
       
   563 
       
   564         def disconnected(self, reason):
       
   565             self.MainPage.resetHMI()
       
   566             #print reason
       
   567             #print "We will be called back when the client disconnects"
       
   568 
   432 
   569     if havewx:
   433     if havewx:
   570         reactor.registerWxApp(app)
   434         reactor.registerWxApp(app)
   571     website = WebInterface()
   435 
   572     site = appserver.NevowSite(website)
   436     # TODO add command line switch
   573 
   437     try:
   574     website_port = 8009
   438         import runtime.NevowServer as NS
   575     listening = False
   439         website = NS.RegisterWebsite(reactor)
   576     while not listening:
   440         pyruntimevars["website"] = website
   577         try:
   441         statuschange.append(NS.website_statuslistener_factory(website))
   578             reactor.listenTCP(website_port, site)
   442     except:
   579             listening = True
   443         print "Nevow Web service failed."
   580         except:
   444 
   581             website_port += 1
       
   582     print "Http interface port :",website_port
       
   583 else:
       
   584     website = None
       
   585 
   445 
   586 if havewx:
   446 if havewx:
   587     from threading import Semaphore
   447     from threading import Semaphore
   588     wx_eval_lock = Semaphore(0)
   448     wx_eval_lock = Semaphore(0)
   589     main_thread = currentThread()
   449     main_thread = currentThread()
   590 
   450 
   591     def statuschange(status):
   451     def statuschangeTskBar(status):
   592         wx.CallAfter(taskbar_instance.UpdateIcon,status)
   452         wx.CallAfter(taskbar_instance.UpdateIcon,status)
       
   453 
       
   454     statuschange.append(statuschangeTskBar)
   593 
   455 
   594     def wx_evaluator(obj, *args, **kwargs):
   456     def wx_evaluator(obj, *args, **kwargs):
   595         tocall,args,kwargs = obj.call
   457         tocall,args,kwargs = obj.call
   596         obj.res = default_evaluator(tocall, *args, **kwargs)
   458         obj.res = default_evaluator(tocall, *args, **kwargs)
   597         wx_eval_lock.release()
   459         wx_eval_lock.release()
   605             o=type('',(object,),dict(call=(tocall, args, kwargs), res=None))
   467             o=type('',(object,),dict(call=(tocall, args, kwargs), res=None))
   606             wx.CallAfter(wx_evaluator,o)
   468             wx.CallAfter(wx_evaluator,o)
   607             wx_eval_lock.acquire()
   469             wx_eval_lock.acquire()
   608             return o.res
   470             return o.res
   609 
   471 
   610     pyroserver = Server(servicename, given_ip, port, WorkingDir, argv, autostart, statuschange, evaluator, website)
   472     pyroserver = Server(servicename, given_ip, port,
       
   473                         WorkingDir, argv, autostart,
       
   474                         statuschange, evaluator, pyruntimevars)
       
   475 
   611     taskbar_instance = BeremizTaskBarIcon(pyroserver, enablewx)
   476     taskbar_instance = BeremizTaskBarIcon(pyroserver, enablewx)
   612 else:
   477 else:
   613     pyroserver = Server(servicename, given_ip, port, WorkingDir, argv, autostart, website=website)
   478     pyroserver = Server(servicename, given_ip, port,
       
   479                         WorkingDir, argv, autostart,
       
   480                         statuschange, pyruntimevars=pyruntimevars)
       
   481 
       
   482 for registrar in registerserverto :
       
   483     registrar(pyroserver)
   614 
   484 
   615 # Exception hooks s
   485 # Exception hooks s
   616 import threading, traceback
   486 import threading, traceback
   617 def LogException(*exp):
   487 def LogException(*exp):
   618     if pyroserver.plcobj is not None:
   488     if pyroserver.plcobj is not None: