48 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" |
48 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" |
49 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> |
49 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> |
50 ''' |
50 ''' |
51 |
51 |
52 WorkingDir = None |
52 WorkingDir = None |
53 |
|
54 |
|
55 class PLCHMI(athena.LiveElement): |
|
56 |
|
57 initialised = False |
|
58 |
|
59 def HMIinitialised(self, result): |
|
60 self.initialised = True |
|
61 |
|
62 def HMIinitialisation(self): |
|
63 self.HMIinitialised(None) |
|
64 |
|
65 |
|
66 class DefaultPLCStartedHMI(PLCHMI): |
|
67 docFactory = loaders.stan( |
|
68 tags.div(render=tags.directive('liveElement'))[ |
|
69 tags.h1["PLC IS NOW STARTED"], |
|
70 ]) |
|
71 |
|
72 |
|
73 class PLCStoppedHMI(PLCHMI): |
|
74 docFactory = loaders.stan( |
|
75 tags.div(render=tags.directive('liveElement'))[ |
|
76 tags.h1["PLC IS STOPPED"], |
|
77 ]) |
|
78 |
|
79 |
|
80 class MainPage(athena.LiveElement): |
|
81 jsClass = "WebInterface.PLC" |
|
82 docFactory = loaders.stan( |
|
83 tags.invisible[ |
|
84 tags.div(render=tags.directive('liveElement'))[ |
|
85 tags.div(id='content')[ |
|
86 tags.div(render=tags.directive('PLCElement'))] |
|
87 ], |
|
88 tags.a(href='settings')['Settings']]) |
|
89 |
|
90 def __init__(self, *a, **kw): |
|
91 athena.LiveElement.__init__(self, *a, **kw) |
|
92 self.pcl_state = False |
|
93 self.HMI = None |
|
94 self.resetPLCStartedHMI() |
|
95 |
|
96 def setPLCState(self, state): |
|
97 self.pcl_state = state |
|
98 if self.HMI is not None: |
|
99 self.callRemote('updateHMI') |
|
100 |
|
101 def setPLCStartedHMI(self, hmi): |
|
102 self.PLCStartedHMIClass = hmi |
|
103 |
|
104 def resetPLCStartedHMI(self): |
|
105 self.PLCStartedHMIClass = DefaultPLCStartedHMI |
|
106 |
|
107 def getHMI(self): |
|
108 return self.HMI |
|
109 |
|
110 def HMIexec(self, function, *args, **kwargs): |
|
111 if self.HMI is not None: |
|
112 getattr(self.HMI, function, lambda: None)(*args, **kwargs) |
|
113 athena.expose(HMIexec) |
|
114 |
|
115 def resetHMI(self): |
|
116 self.HMI = None |
|
117 |
|
118 def PLCElement(self, ctx, data): |
|
119 return self.getPLCElement() |
|
120 renderer(PLCElement) |
|
121 |
|
122 def getPLCElement(self): |
|
123 self.detachFragmentChildren() |
|
124 if self.pcl_state: |
|
125 f = self.PLCStartedHMIClass() |
|
126 else: |
|
127 f = PLCStoppedHMI() |
|
128 f.setFragmentParent(self) |
|
129 self.HMI = f |
|
130 return f |
|
131 athena.expose(getPLCElement) |
|
132 |
|
133 def detachFragmentChildren(self): |
|
134 for child in self.liveFragmentChildren[:]: |
|
135 child.detach() |
|
136 |
|
137 |
53 |
138 class ConfigurableBindings(configurable.Configurable): |
54 class ConfigurableBindings(configurable.Configurable): |
139 |
55 |
140 def __init__(self): |
56 def __init__(self): |
141 configurable.Configurable.__init__(self, None) |
57 configurable.Configurable.__init__(self, None) |
328 def locateChild(self, ctx, segments): |
244 def locateChild(self, ctx, segments): |
329 if segments[0] in customSettingsURLs: |
245 if segments[0] in customSettingsURLs: |
330 return customSettingsURLs[segments[0]](ctx, segments) |
246 return customSettingsURLs[segments[0]](ctx, segments) |
331 return super(SettingsPage, self).locateChild(ctx, segments) |
247 return super(SettingsPage, self).locateChild(ctx, segments) |
332 |
248 |
333 |
|
334 class WebInterface(athena.LivePage): |
|
335 |
|
336 docFactory = loaders.stan([tags.raw(xhtml_header), |
|
337 tags.html(xmlns="http://www.w3.org/1999/xhtml")[ |
|
338 tags.head(render=tags.directive('liveglue'))[ |
|
339 tags.title[PAGE_TITLE], |
|
340 tags.link(rel='stylesheet', |
|
341 type='text/css', |
|
342 href=url.here.child("webform_css")) |
|
343 ], |
|
344 tags.body[ |
|
345 tags.div[ |
|
346 tags.div( |
|
347 render=tags.directive( |
|
348 "MainPage")), |
|
349 ]]]]) |
|
350 MainPage = MainPage() |
|
351 PLCHMI = PLCHMI |
|
352 |
|
353 def child_settings(self, context): |
|
354 return SettingsPage() |
|
355 |
|
356 def __init__(self, plcState=False, *a, **kw): |
|
357 super(WebInterface, self).__init__(*a, **kw) |
|
358 self.jsModules.mapping['WebInterface'] = paths.AbsNeighbourFile( |
|
359 __file__, 'webinterface.js') |
|
360 self.plcState = plcState |
|
361 self.MainPage.setPLCState(plcState) |
|
362 |
|
363 def getHMI(self): |
|
364 return self.MainPage.getHMI() |
|
365 |
|
366 def LoadHMI(self, hmi, jsmodules): |
|
367 for name, path in jsmodules.items(): |
|
368 self.jsModules.mapping[name] = os.path.join(WorkingDir, path) |
|
369 self.MainPage.setPLCStartedHMI(hmi) |
|
370 |
|
371 def UnLoadHMI(self): |
|
372 self.MainPage.resetPLCStartedHMI() |
|
373 |
|
374 def PLCStarted(self): |
|
375 self.plcState = True |
|
376 self.MainPage.setPLCState(True) |
|
377 |
|
378 def PLCStopped(self): |
|
379 self.plcState = False |
|
380 self.MainPage.setPLCState(False) |
|
381 |
|
382 def renderHTTP(self, ctx): |
|
383 """ |
|
384 Force content type to fit with SVG |
|
385 """ |
|
386 req = ctx.locate(inevow.IRequest) |
|
387 req.setHeader('Content-type', 'application/xhtml+xml') |
|
388 return super(WebInterface, self).renderHTTP(ctx) |
|
389 |
|
390 def render_MainPage(self, ctx, data): |
|
391 f = self.MainPage |
|
392 f.setFragmentParent(self) |
|
393 return ctx.tag[f] |
|
394 |
|
395 def child_(self, ctx): |
|
396 self.MainPage.detachFragmentChildren() |
|
397 return WebInterface(plcState=self.plcState) |
|
398 |
|
399 def beforeRender(self, ctx): |
|
400 d = self.notifyOnDisconnect() |
|
401 d.addErrback(self.disconnected) |
|
402 |
|
403 def disconnected(self, reason): |
|
404 self.MainPage.resetHMI() |
|
405 # print reason |
|
406 # print "We will be called back when the client disconnects" |
|
407 |
|
408 |
|
409 def RegisterWebsite(iface, port): |
249 def RegisterWebsite(iface, port): |
410 website = WebInterface() |
250 website = SettingsPage() |
411 site = appserver.NevowSite(website) |
251 site = appserver.NevowSite(website) |
412 |
252 |
413 reactor.listenTCP(port, site, interface=iface) |
253 reactor.listenTCP(port, site, interface=iface) |
414 print(_('HTTP interface port :'), port) |
254 print(_('HTTP interface port :'), port) |
415 return website |
255 return website |
416 |
|
417 |
|
418 class statuslistener(object): |
|
419 |
|
420 def __init__(self, site): |
|
421 self.oldstate = None |
|
422 self.site = site |
|
423 |
|
424 def listen(self, state): |
|
425 if state != self.oldstate: |
|
426 action = {'Started': self.site.PLCStarted, |
|
427 'Stopped': self.site.PLCStopped}.get(state, None) |
|
428 if action is not None: |
|
429 action() |
|
430 self.oldstate = state |
|
431 |
|
432 |
|
433 def website_statuslistener_factory(site): |
|
434 return statuslistener(site).listen |
|
435 |
|
436 |
|