--- a/bacnet/web_settings.py Fri Jun 12 10:30:23 2020 +0200
+++ b/bacnet/web_settings.py Fri Jun 12 14:39:32 2020 +0200
@@ -243,27 +243,6 @@
for name, web_label, c_dtype, web_dtype in BACnet_parameters]
-def _updateWebInterface():
- # Add/Remove buttons to/from the web interface depending on the current state
- # - If there is a saved state => add a delete saved state button
- # Add a "Delete Saved Configuration" button if there is a saved configuration!
- if _SavedConfiguration is None:
- NS.ConfigurableSettings.delSettings("BACnetConfigDelSaved")
- NS.ConfigurableSettings.addSettings(
- "BACnetConfigDelSaved", # name
- _("BACnet Configuration"), # description
- [], # fields (empty, no parameters required!)
- _("Delete Configuration Stored in Persistent Storage"), # button label
- OnButtonDel, # callback
- "BACnetConfigParm") # Add after entry xxxx
def OnButtonSave(**kwargs):
# Function called when user clicks 'Save' button in web interface
@@ -279,8 +258,6 @@
newConfig[par_name] = value
- global _WebviewConfiguration
- _WebviewConfiguration = newConfig
# First check if configuration is OK.
if not _CheckWebConfiguration(newConfig):
@@ -294,13 +271,9 @@
# Configure PLC with the current BACnet parameters
_SetPLCConfiguration(newConfig)
- # File has just been created => Delete button must be shown on web interface!
-def OnButtonDel(**kwargs):
+def OnButtonReset(**kwargs): # Function called when user clicks 'Delete' button in web interface
# The function will delete the file containing the persistent
@@ -314,25 +287,10 @@
global _SavedConfiguration
_SavedConfiguration = None
- # File has just been deleted => Delete button on web interface no longer needed!
-def OnButtonShowCur(**kwargs):
- # Function called when user clicks 'Show Current PLC Configuration' button in web interface
- # The function will load the current PLC configuration into the web form
- global _WebviewConfiguration
- _WebviewConfiguration = _GetPLCConfiguration()
- # File has just been deleted => Delete button on web interface no longer needed!
+# location_str is replaced by extension's value in CTNGenerateC call def _runtime_bacnet_websettings_%(location_str)s_init():
# Callback function, called (by PLCObject.py) when a new PLC program
@@ -346,23 +304,12 @@
# PLC was loaded but we don't have access to the library of compiled code (.so lib)?
# Hmm... This shold never occur!!
- # Get the location (in the Config. Node Tree of Beremiz IDE) the BACnet plugin
- # occupies in the currently loaded PLC project (i.e., the .so file)
- # If the "__bacnet_plugin_location" C variable is not present in the .so file,
- # we conclude that the currently loaded PLC does not have the BACnet plugin
- # included (situation (2b) described above init())
- location = ctypes.c_char_p.in_dll(PLCObject.PLClibraryHandle, "__bacnet_plugin_location")
- # Loaded PLC does not have the BACnet plugin => nothing to do
- # (i.e. do _not_ configure and make available the BACnet web interface)
# Map the get/set functions (written in C code) we will be using to get/set the configuration parameters
for name, web_label, c_dtype, web_dtype in BACnet_parameters:
- GetParamFuncName = "__bacnet_" + location.value + "_get_ConfigParam_" + name
- SetParamFuncName = "__bacnet_" + location.value + "_set_ConfigParam_" + name
+ # location_str is replaced by extension's value in CTNGenerateC call + GetParamFuncName = "__bacnet_%(location_str)s_get_ConfigParam_" + name + SetParamFuncName = "__bacnet_%(location_str)s_set_ConfigParam_" + name GetParamFuncs[name] = getattr(PLCObject.PLClibraryHandle, GetParamFuncName)
GetParamFuncs[name].restype = c_dtype
@@ -399,29 +346,37 @@
if _CheckConfiguration(_SavedConfiguration):
_SetPLCConfiguration(_SavedConfiguration)
+ WebSettings = NS.newExtensionSetting("BACnet") # Configure the web interface to include the BACnet config parameters
- NS.ConfigurableSettings.addSettings(
+ WebSettings.addSettings( "BACnetConfigParm", # name
_("BACnet Configuration"), # description
webFormInterface, # fields
- _("Save Configuration to Persistent Storage"), # button label
+ _("Apply"), # button label
- # Add a "View Current Configuration" button
- NS.ConfigurableSettings.addSettings(
- "BACnetConfigViewCur", # name
+ # Add the Delete button to the web interface + WebSettings.addSettings( + "BACnetConfigDelSaved", # name _("BACnet Configuration"), # description
- [], # fields (empty, no parameters required!)
- _("Show Current PLC Configuration"), # button label
- OnButtonShowCur) # callback
- # Add the Delete button to the web interface, if required
+ annotate.String(label=_("Current state"), + default=lambda *k:getConfigStatus())), + ], # fields (empty, no parameters required!) + _("Reset"), # button label + if _WebviewConfiguration == _DefaultConfiguration : +# location_str is replaced by extension's value in CTNGenerateC call def _runtime_bacnet_websettings_%(location_str)s_cleanup():
# Callback function, called (by PLCObject.py) when a PLC program is unloaded from memory
@@ -429,11 +384,8 @@
#PLCObject.LogMessage("BACnet web server extension::OnUnLoadPLC() Called...")
- # Delete the BACnet specific web interface extensions
- # (Safe to ask to delete, even if it has not been added!)
- NS.ConfigurableSettings.delSettings("BACnetConfigParm")
- NS.ConfigurableSettings.delSettings("BACnetConfigViewCur")
- NS.ConfigurableSettings.delSettings("BACnetConfigDelSaved")
+ NS.removeExtensionSetting("BACnet") _WebviewConfiguration = None
--- a/modbus/web_settings.py Fri Jun 12 10:30:23 2020 +0200
+++ b/modbus/web_settings.py Fri Jun 12 14:39:32 2020 +0200
@@ -328,33 +328,6 @@
-def _updateWebInterface(WebNode_id):
- Add/Remove buttons to/from the web interface depending on the current state
- - If there is a saved state => add a delete saved state button
- config_hash = _WebNodeList[WebNode_id]["config_hash"]
- config_name = _WebNodeList[WebNode_id]["config_name"]
- # Add a "Delete Saved Configuration" button if there is a saved configuration!
- if _WebNodeList[WebNode_id]["SavedConfiguration"] is None:
- NS.ConfigurableSettings.delSettings("ModbusConfigDelSaved" + config_hash)
- def __OnButtonDel(**kwargs):
- return OnButtonDel(WebNode_id = WebNode_id, **kwargs)
- NS.ConfigurableSettings.addSettings(
- "ModbusConfigDelSaved" + config_hash, # name (internal, may not contain spaces, ...)
- _("Modbus Configuration: ") + config_name, # description (user visible label)
- [], # fields (empty, no parameters required!)
- _("Delete Configuration Stored in Persistent Storage"), # button label
- __OnButtonDel, # callback
- "ModbusConfigParm" + config_hash) # Add after entry xxxx
def OnButtonSave(**kwargs):
Function called when user clicks 'Save' button in web interface
@@ -396,13 +369,9 @@
# so we do not set it directly to newConfig
_WebNodeList[WebNode_id]["WebviewConfiguration"] = _GetPLCConfiguration(WebNode_id)
- # File has just been created => Delete button must be shown on web interface!
- _updateWebInterface(WebNode_id)
-def OnButtonDel(**kwargs):
+def OnButtonReset(**kwargs): Function called when user clicks 'Delete' button in web interface
The function will delete the file containing the persistent
@@ -424,28 +393,10 @@
# Reset SavedConfiguration
_WebNodeList[WebNode_id]["SavedConfiguration"] = None
- # File has just been deleted => Delete button on web interface no longer needed!
- _updateWebInterface(WebNode_id)
-def OnButtonShowCur(**kwargs):
- Function called when user clicks 'Show Current PLC Configuration' button in web interface
- The function will load the current PLC configuration into the web form
- Note that this function does not get called directly. The real callback
- function is the dynamic __OnButtonShowCur() function, which will add the
- "WebNode_id" argument, and call this function to do the work.
- WebNode_id = kwargs.get("WebNode_id", None)
- _WebNodeList[WebNode_id]["WebviewConfiguration"] = _GetPLCConfiguration(WebNode_id)
def _AddWebNode(C_node_id, node_type, GetParamFuncs, SetParamFuncs):
Load from the compiled code (.so file, aloready loaded into memmory)
@@ -537,26 +488,33 @@
def __OnButtonSave(**kwargs):
OnButtonSave(WebNode_id=WebNode_id, **kwargs)
- NS.ConfigurableSettings.addSettings(
+ WebSettings = NS.newExtensionSetting("Modbus "+config_hash) + WebSettings.addSettings( "ModbusConfigParm" + config_hash, # name (internal, may not contain spaces, ...)
_("Modbus Configuration: ") + config_name, # description (user visible label)
webFormInterface, # fields
- _("Save Configuration to Persistent Storage"), # button label
+ _("Apply"), # button label __OnButtonSave) # callback
- # Add a "View Current Configuration" button
- def __OnButtonShowCur(**kwargs):
- OnButtonShowCur(WebNode_id=WebNode_id, **kwargs)
+ def __OnButtonReset(**kwargs): + return OnButtonReset(WebNode_id = WebNode_id, **kwargs) + if WebNode_entry["WebviewConfiguration"] == WebNode_entry["DefaultConfiguration"]: - NS.ConfigurableSettings.addSettings(
- "ModbusConfigViewCur" + config_hash, # name (internal, may not contain spaces, ...)
- _("Modbus Configuration: ") + config_name, # description (user visible label)
- [], # fields (empty, no parameters required!)
- _("Show Current PLC Configuration"), # button label
- __OnButtonShowCur) # callback
- # Add the Delete button to the web interface, if required
- _updateWebInterface(WebNode_id)
+ WebSettings.addSettings( + "ModbusConfigDelSaved" + config_hash, # name (internal, may not contain spaces, ...) + _("Modbus Configuration: ") + config_name, # description (user visible label) + annotate.String(label=_("Current state"), + default=lambda *k:getConfigStatus())), + ], # fields (empty, no parameters required!) + _("Reset"), # button label @@ -567,7 +525,6 @@
(i.e. XXX.so file) is transfered to the PLC runtime
- print("_runtime_modbus_websettings_init")
#PLCObject.LogMessage("Modbus web server extension::OnLoadPLC() Called...")
@@ -651,9 +608,7 @@
for WebNode_entry in _WebNodeList:
config_hash = WebNode_entry["config_hash"]
- NS.ConfigurableSettings.delSettings("ModbusConfigParm" + config_hash)
- NS.ConfigurableSettings.delSettings("ModbusConfigViewCur" + config_hash)
- NS.ConfigurableSettings.delSettings("ModbusConfigDelSaved" + config_hash)
+ NS.removeExtensionSetting("Modbus "+config_hash) --- a/runtime/NevowServer.py Fri Jun 12 10:30:23 2020 +0200
+++ b/runtime/NevowServer.py Fri Jun 12 14:39:32 2020 +0200
@@ -26,6 +26,7 @@
from __future__ import absolute_import
from __future__ import print_function
import platform as platform_module
from zope.interface import implements
from nevow import appserver, inevow, tags, loaders, athena, url, rend
@@ -165,8 +166,7 @@
setattr(self, 'bind_' + name, _bind)
self.bindingsNames.append(name)
- def addSettings(self, name, desc, fields, btnlabel, callback,
+ def addSettings(self, name, desc, fields, btnlabel, callback): return annotate.MethodBinding(
@@ -180,32 +180,20 @@
setattr(self, 'action_' + name, callback)
- if addAfterName not in self.bindingsNames:
- # Just append new setting if not yet present
- if name not in self.bindingsNames:
- self.bindingsNames.append(name)
- # We need to insert new setting
- # imediately _after_ addAfterName
+ self.bindingsNames.append(name) - # First remove new setting if already present
- # to make sure it goes into correct place
- if name in self.bindingsNames:
- self.bindingsNames.remove(name)
- # Now add new setting in correct place
- self.bindingsNames.insert(
- self.bindingsNames.index(addAfterName)+1,
- def delSettings(self, name):
- if name in self.bindingsNames:
- self.bindingsNames.remove(name)
ConfigurableSettings = ConfigurableBindings()
+def newExtensionSetting(ext_name): + global extensions_settings_od + settings = ConfigurableBindings() + extensions_settings_od[ext_name] = settings +def removeExtensionSetting(ext_name): + global extensions_settings_od + extensions_settings_od.pop(ext_name) class ISettings(annotate.TypedInterface):
platform = annotate.String(label=_("Platform"),
@@ -233,6 +221,7 @@
+extensions_settings_od = collections.OrderedDict() class SettingsPage(rend.Page):
@@ -243,6 +232,25 @@
child_webinterface_css = File(paths.AbsNeighbourFile(__file__, 'webinterface.css'), 'text/css')
+ def __getattr__(self, name): + global extensions_settings_od + if name.startswith('configurable_'): + def configurable_something(ctx): + return extensions_settings_od[ext_name] + return configurable_something + def extensions_settings(self, context, data): + """ Project extensions settings + Extensions added to Configuration Tree in IDE have their setting rendered here + global extensions_settings_od + for ext_name in extensions_settings_od: + res += [tags.h2[ext_name], webform.renderForms(ext_name)] docFactory = loaders.stan([tags.html[
@@ -260,12 +268,16 @@
webform.renderForms('staticSettings'),
tags.h1["Extensions settings:"],
webform.renderForms('dynamicSettings'),
def configurable_staticSettings(self, ctx):
return configurable.TypedInterfaceConfigurable(self)
def configurable_dynamicSettings(self, ctx):
+ """ Runtime Extensions settings + Extensions loaded through Beremiz_service -e or optional runtime features render setting forms here return ConfigurableSettings
def sendLogMessage(self, level, message, **kwargs):