SVGHMI: More configuration parameters : network interface, TCP port, URL path and watchdog enabling.
--- a/svghmi/svghmi.py Thu Jul 01 14:33:14 2021 +0200
+++ b/svghmi/svghmi.py Mon Jul 05 10:51:02 2021 +0200
@@ -279,11 +279,15 @@
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="SVGHMI">
<xsd:complexType>
- <xsd:attribute name="OnStart" type="xsd:string" use="optional"/>
- <xsd:attribute name="OnStop" type="xsd:string" use="optional"/>
- <xsd:attribute name="OnWatchdog" type="xsd:string" use="optional"/>
- <xsd:attribute name="WatchdogInitial" type="xsd:integer" use="optional"/>
- <xsd:attribute name="WatchdogInterval" type="xsd:integer" use="optional"/>
+ <xsd:attribute name="OnStart" type="xsd:string" use="optional" default="chromium {url}"/>
+ <xsd:attribute name="OnStop" type="xsd:string" use="optional" default="echo 'please close chromium window at {url}'"/>
+ <xsd:attribute name="EnableWatchdog" type="xsd:boolean" use="optional" default="false"/>
+ <xsd:attribute name="OnWatchdog" type="xsd:string" use="optional" default="chromium {url}"/>
+ <xsd:attribute name="WatchdogInitial" type="xsd:integer" use="optional" default="30"/>
+ <xsd:attribute name="WatchdogInterval" type="xsd:integer" use="optional" default="5"/>
+ <xsd:attribute name="Port" type="xsd:integer" use="optional" default="8008"/>
+ <xsd:attribute name="Interface" type="xsd:string" use="optional" default="localhost"/>
+ <xsd:attribute name="Path" type="xsd:string" use="optional" default=""/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
@@ -532,50 +536,96 @@
res += ((target_fname, open(target_path, "rb")),)
+ port = self.GetParamsAttributes("SVGHMI.Port")["value"]
+ interface = self.GetParamsAttributes("SVGHMI.Interface")["value"]
+ path = self.GetParamsAttributes("SVGHMI.Path")["value"].format(name=view_name)
+ enable_watchdog = self.GetParamsAttributes("SVGHMI.EnableWatchdog")["value"]
+ url="http://"+interface+("" if port==80 else (":"+str(port))
+ ) + (("/"+path) if path else ""
+ ) + ("#watchdog" if enable_watchdog else "")
+
svghmi_cmds = {}
for thing in ["Start", "Stop", "Watchdog"]:
given_command = self.GetParamsAttributes("SVGHMI.On"+thing)["value"]
svghmi_cmds[thing] = (
"Popen(" +
- repr(shlex.split(given_command.format(port="8008", name=view_name))) +
+ repr(shlex.split(given_command.format(
+ port=port,
+ name=view_name,
+ url=url))) +
")") if given_command else "pass # no command given"
runtimefile_path = os.path.join(buildpath, "runtime_%s_svghmi_.py" % location_str)
runtimefile = open(runtimefile_path, 'w')
runtimefile.write("""
# TODO : multiple watchdog (one for each svghmi instance)
-def svghmi_watchdog_trigger():
+def svghmi_{location}_watchdog_trigger():
{svghmi_cmds[Watchdog]}
svghmi_watchdog = None
def _runtime_{location}_svghmi_start():
- global svghmi_watchdog
+ global svghmi_watchdog, svghmi_servers
+
+ srv = svghmi_servers.get("{interface}:{port}", None)
+ if srv is not None:
+ svghmi_root, svghmi_listener, path_list = srv
+ if '{path}' in path_list:
+ raise Exception("SVGHMI {view_name}: path {path} already used on {interface}:{port}")
+ else:
+ svghmi_root = Resource()
+ svghmi_root.putChild("ws", WebSocketResource(HMIWebSocketServerFactory()))
+
+ svghmi_listener = reactor.listenTCP({port}, Site(svghmi_root), interface='{interface}')
+ path_list = []
+ svghmi_servers["{interface}:{port}"] = (svghmi_root, svghmi_listener, path_list)
+
svghmi_root.putChild(
- '{view_name}',
+ '{path}',
NoCacheFile('{xhtml}',
- defaultType='application/xhtml+xml'))
+ defaultType='application/xhtml+xml'))
+
+ path_list.append("{path}")
{svghmi_cmds[Start]}
- svghmi_watchdog = Watchdog(
- {watchdog_initial},
- {watchdog_interval},
- svghmi_watchdog_trigger)
+ if {enable_watchdog}:
+ if svghmi_watchdog is None:
+ svghmi_watchdog = Watchdog(
+ {watchdog_initial},
+ {watchdog_interval},
+ svghmi_{location}_watchdog_trigger)
+ else:
+ raise Exception("SVGHMI {view_name}: only one watchdog allowed")
+
def _runtime_{location}_svghmi_stop():
- global svghmi_watchdog
+ global svghmi_watchdog, svghmi_servers
+
if svghmi_watchdog is not None:
svghmi_watchdog.cancel()
svghmi_watchdog = None
- svghmi_root.delEntity('{view_name}')
+ svghmi_root, svghmi_listener, path_list = svghmi_servers["{interface}:{port}"]
+ svghmi_root.delEntity('{path}')
+
+ path_list.remove('{path}')
+
+ if len(path_list)==0:
+ svghmi_root.delEntity("ws")
+ svghmi_listener.stopListening()
+ svghmi_servers.pop("{interface}:{port}")
+
{svghmi_cmds[Stop]}
""".format(location=location_str,
xhtml=target_fname,
view_name=view_name,
svghmi_cmds=svghmi_cmds,
+ port = port,
+ interface = interface,
+ path = path,
+ enable_watchdog = enable_watchdog,
watchdog_initial = self.GetParamsAttributes("SVGHMI.WatchdogInitial")["value"],
watchdog_interval = self.GetParamsAttributes("SVGHMI.WatchdogInterval")["value"],
))
--- a/svghmi/svghmi_server.py Thu Jul 01 14:33:14 2021 +0200
+++ b/svghmi/svghmi_server.py Mon Jul 05 10:51:02 2021 +0200
@@ -142,8 +142,7 @@
class HMIWebSocketServerFactory(WebSocketServerFactory):
protocol = HMIProtocol
-svghmi_root = None
-svghmi_listener = None
+svghmi_servers = {}
svghmi_send_thread = None
def SendThreadProc():
@@ -165,19 +164,14 @@
# this happens when finishing
break
-
-def watchdog_trigger():
- print("SVGHMI watchdog trigger")
-
+def AddPathToSVGHMIServers(path, factory):
+ for k,v in svghmi_servers.iteritems():
+ svghmi_root, svghmi_listener, path_list = v
+ svghmi_root.putChild(path, factory())
# Called by PLCObject at start
def _runtime_00_svghmi_start():
- global svghmi_listener, svghmi_root, svghmi_send_thread
-
- svghmi_root = Resource()
- svghmi_root.putChild("ws", WebSocketResource(HMIWebSocketServerFactory()))
-
- svghmi_listener = reactor.listenTCP(8008, Site(svghmi_root), interface='localhost')
+ global svghmi_send_thread
# start a thread that call the C part of SVGHMI
svghmi_send_thread = Thread(target=SendThreadProc, name="SVGHMI Send")
@@ -186,14 +180,10 @@
# Called by PLCObject at stop
def _runtime_00_svghmi_stop():
- global svghmi_listener, svghmi_root, svghmi_send_thread, svghmi_session
+ global svghmi_send_thread, svghmi_session
if svghmi_session is not None:
svghmi_session.close()
- svghmi_root.delEntity("ws")
- svghmi_root = None
- svghmi_listener.stopListening()
- svghmi_listener = None
# plc cleanup calls svghmi_(locstring)_cleanup and unlocks send thread
svghmi_send_thread.join()
svghmi_send_thread = None
--- a/tests/svghmi/py_ext_0@py_ext/pyfile.xml Thu Jul 01 14:33:14 2021 +0200
+++ b/tests/svghmi/py_ext_0@py_ext/pyfile.xml Mon Jul 05 10:51:02 2021 +0200
@@ -87,7 +87,7 @@
<start>
<xhtml:p><![CDATA[
-svghmi_root.putChild("alarms", AlarmJsonResource())
+AddPathToSVGHMIServers("alarms", AlarmJsonResource)
]]></xhtml:p>
--- a/tests/svghmi/svghmi_0@svghmi/confnode.xml Thu Jul 01 14:33:14 2021 +0200
+++ b/tests/svghmi/svghmi_0@svghmi/confnode.xml Mon Jul 05 10:51:02 2021 +0200
@@ -1,2 +1,2 @@
<?xml version='1.0' encoding='utf-8'?>
-<SVGHMI xmlns:xsd="http://www.w3.org/2001/XMLSchema" OnWatchdog="echo Watchdog for {name} !" OnStart="chromium http://127.0.0.1:{port}/{name}" OnStop="echo Closing {name}" WatchdogInitial="10" WatchdogInterval="5"/>
+<SVGHMI xmlns:xsd="http://www.w3.org/2001/XMLSchema" OnWatchdog="echo Watchdog for {name} !" WatchdogInitial="10" WatchdogInterval="5" EnableWatchdog="true" Path="{name}"/>