--- a/Beremiz_service.py Fri Jan 30 10:45:11 2015 +0100
+++ b/Beremiz_service.py Fri Jan 30 20:42:24 2015 +0100
@@ -2,7 +2,7 @@
#This file is part of Beremiz, a Integrated Development Environment for
-#programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
+#programming IEC 61131-3 automates supporting plcopen standard and CanFestival. #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
@@ -36,7 +36,7 @@
-a - autostart PLC (0:disable 1:enable) (default:0)
-x - enable/disable wxTaskbarIcon (0:disable 1:enable) (default:1)
-t - enable/disable Twisted web interface (0:disable 1:enable) (default:1)
working_dir - directory where are stored PLC files
@@ -83,6 +83,8 @@
+CWD = os.path.split(os.path.realpath(__file__))[0] @@ -109,14 +111,13 @@
app=wx.App(redirect=False)
# Import module for internationalization
- CWD = os.path.split(os.path.realpath(__file__))[0]
return os.path.join(CWD,*args)
# Get folder containing translation files
localedir = os.path.join(CWD,"locale")
# Get the default language
@@ -139,11 +140,11 @@
if __name__ == '__main__':
__builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation
defaulticon = wx.Image(Bpath("images", "brz.png"))
starticon = wx.Image(Bpath("images", "icoplay24.png"))
stopicon = wx.Image(Bpath("images", "icostop24.png"))
class ParamsEntryDialog(wx.TextEntryDialog):
if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
@@ -151,12 +152,12 @@
event(self, id, function)
- def __init__(self, parent, message, caption = "Please enter text", defaultValue = "",
+ def __init__(self, parent, message, caption = "Please enter text", defaultValue = "", style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition):
wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos)
if wx.VERSION >= (2, 8, 0):
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId())
@@ -164,7 +165,7 @@
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId())
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId())
texts = {"value" : value}
@@ -176,13 +177,13 @@
return self.GetSizer().GetItem(1).GetWindow().GetValue()
def SetTests(self, tests):
class BeremizTaskBarIcon(wx.TaskBarIcon):
TBMENU_START = wx.NewId()
@@ -193,14 +194,14 @@
TBMENU_WXINSPECTOR = wx.NewId()
TBMENU_CHANGE_WD = wx.NewId()
def __init__(self, pyroserver, level):
wx.TaskBarIcon.__init__(self)
self.pyroserver = pyroserver
self.Bind(wx.EVT_MENU, self.OnTaskBarStartPLC, id=self.TBMENU_START)
self.Bind(wx.EVT_MENU, self.OnTaskBarStopPLC, id=self.TBMENU_STOP)
@@ -211,7 +212,7 @@
self.Bind(wx.EVT_MENU, self.OnTaskBarChangePort, id=self.TBMENU_CHANGE_PORT)
self.Bind(wx.EVT_MENU, self.OnTaskBarChangeWorkingDir, id=self.TBMENU_CHANGE_WD)
self.Bind(wx.EVT_MENU, self.OnTaskBarQuit, id=self.TBMENU_QUIT)
def CreatePopupMenu(self):
This method is called by the base class when it needs to popup
@@ -234,7 +235,7 @@
menu.Append(self.TBMENU_QUIT, _("Quit"))
The various platforms have different requirements for the
@@ -247,15 +248,15 @@
# wxMac can be any size upto 128x128, so leave the source img alone....
icon = wx.IconFromBitmap(img.ConvertToBitmap() )
def OnTaskBarStartPLC(self, evt):
- if self.pyroserver.plcobj is not None:
+ if self.pyroserver.plcobj is not None: self.pyroserver.plcobj.StartPLC()
def OnTaskBarStopPLC(self, evt):
if self.pyroserver.plcobj is not None:
Thread(target=self.pyroserver.plcobj.StopPLC).start()
def OnTaskBarChangeInterface(self, evt):
dlg = ParamsEntryDialog(None, _("Enter the IP of the interface to bind"), defaultValue=self.pyroserver.ip_addr)
dlg.SetTests([(re.compile('\d{1,3}(?:\.\d{1,3}){3}$').match, _("IP is not valid!")),
@@ -264,38 +265,38 @@
if dlg.ShowModal() == wx.ID_OK:
self.pyroserver.ip_addr = dlg.GetValue()
def OnTaskBarChangePort(self, evt):
dlg = ParamsEntryDialog(None, _("Enter a port number "), defaultValue=str(self.pyroserver.port))
dlg.SetTests([(UnicodeType.isdigit, _("Port number must be an integer!")), (lambda port : 0 <= int(port) <= 65535 , _("Port number must be 0 <= port <= 65535!"))])
if dlg.ShowModal() == wx.ID_OK:
self.pyroserver.port = int(dlg.GetValue())
def OnTaskBarChangeWorkingDir(self, evt):
dlg = wx.DirDialog(None, _("Choose a working directory "), self.pyroserver.workdir, wx.DD_NEW_DIR_BUTTON)
if dlg.ShowModal() == wx.ID_OK:
self.pyroserver.workdir = dlg.GetPath()
def OnTaskBarChangeName(self, evt):
dlg = ParamsEntryDialog(None, _("Enter a name "), defaultValue=self.pyroserver.name)
dlg.SetTests([(lambda name : len(name) is not 0 , _("Name must not be null!"))])
if dlg.ShowModal() == wx.ID_OK:
self.pyroserver.name = dlg.GetValue()
self.pyroserver.Restart()
def _LiveShellLocals(self):
if self.pyroserver.plcobj is not None:
return {"locals":self.pyroserver.plcobj.python_runtime_vars}
def OnTaskBarLiveShell(self, evt):
frame = py.crust.CrustFrame(**self._LiveShellLocals())
def OnTaskBarWXInspector(self, evt):
# Activate the widget inspection tool
from wx.lib.inspection import InspectionTool
@@ -304,13 +305,13 @@
InspectionTool().Show(wnd, True)
def OnTaskBarQuit(self, evt):
if wx.Platform == '__WXMSW__':
Thread(target=self.pyroserver.Quit).start()
wx.CallAfter(wx.GetApp().ExitMainLoop)
def UpdateIcon(self, plcstatus):
if plcstatus is "Started" :
currenticon = self.MakeIcon(starticon)
@@ -348,11 +349,11 @@
self.statuschange = statuschange
self.evaluator = evaluator
@@ -367,28 +368,28 @@
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)
uri = self.daemon.connect(self.plcobj,"PLCObject")
print "Pyro port :",self.port
print "Pyro object's uri :",uri
print "Current working directory :",self.workdir
# Configure and publish service
# Not publish service if localhost in address params
- if (self.servicename is not None and
- self.ip_addr is not None and
- self.ip_addr != "localhost" and
+ if (self.servicename is not None and + self.ip_addr is not None and + self.ip_addr != "localhost" and self.ip_addr != "127.0.0.1"):
print "Publishing service on local network"
self.servicepublisher = ServicePublisher.ServicePublisher()
self.servicepublisher.RegisterService(self.servicename, self.ip_addr, self.port)
if self.autostart and self.plcobj.GetPLCstatus()[0] != "Empty":
self.daemon.requestLoop()
if self.plcobj is not None:
@@ -410,78 +411,78 @@
from twisted.python import log, util
from nevow import rend, appserver, inevow, tags, loaders, athena
from nevow.page import renderer
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):
def HMIinitialisation(self):
self.HMIinitialised(None)
class DefaultPLCStartedHMI(PLCHMI):
- docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
+ 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(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):
self.callRemote('updateHMI')
def setPLCStartedHMI(self, hmi):
self.PLCStartedHMIClass = hmi
def resetPLCStartedHMI(self):
self.PLCStartedHMIClass = DefaultPLCStartedHMI
def HMIexec(self, function, *args, **kwargs):
getattr(self.HMI, function, lambda:None)(*args, **kwargs)
def PLCElement(self, ctx, data):
return self.getPLCElement()
self.detachFragmentChildren()
@@ -496,7 +497,7 @@
def detachFragmentChildren(self):
for child in self.liveFragmentChildren[:]:
class WebInterface(athena.LivePage):
docFactory = loaders.stan([tags.raw(xhtml_header),
@@ -508,7 +509,7 @@
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'))
@@ -517,23 +518,23 @@
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
@@ -550,21 +551,21 @@
self.MainPage.detachFragmentChildren()
return WebInterface(plcState=self.plcState)
def beforeRender(self, ctx):
d = self.notifyOnDisconnect()
d.addErrback(self.disconnected)
def disconnected(self, reason):
#print "We will be called back when the client disconnects"
reactor.registerWxApp(app)
site = appserver.NevowSite(website)
@@ -584,23 +585,23 @@
def statuschange(status):
wx.CallAfter(taskbar_instance.UpdateIcon,status)
def wx_evaluator(obj, *args, **kwargs):
tocall,args,kwargs = obj.call
obj.res = default_evaluator(tocall, *args, **kwargs)
def evaluator(tocall, *args, **kwargs):
if(main_thread == currentThread()):
- # avoid dead lock if called from the wx mainloop
+ # avoid dead lock if called from the wx mainloop return default_evaluator(tocall, *args, **kwargs)
o=type('',(object,),dict(call=(tocall, args, kwargs), res=None))
wx.CallAfter(wx_evaluator,o)
pyroserver = Server(servicename, given_ip, port, WorkingDir, argv, autostart, statuschange, evaluator, website)
taskbar_instance = BeremizTaskBarIcon(pyroserver, enablewx)