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() |