Beremiz_service.py
changeset 1067 4f460c1dffb5
parent 1051 847d68c3e7ff
child 1121 d3838e8f1b90
equal deleted inserted replaced
1066:b6a5ae4a68d7 1067:4f460c1dffb5
    21 #You should have received a copy of the GNU General Public
    21 #You should have received a copy of the GNU General Public
    22 #License along with this library; if not, write to the Free Software
    22 #License along with this library; if not, write to the Free Software
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    24 
    24 
    25 import os, sys, getopt
    25 import os, sys, getopt
    26 from threading import Thread,Timer
    26 from threading import Thread
    27 
    27 
    28 def usage():
    28 def usage():
    29     print """
    29     print """
    30 Usage of Beremiz PLC execution service :\n
    30 Usage of Beremiz PLC execution service :\n
    31 %s {[-n servicename] [-i IP] [-p port] [-x enabletaskbar] [-a autostart]|-h|--help} working_dir
    31 %s {[-n servicename] [-i IP] [-p port] [-x enabletaskbar] [-a autostart]|-h|--help} working_dir
   112         
   112         
   113         # Import module for internationalization
   113         # Import module for internationalization
   114         import gettext
   114         import gettext
   115         
   115         
   116         CWD = os.path.split(os.path.realpath(__file__))[0]
   116         CWD = os.path.split(os.path.realpath(__file__))[0]
       
   117         def Bpath(*args):
       
   118             return os.path.join(CWD,*args)
   117         
   119         
   118         # Get folder containing translation files
   120         # Get folder containing translation files
   119         localedir = os.path.join(CWD,"locale")
   121         localedir = os.path.join(CWD,"locale")
   120         # Get the default language
   122         # Get the default language
   121         langid = wx.LANGUAGE_DEFAULT
   123         langid = wx.LANGUAGE_DEFAULT
   136             return wx.GetTranslation(message).encode("utf-8")
   138             return wx.GetTranslation(message).encode("utf-8")
   137 
   139 
   138         if __name__ == '__main__':
   140         if __name__ == '__main__':
   139             __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation
   141             __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation
   140         
   142         
   141         try:
   143         defaulticon = wx.Image(Bpath("images", "brz.png"))
   142             from wx.lib.embeddedimage import PyEmbeddedImage
   144         starticon = wx.Image(Bpath("images", "icoplay24.png"))
   143         except:
   145         stopicon = wx.Image(Bpath("images", "icostop24.png"))
   144             import cStringIO
       
   145             import base64
       
   146             
       
   147             class PyEmbeddedImage:
       
   148                 def __init__(self, image_string):
       
   149                     stream = cStringIO.StringIO(base64.b64decode(image_string))
       
   150                     self.Image = wx.ImageFromStream(stream)
       
   151                 def GetImage(self):
       
   152                     return self.Image
       
   153         
       
   154         defaulticon = PyEmbeddedImage(
       
   155         "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAABc5J"
       
   156         "REFUSIl9lW1MW9cZx3/n2vf6BQO2MZiXGBISILCVUEUlitYpjaKpXZJ1XZZ2kzJVY9r6IeLD"
       
   157         "pGTaNG3KtGmNNGlbpW3VFhRp0l6aZCllpVUqtVNJtBFKE5QXLxCjpCYEY7DBr9hcm3vPPgQY"
       
   158         "IQmPdKR7/vd5/v/n5dxzhZSSNeYBOoGDQGcoFPINDAyUDQ0NOUdGRmyGYSiBQGCpoaGhuGnT"
       
   159         "psShQ4f6WltbewEBVAK3gCBgrjJKKZFSKlLKeillt5Ty40gkMnnw4MFFQG60ysrKZHd3dyoe"
       
   160         "j//bNM0Le/fuPd/e3r5lmRMpJWK5ghrgFeBIT09P4/Hjx73pdFo47HaaNlfRutnJru0OKsoE"
       
   161         "E3GVqaSNa6EUw1dvIKWkoqKCrVu3FoeHh9WamppfRiKRn6wUYAUcwE7g2e7u7vrTp09XGIZB"
       
   162         "W1Mdv3qtmoBPrG0hHVsMhKLj6nqOqOWn/Pjnv2dgYIC5uTl1uSM71/pbgUbg6bNnz/rPnDnj"
       
   163         "dzoddO0P8Oo+jY2suDDD1Zv9DA1dfghXVbVBCFEqpcwAKEDTxMSE58SJE8+oqsq3nq/l1X0a"
       
   164         "QihYtNLHLqRET03wuYp7fO9r26mpKlsVUBSl0W63V6/shZTyyIEDB344Njb21JYaG7/5bgkA"
       
   165         "Dm8zTS/+7bHZLy0mSN+7yNztt8nPjYHFwfvXDf1P70zZ0ok0LS0tZy9fvvxNAGswGFQnJyef"
       
   166         "KnM5+NHLzuUDsrFZ7R68zS/hrGon1PcNMPI0BIzs9tcCNvNfDqxW64uqqvqKxWJc6e3trVVV"
       
   167         "leaAk6ryJ5N/9tH3GXv7Je7/5xermN3diMPXCkDfgrkg3UU0txWLxeLw+/1fB1BGR0frbTYb"
       
   168         "TXWWDbNeysUoZKbIRIZBPviOzKU8ejLMHyPFcMprrweQ7iUAXC7XPiGEak2lUk02m42mWn1D"
       
   169         "gfrnTiKNIrbyzSAUjEKWCx+/Mf+HyELBrLBvBhAIKDdgGsrLy+sAv1UIUa1pGv7yxQ0FbGX1"
       
   170         "D+0LQmHW7fVavE5Mo/gAFCCcoOs6NpvNA7gVRVGCmqYRz1hXg7NFU39rjshawjcuvs4P+o/y"
       
   171         "24uvE1+I4VCdfGfXUb76+VdWfQQCkbJSKBQoFApJTdMsCvApQDSlAjCTN7I/y5CNllpq1wqE"
       
   172         "YmPciIzwwdi7BKevreK7Gp5dfbYoFoozJrquo+v6rMViWbQCV4QQzGTsQJY3kzIhvFpgfYte"
       
   173         "7jhCMp9kk7uep+ueWcWj6f8Xqioq8ck0xcIS6XT6vpRy3gqMqKpqRBfKLLNF1ZRV6YBiPDrw"
       
   174         "vduefwTL6hl6b74FgFVR0T4rJTU3jcvlymcymal8Ph+z9vf3p7u6uv5y/vz5bw994ld2fmUH"
       
   175         "7nYFRVG4Gb3Guv8FpmmQzCcIJ+5w8c5HRFL3UYRC+ZKX633j6LpObW3tDcMwrsODq4Jbt27V"
       
   176         "HT58+N7o6KgCYHfY2f2lXfi+6CJbnsAwjUeyXzFFKLgdHqb+mmL8xh22bduWmJycfHN2dvbX"
       
   177         "uVwuoQC0tbXlKisrYytBi/lFZsKzOErtTyQWCOxWO36ljvl/FLk+dJOSkhJTUZR35+fn+3K5"
       
   178         "XAIeXNcASz6fbxzwrxDYVQdqpARvs498IYchDUxpogiBVVFxqE7U/5Zx4c8fEo/FKS0tlR0d"
       
   179         "HZ8ODg6+l06nr6zwrAp4PJ6Qpmlf2L9/fywYDFaOXB0RI1dHaGpuoq29Fa1Uxe62YeZMInei"
       
   180         "jAY/IRqNAtDZ2blUV1fXPzg4+F5VVdU/H6p0eYjqsWPHvnz37t0XwuHw7d27d4eTyeTvLl26"
       
   181         "FJiamnpim6qrq9mzZ094fHz875FI5J3p6ekr631WBARgaWlpCezYsePeuXPnzFAo5Dp58uS+"
       
   182         "dDp91GKxNBYKBW82m3Vomqa7XK7pbDYbnJmZuR2LxYL5fP79WCyWeeys1h/D9e97enqsp06d"
       
   183         "8mWzWU+xWPTkcjmXaZpxwzDCsVhsbqNggP8BMJOU3UUUf+0AAAAASUVORK5CYII=")
       
   184         
       
   185         #----------------------------------------------------------------------
       
   186         starticon = PyEmbeddedImage(
       
   187         "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAABbpJ"
       
   188         "REFUSIl9lltsFNcdxn9nZnbHs15fd23j9TXYC0UCKzEhMQ+oIS2g1kQ1pbFStX0opFWsovSh"
       
   189         "rUqp2pS2ioTUolaKFOGHqGkiJcKRuDhOaZRiZCsCXyBgCBBfMfbu+oa9s17wzuzl9MH24mDD"
       
   190         "XzoPc/6fft+c72jOGSGlZEVlAU8D9cB20zQ9HR0duRcvXszq7e01EomEUlFREa+srLR8Pl+g"
       
   191         "sbHx3zk5ORcAFfACA8Bt4CFUSomUUkgpS6SUB6SUH5umOXLgwIEHqqrKJfGao7S0VB49ejRo"
       
   192         "2/YnUsrT+/fvb66pqSldYiKlRCytoBB4Gfjx6dOnq5qamjwTExOKqqqU+QrYUJFN7QY32Qbc"
       
   193         "vSeYCGtcux1i5M5dAPx+P1VVVQvnzp0ziouLfx8MBt9cXoAGZABbgZ1HjhwpO378eEEymaSi"
       
   194         "tIBjPy9lU5nKoyWExF2yjy+mN3HsH+/Q3d3NwMCAsZTI9pVaDXgK2Hr27Nn85ubmEpdh8IMX"
       
   195         "ffxirwshVrGXHBQSC/dIRvoZGuz/WkvTtHIhhCGlXABQgI2Tk5P5hw8f3uZwOGj8VjGHXnoC"
       
   196         "HJCpJFbkLtr8FXbX+XC79HRPVVW/qqre9LtIKX/S0NDwy76+vq1lhTr/fM2NAmTk+fHv/dea"
       
   197         "BlZkDHP0PHODH2NHg1gykw8/X7Dfb7vjTNgJqqurT3R1db0GoF2/fl0fGhqqdWca/K7RhZLO"
       
   198         "WSBU55oGGXlVZORVkeV7nsFPDqKL+9TWJCI3n9rojX2mYhjGj4QQv5FSziunTp0qdjqd4hvl"
       
   199         "Lnz5j49lrPMNhv7zM6b63knPuQpryMj3A9A2L++nvDaZXheqqrrXrVu3D0C5detWudPpxO/T"
       
   200         "Hk8HYnOD3J+8yr3bH6XnZNImHg3xfsgenfHo5QAyJwFAdnb2HiGEppmmWa3rOhtKrCcalNT9"
       
   201         "llTSwvBsXISn4nRdbJ5/czRsWvlGhQAEYtFg0kl2dnYZUKgB5U6nk5L82BMNXIU1X3uOWFH5"
       
   202         "eWIuy/YYWcjU4qQAxQ22bWMYhgfIU1RV/UrXdWaiDyOyUiLROktoJfDtC8fZfWQbb//v75ix"
       
   203         "MDlGnvjVC3+gflNDWiMQKPMalmVh2/a8w+HQFKAHIBR2ABCOS+uN6cTMoFstXmlwZbSba7tv"
       
   204         "8hfzT7z+7k+ZnZ0BoK5yR1qjCBV7MoVt29i2PaWqqq0BvUIIQqYORHlrKj6R9BoVj0b04oY9"
       
   205         "nEt+yvz3Y5yR/+Xap3XsDb/EtvV1aY1DdTA7HsW2bCKRyLiUclYBelRVldNWAfPSm4oV5ZQJ"
       
   206         "Vn/G9Zv2oWt6Ous7e4K81XiC1wNNBO6OIWKgB7Mwp000TYuFw+GxWCw2qbS2tk7k5uae/eDD"
       
   207         "Fn594p6SFyxRCjKLUBWF8fBoegTNMVLLm/kwdMyGGON/nePLklv0dl/Cii3gdrtvAzdg8aig"
       
   208         "vb296uDBgwMjIyMCwFvoZXv9NvRnIKqHSckUyQdJrtfexPqm5LGVAuNdVaofcCVywfpexLYD"
       
   209         "CsDOnTvnioqKzGXdzNQMV9tvkJEyUITyeOAjpYyAc9gxYc/GWyK2HYDF4xog6fV6h1i8FwCo"
       
   210         "LK/EncwhkWGxEH9AXLMXM2H1CpQBifI3yeapZ+70d43+cSo4+95yL23g8XiGFUWp3bVrV/Ty"
       
   211         "5ctZnR2ddHZ08uxzz1K9eT1GRhJls1gFlsfieK+WpJ5e/3z7pcuXzmia1rJSs3xlOg8dOvTD"
       
   212         "8fHx7wQCgb4tW7bMm6b55/Pnz+eGw+FFGJDT5iT1XRWlfxHMZ06+/Vz9dCAQeG9kZKR1x44d"
       
   213         "nSdPnkyuZSAArbq6eqOiKAP9/f3xlpaWgra2tlei0eiryWSyKGKa2TcaL+muwcxU5aDf9Gi+"
       
   214         "L0Oh0BehUOiaZVlnAoHAzFr7Ih75bVnVb2pqcvf09Phi0ei6+/rUC6lw1k0p5bSUctThcIwP"
       
   215         "Dw/HnwT4P6CDl+TMvD0JAAAAAElFTkSuQmCC")
       
   216         
       
   217         #----------------------------------------------------------------------
       
   218         stopicon = PyEmbeddedImage(
       
   219         "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAABPRJ"
       
   220         "REFUSImdlllsVGUUx3/f/e4sd5iZLjNt6XSFdtgkjWFRePABDaCBGgjamIg81CU0aoxbRHww"
       
   221         "+EDkhWjEB5rYGEMUxQTCJg8EoQ2BbgrFCNJWltplgC63naEzd+bO50NLLVAq4STfwz3nfP/f"
       
   222         "PSf3O98VSikmmQ94HFgDLDdNM1BfX5955swZX0tLi5FKpbSSkpJkaWlpIhQKdVdVVX2XkZFx"
       
   223         "EpBAEGgHLgH/iSqlUEoJpVSBUqpaKXXYNM0r1dXVt6WUajx5ylVYWKi2bdvWY1nWUaXUgQ0b"
       
   224         "NtRWVFQUjmuilEKMV5ALvAhsPHDgQFlNTU2gr69Pk1JSFMphTomfRXO8+A243i/oG9I5f6mX"
       
   225         "K1evAxAOhykrKxs9duyYkZ+f/0lPT8/2OwXogBtYDKzYunVr0c6dO3Ns26akMIcdbxQyv0hy"
       
   226         "rwmh8Bas5/eb89nxRR1NTU20t7cb4x1ZPjlXB2YBiw8ePJhdW1tb4DEMXng6xJtrPQhxn/Y4"
       
   227         "QSM12o89fJnOjst3hXRdLxZCGEqpUQANmBuJRLK3bNmy1OFwUPVMPm9VTiMOqLRNYvg6+shv"
       
   228         "rFoWwutxTcSklGEpZXDiXZRSr6xbt+6dtra2xUW5Lr7c7EUD3Flhwmu/nRKQGO7CvHaCwY7D"
       
   229         "WNEeEmoGe0+PWnuOXHWmrBTl5eW7GxsbNwPoFy5ccHV2di7yzjD4uMqDNtFngZDOKQHurDLc"
       
   230         "WWX4Qk/ScfRVXCLGoorU8J+z5gbjxyWGYbwshPhQKTWi7d+/P9/pdIp5xR5C2Q9uS1fDp3T+"
       
   231         "8jo32uomfJ7cCtzZYQCOjKhYOmgxI+hBSumdOXPmegDt4sWLxU6nk3BIf7A6EB/sIBY5R/+l"
       
   232         "nyd8yrZIRnvZ02tduxVwFQOojBQAfr9/tRBC103TLHe5XMwpSEwLKFj2EWk7gRGYOyaeTtJ4"
       
   233         "pnZk+7UhM5FtlAhAIMYAESd+v78IyNWBYqfTSUF2fFqAJ7firufhRFSdTg36rIDhQ6XHnAI0"
       
   234         "L1iWhWEYASBLl1L+JaWcfSuqk+u3AUikRer4ADffg/w7gt80fs35r34k3BYh2xNAarooAJ4d"
       
   235         "vsHgaP8EWMR17GiaVo8r0+Fw6DrQDDzXO+RgQSjBUFIlPh+wB0vLZD6TrLWrkWRXB29fGAK6"
       
   236         "pql1rNXVmrCklJYGtAgh6DXHDsuuG8k+O9M5895tq+atpSwwZ9o2TjZlWTGl1IAGNEsp1c1E"
       
   237         "DiMqmI7nZRQJ7j/G6xZWMS/vsYcGkEzG4vF4RDt06FBfZmbmwR/27uOD3f1aVk+BljMjD6lp"
       
   238         "/DN07a4VTYw8tL4rrQZgbNixadOm90+dOvX82cZmcbaxmWBukOVrlvJudw1R1xDp8a+kuPM6"
       
   239         "Gx8S4LXtCIwNO1asWDGYl5dn3gneunGLc7/+gTttoAntQRrTmgMmpimAHQwGOycnlBaX4rUz"
       
   240         "8LszMRweXLr7kWB35oMdCAT+1jRt0cqVK6Otra2+hvoGGuobWPLEEsoXzkbPkLhvR4CBRwJY"
       
   241         "Xq/3SGVlZbq7u7utsrJyxDTNz06cOJHZ0tRCS1MLAKuRwNQT9v8AyV27dn1fXl7eqmlae11d"
       
   242         "XXLfvn0/+Xy+l6LR6Gu2befFYjFfzrk2FzeHp7mK7jdxz2/LffGamhpvc3NzyLKsbFd3z1PG"
       
   243         "aHyBTKdjum0POGzbFAp7qo0xVOtJZdf/C/wRDnL5FYGSAAAAAElFTkSuQmCC")
       
   244         
   146         
   245         class ParamsEntryDialog(wx.TextEntryDialog):
   147         class ParamsEntryDialog(wx.TextEntryDialog):
   246             if wx.VERSION < (2, 6, 0):
   148             if wx.VERSION < (2, 6, 0):
   247                 def Bind(self, event, function, id = None):
   149                 def Bind(self, event, function, id = None):
   248                     if id is not None:
   150                     if id is not None:
   407                 self.RemoveIcon()
   309                 self.RemoveIcon()
   408                 wx.CallAfter(wx.GetApp().Exit)
   310                 wx.CallAfter(wx.GetApp().Exit)
   409             
   311             
   410             def UpdateIcon(self, plcstatus):
   312             def UpdateIcon(self, plcstatus):
   411                 if plcstatus is "Started" :
   313                 if plcstatus is "Started" :
   412                     currenticon = self.MakeIcon(starticon.GetImage())
   314                     currenticon = self.MakeIcon(starticon)
   413                 elif plcstatus is "Stopped":
   315                 elif plcstatus is "Stopped":
   414                     currenticon = self.MakeIcon(stopicon.GetImage())
   316                     currenticon = self.MakeIcon(stopicon)
   415                 else:
   317                 else:
   416                     currenticon = self.MakeIcon(defaulticon.GetImage())
   318                     currenticon = self.MakeIcon(defaulticon)
   417                 self.SetIcon(currenticon, "Beremiz Service")
   319                 self.SetIcon(currenticon, "Beremiz Service")
   418 
   320 
   419 from runtime import PLCObject, PLCprint, ServicePublisher
   321 from runtime import PLCObject, PLCprint, ServicePublisher
   420 import Pyro.core as pyro
   322 import Pyro.core as pyro
   421 
   323 
   701     pyroserver = Server(servicename, given_ip, port, WorkingDir, argv, autostart, statuschange, evaluator, website)
   603     pyroserver = Server(servicename, given_ip, port, WorkingDir, argv, autostart, statuschange, evaluator, website)
   702     taskbar_instance = BeremizTaskBarIcon(pyroserver, enablewx)
   604     taskbar_instance = BeremizTaskBarIcon(pyroserver, enablewx)
   703 else:
   605 else:
   704     pyroserver = Server(servicename, given_ip, port, WorkingDir, argv, autostart, website=website)
   606     pyroserver = Server(servicename, given_ip, port, WorkingDir, argv, autostart, website=website)
   705 
   607 
       
   608 # Exception hooks s
       
   609 import threading, traceback
       
   610 def LogException(*exp):
       
   611     if pyroserver.plcobj is not None:
       
   612         pyroserver.plcobj.LogMessage(0,'\n'.join(traceback.format_exception(*exp)))
       
   613     else:
       
   614         traceback.print_exception(e_type, e_value, e_traceback)
       
   615 
       
   616 sys.excepthook = LogException
       
   617 def installThreadExcepthook():
       
   618     init_old = threading.Thread.__init__
       
   619     def init(self, *args, **kwargs):
       
   620         init_old(self, *args, **kwargs)
       
   621         run_old = self.run
       
   622         def run_with_except_hook(*args, **kw):
       
   623             try:
       
   624                 run_old(*args, **kw)
       
   625             except (KeyboardInterrupt, SystemExit):
       
   626                 raise
       
   627             except:
       
   628                 sys.excepthook(*sys.exc_info())
       
   629         self.run = run_with_except_hook
       
   630     threading.Thread.__init__ = init
       
   631 installThreadExcepthook()
       
   632 
   706 if havetwisted or havewx:
   633 if havetwisted or havewx:
   707     pyro_thread=Thread(target=pyroserver.Loop)
   634     pyro_thread=Thread(target=pyroserver.Loop)
   708     pyro_thread.start()
   635     pyro_thread.start()
   709 
   636 
   710     if havetwisted:
   637     if havetwisted: