--- a/Beremiz_service.py Mon Feb 02 23:45:30 2015 +0100
+++ b/Beremiz_service.py Thu Feb 05 01:35:02 2015 +0100
@@ -340,7 +340,10 @@
- def __init__(self, servicename, ip_addr, port, workdir, argv, autostart=False, statuschange=None, evaluator=default_evaluator, website=None):
+ def __init__(self, servicename, ip_addr, port, + workdir, argv, autostart=False, + statuschange=None, evaluator=default_evaluator, self.servicename = servicename
@@ -371,7 +374,9 @@
self.daemon=pyro.Daemon(host=self.ip_addr, port=self.port)
- self.plcobj = PLCObject(self.workdir, self.daemon, self.argv, self.statuschange, self.evaluator, self.website)
+ self.plcobj = PLCObject(self.workdir, self.daemon, self.argv, + self.statuschange, self.evaluator, uri = self.daemon.connect(self.plcobj,"PLCObject")
print "Pyro port :",self.port
@@ -412,185 +417,42 @@
from twisted.internet import wxreactor
- from twisted.internet import reactor, task
- from twisted.python import log, util
- from nevow import rend, appserver, inevow, tags, loaders, athena
- from nevow.page import renderer
+ from twisted.internet import reactor - print "Twisted unavailable !"
+ print "Twisted unavailable." - xhtml_header = '''<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
-"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
- class PLCHMI(athena.LiveElement):
- def HMIinitialised(self, result):
- self.initialised = True
- def HMIinitialisation(self):
- self.HMIinitialised(None)
- class DefaultPLCStartedHMI(PLCHMI):
- docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
- tags.h1["PLC IS NOW STARTED"],
- class PLCStoppedHMI(PLCHMI):
- docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
- tags.h1["PLC IS STOPPED"],
- class MainPage(athena.LiveElement):
- jsClass = u"WebInterface.PLC"
- docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
- tags.div(id='content')[
- tags.div(render = tags.directive('PLCElement')),
- def __init__(self, *a, **kw):
- athena.LiveElement.__init__(self, *a, **kw)
- self.resetPLCStartedHMI()
- def setPLCState(self, state):
- if self.HMI is not None:
- self.callRemote('updateHMI')
- def setPLCStartedHMI(self, hmi):
- self.PLCStartedHMIClass = hmi
- def resetPLCStartedHMI(self):
- self.PLCStartedHMIClass = DefaultPLCStartedHMI
- def HMIexec(self, function, *args, **kwargs):
- if self.HMI is not None:
- getattr(self.HMI, function, lambda:None)(*args, **kwargs)
- def PLCElement(self, ctx, data):
- return self.getPLCElement()
- def getPLCElement(self):
- self.detachFragmentChildren()
- f = self.PLCStartedHMIClass()
- f.setFragmentParent(self)
- athena.expose(getPLCElement)
- def detachFragmentChildren(self):
- for child in self.liveFragmentChildren[:]:
- class WebInterface(athena.LivePage):
- docFactory = loaders.stan([tags.raw(xhtml_header),
- tags.html(xmlns="http://www.w3.org/1999/xhtml")[
- tags.head(render=tags.directive('liveglue')),
- tags.div( render = tags.directive( "MainPage" ))
- def __init__(self, plcState=False, *a, **kw):
- super(WebInterface, self).__init__(*a, **kw)
- self.jsModules.mapping[u'WebInterface'] = util.sibpath(__file__, os.path.join('runtime', 'webinterface.js'))
- self.plcState = plcState
- self.MainPage.setPLCState(plcState)
- return self.MainPage.getHMI()
- def LoadHMI(self, hmi, jsmodules):
- for name, path in jsmodules.iteritems():
- self.jsModules.mapping[name] = os.path.join(WorkingDir, path)
- self.MainPage.setPLCStartedHMI(hmi)
- self.MainPage.resetPLCStartedHMI()
- self.MainPage.setPLCState(True)
- self.MainPage.setPLCState(False)
- def renderHTTP(self, ctx):
- Force content type to fit with SVG
- req = inevow.IRequest(ctx)
- req.setHeader('Content-type', 'application/xhtml+xml')
- return super(WebInterface, self).renderHTTP(ctx)
- def render_MainPage(self, ctx, data):
- f.setFragmentParent(self)
- self.MainPage.detachFragmentChildren()
- return WebInterface(plcState=self.plcState)
- def beforeRender(self, ctx):
- d = self.notifyOnDisconnect()
- d.addErrback(self.disconnected)
- def disconnected(self, reason):
- self.MainPage.resetHMI()
- #print "We will be called back when the client disconnects"
reactor.registerWxApp(app)
- website = WebInterface()
- site = appserver.NevowSite(website)
- reactor.listenTCP(website_port, site)
- print "Http interface port :",website_port
+ # TODO add command line switch + import runtime.NevowServer as NS + website = NS.RegisterWebsite(reactor) + pyruntimevars["website"] = website + statuschange.append(NS.website_statuslistener_factory(website)) + print "Nevow Web service failed." from threading import Semaphore
wx_eval_lock = Semaphore(0)
main_thread = currentThread()
- def statuschange(status):
+ def statuschangeTskBar(status): wx.CallAfter(taskbar_instance.UpdateIcon,status)
+ statuschange.append(statuschangeTskBar) def wx_evaluator(obj, *args, **kwargs):
tocall,args,kwargs = obj.call
obj.res = default_evaluator(tocall, *args, **kwargs)
@@ -607,10 +469,18 @@
- pyroserver = Server(servicename, given_ip, port, WorkingDir, argv, autostart, statuschange, evaluator, website)
+ pyroserver = Server(servicename, given_ip, port, + WorkingDir, argv, autostart, + statuschange, evaluator, pyruntimevars) taskbar_instance = BeremizTaskBarIcon(pyroserver, enablewx)
- pyroserver = Server(servicename, given_ip, port, WorkingDir, argv, autostart, website=website)
+ pyroserver = Server(servicename, given_ip, port, + WorkingDir, argv, autostart, + statuschange, pyruntimevars=pyruntimevars) +for registrar in registerserverto : import threading, traceback
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/NevowServer.py Thu Feb 05 01:35:02 2015 +0100
@@ -0,0 +1,180 @@
+from nevow import rend, appserver, inevow, tags, loaders, athena +from nevow.page import renderer +from twisted.python import util +xhtml_header = '''<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +class PLCHMI(athena.LiveElement): + def HMIinitialised(self, result): + self.initialised = True + def HMIinitialisation(self): + self.HMIinitialised(None) +class DefaultPLCStartedHMI(PLCHMI): + docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ + tags.h1["PLC IS NOW STARTED"], +class PLCStoppedHMI(PLCHMI): + docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ + tags.h1["PLC IS STOPPED"], +class MainPage(athena.LiveElement): + jsClass = u"WebInterface.PLC" + docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ + tags.div(id='content')[ + tags.div(render = tags.directive('PLCElement')), + def __init__(self, *a, **kw): + athena.LiveElement.__init__(self, *a, **kw) + self.resetPLCStartedHMI() + def setPLCState(self, state): + if self.HMI is not None: + self.callRemote('updateHMI') + def setPLCStartedHMI(self, hmi): + self.PLCStartedHMIClass = hmi + def resetPLCStartedHMI(self): + self.PLCStartedHMIClass = DefaultPLCStartedHMI + def HMIexec(self, function, *args, **kwargs): + if self.HMI is not None: + getattr(self.HMI, function, lambda:None)(*args, **kwargs) + def PLCElement(self, ctx, data): + return self.getPLCElement() + def getPLCElement(self): + self.detachFragmentChildren() + f = self.PLCStartedHMIClass() + f.setFragmentParent(self) + athena.expose(getPLCElement) + def detachFragmentChildren(self): + for child in self.liveFragmentChildren[:]: +class WebInterface(athena.LivePage): + docFactory = loaders.stan([tags.raw(xhtml_header), + tags.html(xmlns="http://www.w3.org/1999/xhtml")[ + tags.head(render=tags.directive('liveglue')), + tags.div( render = tags.directive( "MainPage" )) + def __init__(self, plcState=False, *a, **kw): + super(WebInterface, self).__init__(*a, **kw) + self.jsModules.mapping[u'WebInterface'] = util.sibpath(__file__, 'webinterface.js') + self.plcState = plcState + self.MainPage.setPLCState(plcState) + return self.MainPage.getHMI() + def LoadHMI(self, hmi, jsmodules): + for name, path in jsmodules.iteritems(): + self.jsModules.mapping[name] = os.path.join(WorkingDir, path) + self.MainPage.setPLCStartedHMI(hmi) + self.MainPage.resetPLCStartedHMI() + self.MainPage.setPLCState(True) + self.MainPage.setPLCState(False) + def renderHTTP(self, ctx): + Force content type to fit with SVG + req = inevow.IRequest(ctx) + req.setHeader('Content-type', 'application/xhtml+xml') + return super(WebInterface, self).renderHTTP(ctx) + def render_MainPage(self, ctx, data): + f.setFragmentParent(self) + self.MainPage.detachFragmentChildren() + return WebInterface(plcState=self.plcState) + def beforeRender(self, ctx): + d = self.notifyOnDisconnect() + d.addErrback(self.disconnected) + def disconnected(self, reason): + self.MainPage.resetHMI() + #print "We will be called back when the client disconnects" +def RegisterWebsite(reactor): + website = WebInterface() + site = appserver.NevowSite(website) + website_port_range = 10 + while not listening and port_offset < website_port_range: + reactor.listenTCP(website_port + port_offset, site) + print "Http interface port :",website_port + port_offset + except: # TODO narrow exception + def __init__(self, site): + def listen(self, state): + if state != self.oldstate: + {'Started': self.site.PLCStarted, + 'Stopped': self.site.PLCStopped}[state]() +def website_statuslistener_factory(site): + return statuslistener(site).listen --- a/runtime/PLCObject.py Mon Feb 02 23:45:30 2015 +0100
+++ b/runtime/PLCObject.py Thu Feb 05 01:35:02 2015 +0100
@@ -51,7 +51,7 @@
class PLCObject(pyro.ObjBase):
- def __init__(self, workingdir, daemon, argv, statuschange, evaluator, website):
+ def __init__(self, workingdir, daemon, argv, statuschange, evaluator, pyruntimevars): pyro.ObjBase.__init__(self)
self.evaluator = evaluator
self.argv = [workingdir] + argv # force argv[0] to be "path" to exec...
@@ -65,7 +65,7 @@
self.statuschange = statuschange
+ self.pyruntimevars = pyruntimevars self._loading_error = None
self.python_runtime_vars = None
@@ -85,7 +85,8 @@
if self.statuschange is not None:
- self.statuschange(self.PLCStatus)
+ for callee in self.statuschange: def LogMessage(self, *args):
@@ -262,8 +263,9 @@
def PythonRuntimeInit(self):
MethodNames = ["init", "start", "stop", "cleanup"]
self.python_runtime_vars = globals().copy()
+ self.python_runtime_vars.update(self.pyruntimevars) self.python_runtime_vars["WorkingDir"] = self.workingdir
- self.python_runtime_vars["website"] = self.website
for methodname in MethodNames :
self.python_runtime_vars["_runtime_%s"%methodname] = []
self.python_runtime_vars["PLCObject"] = self
@@ -300,17 +302,12 @@
self.PythonRuntimeCall("init")
- if self.website is not None:
- self.website.PLCStarted()
def PythonRuntimeCleanup(self):
if self.python_runtime_vars is not None:
self.PythonRuntimeCall("cleanup")
- if self.website is not None:
- self.website.PLCStopped()
self.python_runtime_vars = None
def PythonThreadProc(self):