--- a/ProjectController.py Wed Aug 01 13:09:45 2018 +0300
+++ b/ProjectController.py Wed Aug 08 13:46:19 2018 +0200
@@ -65,7 +65,8 @@
base_folder = paths.AbsParentDir(__file__)
-MATIEC_ERROR_MODEL = re.compile(".*\.st:(\d+)-(\d+)\.\.(\d+)-(\d+): (?:error)|(?:warning) : (.*)$")
+MATIEC_ERROR_MODEL = re.compile(
+ ".*\.st:(\d+)-(\d+)\.\.(\d+)-(\d+): (?:error)|(?:warning) : (.*)$")
def ExtractChildrenTypesFromCatalog(catalog):
@@ -94,6 +95,7 @@
class Iec2CSettings(object):
+
def __init__(self):
self.iec2c = None
self.iec2c_buildopts = None
@@ -109,11 +111,12 @@
return path
def findCmd(self):
- cmd = "iec2c"+(".exe" if wx.Platform == '__WXMSW__' else "")
+ cmd = "iec2c" + (".exe" if wx.Platform == '__WXMSW__' else "")
paths = [
os.path.join(base_folder, "matiec")
]
- path = self.findObject(paths, lambda p: os.path.isfile(os.path.join(p, cmd)))
+ path = self.findObject(
+ paths, lambda p: os.path.isfile(os.path.join(p, cmd)))
# otherwise use iec2c from PATH
if path is not None:
@@ -126,7 +129,8 @@
os.path.join(base_folder, "matiec", "lib"),
"/usr/lib/matiec"
]
- path = self.findObject(paths, lambda p: os.path.isfile(os.path.join(p, "ieclib.txt")))
+ path = self.findObject(
+ paths, lambda p: os.path.isfile(os.path.join(p, "ieclib.txt")))
return path
def findLibCPath(self):
@@ -146,7 +150,8 @@
buildopt = ""
try:
- # Invoke compiler. Output files are listed to stdout, errors to stderr
+ # Invoke compiler.
+ # Output files are listed to stdout, errors to stderr
_status, result, _err_result = ProcessLogger(None, buildcmd,
no_stdout=True,
no_stderr=True).spin()
@@ -186,16 +191,17 @@
<xsd:element name="TargetType">
<xsd:complexType>
<xsd:choice minOccurs="0">
- """+targets.GetTargetChoices()+"""
+ """ + targets.GetTargetChoices() + """
</xsd:choice>
</xsd:complexType>
- </xsd:element>"""+(("""
+ </xsd:element>""" + (("""
<xsd:element name="Libraries" minOccurs="0">
<xsd:complexType>
- """+"\n".join(['<xsd:attribute name=' +
- '"Enable_' + libname + '_Library" ' +
- 'type="xsd:boolean" use="optional" default="false"/>'
- for libname, _lib in features.libraries])+"""
+ """ + "\n".join(['<xsd:attribute name=' +
+ '"Enable_' + libname + '_Library" ' +
+ 'type="xsd:boolean" use="optional" default="' +
+ ('true' if default else 'false') + '"/>'
+ for libname, _lib, default in features.libraries]) + """
</xsd:complexType>
</xsd:element>""") if len(features.libraries) > 0 else '') + """
</xsd:sequence>
@@ -209,6 +215,7 @@
class ProjectController(ConfigTreeNode, PLCControler):
+
"""
This class define Root object of the confnode tree.
It is responsible of :
@@ -219,7 +226,8 @@
- ...
"""
- # For root object, available Children Types are modules of the confnode packages.
+ # For root object, available Children Types are modules of the confnode
+ # packages.
CTNChildrenTypes = ExtractChildrenTypesFromCatalog(features.catalog)
XSD = GetProjectControllerXSD()
EditorType = ProjectNodeEditor
@@ -270,8 +278,10 @@
def LoadLibraries(self):
self.Libraries = []
TypeStack = []
- for libname, clsname in features.libraries:
- if self.BeremizRoot.Libraries is not None and getattr(self.BeremizRoot.Libraries, "Enable_"+libname+"_Library"):
+ for libname, clsname, _default in features.libraries:
+ if self.BeremizRoot.Libraries is not None and \
+ getattr(self.BeremizRoot.Libraries,
+ "Enable_" + libname + "_Library"):
Lib = GetClassImporter(clsname)()(self, libname, TypeStack)
TypeStack.append(Lib.GetTypes())
self.Libraries.append(Lib)
@@ -361,7 +371,8 @@
target = self.Parser.CreateElement("TargetType", "BeremizRoot")
temp_root.setTargetType(target)
target_name = self.GetDefaultTargetName()
- target.setcontent(self.Parser.CreateElement(target_name, "TargetType"))
+ target.setcontent(
+ self.Parser.CreateElement(target_name, "TargetType"))
return target
def GetParamsAttributes(self, path=None):
@@ -369,7 +380,8 @@
if params[0]["name"] == "BeremizRoot":
for child in params[0]["children"]:
if child["name"] == "TargetType" and child["value"] == '':
- child.update(self.GetTarget().getElementInfos("TargetType"))
+ child.update(
+ self.GetTarget().getElementInfos("TargetType"))
return params
def SetParamsAttribute(self, path, value):
@@ -403,7 +415,8 @@
def _getProjectFilesPath(self, project_path=None):
if project_path is not None:
return os.path.join(project_path, "project_files")
- projectfiles_path = os.path.join(self.GetProjectPath(), "project_files")
+ projectfiles_path = os.path.join(
+ self.GetProjectPath(), "project_files")
if not os.path.exists(projectfiles_path):
os.mkdir(projectfiles_path)
return projectfiles_path
@@ -414,7 +427,8 @@
def SetProjectDefaultConfiguration(self):
# Sets default task and instance for new project
- config = self.Project.getconfiguration(self.GetProjectMainConfigurationName())
+ config = self.Project.getconfiguration(
+ self.GetProjectMainConfigurationName())
resource = config.getresource()[0].getname()
config = config.getname()
resource_tagname = ComputeConfigurationResourceName(config, resource)
@@ -471,7 +485,8 @@
if error is not None:
if self.Project is not None:
(fname_err, lnum, src) = (("PLC",) + error)
- self.logger.write_warning(XSDSchemaErrorMessage.format(a1=fname_err, a2=lnum, a3=src))
+ self.logger.write_warning(
+ XSDSchemaErrorMessage.format(a1=fname_err, a2=lnum, a3=src))
else:
return error, False
if len(self.GetProjectConfigNames()) == 0:
@@ -528,14 +543,17 @@
def CheckNewProjectPath(self, old_project_path, new_project_path):
if old_project_path == new_project_path:
message = (_("Save path is the same as path of a project! \n"))
- dialog = wx.MessageDialog(self.AppFrame, message, _("Error"), wx.OK | wx.ICON_ERROR)
+ dialog = wx.MessageDialog(
+ self.AppFrame, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
return False
else:
plc_file = os.path.join(new_project_path, "plc.xml")
if os.path.isfile(plc_file):
- message = (_("Selected directory already contains another project. Overwrite? \n"))
- dialog = wx.MessageDialog(self.AppFrame, message, _("Error"), wx.YES_NO | wx.ICON_ERROR)
+ message = (
+ _("Selected directory already contains another project. Overwrite? \n"))
+ dialog = wx.MessageDialog(
+ self.AppFrame, message, _("Error"), wx.YES_NO | wx.ICON_ERROR)
answer = dialog.ShowModal()
return answer == wx.ID_YES
return True
@@ -543,7 +561,8 @@
def SaveProject(self, from_project_path=None):
if self.CheckProjectPathPerm(False):
if from_project_path is not None:
- old_projectfiles_path = self._getProjectFilesPath(from_project_path)
+ old_projectfiles_path = self._getProjectFilesPath(
+ from_project_path)
if os.path.isdir(old_projectfiles_path):
shutil.copytree(old_projectfiles_path,
self._getProjectFilesPath(self.ProjectPath))
@@ -558,7 +577,8 @@
path = os.getenv("USERPROFILE")
else:
path = os.getenv("HOME")
- dirdialog = wx.DirDialog(self.AppFrame, _("Choose a directory to save project"), path, wx.DD_NEW_DIR_BUTTON)
+ dirdialog = wx.DirDialog(
+ self.AppFrame, _("Choose a directory to save project"), path, wx.DD_NEW_DIR_BUTTON)
answer = dirdialog.ShowModal()
dirdialog.Destroy()
if answer == wx.ID_OK:
@@ -582,7 +602,8 @@
if len(self.Libraries) == 0:
return [], [], ()
self.GetIECProgramsAndVariables()
- LibIECCflags = '"-I%s" -Wno-unused-function' % os.path.abspath(self.GetIECLibPath())
+ LibIECCflags = '"-I%s" -Wno-unused-function' % os.path.abspath(
+ self.GetIECLibPath())
LocatedCCodeAndFlags = []
Extras = []
for lib in self.Libraries:
@@ -590,7 +611,7 @@
LocatedCCodeAndFlags.append(res[:2])
if len(res) > 2:
Extras.extend(res[2:])
- return map(list, zip(*LocatedCCodeAndFlags))+[tuple(Extras)]
+ return map(list, zip(*LocatedCCodeAndFlags)) + [tuple(Extras)]
# Update PLCOpenEditor ConfNode Block types from loaded confnodes
def RefreshConfNodesBlockLists(self):
@@ -656,7 +677,8 @@
self.DefaultBuildPath = os.path.join(self.ProjectPath, "build")
# Create a build path in temp folder
else:
- self.DefaultBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build")
+ self.DefaultBuildPath = os.path.join(
+ tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build")
if not os.path.exists(self.DefaultBuildPath):
os.makedirs(self.DefaultBuildPath)
@@ -681,19 +703,23 @@
locations = []
filepath = os.path.join(self._getBuildPath(), "LOCATED_VARIABLES.h")
if os.path.isfile(filepath):
- # IEC2C compiler generate a list of located variables : LOCATED_VARIABLES.h
- location_file = open(os.path.join(self._getBuildPath(), "LOCATED_VARIABLES.h"))
+ # IEC2C compiler generate a list of located variables :
+ # LOCATED_VARIABLES.h
+ location_file = open(
+ os.path.join(self._getBuildPath(), "LOCATED_VARIABLES.h"))
# each line of LOCATED_VARIABLES.h declares a located variable
lines = [line.strip() for line in location_file.readlines()]
# This regular expression parses the lines genereated by IEC2C
- LOCATED_MODEL = re.compile("__LOCATED_VAR\((?P<IEC_TYPE>[A-Z]*),(?P<NAME>[_A-Za-z0-9]*),(?P<DIR>[QMI])(?:,(?P<SIZE>[XBWDL]))?,(?P<LOC>[,0-9]*)\)")
+ LOCATED_MODEL = re.compile(
+ "__LOCATED_VAR\((?P<IEC_TYPE>[A-Z]*),(?P<NAME>[_A-Za-z0-9]*),(?P<DIR>[QMI])(?:,(?P<SIZE>[XBWDL]))?,(?P<LOC>[,0-9]*)\)")
for line in lines:
# If line match RE,
result = LOCATED_MODEL.match(line)
if result:
# Get the resulting dict
resdict = result.groupdict()
- # rewrite string for variadic location as a tuple of integers
+ # rewrite string for variadic location as a tuple of
+ # integers
resdict['LOC'] = tuple(map(int, resdict['LOC'].split(',')))
# set located size to 'X' if not given
if not resdict['SIZE']:
@@ -719,16 +745,20 @@
# Update PLCOpenEditor ConfNode Block types before generate ST code
self.RefreshConfNodesBlockLists()
- self.logger.write(_("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n"))
+ self.logger.write(
+ _("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n"))
# ask PLCOpenEditor controller to write ST/IL/SFC code file
- _program, errors, warnings = self.GenerateProgram(self._getIECgeneratedcodepath())
+ _program, errors, warnings = self.GenerateProgram(
+ self._getIECgeneratedcodepath())
if len(warnings) > 0:
- self.logger.write_warning(_("Warnings in ST/IL/SFC code generator :\n"))
+ self.logger.write_warning(
+ _("Warnings in ST/IL/SFC code generator :\n"))
for warning in warnings:
self.logger.write_warning("%s\n" % warning)
if len(errors) > 0:
# Failed !
- self.logger.write_error(_("Error in ST/IL/SFC code generator :\n%s\n") % errors[0])
+ self.logger.write_error(
+ _("Error in ST/IL/SFC code generator :\n%s\n") % errors[0])
return False
plc_file = open(self._getIECcodepath(), "w")
# Add ST Library from confnodes
@@ -763,9 +793,11 @@
self._getIECcodepath())
try:
- # Invoke compiler. Output files are listed to stdout, errors to stderr
+ # Invoke compiler.
+ # Output files are listed to stdout, errors to stderr
status, result, err_result = ProcessLogger(self.logger, buildcmd,
- no_stdout=True, no_stderr=True).spin()
+ no_stdout=True,
+ no_stderr=True).spin()
except Exception, e:
self.logger.write_error(buildcmd + "\n")
self.logger.write_error(repr(e) + "\n")
@@ -794,29 +826,36 @@
if first_line <= i <= last_line:
if last_section is not None:
- self.logger.write_warning("In section: " + last_section)
+ self.logger.write_warning(
+ "In section: " + last_section)
last_section = None # only write section once
self.logger.write_warning("%04d: %s" % (i, line))
f.close()
- self.logger.write_error(_("Error : IEC to C compiler returned %d\n") % status)
+ self.logger.write_error(
+ _("Error : IEC to C compiler returned %d\n") % status)
return False
# Now extract C files of stdout
- C_files = [fname for fname in result.splitlines() if fname[-2:] == ".c" or fname[-2:] == ".C"]
+ C_files = [fname for fname in result.splitlines() if fname[
+ -2:] == ".c" or fname[-2:] == ".C"]
# remove those that are not to be compiled because included by others
C_files.remove("POUS.c")
if not C_files:
- self.logger.write_error(_("Error : At least one configuration and one resource must be declared in PLC !\n"))
+ self.logger.write_error(
+ _("Error : At least one configuration and one resource must be declared in PLC !\n"))
return False
# transform those base names to full names with path
- C_files = map(lambda filename: os.path.join(buildpath, filename), C_files)
+ C_files = map(
+ lambda filename: os.path.join(buildpath, filename), C_files)
# prepend beremiz include to configuration header
- H_files = [fname for fname in result.splitlines() if fname[-2:] == ".h" or fname[-2:] == ".H"]
+ H_files = [fname for fname in result.splitlines() if fname[
+ -2:] == ".h" or fname[-2:] == ".H"]
H_files.remove("LOCATED_VARIABLES.h")
- H_files = map(lambda filename: os.path.join(buildpath, filename), H_files)
+ H_files = map(
+ lambda filename: os.path.join(buildpath, filename), H_files)
for H_file in H_files:
with file(H_file, 'r') as original:
data = original.read()
@@ -824,7 +863,8 @@
modified.write('#include "beremiz.h"\n' + data)
self.logger.write(_("Extracting Located Variables...\n"))
- # Keep track of generated located variables for later use by self._Generate_C
+ # Keep track of generated located variables for later use by
+ # self._Generate_C
self.PLCGeneratedLocatedVars = self.GetLocations()
# Keep track of generated C files for later use by self.CTNGenerate_C
self.PLCGeneratedCFiles = C_files
@@ -859,11 +899,11 @@
else:
return None
- #######################################################################
+ #
#
# C CODE GENERATION METHODS
#
- #######################################################################
+ #
def CTNGenerate_C(self, buildpath, locations):
"""
@@ -902,7 +942,8 @@
csvfile = os.path.join(self._getBuildPath(), "VARIABLES.csv")
# describes CSV columns
ProgramsListAttributeName = ["num", "C_path", "type"]
- VariablesListAttributeName = ["num", "vartype", "IEC_path", "C_path", "type"]
+ VariablesListAttributeName = [
+ "num", "vartype", "IEC_path", "C_path", "type"]
self._ProgramList = []
self._VariablesList = []
self._DbgVariablesList = []
@@ -922,9 +963,11 @@
# first section contains programs
for line in ListGroup[0]:
# Split and Maps each field to dictionnary entries
- attrs = dict(zip(ProgramsListAttributeName, line.strip().split(';')))
+ attrs = dict(
+ zip(ProgramsListAttributeName, line.strip().split(';')))
# Truncate "C_path" to remove conf an resources names
- attrs["C_path"] = '__'.join(attrs["C_path"].split(".", 2)[1:])
+ attrs["C_path"] = '__'.join(
+ attrs["C_path"].split(".", 2)[1:])
# Push this dictionnary into result.
self._ProgramList.append(attrs)
@@ -933,7 +976,8 @@
Idx = 0
for line in ListGroup[1]:
# Split and Maps each field to dictionnary entries
- attrs = dict(zip(VariablesListAttributeName, line.strip().split(';')))
+ attrs = dict(
+ zip(VariablesListAttributeName, line.strip().split(';')))
# Truncate "C_path" to remove conf an resources names
parts = attrs["C_path"].split(".", 2)
if len(parts) > 2:
@@ -964,7 +1008,8 @@
self._Ticktime = int(ListGroup[2][0])
except Exception:
- self.logger.write_error(_("Cannot open/parse VARIABLES.csv!\n"))
+ self.logger.write_error(
+ _("Cannot open/parse VARIABLES.csv!\n"))
self.logger.write_error(traceback.format_exc())
self.ResetIECProgramsAndVariables()
return False
@@ -1034,16 +1079,16 @@
"retrieve_calls": "\n ".join([
"__retrieve_%s();" % locstr for locstr in locstrs]),
"publish_calls": "\n ".join([ # Call publish in reverse order
- "__publish_%s();" % locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]),
+ "__publish_%s();" % locstrs[i - 1] for i in xrange(len(locstrs), 0, -1)]),
"init_calls": "\n ".join([
- "init_level=%d; " % (i+1) +
+ "init_level=%d; " % (i + 1) +
"if((res = __init_%s(argc,argv))){" % locstr +
# "printf(\"%s\"); "%locstr + #for debug
"return res;}" for i, locstr in enumerate(locstrs)]),
"cleanup_calls": "\n ".join([
"if(init_level >= %d) " % i +
- "__cleanup_%s();" % locstrs[i-1] for i in xrange(len(locstrs), 0, -1)])
- }
+ "__cleanup_%s();" % locstrs[i - 1] for i in xrange(len(locstrs), 0, -1)])
+ }
else:
plc_main_code = targets.GetCode("plc_main_head.c") % {
"calls_prototypes": "\n",
@@ -1052,7 +1097,8 @@
"init_calls": "\n",
"cleanup_calls": "\n"
}
- plc_main_code += targets.GetTargetCode(self.GetTarget().getcontent().getLocalTag())
+ plc_main_code += targets.GetTargetCode(
+ self.GetTarget().getcontent().getLocalTag())
plc_main_code += targets.GetCode("plc_main_tail.c")
return plc_main_code
@@ -1124,21 +1170,25 @@
buildpath,
self.PLCGeneratedLocatedVars)
except Exception:
- self.logger.write_error(_("Runtime IO extensions C code generation failed !\n"))
+ self.logger.write_error(
+ _("Runtime IO extensions C code generation failed !\n"))
self.logger.write_error(traceback.format_exc())
self.ResetBuildMD5()
return False
# Generate C code and compilation params from liraries
try:
- LibCFilesAndCFLAGS, LibLDFLAGS, LibExtraFiles = self.GetLibrariesCCode(buildpath)
+ LibCFilesAndCFLAGS, LibLDFLAGS, LibExtraFiles = self.GetLibrariesCCode(
+ buildpath)
except Exception:
- self.logger.write_error(_("Runtime library extensions C code generation failed !\n"))
+ self.logger.write_error(
+ _("Runtime library extensions C code generation failed !\n"))
self.logger.write_error(traceback.format_exc())
self.ResetBuildMD5()
return False
- self.LocationCFilesAndCFLAGS = LibCFilesAndCFLAGS + CTNLocationCFilesAndCFLAGS
+ self.LocationCFilesAndCFLAGS = LibCFilesAndCFLAGS + \
+ CTNLocationCFilesAndCFLAGS
self.LDFLAGS = CTNLDFLAGS + LibLDFLAGS
ExtraFiles = CTNExtraFiles + LibExtraFiles
@@ -1157,7 +1207,8 @@
del ExtraFiles
# Header file for extensions
- open(os.path.join(buildpath, "beremiz.h"), "w").write(targets.GetHeader())
+ open(os.path.join(buildpath, "beremiz.h"), "w").write(
+ targets.GetHeader())
# Template based part of C code generation
# files are stacked at the beginning, as files of confnode tree root
@@ -1176,10 +1227,12 @@
raise Exception
code_path = os.path.join(buildpath, filename)
open(code_path, "w").write(code)
- # Insert this file as first file to be compiled at root confnode
- self.LocationCFilesAndCFLAGS[0][1].insert(0, (code_path, self.plcCFLAGS))
+ # Insert this file as first file to be compiled at root
+ # confnode
+ self.LocationCFilesAndCFLAGS[0][1].insert(
+ 0, (code_path, self.plcCFLAGS))
except Exception:
- self.logger.write_error(name+_(" generation failed !\n"))
+ self.logger.write_error(name + _(" generation failed !\n"))
self.logger.write_error(traceback.format_exc())
self.ResetBuildMD5()
return False
@@ -1189,12 +1242,16 @@
def ShowError(self, logger, from_location, to_location):
chunk_infos = self.GetChunkInfos(from_location, to_location)
for infos, (start_row, start_col) in chunk_infos:
- row = 1 if from_location[0] < start_row else (from_location[0] - start_row)
- col = 1 if (start_row != from_location[0]) else (from_location[1] - start_col)
+ row = 1 if from_location[0] < start_row else (
+ from_location[0] - start_row)
+ col = 1 if (start_row != from_location[0]) else (
+ from_location[1] - start_col)
start = (row, col)
- row = 1 if to_location[0] < start_row else (to_location[0] - start_row)
- col = 1 if (start_row != to_location[0]) else (to_location[1] - start_col)
+ row = 1 if to_location[0] < start_row else (
+ to_location[0] - start_row)
+ col = 1 if (start_row != to_location[0]) else (
+ to_location[1] - start_col)
end = (row, col)
if self.AppFrame is not None:
@@ -1225,7 +1282,8 @@
if self._IECCodeView is None:
plc_file = self._getIECcodepath()
- self._IECCodeView = IECCodeViewer(self.AppFrame.TabsOpened, "", self.AppFrame, None, instancepath=name)
+ self._IECCodeView = IECCodeViewer(
+ self.AppFrame.TabsOpened, "", self.AppFrame, None, instancepath=name)
self._IECCodeView.SetTextSyntax("ALL")
self._IECCodeView.SetKeywords(IEC_KEYWORDS)
try:
@@ -1246,7 +1304,8 @@
if self._IECRawCodeView is None:
controler = MiniTextControler(self._getIECrawcodepath(), self)
- self._IECRawCodeView = IECCodeViewer(self.AppFrame.TabsOpened, "", self.AppFrame, controler, instancepath=name)
+ self._IECRawCodeView = IECCodeViewer(
+ self.AppFrame.TabsOpened, "", self.AppFrame, controler, instancepath=name)
self._IECRawCodeView.SetTextSyntax("ALL")
self._IECRawCodeView.SetKeywords(IEC_KEYWORDS)
self._IECRawCodeView.RefreshView()
@@ -1260,7 +1319,8 @@
elif name == "Project Files":
if self._ProjectFilesView is None:
- self._ProjectFilesView = FileManagementPanel(self.AppFrame.TabsOpened, self, name, self._getProjectFilesPath(), True)
+ self._ProjectFilesView = FileManagementPanel(
+ self.AppFrame.TabsOpened, self, name, self._getProjectFilesPath(), True)
extensions = []
for extension, name, editor in features.file_editors:
@@ -1302,7 +1362,8 @@
name = "::".join([filepath, editor_name])
editor = editors[editor_name]()
- self._FileEditors[filepath] = editor(self.AppFrame.TabsOpened, self, name, self.AppFrame)
+ self._FileEditors[filepath] = editor(
+ self.AppFrame.TabsOpened, self, name, self.AppFrame)
self._FileEditors[filepath].SetIcon(GetBitmap("FILE"))
if isinstance(self._FileEditors[filepath], DebugViewer):
self._FileEditors[filepath].SetDataProducer(self)
@@ -1352,6 +1413,31 @@
if self.AppFrame is not None:
self.AppFrame.LogViewer.SetLogCounters(log_count)
+ DefaultMethods = {
+ "_Run": False,
+ "_Stop": False,
+ "_Transfer": False,
+ "_Connect": True,
+ "_Disconnect": False
+ }
+
+ MethodsFromStatus = {
+ "Started": {"_Stop": True,
+ "_Transfer": True,
+ "_Connect": False,
+ "_Disconnect": True},
+ "Stopped": {"_Run": True,
+ "_Transfer": True,
+ "_Connect": False,
+ "_Disconnect": True},
+ "Empty": {"_Transfer": True,
+ "_Connect": False,
+ "_Disconnect": True},
+ "Broken": {"_Connect": False,
+ "_Disconnect": True},
+ "Disconnected": {},
+ }
+
def UpdateMethodsFromPLCStatus(self):
updated = False
status = None
@@ -1364,32 +1450,24 @@
self._SetConnector(None, False)
status = "Disconnected"
if self.previous_plcstate != status:
- for args in {
- "Started": [("_Run", False),
- ("_Stop", True)],
- "Stopped": [("_Run", True),
- ("_Stop", False)],
- "Empty": [("_Run", False),
- ("_Stop", False)],
- "Broken": [],
- "Disconnected": [("_Run", False),
- ("_Stop", False),
- ("_Transfer", False),
- ("_Connect", True),
- ("_Disconnect", False)],
- }.get(status, []):
- self.ShowMethod(*args)
+ allmethods = self.DefaultMethods.copy()
+ allmethods.update(
+ self.MethodsFromStatus.get(status, {}))
+ for method, active in allmethods.items():
+ self.ShowMethod(method, active)
self.previous_plcstate = status
if self.AppFrame is not None:
updated = True
self.AppFrame.RefreshStatusToolBar()
if status == "Disconnected":
- self.AppFrame.ConnectionStatusBar.SetStatusText(self.GetTextStatus(status), 1)
+ self.AppFrame.ConnectionStatusBar.SetStatusText(
+ self.GetTextStatus(status), 1)
self.AppFrame.ConnectionStatusBar.SetStatusText('', 2)
else:
self.AppFrame.ConnectionStatusBar.SetStatusText(
_("Connected to URI: %s") % self.BeremizRoot.getURI_location().strip(), 1)
- self.AppFrame.ConnectionStatusBar.SetStatusText(self.GetTextStatus(status), 2)
+ self.AppFrame.ConnectionStatusBar.SetStatusText(
+ self.GetTextStatus(status), 2)
return updated
def GetTextStatus(self, status):
@@ -1399,12 +1477,13 @@
"Empty": _("Empty"),
"Broken": _("Broken"),
"Disconnected": _("Disconnected")
- }
+ }
return msgs.get(status, status)
def ShowPLCProgress(self, status="", progress=0):
self.AppFrame.ProgressStatusBar.Show()
- self.AppFrame.ConnectionStatusBar.SetStatusText(self.GetTextStatus(status), 1)
+ self.AppFrame.ConnectionStatusBar.SetStatusText(
+ self.GetTextStatus(status), 1)
self.AppFrame.ProgressStatusBar.SetValue(progress)
def HidePLCProgress(self):
@@ -1420,19 +1499,23 @@
def SnapshotAndResetDebugValuesBuffers(self):
if self._connector is not None:
plc_status, Traces = self._connector.GetTraceVariables()
- # print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
+ # print [dict.keys() for IECPath, (dict, log, status, fvalue) in
+ # self.IECdebug_datas.items()]
if plc_status == "Started":
if len(Traces) > 0:
for debug_tick, debug_buff in Traces:
- debug_vars = UnpackDebugBuffer(debug_buff, self.TracedIECTypes)
+ debug_vars = UnpackDebugBuffer(
+ debug_buff, self.TracedIECTypes)
if debug_vars is not None and len(debug_vars) == len(self.TracedIECPath):
for IECPath, values_buffer, value in izip(
self.TracedIECPath,
self.DebugValuesBuffers,
debug_vars):
- IECdebug_data = self.IECdebug_datas.get(IECPath, None)
+ IECdebug_data = self.IECdebug_datas.get(
+ IECPath, None)
if IECdebug_data is not None and value is not None:
- forced = IECdebug_data[2:4] == ["Forced", value]
+ forced = IECdebug_data[2:4] == [
+ "Forced", value]
if not IECdebug_data[4] and len(values_buffer) > 0:
values_buffer[-1] = (value, forced)
else:
@@ -1461,14 +1544,17 @@
IECPathsToPop.append(IECPath)
elif IECPath != "__tick__":
# Convert
- Idx, IEC_Type = self._IECPathToIdx.get(IECPath, (None, None))
+ Idx, IEC_Type = self._IECPathToIdx.get(
+ IECPath, (None, None))
if Idx is not None:
if IEC_Type in DebugTypesSize:
Idxs.append((Idx, IEC_Type, fvalue, IECPath))
else:
- self.logger.write_warning(_("Debug: Unsupported type to debug '%s'\n") % IEC_Type)
+ self.logger.write_warning(
+ _("Debug: Unsupported type to debug '%s'\n") % IEC_Type)
else:
- self.logger.write_warning(_("Debug: Unknown variable '%s'\n") % IECPath)
+ self.logger.write_warning(
+ _("Debug: Unknown variable '%s'\n") % IECPath)
for IECPathToPop in IECPathsToPop:
self.IECdebug_datas.pop(IECPathToPop)
@@ -1495,8 +1581,10 @@
# Links between PLC located variables and real variables are not ready
if self.IsPLCStarted():
# Timer to prevent rapid-fire when registering many variables
- # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead
- self.DebugTimer = Timer(0.5, wx.CallAfter, args=[self.RegisterDebugVarToConnector])
+ # use wx.CallAfter use keep using same thread. TODO : use wx.Timer
+ # instead
+ self.DebugTimer = Timer(
+ 0.5, wx.CallAfter, args=[self.RegisterDebugVarToConnector])
# Rearm anti-rapid-fire timer
self.DebugTimer.start()
@@ -1600,9 +1688,11 @@
if len(self.TracedIECPath) == len(buffers):
for IECPath, values in izip(self.TracedIECPath, buffers):
if len(values) > 0:
- self.CallWeakcallables(IECPath, "NewValues", debug_ticks, values)
+ self.CallWeakcallables(
+ IECPath, "NewValues", debug_ticks, values)
if len(debug_ticks) > 0:
- self.CallWeakcallables("__tick__", "NewDataAvailable", debug_ticks)
+ self.CallWeakcallables(
+ "__tick__", "NewDataAvailable", debug_ticks)
delay = time.time() - start_time
next_refresh = max(REFRESH_PERIOD - delay, 0.2 * delay)
@@ -1667,7 +1757,8 @@
def _Connect(self):
# don't accept re-connetion if already connected
if self._connector is not None:
- self.logger.write_error(_("Already connected. Please disconnect\n"))
+ self.logger.write_error(
+ _("Already connected. Please disconnect\n"))
return
# Get connector uri
@@ -1705,7 +1796,8 @@
try:
self._SetConnector(connectors.ConnectorFactory(uri, self))
except Exception:
- self.logger.write_error(_("Exception while connecting %s!\n") % uri)
+ self.logger.write_error(
+ _("Exception while connecting %s!\n") % uri)
self.logger.write_error(traceback.format_exc())
# Did connection success ?
@@ -1713,10 +1805,6 @@
# Oups.
self.logger.write_error(_("Connection failed to %s!\n") % uri)
else:
- self.ShowMethod("_Connect", False)
- self.ShowMethod("_Disconnect", True)
- self.ShowMethod("_Transfer", True)
-
self.CompareLocalAndRemotePLC()
# Init with actual PLC status and print it
@@ -1726,7 +1814,8 @@
self.logger.write(_("Debugger ready\n"))
self._connect_debug()
else:
- self.logger.write_warning(_("Debug does not match PLC - stop/transfert/start to re-enable\n"))
+ self.logger.write_warning(
+ _("Debug does not match PLC - stop/transfert/start to re-enable\n"))
def CompareLocalAndRemotePLC(self):
if self._connector is None:
@@ -1737,7 +1826,8 @@
if MD5 is not None:
if not self._connector.MatchMD5(MD5):
# self.logger.write_warning(
- # _("Latest build does not match with target, please transfer.\n"))
+ # _("Latest build does not match with target, please
+ # transfer.\n"))
self.EnableMethod("_Transfer", True)
else:
# self.logger.write(
@@ -1770,7 +1860,8 @@
# Check if md5 file is empty : ask user to build PLC
if MD5 is None:
- self.logger.write_error(_("Failed : Must build before transfer.\n"))
+ self.logger.write_error(
+ _("Failed : Must build before transfer.\n"))
return False
# Compare PLC project with PLC on target
@@ -1805,7 +1896,8 @@
self.logger.write_error(_("Transfer failed\n"))
self.HidePLCProgress()
else:
- self.logger.write_error(_("No PLC to transfer (did build succeed ?)\n"))
+ self.logger.write_error(
+ _("No PLC to transfer (did build succeed ?)\n"))
wx.CallAfter(self.UpdateMethodsFromPLCStatus)
--- a/bacnet/BacnetSlaveEditor.py Wed Aug 01 13:09:45 2018 +0300
+++ b/bacnet/BacnetSlaveEditor.py Wed Aug 08 13:46:19 2018 +0200
@@ -23,329 +23,327 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from __future__ import absolute_import
+from collections import Counter
+
import wx
-from collections import Counter
-from pickle import dump
+
+# Import some libraries on Beremiz code
from util.BitmapLibrary import GetBitmap
-
-
-
-# Import some libraries on Beremiz code...
-from controls.CustomGrid import CustomGrid
-from controls.CustomTable import CustomTable
+from controls.CustomGrid import CustomGrid
+from controls.CustomTable import CustomTable
from editors.ConfTreeNodeEditor import ConfTreeNodeEditor
-from graphics.GraphicCommons import ERROR_HIGHLIGHT
-
+from graphics.GraphicCommons import ERROR_HIGHLIGHT
# BACnet Engineering units taken from: ASHRAE 135-2016, clause/chapter 21
-BACnetEngineeringUnits = [
- ('(Acceleration) meters-per-second-per-second (166)', 166 ),
- ('(Area) square-meters (0)', 0 ),
- ('(Area) square-centimeters (116)', 116 ),
- ('(Area) square-feet (1)', 1 ),
- ('(Area) square-inches (115)', 115 ),
- ('(Currency) currency1 (105)', 105 ),
- ('(Currency) currency2 (106)', 106 ),
- ('(Currency) currency3 (107)', 107 ),
- ('(Currency) currency4 (108)', 108 ),
- ('(Currency) currency5 (109)', 109 ),
- ('(Currency) currency6 (110)', 110 ),
- ('(Currency) currency7 (111)', 111 ),
- ('(Currency) currency8 (112)', 112 ),
- ('(Currency) currency9 (113)', 113 ),
- ('(Currency) currency10 (114)', 114 ),
- ('(Electrical) milliamperes (2)', 2 ),
- ('(Electrical) amperes (3)', 3 ),
- ('(Electrical) amperes-per-meter (167)', 167 ),
- ('(Electrical) amperes-per-square-meter (168)', 168 ),
- ('(Electrical) ampere-square-meters (169)', 169 ),
- ('(Electrical) decibels (199)', 199 ),
- ('(Electrical) decibels-millivolt (200)', 200 ),
- ('(Electrical) decibels-volt (201)', 201 ),
- ('(Electrical) farads (170)', 170 ),
- ('(Electrical) henrys (171)', 171 ),
- ('(Electrical) ohms (4)', 4 ),
- ('(Electrical) ohm-meter-squared-per-meter (237)', 237 ),
- ('(Electrical) ohm-meters (172)', 172 ),
- ('(Electrical) milliohms (145)', 145 ),
- ('(Electrical) kilohms (122)', 122 ),
- ('(Electrical) megohms (123)', 123 ),
- ('(Electrical) microsiemens (190)', 190 ),
- ('(Electrical) millisiemens (202)', 202 ),
- ('(Electrical) siemens (173)', 173 ),
- ('(Electrical) siemens-per-meter (174)', 174 ),
- ('(Electrical) teslas (175)', 175 ),
- ('(Electrical) volts (5)', 5 ),
- ('(Electrical) millivolts (124)', 124 ),
- ('(Electrical) kilovolts (6)', 6 ),
- ('(Electrical) megavolts (7)', 7 ),
- ('(Electrical) volt-amperes (8)', 8 ),
- ('(Electrical) kilovolt-amperes (9)', 9 ),
- ('(Electrical) megavolt-amperes (10)', 10 ),
- ('(Electrical) volt-amperes-reactive (11)', 11 ),
- ('(Electrical) kilovolt-amperes-reactive (12)', 12 ),
- ('(Electrical) megavolt-amperes-reactive (13)', 13 ),
- ('(Electrical) volts-per-degree-kelvin (176)', 176 ),
- ('(Electrical) volts-per-meter (177)', 177 ),
- ('(Electrical) degrees-phase (14)', 14 ),
- ('(Electrical) power-factor (15)', 15 ),
- ('(Electrical) webers (178)', 178 ),
- ('(Energy) ampere-seconds (238)', 238 ),
- ('(Energy) volt-ampere-hours (239)', 239 ),
- ('(Energy) kilovolt-ampere-hours (240)', 240 ),
- ('(Energy) megavolt-ampere-hours (241)', 241 ),
- ('(Energy) volt-ampere-hours-reactive (242)', 242 ),
- ('(Energy) kilovolt-ampere-hours-reactive (243)', 243 ),
- ('(Energy) megavolt-ampere-hours-reactive (244)', 244 ),
- ('(Energy) volt-square-hours (245)', 245 ),
- ('(Energy) ampere-square-hours (246)', 246 ),
- ('(Energy) joules (16)', 16 ),
- ('(Energy) kilojoules (17)', 17 ),
- ('(Energy) kilojoules-per-kilogram (125)', 125 ),
- ('(Energy) megajoules (126)', 126 ),
- ('(Energy) watt-hours (18)', 18 ),
- ('(Energy) kilowatt-hours (19)', 19 ),
- ('(Energy) megawatt-hours (146)', 146 ),
- ('(Energy) watt-hours-reactive (203)', 203 ),
- ('(Energy) kilowatt-hours-reactive (204)', 204 ),
- ('(Energy) megawatt-hours-reactive (205)', 205 ),
- ('(Energy) btus (20)', 20 ),
- ('(Energy) kilo-btus (147)', 147 ),
- ('(Energy) mega-btus (148)', 148 ),
- ('(Energy) therms (21)', 21 ),
- ('(Energy) ton-hours (22)', 22 ),
- ('(Enthalpy) joules-per-kilogram-dry-air (23)', 23 ),
- ('(Enthalpy) kilojoules-per-kilogram-dry-air (149)', 149 ),
- ('(Enthalpy) megajoules-per-kilogram-dry-air (150)', 150 ),
- ('(Enthalpy) btus-per-pound-dry-air (24)', 24 ),
- ('(Enthalpy) btus-per-pound (117)', 117 ),
- ('(Entropy) joules-per-degree-kelvin (127)', 127 ),
- ('(Entropy) kilojoules-per-degree-kelvin (151)', 151 ),
- ('(Entropy) megajoules-per-degree-kelvin (152)', 152 ),
- ('(Entropy) joules-per-kilogram-degree-kelvin (128)', 128 ),
- ('(Force) newton (153)', 153 ),
- ('(Frequency) cycles-per-hour (25)', 25 ),
- ('(Frequency) cycles-per-minute (26)', 26 ),
- ('(Frequency) hertz (27)', 27 ),
- ('(Frequency) kilohertz (129)', 129 ),
- ('(Frequency) megahertz (130)', 130 ),
- ('(Frequency) per-hour (131)', 131 ),
- ('(Humidity) grams-of-water-per-kilogram-dry-air (28)', 28 ),
- ('(Humidity) percent-relative-humidity (29)', 29 ),
- ('(Length) micrometers (194)', 194 ),
- ('(Length) millimeters (30)', 30 ),
- ('(Length) centimeters (118)', 118 ),
- ('(Length) kilometers (193)', 193 ),
- ('(Length) meters (31)', 31 ),
- ('(Length) inches (32)', 32 ),
- ('(Length) feet (33)', 33 ),
- ('(Light) candelas (179)', 179 ),
- ('(Light) candelas-per-square-meter (180)', 180 ),
- ('(Light) watts-per-square-foot (34)', 34 ),
- ('(Light) watts-per-square-meter (35)', 35 ),
- ('(Light) lumens (36)', 36 ),
- ('(Light) luxes (37)', 37 ),
- ('(Light) foot-candles (38)', 38 ),
- ('(Mass) milligrams (196)', 196 ),
- ('(Mass) grams (195)', 195 ),
- ('(Mass) kilograms (39)', 39 ),
- ('(Mass) pounds-mass (40)', 40 ),
- ('(Mass) tons (41)', 41 ),
- ('(Mass Flow) grams-per-second (154)', 154 ),
- ('(Mass Flow) grams-per-minute (155)', 155 ),
- ('(Mass Flow) kilograms-per-second (42)', 42 ),
- ('(Mass Flow) kilograms-per-minute (43)', 43 ),
- ('(Mass Flow) kilograms-per-hour (44)', 44 ),
- ('(Mass Flow) pounds-mass-per-second (119)', 119 ),
- ('(Mass Flow) pounds-mass-per-minute (45)', 45 ),
- ('(Mass Flow) pounds-mass-per-hour (46)', 46 ),
- ('(Mass Flow) tons-per-hour (156)', 156 ),
- ('(Power) milliwatts (132)', 132 ),
- ('(Power) watts (47)', 47 ),
- ('(Power) kilowatts (48)', 48 ),
- ('(Power) megawatts (49)', 49 ),
- ('(Power) btus-per-hour (50)', 50 ),
- ('(Power) kilo-btus-per-hour (157)', 157 ),
- ('(Power) joule-per-hours (247)', 247 ),
- ('(Power) horsepower (51)', 51 ),
- ('(Power) tons-refrigeration (52)', 52 ),
- ('(Pressure) pascals (53)', 53 ),
- ('(Pressure) hectopascals (133)', 133 ),
- ('(Pressure) kilopascals (54)', 54 ),
- ('(Pressure) millibars (134)', 134 ),
- ('(Pressure) bars (55)', 55 ),
- ('(Pressure) pounds-force-per-square-inch (56)', 56 ),
- ('(Pressure) millimeters-of-water (206)', 206 ),
- ('(Pressure) centimeters-of-water (57)', 57 ),
- ('(Pressure) inches-of-water (58)', 58 ),
- ('(Pressure) millimeters-of-mercury (59)', 59 ),
- ('(Pressure) centimeters-of-mercury (60)', 60 ),
- ('(Pressure) inches-of-mercury (61)', 61 ),
- ('(Temperature) degrees-celsius (62)', 62 ),
- ('(Temperature) degrees-kelvin (63)', 63 ),
- ('(Temperature) degrees-kelvin-per-hour (181)', 181 ),
- ('(Temperature) degrees-kelvin-per-minute (182)', 182 ),
- ('(Temperature) degrees-fahrenheit (64)', 64 ),
- ('(Temperature) degree-days-celsius (65)', 65 ),
- ('(Temperature) degree-days-fahrenheit (66)', 66 ),
- ('(Temperature) delta-degrees-fahrenheit (120)', 120 ),
- ('(Temperature) delta-degrees-kelvin (121)', 121 ),
- ('(Time) years (67)', 67 ),
- ('(Time) months (68)', 68 ),
- ('(Time) weeks (69)', 69 ),
- ('(Time) days (70)', 70 ),
- ('(Time) hours (71)', 71 ),
- ('(Time) minutes (72)', 72 ),
- ('(Time) seconds (73)', 73 ),
- ('(Time) hundredths-seconds (158)', 158 ),
- ('(Time) milliseconds (159)', 159 ),
- ('(Torque) newton-meters (160)', 160 ),
- ('(Velocity) millimeters-per-second (161)', 161 ),
- ('(Velocity) millimeters-per-minute (162)', 162 ),
- ('(Velocity) meters-per-second (74)', 74 ),
- ('(Velocity) meters-per-minute (163)', 163 ),
- ('(Velocity) meters-per-hour (164)', 164 ),
- ('(Velocity) kilometers-per-hour (75)', 75 ),
- ('(Velocity) feet-per-second (76)', 76 ),
- ('(Velocity) feet-per-minute (77)', 77 ),
- ('(Velocity) miles-per-hour (78)', 78 ),
- ('(Volume) cubic-feet (79)', 79 ),
- ('(Volume) cubic-meters (80)', 80 ),
- ('(Volume) imperial-gallons (81)', 81 ),
- ('(Volume) milliliters (197)', 197 ),
- ('(Volume) liters (82)', 82 ),
- ('(Volume) us-gallons (83)', 83 ),
- ('(Volumetric Flow) cubic-feet-per-second (142)', 142 ),
- ('(Volumetric Flow) cubic-feet-per-minute (84)', 84 ),
- ('(Volumetric Flow) million-standard-cubic-feet-per-minute (254)', 254 ),
- ('(Volumetric Flow) cubic-feet-per-hour (191)', 191 ),
- ('(Volumetric Flow) cubic-feet-per-day (248)', 248 ),
- ('(Volumetric Flow) standard-cubic-feet-per-day (47808)', 47808 ),
- ('(Volumetric Flow) million-standard-cubic-feet-per-day (47809)', 47809 ),
- ('(Volumetric Flow) thousand-cubic-feet-per-day (47810)', 47810 ),
- ('(Volumetric Flow) thousand-standard-cubic-feet-per-day (47811)', 47811 ),
- ('(Volumetric Flow) pounds-mass-per-day (47812)', 47812 ),
- ('(Volumetric Flow) cubic-meters-per-second (85)', 85 ),
- ('(Volumetric Flow) cubic-meters-per-minute (165)', 165 ),
- ('(Volumetric Flow) cubic-meters-per-hour (135)', 135 ),
- ('(Volumetric Flow) cubic-meters-per-day (249)', 249 ),
- ('(Volumetric Flow) imperial-gallons-per-minute (86)', 86 ),
- ('(Volumetric Flow) milliliters-per-second (198)', 198 ),
- ('(Volumetric Flow) liters-per-second (87)', 87 ),
- ('(Volumetric Flow) liters-per-minute (88)', 88 ),
- ('(Volumetric Flow) liters-per-hour (136)', 136 ),
- ('(Volumetric Flow) us-gallons-per-minute (89)', 89 ),
- ('(Volumetric Flow) us-gallons-per-hour (192)', 192 ),
- ('(Other) degrees-angular (90)', 90 ),
- ('(Other) degrees-celsius-per-hour (91)', 91 ),
- ('(Other) degrees-celsius-per-minute (92)', 92 ),
- ('(Other) degrees-fahrenheit-per-hour (93)', 93 ),
- ('(Other) degrees-fahrenheit-per-minute (94)', 94 ),
- ('(Other) joule-seconds (183)', 183 ),
- ('(Other) kilograms-per-cubic-meter (186)', 186 ),
- ('(Other) kilowatt-hours-per-square-meter (137)', 137 ),
- ('(Other) kilowatt-hours-per-square-foot (138)', 138 ),
- ('(Other) watt-hours-per-cubic-meter (250)', 250 ),
- ('(Other) joules-per-cubic-meter (251)', 251 ),
- ('(Other) megajoules-per-square-meter (139)', 139 ),
- ('(Other) megajoules-per-square-foot (140)', 140 ),
- ('(Other) mole-percent (252)', 252 ),
- ('(Other) no-units (95)', 95 ),
- ('(Other) newton-seconds (187)', 187 ),
- ('(Other) newtons-per-meter (188)', 188 ),
- ('(Other) parts-per-million (96)', 96 ),
- ('(Other) parts-per-billion (97)', 97 ),
- ('(Other) pascal-seconds (253)', 253 ),
- ('(Other) percent (98)', 98 ),
- ('(Other) percent-obscuration-per-foot (143)', 143 ),
- ('(Other) percent-obscuration-per-meter (144)', 144 ),
- ('(Other) percent-per-second (99)', 99 ),
- ('(Other) per-minute (100)', 100 ),
- ('(Other) per-second (101)', 101 ),
- ('(Other) psi-per-degree-fahrenheit (102)', 102 ),
- ('(Other) radians (103)', 103 ),
- ('(Other) radians-per-second (184)', 184 ),
- ('(Other) revolutions-per-minute (104)', 104 ),
- ('(Other) square-meters-per-newton (185)', 185 ),
- ('(Other) watts-per-meter-per-degree-kelvin (189)', 189 ),
- ('(Other) watts-per-square-meter-degree-kelvin (141)', 141 ),
- ('(Other) per-mille (207)', 207 ),
- ('(Other) grams-per-gram (208)', 208 ),
- ('(Other) kilograms-per-kilogram (209)', 209 ),
- ('(Other) grams-per-kilogram (210)', 210 ),
- ('(Other) milligrams-per-gram (211)', 211 ),
- ('(Other) milligrams-per-kilogram (212)', 212 ),
- ('(Other) grams-per-milliliter (213)', 213 ),
- ('(Other) grams-per-liter (214)', 214 ),
- ('(Other) milligrams-per-liter (215)', 215 ),
- ('(Other) micrograms-per-liter (216)', 216 ),
- ('(Other) grams-per-cubic-meter (217)', 217 ),
- ('(Other) milligrams-per-cubic-meter (218)', 218 ),
- ('(Other) micrograms-per-cubic-meter (219)', 219 ),
- ('(Other) nanograms-per-cubic-meter (220)', 220 ),
- ('(Other) grams-per-cubic-centimeter (221)', 221 ),
- ('(Other) becquerels (222)', 222 ),
- ('(Other) kilobecquerels (223)', 223 ),
- ('(Other) megabecquerels (224)', 224 ),
- ('(Other) gray (225)', 225 ),
- ('(Other) milligray (226)', 226 ),
- ('(Other) microgray (227)', 227 ),
- ('(Other) sieverts (228)', 228 ),
- ('(Other) millisieverts (229)', 229 ),
- ('(Other) microsieverts (230)', 230 ),
- ('(Other) microsieverts-per-hour (231)', 231 ),
- ('(Other) millirems (47814)', 47814 ),
- ('(Other) millirems-per-hour (47815)', 47815 ),
- ('(Other) decibels-a (232)', 232 ),
- ('(Other) nephelometric-turbidity-unit (233)', 233 ),
- ('(Other) pH (234)', 234 ),
- ('(Other) grams-per-square-meter (235)', 235 ),
- ('(Other) minutes-per-degree-kelvin (236)', 236 )
- ] # BACnetEngineeringUnits
-
-
-
+BACnetEngineeringUnits = [
+ ('(Acceleration) meters-per-second-per-second (166)', 166),
+ ('(Area) square-meters (0)', 0),
+ ('(Area) square-centimeters (116)', 116),
+ ('(Area) square-feet (1)', 1),
+ ('(Area) square-inches (115)', 115),
+ ('(Currency) currency1 (105)', 105),
+ ('(Currency) currency2 (106)', 106),
+ ('(Currency) currency3 (107)', 107),
+ ('(Currency) currency4 (108)', 108),
+ ('(Currency) currency5 (109)', 109),
+ ('(Currency) currency6 (110)', 110),
+ ('(Currency) currency7 (111)', 111),
+ ('(Currency) currency8 (112)', 112),
+ ('(Currency) currency9 (113)', 113),
+ ('(Currency) currency10 (114)', 114),
+ ('(Electrical) milliamperes (2)', 2),
+ ('(Electrical) amperes (3)', 3),
+ ('(Electrical) amperes-per-meter (167)', 167),
+ ('(Electrical) amperes-per-square-meter (168)', 168),
+ ('(Electrical) ampere-square-meters (169)', 169),
+ ('(Electrical) decibels (199)', 199),
+ ('(Electrical) decibels-millivolt (200)', 200),
+ ('(Electrical) decibels-volt (201)', 201),
+ ('(Electrical) farads (170)', 170),
+ ('(Electrical) henrys (171)', 171),
+ ('(Electrical) ohms (4)', 4),
+ ('(Electrical) ohm-meter-squared-per-meter (237)', 237),
+ ('(Electrical) ohm-meters (172)', 172),
+ ('(Electrical) milliohms (145)', 145),
+ ('(Electrical) kilohms (122)', 122),
+ ('(Electrical) megohms (123)', 123),
+ ('(Electrical) microsiemens (190)', 190),
+ ('(Electrical) millisiemens (202)', 202),
+ ('(Electrical) siemens (173)', 173),
+ ('(Electrical) siemens-per-meter (174)', 174),
+ ('(Electrical) teslas (175)', 175),
+ ('(Electrical) volts (5)', 5),
+ ('(Electrical) millivolts (124)', 124),
+ ('(Electrical) kilovolts (6)', 6),
+ ('(Electrical) megavolts (7)', 7),
+ ('(Electrical) volt-amperes (8)', 8),
+ ('(Electrical) kilovolt-amperes (9)', 9),
+ ('(Electrical) megavolt-amperes (10)', 10),
+ ('(Electrical) volt-amperes-reactive (11)', 11),
+ ('(Electrical) kilovolt-amperes-reactive (12)', 12),
+ ('(Electrical) megavolt-amperes-reactive (13)', 13),
+ ('(Electrical) volts-per-degree-kelvin (176)', 176),
+ ('(Electrical) volts-per-meter (177)', 177),
+ ('(Electrical) degrees-phase (14)', 14),
+ ('(Electrical) power-factor (15)', 15),
+ ('(Electrical) webers (178)', 178),
+ ('(Energy) ampere-seconds (238)', 238),
+ ('(Energy) volt-ampere-hours (239)', 239),
+ ('(Energy) kilovolt-ampere-hours (240)', 240),
+ ('(Energy) megavolt-ampere-hours (241)', 241),
+ ('(Energy) volt-ampere-hours-reactive (242)', 242),
+ ('(Energy) kilovolt-ampere-hours-reactive (243)', 243),
+ ('(Energy) megavolt-ampere-hours-reactive (244)', 244),
+ ('(Energy) volt-square-hours (245)', 245),
+ ('(Energy) ampere-square-hours (246)', 246),
+ ('(Energy) joules (16)', 16),
+ ('(Energy) kilojoules (17)', 17),
+ ('(Energy) kilojoules-per-kilogram (125)', 125),
+ ('(Energy) megajoules (126)', 126),
+ ('(Energy) watt-hours (18)', 18),
+ ('(Energy) kilowatt-hours (19)', 19),
+ ('(Energy) megawatt-hours (146)', 146),
+ ('(Energy) watt-hours-reactive (203)', 203),
+ ('(Energy) kilowatt-hours-reactive (204)', 204),
+ ('(Energy) megawatt-hours-reactive (205)', 205),
+ ('(Energy) btus (20)', 20),
+ ('(Energy) kilo-btus (147)', 147),
+ ('(Energy) mega-btus (148)', 148),
+ ('(Energy) therms (21)', 21),
+ ('(Energy) ton-hours (22)', 22),
+ ('(Enthalpy) joules-per-kilogram-dry-air (23)', 23),
+ ('(Enthalpy) kilojoules-per-kilogram-dry-air (149)', 149),
+ ('(Enthalpy) megajoules-per-kilogram-dry-air (150)', 150),
+ ('(Enthalpy) btus-per-pound-dry-air (24)', 24),
+ ('(Enthalpy) btus-per-pound (117)', 117),
+ ('(Entropy) joules-per-degree-kelvin (127)', 127),
+ ('(Entropy) kilojoules-per-degree-kelvin (151)', 151),
+ ('(Entropy) megajoules-per-degree-kelvin (152)', 152),
+ ('(Entropy) joules-per-kilogram-degree-kelvin (128)', 128),
+ ('(Force) newton (153)', 153),
+ ('(Frequency) cycles-per-hour (25)', 25),
+ ('(Frequency) cycles-per-minute (26)', 26),
+ ('(Frequency) hertz (27)', 27),
+ ('(Frequency) kilohertz (129)', 129),
+ ('(Frequency) megahertz (130)', 130),
+ ('(Frequency) per-hour (131)', 131),
+ ('(Humidity) grams-of-water-per-kilogram-dry-air (28)', 28),
+ ('(Humidity) percent-relative-humidity (29)', 29),
+ ('(Length) micrometers (194)', 194),
+ ('(Length) millimeters (30)', 30),
+ ('(Length) centimeters (118)', 118),
+ ('(Length) kilometers (193)', 193),
+ ('(Length) meters (31)', 31),
+ ('(Length) inches (32)', 32),
+ ('(Length) feet (33)', 33),
+ ('(Light) candelas (179)', 179),
+ ('(Light) candelas-per-square-meter (180)', 180),
+ ('(Light) watts-per-square-foot (34)', 34),
+ ('(Light) watts-per-square-meter (35)', 35),
+ ('(Light) lumens (36)', 36),
+ ('(Light) luxes (37)', 37),
+ ('(Light) foot-candles (38)', 38),
+ ('(Mass) milligrams (196)', 196),
+ ('(Mass) grams (195)', 195),
+ ('(Mass) kilograms (39)', 39),
+ ('(Mass) pounds-mass (40)', 40),
+ ('(Mass) tons (41)', 41),
+ ('(Mass Flow) grams-per-second (154)', 154),
+ ('(Mass Flow) grams-per-minute (155)', 155),
+ ('(Mass Flow) kilograms-per-second (42)', 42),
+ ('(Mass Flow) kilograms-per-minute (43)', 43),
+ ('(Mass Flow) kilograms-per-hour (44)', 44),
+ ('(Mass Flow) pounds-mass-per-second (119)', 119),
+ ('(Mass Flow) pounds-mass-per-minute (45)', 45),
+ ('(Mass Flow) pounds-mass-per-hour (46)', 46),
+ ('(Mass Flow) tons-per-hour (156)', 156),
+ ('(Power) milliwatts (132)', 132),
+ ('(Power) watts (47)', 47),
+ ('(Power) kilowatts (48)', 48),
+ ('(Power) megawatts (49)', 49),
+ ('(Power) btus-per-hour (50)', 50),
+ ('(Power) kilo-btus-per-hour (157)', 157),
+ ('(Power) joule-per-hours (247)', 247),
+ ('(Power) horsepower (51)', 51),
+ ('(Power) tons-refrigeration (52)', 52),
+ ('(Pressure) pascals (53)', 53),
+ ('(Pressure) hectopascals (133)', 133),
+ ('(Pressure) kilopascals (54)', 54),
+ ('(Pressure) millibars (134)', 134),
+ ('(Pressure) bars (55)', 55),
+ ('(Pressure) pounds-force-per-square-inch (56)', 56),
+ ('(Pressure) millimeters-of-water (206)', 206),
+ ('(Pressure) centimeters-of-water (57)', 57),
+ ('(Pressure) inches-of-water (58)', 58),
+ ('(Pressure) millimeters-of-mercury (59)', 59),
+ ('(Pressure) centimeters-of-mercury (60)', 60),
+ ('(Pressure) inches-of-mercury (61)', 61),
+ ('(Temperature) degrees-celsius (62)', 62),
+ ('(Temperature) degrees-kelvin (63)', 63),
+ ('(Temperature) degrees-kelvin-per-hour (181)', 181),
+ ('(Temperature) degrees-kelvin-per-minute (182)', 182),
+ ('(Temperature) degrees-fahrenheit (64)', 64),
+ ('(Temperature) degree-days-celsius (65)', 65),
+ ('(Temperature) degree-days-fahrenheit (66)', 66),
+ ('(Temperature) delta-degrees-fahrenheit (120)', 120),
+ ('(Temperature) delta-degrees-kelvin (121)', 121),
+ ('(Time) years (67)', 67),
+ ('(Time) months (68)', 68),
+ ('(Time) weeks (69)', 69),
+ ('(Time) days (70)', 70),
+ ('(Time) hours (71)', 71),
+ ('(Time) minutes (72)', 72),
+ ('(Time) seconds (73)', 73),
+ ('(Time) hundredths-seconds (158)', 158),
+ ('(Time) milliseconds (159)', 159),
+ ('(Torque) newton-meters (160)', 160),
+ ('(Velocity) millimeters-per-second (161)', 161),
+ ('(Velocity) millimeters-per-minute (162)', 162),
+ ('(Velocity) meters-per-second (74)', 74),
+ ('(Velocity) meters-per-minute (163)', 163),
+ ('(Velocity) meters-per-hour (164)', 164),
+ ('(Velocity) kilometers-per-hour (75)', 75),
+ ('(Velocity) feet-per-second (76)', 76),
+ ('(Velocity) feet-per-minute (77)', 77),
+ ('(Velocity) miles-per-hour (78)', 78),
+ ('(Volume) cubic-feet (79)', 79),
+ ('(Volume) cubic-meters (80)', 80),
+ ('(Volume) imperial-gallons (81)', 81),
+ ('(Volume) milliliters (197)', 197),
+ ('(Volume) liters (82)', 82),
+ ('(Volume) us-gallons (83)', 83),
+ ('(Volumetric Flow) cubic-feet-per-second (142)', 142),
+ ('(Volumetric Flow) cubic-feet-per-minute (84)', 84),
+ ('(Volumetric Flow) million-standard-cubic-feet-per-minute (254)', 254),
+ ('(Volumetric Flow) cubic-feet-per-hour (191)', 191),
+ ('(Volumetric Flow) cubic-feet-per-day (248)', 248),
+ ('(Volumetric Flow) standard-cubic-feet-per-day (47808)', 47808),
+ ('(Volumetric Flow) million-standard-cubic-feet-per-day (47809)', 47809),
+ ('(Volumetric Flow) thousand-cubic-feet-per-day (47810)', 47810),
+ ('(Volumetric Flow) thousand-standard-cubic-feet-per-day (47811)', 47811),
+ ('(Volumetric Flow) pounds-mass-per-day (47812)', 47812),
+ ('(Volumetric Flow) cubic-meters-per-second (85)', 85),
+ ('(Volumetric Flow) cubic-meters-per-minute (165)', 165),
+ ('(Volumetric Flow) cubic-meters-per-hour (135)', 135),
+ ('(Volumetric Flow) cubic-meters-per-day (249)', 249),
+ ('(Volumetric Flow) imperial-gallons-per-minute (86)', 86),
+ ('(Volumetric Flow) milliliters-per-second (198)', 198),
+ ('(Volumetric Flow) liters-per-second (87)', 87),
+ ('(Volumetric Flow) liters-per-minute (88)', 88),
+ ('(Volumetric Flow) liters-per-hour (136)', 136),
+ ('(Volumetric Flow) us-gallons-per-minute (89)', 89),
+ ('(Volumetric Flow) us-gallons-per-hour (192)', 192),
+ ('(Other) degrees-angular (90)', 90),
+ ('(Other) degrees-celsius-per-hour (91)', 91),
+ ('(Other) degrees-celsius-per-minute (92)', 92),
+ ('(Other) degrees-fahrenheit-per-hour (93)', 93),
+ ('(Other) degrees-fahrenheit-per-minute (94)', 94),
+ ('(Other) joule-seconds (183)', 183),
+ ('(Other) kilograms-per-cubic-meter (186)', 186),
+ ('(Other) kilowatt-hours-per-square-meter (137)', 137),
+ ('(Other) kilowatt-hours-per-square-foot (138)', 138),
+ ('(Other) watt-hours-per-cubic-meter (250)', 250),
+ ('(Other) joules-per-cubic-meter (251)', 251),
+ ('(Other) megajoules-per-square-meter (139)', 139),
+ ('(Other) megajoules-per-square-foot (140)', 140),
+ ('(Other) mole-percent (252)', 252),
+ ('(Other) no-units (95)', 95),
+ ('(Other) newton-seconds (187)', 187),
+ ('(Other) newtons-per-meter (188)', 188),
+ ('(Other) parts-per-million (96)', 96),
+ ('(Other) parts-per-billion (97)', 97),
+ ('(Other) pascal-seconds (253)', 253),
+ ('(Other) percent (98)', 98),
+ ('(Other) percent-obscuration-per-foot (143)', 143),
+ ('(Other) percent-obscuration-per-meter (144)', 144),
+ ('(Other) percent-per-second (99)', 99),
+ ('(Other) per-minute (100)', 100),
+ ('(Other) per-second (101)', 101),
+ ('(Other) psi-per-degree-fahrenheit (102)', 102),
+ ('(Other) radians (103)', 103),
+ ('(Other) radians-per-second (184)', 184),
+ ('(Other) revolutions-per-minute (104)', 104),
+ ('(Other) square-meters-per-newton (185)', 185),
+ ('(Other) watts-per-meter-per-degree-kelvin (189)', 189),
+ ('(Other) watts-per-square-meter-degree-kelvin (141)', 141),
+ ('(Other) per-mille (207)', 207),
+ ('(Other) grams-per-gram (208)', 208),
+ ('(Other) kilograms-per-kilogram (209)', 209),
+ ('(Other) grams-per-kilogram (210)', 210),
+ ('(Other) milligrams-per-gram (211)', 211),
+ ('(Other) milligrams-per-kilogram (212)', 212),
+ ('(Other) grams-per-milliliter (213)', 213),
+ ('(Other) grams-per-liter (214)', 214),
+ ('(Other) milligrams-per-liter (215)', 215),
+ ('(Other) micrograms-per-liter (216)', 216),
+ ('(Other) grams-per-cubic-meter (217)', 217),
+ ('(Other) milligrams-per-cubic-meter (218)', 218),
+ ('(Other) micrograms-per-cubic-meter (219)', 219),
+ ('(Other) nanograms-per-cubic-meter (220)', 220),
+ ('(Other) grams-per-cubic-centimeter (221)', 221),
+ ('(Other) becquerels (222)', 222),
+ ('(Other) kilobecquerels (223)', 223),
+ ('(Other) megabecquerels (224)', 224),
+ ('(Other) gray (225)', 225),
+ ('(Other) milligray (226)', 226),
+ ('(Other) microgray (227)', 227),
+ ('(Other) sieverts (228)', 228),
+ ('(Other) millisieverts (229)', 229),
+ ('(Other) microsieverts (230)', 230),
+ ('(Other) microsieverts-per-hour (231)', 231),
+ ('(Other) millirems (47814)', 47814),
+ ('(Other) millirems-per-hour (47815)', 47815),
+ ('(Other) decibels-a (232)', 232),
+ ('(Other) nephelometric-turbidity-unit (233)', 233),
+ ('(Other) pH (234)', 234),
+ ('(Other) grams-per-square-meter (235)', 235),
+ ('(Other) minutes-per-degree-kelvin (236)', 236)
+] # BACnetEngineeringUnits
+
+
# ObjectID (22 bits ID + 10 bits type) => max = 2^22-1 = 4194303
# However, ObjectID 4194303 is not allowed!
-# 4194303 is used as a special value when object Id reference is referencing an undefined object
+# 4194303 is used as a special value when object Id reference is referencing an undefined object
# (similar to NULL in C)
BACnetObjectID_MAX = 4194302
BACnetObjectID_NUL = 4194303
-
# A base class
# what would be a purely virtual class in C++
-class ObjectProperties:
+class ObjectProperties(object):
# this __init_() function is currently not beeing used!
+
def __init__(self):
- #nothing to do
+ # nothing to do
return
class BinaryObject(ObjectProperties):
- # 'PropertyNames' will be used as the header for each column of the Object Properties grid!
- # Warning: The rest of the code depends on the existance of an "Object Identifier" and "Object Name"
- # Be sure to use these exact names for these BACnet object properties!
- PropertyNames = ["Object Identifier", "Object Name", "Description"]
- ColumnAlignments = [ wx.ALIGN_RIGHT , wx.ALIGN_LEFT, wx.ALIGN_LEFT]
- ColumnSizes = [ 40 , 80 , 80 ]
- PropertyConfig = {"Object Identifier": {"GridCellEditor" : wx.grid.GridCellNumberEditor,
- "GridCellRenderer" : wx.grid.GridCellNumberRenderer,
- "GridCellEditorParam": "0,4194302"
- # syntax for GridCellNumberEditor -> "min,max"
- # ObjectID (22 bits ID + 10 bits type) => max = 2^22-1
- },
- "Object Name" : {"GridCellEditor" : wx.grid.GridCellTextEditor,
- "GridCellRenderer": wx.grid.GridCellStringRenderer},
- "Description" : {"GridCellEditor" : wx.grid.GridCellTextEditor,
- "GridCellRenderer": wx.grid.GridCellStringRenderer}
- }
-
+ # 'PropertyNames' will be used as the header for each column of the Object Properties grid!
+ # Warning: The rest of the code depends on the existance of an "Object Identifier" and "Object Name"
+ # Be sure to use these exact names for these BACnet object properties!
+ PropertyNames = ["Object Identifier", "Object Name", "Description"]
+ ColumnAlignments = [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
+ ColumnSizes = [40, 80, 80]
+ PropertyConfig = {
+ "Object Identifier": {"GridCellEditor": wx.grid.GridCellNumberEditor,
+ "GridCellRenderer": wx.grid.GridCellNumberRenderer,
+ # syntax for GridCellNumberEditor -> "min,max"
+ # ObjectID (22 bits ID + 10 bits type) => max = 2^22-1
+ "GridCellEditorParam": "0,4194302"},
+ "Object Name": {"GridCellEditor": wx.grid.GridCellTextEditor,
+ "GridCellRenderer": wx.grid.GridCellStringRenderer},
+ "Description": {"GridCellEditor": wx.grid.GridCellTextEditor,
+ "GridCellRenderer": wx.grid.GridCellStringRenderer}
+ }
+
+
class AnalogObject(ObjectProperties):
- # 'PropertyNames' will be used as the header for each column of the Object Properties grid!
- # Warning: The rest of the code depends on the existance of an "Object Identifier" and "Object Name"
+ # 'PropertyNames' will be used as the header for each column of the Object Properties grid!
+ # Warning: The rest of the code depends on the existance of an "Object Identifier" and "Object Name"
# Be sure to use these exact names for these BACnet object properties!
#
# NOTE: Although it is not listed here (so it does not show up in the GUI, this object will also
@@ -353,200 +351,194 @@
# will store the ID corresponding to the "Engineering Units" currently chosen.
# This virtual property is kept synchronised to the "Engineering Units" property
# by the function PropertyChanged() which should be called by the OnCellChange event handler.
- PropertyNames = ["Object Identifier", "Object Name", "Description", "Engineering Units"] #'Unit ID'
- ColumnAlignments = [ wx.ALIGN_RIGHT , wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT ]
- ColumnSizes = [ 40 , 80 , 80 , 200 ]
- PropertyConfig = {"Object Identifier": {"GridCellEditor" : wx.grid.GridCellNumberEditor,
- "GridCellRenderer" : wx.grid.GridCellNumberRenderer,
- "GridCellEditorParam": "0,4194302"
- # syntax for GridCellNumberEditor -> "min,max"
- # ObjectID (22 bits ID + 10 bits type) => max = 2^22-1
- },
- "Object Name" : {"GridCellEditor" : wx.grid.GridCellTextEditor,
- "GridCellRenderer" : wx.grid.GridCellStringRenderer},
- "Description" : {"GridCellEditor" : wx.grid.GridCellTextEditor,
- "GridCellRenderer" : wx.grid.GridCellStringRenderer},
- "Engineering Units": {"GridCellEditor" : wx.grid.GridCellChoiceEditor,
- "GridCellRenderer" : wx.grid.GridCellStringRenderer,
- # use string renderer with choice editor!
- "GridCellEditorParam": ','.join([x[0] for x in BACnetEngineeringUnits])
- # syntax for GridCellChoiceEditor -> comma separated values
- }
- }
-
- # obj_properties should be a dictionary, with keys "Object Identifier", "Object Name", "Description", ...
+ PropertyNames = ["Object Identifier", "Object Name",
+ "Description", "Engineering Units"] # 'Unit ID'
+ ColumnAlignments = [
+ wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
+ ColumnSizes = [40, 80, 80, 200]
+ PropertyConfig = {
+ "Object Identifier": {"GridCellEditor": wx.grid.GridCellNumberEditor,
+ "GridCellRenderer": wx.grid.GridCellNumberRenderer,
+ "GridCellEditorParam": "0,4194302"},
+ "Object Name": {"GridCellEditor": wx.grid.GridCellTextEditor,
+ "GridCellRenderer": wx.grid.GridCellStringRenderer},
+ "Description": {"GridCellEditor": wx.grid.GridCellTextEditor,
+ "GridCellRenderer": wx.grid.GridCellStringRenderer},
+ "Engineering Units": {"GridCellEditor": wx.grid.GridCellChoiceEditor,
+ # use string renderer with choice editor!
+ "GridCellRenderer": wx.grid.GridCellStringRenderer,
+ # syntax for GridCellChoiceEditor -> comma separated values
+ "GridCellEditorParam": ','.join([x[0] for x in BACnetEngineeringUnits])}
+ }
+
+ # obj_properties should be a dictionary, with keys "Object Identifier",
+ # "Object Name", "Description", ...
def UpdateVirtualProperties(self, obj_properties):
- obj_properties["Unit ID"] = [x[1] for x in BACnetEngineeringUnits if x[0] == obj_properties["Engineering Units"]][0]
-
-
+ obj_properties["Unit ID"] = [x[1]
+ for x in BACnetEngineeringUnits if x[0] == obj_properties["Engineering Units"]][0]
+
class MultiSObject(ObjectProperties):
- # 'PropertyNames' will be used as the header for each column of the Object Properties grid!
- # Warning: The rest of the code depends on the existance of an "Object Identifier" and "Object Name"
- # Be sure to use these exact names for these BACnet object properties!
- PropertyNames = ["Object Identifier", "Object Name", "Description", "Number of States"]
- ColumnAlignments = [ wx.ALIGN_RIGHT , wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_CENTER ]
- ColumnSizes = [ 40 , 80 , 80 , 120 ]
- PropertyConfig = {"Object Identifier": {"GridCellEditor" : wx.grid.GridCellNumberEditor,
- "GridCellRenderer" : wx.grid.GridCellNumberRenderer,
- "GridCellEditorParam": "0,4194302"
- # syntax for GridCellNumberEditor -> "min,max"
- # ObjectID (22 bits ID + 10 bits type) => max = 2^22-1
- },
- "Object Name" : {"GridCellEditor" : wx.grid.GridCellTextEditor,
- "GridCellRenderer" : wx.grid.GridCellStringRenderer},
- "Description" : {"GridCellEditor" : wx.grid.GridCellTextEditor,
- "GridCellRenderer" : wx.grid.GridCellStringRenderer},
- "Number of States" : {"GridCellEditor" : wx.grid.GridCellNumberEditor,
- "GridCellRenderer" : wx.grid.GridCellNumberRenderer,
- "GridCellEditorParam": "1,255" # syntax for GridCellNumberEditor -> "min,max"
- # MultiState Values are encoded in unsigned integer
- # (in BACnet => uint8_t), and can not be 0.
- # See ASHRAE 135-2016, section 12.20.4
- }
- }
-
+ # 'PropertyNames' will be used as the header for each column of the Object Properties grid!
+ # Warning: The rest of the code depends on the existance of an "Object Identifier" and "Object Name"
+ # Be sure to use these exact names for these BACnet object properties!
+ PropertyNames = [
+ "Object Identifier", "Object Name", "Description", "Number of States"]
+ ColumnAlignments = [
+ wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_CENTER]
+ ColumnSizes = [40, 80, 80, 120]
+ PropertyConfig = {
+ "Object Identifier": {"GridCellEditor": wx.grid.GridCellNumberEditor,
+ "GridCellRenderer": wx.grid.GridCellNumberRenderer,
+ "GridCellEditorParam": "0,4194302"},
+ "Object Name": {"GridCellEditor": wx.grid.GridCellTextEditor,
+ "GridCellRenderer": wx.grid.GridCellStringRenderer},
+ "Description": {"GridCellEditor": wx.grid.GridCellTextEditor,
+ "GridCellRenderer": wx.grid.GridCellStringRenderer},
+ # MultiState Values are encoded in unsigned integer
+ # (in BACnet => uint8_t), and can not be 0.
+ # See ASHRAE 135-2016, section 12.20.4
+ "Number of States": {"GridCellEditor": wx.grid.GridCellNumberEditor,
+ "GridCellRenderer": wx.grid.GridCellNumberRenderer,
+ # syntax for GridCellNumberEditor -> "min,max"
+ "GridCellEditorParam": "1,255"}
+ }
# The default values to use for each BACnet object type
#
# Note that the 'internal plugin parameters' get stored in the data table, but
-# are not visible in the GUI. They are used to generate the
+# are not visible in the GUI. They are used to generate the
# EDE files as well as the C code
class BVObject(BinaryObject):
- DefaultValues = {"Object Identifier":"",
- "Object Name" :"Binary Value",
- "Description" :"",
- # internal plugin parameters...
- "BACnetObjTypeID" :5,
- "Ctype" :"uint8_t",
- "Settable" :"Y"
- }
+ DefaultValues = {"Object Identifier": "",
+ "Object Name": "Binary Value",
+ "Description": "",
+ # internal plugin parameters...
+ "BACnetObjTypeID": 5,
+ "Ctype": "uint8_t",
+ "Settable": "Y"}
+
class BOObject(BinaryObject):
- DefaultValues = {"Object Identifier":"",
- "Object Name" :"Binary Output",
- "Description" :"",
- # internal plugin parameters...
- "BACnetObjTypeID" :4,
- "Ctype" :"uint8_t",
- "Settable" :"Y"
- }
+ DefaultValues = {"Object Identifier": "",
+ "Object Name": "Binary Output",
+ "Description": "",
+ # internal plugin parameters...
+ "BACnetObjTypeID": 4,
+ "Ctype": "uint8_t",
+ "Settable": "Y"}
+
class BIObject(BinaryObject):
- DefaultValues = {"Object Identifier":"",
- "Object Name" :"Binary Input",
- "Description" :"",
- # internal plugin parameters...
- "BACnetObjTypeID" :3,
- "Ctype" :"uint8_t",
- "Settable" :"N"
- }
+ DefaultValues = {"Object Identifier": "",
+ "Object Name": "Binary Input",
+ "Description": "",
+ # internal plugin parameters...
+ "BACnetObjTypeID": 3,
+ "Ctype": "uint8_t",
+ "Settable": "N"}
+
class AVObject(AnalogObject):
- DefaultValues = {"Object Identifier":"",
- "Object Name" :"Analog Value",
- "Description" :"",
- "Engineering Units":'(Other) no-units (95)',
- # internal plugin parameters...
- "Unit ID" :95, # the ID of the engineering unit
- # will get updated by UpdateVirtualProperties()
- "BACnetObjTypeID" :2,
- "Ctype" :"float",
- "Settable" :"Y"
- }
+ DefaultValues = {"Object Identifier": "",
+ "Object Name": "Analog Value",
+ "Description": "",
+ "Engineering Units": '(Other) no-units (95)',
+ # internal plugin parameters...
+ "Unit ID": 95, # the ID of the engineering unit
+ # will get updated by
+ # UpdateVirtualProperties()
+ "BACnetObjTypeID": 2,
+ "Ctype": "float",
+ "Settable": "Y"}
+
class AOObject(AnalogObject):
- DefaultValues = {"Object Identifier":"",
- "Object Name" :"Analog Output",
- "Description" :"",
- "Engineering Units":'(Other) no-units (95)',
- # internal plugin parameters...
- "Unit ID" :95, # the ID of the engineering unit
- # will get updated by UpdateVirtualProperties()
- "BACnetObjTypeID" :1,
- "Ctype" :"float",
- "Settable" :"Y"
- }
+ DefaultValues = {"Object Identifier": "",
+ "Object Name": "Analog Output",
+ "Description": "",
+ "Engineering Units": '(Other) no-units (95)',
+ # internal plugin parameters...
+ "Unit ID": 95, # the ID of the engineering unit
+ # will get updated by
+ # UpdateVirtualProperties()
+ "BACnetObjTypeID": 1,
+ "Ctype": "float",
+ "Settable": "Y"}
+
class AIObject(AnalogObject):
- DefaultValues = {"Object Identifier":"",
- "Object Name" :"Analog Input",
- "Description" :"",
- "Engineering Units":'(Other) no-units (95)',
- # internal plugin parameters...
- "Unit ID" :95, # the ID of the engineering unit
- # will get updated by UpdateVirtualProperties()
- "BACnetObjTypeID" :0,
- "Ctype" :"float",
- "Settable" :"N"
- }
+ DefaultValues = {"Object Identifier": "",
+ "Object Name": "Analog Input",
+ "Description": "",
+ "Engineering Units": '(Other) no-units (95)',
+ # internal plugin parameters...
+ "Unit ID": 95, # the ID of the engineering unit
+ # will get updated by
+ # UpdateVirtualProperties()
+ "BACnetObjTypeID": 0,
+ "Ctype": "float",
+ "Settable": "N"}
+
class MSVObject(MultiSObject):
- DefaultValues = {"Object Identifier":"",
- "Object Name" :"Multi-state Value",
- "Description" :"",
- "Number of States" :"255",
- # internal plugin parameters...
- "BACnetObjTypeID" :19,
- "Ctype" :"uint8_t",
- "Settable" :"Y"
- }
+ DefaultValues = {"Object Identifier": "",
+ "Object Name": "Multi-state Value",
+ "Description": "",
+ "Number of States": "255",
+ # internal plugin parameters...
+ "BACnetObjTypeID": 19,
+ "Ctype": "uint8_t",
+ "Settable": "Y"}
+
class MSOObject(MultiSObject):
- DefaultValues = {"Object Identifier":"",
- "Object Name" :"Multi-state Output",
- "Description" :"",
- "Number of States" :"255",
- # internal plugin parameters...
- "BACnetObjTypeID" :14,
- "Ctype" :"uint8_t",
- "Settable" :"Y"
- }
+ DefaultValues = {"Object Identifier": "",
+ "Object Name": "Multi-state Output",
+ "Description": "",
+ "Number of States": "255",
+ # internal plugin parameters...
+ "BACnetObjTypeID": 14,
+ "Ctype": "uint8_t",
+ "Settable": "Y"}
+
class MSIObject(MultiSObject):
- DefaultValues = {"Object Identifier":"",
- "Object Name" :"Multi-state Input",
- "Description" :"",
- "Number of States" :"255",
- # internal plugin parameters...
- "BACnetObjTypeID" :13,
- "Ctype" :"uint8_t",
- "Settable" :"N"
- }
-
-
-
-
-
-
-
-
+ DefaultValues = {"Object Identifier": "",
+ "Object Name": "Multi-state Input",
+ "Description": "",
+ "Number of States": "255",
+ # internal plugin parameters...
+ "BACnetObjTypeID": 13,
+ "Ctype": "uint8_t",
+ "Settable": "N"}
class ObjectTable(CustomTable):
# A custom wx.grid.PyGridTableBase using user supplied data
- #
- # This will basically store a list of BACnet objects that the slave will support/implement.
- # There will be one instance of this ObjectTable class for each BACnet object type
+ #
+ # This will basically store a list of BACnet objects that the slave will support/implement.
+ # There will be one instance of this ObjectTable class for each BACnet object type
# (e.g. Binary Value, Analog Input, Multi State Output, ...)
- #
+ #
# The list of BACnet objects will actually be stored within the self.data variable
# (declared in CustomTable). Self.data will be a list of dictionaries (one entry per BACnet
# object). All of these dictionaries in the self.data list will have entries whose keys actually
- # depend on the BACnet type object being handled. The keys in the dictionary will be
+ # depend on the BACnet type object being handled. The keys in the dictionary will be
# the entries in the PropertyNames list of one of the following classes:
# (BVObject, BOObject, BIObject, AVObject, AOObject, AIObject, MSVObject, MSOObject, MSIObject).
#
- # For example, when handling Binary Value BACnet objects,
+ # For example, when handling Binary Value BACnet objects,
# self.data will be a list of dictionaries (one entry per row)
# self.data[n] will be a dictionary, with keys "Object Identifier", "Object Name", "Description"
- # for example: self.data[n] = {"Object Identifier":33, "Object Name":"room1", "Description":"xx"}
- #
+ # for example: self.data[n] = {"Object Identifier":33, "Object Name":"room1", "Description":"xx"}
+ #
# Note that this ObjectTable class merely stores the configuration data.
- # It does not control the display nor the editing of this data.
+ # It does not control the display nor the editing of this data.
# This data is typically displayed within a grid, that is controlled by the ObjectGrid class.
#
+
def __init__(self, parent, data, BACnetObjectType):
# parent : the _BacnetSlavePlug object that is instantiating this ObjectTable
# data : a list with the data to be shown on the grid
@@ -560,35 +552,37 @@
# (in particular, the UpdateVirtualProperties() method)
#
# The base class must be initialized *first*
- CustomTable.__init__(self, parent, data, BACnetObjectType.PropertyNames)
+ CustomTable.__init__(
+ self, parent, data, BACnetObjectType.PropertyNames)
self.BACnetObjectType = BACnetObjectType()
- self.ChangesToSave = False
-
- #def _GetRowEdit(self, row):
- #row_edit = self.GetValueByName(row, "Edit")
- #var_type = self.Parent.GetTagName()
- #bodytype = self.Parent.Controler.GetEditedElementBodyType(var_type)
- #if bodytype in ["ST", "IL"]:
- #row_edit = True;
- #return row_edit
+ self.ChangesToSave = False
+
+ # def _GetRowEdit(self, row):
+ # row_edit = self.GetValueByName(row, "Edit")
+ # var_type = self.Parent.GetTagName()
+ # bodytype = self.Parent.Controler.GetEditedElementBodyType(var_type)
+ # if bodytype in ["ST", "IL"]:
+ # row_edit = True;
+ # return row_edit
def _updateColAttrs(self, grid):
# wx.grid.Grid -> update the column attributes to add the
# appropriate renderer given the column name.
- #
+ #
# Otherwise default to the default renderer.
- #print "ObjectTable._updateColAttrs() called!!!"
+ # print "ObjectTable._updateColAttrs() called!!!"
for row in range(self.GetNumberRows()):
for col in range(self.GetNumberCols()):
- PropertyName = self.BACnetObjectType.PropertyNames[col]
+ PropertyName = self.BACnetObjectType.PropertyNames[col]
PropertyConfig = self.BACnetObjectType.PropertyConfig[PropertyName]
- grid.SetReadOnly (row, col, False)
- grid.SetCellEditor (row, col, PropertyConfig["GridCellEditor"] ())
- grid.SetCellRenderer (row, col, PropertyConfig["GridCellRenderer"]())
+ grid.SetReadOnly(row, col, False)
+ grid.SetCellEditor(row, col, PropertyConfig["GridCellEditor"]())
+ grid.SetCellRenderer(row, col, PropertyConfig["GridCellRenderer"]())
grid.SetCellBackgroundColour(row, col, wx.WHITE)
- grid.SetCellTextColour (row, col, wx.BLACK)
+ grid.SetCellTextColour(row, col, wx.BLACK)
if "GridCellEditorParam" in PropertyConfig:
- grid.GetCellEditor(row, col).SetParameters(PropertyConfig["GridCellEditorParam"])
+ grid.GetCellEditor(row, col).SetParameters(
+ PropertyConfig["GridCellEditorParam"])
self.ResizeRow(grid, row)
def FindValueByName(self, PropertyName, PropertyValue):
@@ -600,8 +594,8 @@
if int(self.GetValueByName(row, PropertyName)) == PropertyValue:
return row
return None
-
- # Return a list containing all the values under the column named 'colname'
+
+ # Return a list containing all the values under the column named 'colname'
def GetAllValuesByName(self, colname):
values = []
for row in range(self.GetNumberRows()):
@@ -610,13 +604,15 @@
# Returns a dictionary with:
# keys: IDs of BACnet objects
- # value: number of BACnet objects using this same Id
+ # value: number of BACnet objects using this same Id
# (values larger than 1 indicates an error as BACnet requires unique
# object IDs for objects of the same type)
def GetObjectIDCount(self):
- # The dictionary is built by first creating a list containing the IDs of all BACnet objects
+ # The dictionary is built by first creating a list containing the IDs
+ # of all BACnet objects
ObjectIDs = self.GetAllValuesByName("Object Identifier")
- ObjectIDs_as_int = [int(x) for x in ObjectIDs] # list of integers instead of strings...
+ # list of integers instead of strings...
+ ObjectIDs_as_int = [int(x) for x in ObjectIDs]
# This list is then transformed into a collections.Counter class
# Which is then transformed into a dictionary using dict()
return dict(Counter(ObjectIDs_as_int))
@@ -639,11 +635,10 @@
self.BACnetObjectType.UpdateVirtualProperties(ObjProp)
-
class ObjectGrid(CustomGrid):
# A custom wx.grid.Grid (CustomGrid derives from wx.grid.Grid)
- #
- # Needed mostly to customise the initial values of newly added rows, and to
+ #
+ # Needed mostly to customise the initial values of newly added rows, and to
# validate if the inserted data follows BACnet rules.
#
#
@@ -656,82 +651,87 @@
# The grid uses one line/row per BACnet object, and one column for each property of the BACnet
# object. The column titles change depending on the specific type of BACnet object being edited
# (BVObject, BOObject, BIObject, AVObject, AOObject, AIObject, MSVObject, MSOObject, MSIObject).
- # The editor to use for each column is also obtained from that class (e.g. TextEditor,
+ # The editor to use for each column is also obtained from that class (e.g. TextEditor,
# NumberEditor, ...)
#
# This class does NOT store the data in the grid. It merely controls its display and editing.
# The data in the grid is stored within an object of class ObjectTable
#
+
def __init__(self, *args, **kwargs):
CustomGrid.__init__(self, *args, **kwargs)
# Called when a new row is added by clicking Add button
- # call graph: CustomGrid.OnAddButton() --> CustomGrid.AddRow() --> ObjectGrid._AddRow()
+ # call graph: CustomGrid.OnAddButton() --> CustomGrid.AddRow() -->
+ # ObjectGrid._AddRow()
def _AddRow(self, new_row):
if new_row > 0:
self.Table.InsertRow(new_row, self.Table.GetRow(new_row - 1).copy())
else:
self.Table.InsertRow(new_row, self.DefaultValue.copy())
- self.Table.SetValueByName(new_row, "Object Identifier", BACnetObjectID_NUL) # start off with invalid object ID
+ # start off with invalid object ID
+ self.Table.SetValueByName(new_row, "Object Identifier", BACnetObjectID_NUL)
# Find an apropriate BACnet object ID for the new object.
# We choose a first attempt (based on object ID of previous line + 1)
new_object_id = 0
if new_row > 0:
- new_object_id = int(self.Table.GetValueByName(new_row - 1, "Object Identifier"))
+ new_object_id = int(
+ self.Table.GetValueByName(new_row - 1, "Object Identifier"))
new_object_id += 1
- # Check whether the chosen object ID is not already in use.
+ # Check whether the chosen object ID is not already in use.
# If in use, add 1 to the attempted object ID and recheck...
while self.Table.FindValueByName("Object Identifier", new_object_id) is not None:
new_object_id += 1
- # if reached end of object IDs, cycle back to 0
+ # if reached end of object IDs, cycle back to 0
# (remember, we may have started at any inital object ID > 0, so it makes sense to cyclce back to 0)
- # warning: We risk entering an inifinite loop if all object IDs are already used.
+ # warning: We risk entering an inifinite loop if all object IDs are already used.
# The likelyhood of this happening is extremely low, (we would need 2^22 elements in the table!)
# so don't worry about it for now.
if new_object_id > BACnetObjectID_MAX:
new_object_id = 0
# Set the object ID of the new object to the apropriate value
# ... and append the ID to the default object name (so the name becomes unique)
- new_object_name = self.DefaultValue.get("Object Name") + " " + str(new_object_id)
- self.Table.SetValueByName(new_row, "Object Name" , new_object_name)
+ new_object_name = self.DefaultValue.get(
+ "Object Name") + " " + str(new_object_id)
+ self.Table.SetValueByName(
+ new_row, "Object Name", new_object_name)
self.Table.SetValueByName(new_row, "Object Identifier", new_object_id)
self.Table.ResetView(self)
return new_row
-
# Called when a object ID is changed
# call graph: ObjectEditor.OnVariablesGridCellChange() --> this method
# Will check whether there is a duplicate object ID, and highlight it if so.
def HighlightDuplicateObjectIDs(self):
if self.Table.GetNumberRows() < 2:
- # Less than 2 rows. No duplicates are possible!
+ # Less than 2 rows. No duplicates are possible!
return
IDsCount = self.Table.GetObjectIDCount()
# check ALL object IDs for duplicates...
for row in range(self.Table.GetNumberRows()):
obj_id1 = int(self.Table.GetValueByName(row, "Object Identifier"))
if IDsCount[obj_id1] > 1:
- # More than 1 BACnet object using this ID! Let us Highlight this row with errors...
+ # More than 1 BACnet object using this ID! Let us Highlight this row with errors...
# TODO: change the hardcoded column number '0' to a number obtained at runtime
# that is guaranteed to match the column titled "Object Identifier"
self.SetCellBackgroundColour(row, 0, ERROR_HIGHLIGHT[0])
- self.SetCellTextColour (row, 0, ERROR_HIGHLIGHT[1])
- else:
+ self.SetCellTextColour(row, 0, ERROR_HIGHLIGHT[1])
+ else:
self.SetCellBackgroundColour(row, 0, wx.WHITE)
- self.SetCellTextColour (row, 0, wx.BLACK)
- # Refresh the graphical display to take into account any changes we may have made
+ self.SetCellTextColour(row, 0, wx.BLACK)
+ # Refresh the graphical display to take into account any changes we may
+ # have made
self.ForceRefresh()
- return None
-
+ return None
# Called when the user changes the name of BACnet object (using the GUI grid)
- # call graph: ObjectEditor.OnVariablesGridCellChange() -->
+ # call graph: ObjectEditor.OnVariablesGridCellChange() -->
# --> BacnetSlaveEditorPlug.HighlightAllDuplicateObjectNames() -->
# --> ObjectEditor.HighlightDuplicateObjectNames() -->
# --> (this method)
# Will check whether there is a duplicate BACnet object name, and highlight it if so.
#
- # Since the names of BACnet objects must be unique within the whole bacnet server (and
+ # Since the names of BACnet objects must be unique within the whole bacnet server (and
# not just among the BACnet objects of the same class (e.g. Analog Value, Binary Input, ...)
# to work properly this method must be passed a list of the names of all BACnet objects
# currently configured.
@@ -743,18 +743,17 @@
# TODO: change the hardcoded column number '1' to a number obtained at runtime
# that is guaranteed to match the column titled "Object Name"
if AllObjectNamesFreq[self.Table.GetValueByName(row, "Object Name")] > 1:
- # This is an error! Highlight it...
+ # This is an error! Highlight it...
self.SetCellBackgroundColour(row, 1, ERROR_HIGHLIGHT[0])
- self.SetCellTextColour (row, 1, ERROR_HIGHLIGHT[1])
- else:
+ self.SetCellTextColour(row, 1, ERROR_HIGHLIGHT[1])
+ else:
self.SetCellBackgroundColour(row, 1, wx.WHITE)
- self.SetCellTextColour (row, 1, wx.BLACK)
- # Refresh the graphical display to take into account any changes we may have made
+ self.SetCellTextColour(row, 1, wx.BLACK)
+ # Refresh the graphical display to take into account any changes we may
+ # have made
self.ForceRefresh()
- return None
-
-
-
+ return None
+
class ObjectEditor(wx.Panel):
# This ObjectEditor class:
@@ -763,14 +762,15 @@
# This 'window' is currenty displayed within one tab of the bacnet plugin, but this
# may change in the future!
#
- # It includes a grid to display all the BACnet objects of its type , as well as the buttons
+ # It includes a grid to display all the BACnet objects of its type , as well as the buttons
# to insert, delete and move (up/down) a BACnet object in the grid.
# It also includes the sizers and spacers required to lay out the grid and buttons
# in the wndow.
#
+
def __init__(self, parent, window, controller, ObjTable):
# window: the window in which the editor will open.
- # controller: The ConfigTreeNode object that controlls the data presented by
+ # controller: The ConfigTreeNode object that controlls the data presented by
# this 'config tree node editor'
#
# parent: wx._controls.Notebook
@@ -778,57 +778,62 @@
# controller: controller will be an object of class
# FinalCTNClass (i.e. beremiz.ConfigTreeNode.FinalCTNClass )
# (FinalCTNClass inherits from: ConfigTreeNode and _BacnetSlavePlug)
- # (For the BACnet plugin, it is easier to think of controller as a _BacnetSlavePlug,
+ # (For the BACnet plugin, it is easier to think of controller as a _BacnetSlavePlug,
# as the other classes are generic to all plugins!!)
#
# ObjTable: The object of class ObjectTable that stores the data displayed in the grid.
# This object is instantiated and managed by the _BacnetSlavePlug class.
#
- self.window = window
- self.controller = controller
+ self.window = window
+ self.controller = controller
self.ObjTable = ObjTable
-
+
wx.Panel.__init__(self, parent)
-
+
# The main sizer, 2 rows: top row for buttons, bottom row for 2D grid
self.MainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=0)
self.MainSizer.AddGrowableCol(0)
self.MainSizer.AddGrowableRow(1)
- # sizer placed on top row of main sizer:
+ # sizer placed on top row of main sizer:
# 1 row; 6 columns: 1 static text, one stretchable spacer, 4 buttons
controls_sizer = wx.FlexGridSizer(cols=6, hgap=4, rows=1, vgap=5)
controls_sizer.AddGrowableCol(0)
controls_sizer.AddGrowableRow(0)
- self.MainSizer.Add(controls_sizer, border=5, flag=wx.GROW|wx.ALL)
+ self.MainSizer.Add(controls_sizer, border=5, flag=wx.GROW | wx.ALL)
# the buttons that populate the controls sizer (itself in top row of the main sizer)
# NOTE: the _("string") function will translate the "string" to the local language
- controls_sizer.Add(wx.StaticText(self, label=_('Object Properties:')), flag=wx.ALIGN_BOTTOM)
+ controls_sizer.Add(
+ wx.StaticText(self, label=_('Object Properties:')), flag=wx.ALIGN_BOTTOM)
controls_sizer.AddStretchSpacer()
for name, bitmap, help in [
- ("AddButton" , "add_element" , _("Add variable" )),
- ("DeleteButton", "remove_element", _("Remove variable" )),
- ("UpButton" , "up" , _("Move variable up" )),
- ("DownButton" , "down" , _("Move variable down"))]:
- button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap),
- size=wx.Size(28, 28),
- style=wx.NO_BORDER)
+ ("AddButton", "add_element", _("Add variable")),
+ ("DeleteButton", "remove_element", _("Remove variable")),
+ ("UpButton", "up", _("Move variable up")),
+ ("DownButton", "down", _("Move variable down"))]:
+ button = wx.lib.buttons.GenBitmapButton(
+ self, bitmap=GetBitmap(bitmap),
+ size=wx.Size(28, 28),
+ style=wx.NO_BORDER)
button.SetToolTipString(help)
setattr(self, name, button)
- controls_sizer.Add(button)
-
- # the variable grid that will populate the bottom row of the main sizer
+ controls_sizer.Add(button)
+
+ # the variable grid that will populate the bottom row of the main sizer
panel = self
self.VariablesGrid = ObjectGrid(panel, style=wx.VSCROLL)
- #self.VariablesGrid.SetDropTarget(VariableDropTarget(self)) # use only to enable drag'n'drop
- self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange)
- #self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick)
- #self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown)
+ # use only to enable drag'n'drop
+ # self.VariablesGrid.SetDropTarget(VariableDropTarget(self))
+ self.VariablesGrid.Bind(
+ wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange)
+ # self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick)
+ # self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown)
self.MainSizer.Add(self.VariablesGrid, flag=wx.GROW)
-
+
# Configure the Variables Grid...
- self.VariablesGrid.SetRowLabelSize(0) # do not include a leftmost column containing the 'row label'
+ # do not include a leftmost column containing the 'row label'
+ self.VariablesGrid.SetRowLabelSize(0)
self.VariablesGrid.SetButtons({"Add": self.AddButton,
"Delete": self.DeleteButton,
"Up": self.UpButton,
@@ -837,10 +842,11 @@
# NOTE: ObjTable.BACnetObjectType will contain the class name of one of the following classes
# (BVObject, BIObject, BOObject, AVObject, AIObject, AOObject, MSVObject, MSIObject, MSOObject)
# which inherit from one of (BinaryObject, AnalogObject, MultiSObject)
- self.VariablesGrid.SetDefaultValue(self.ObjTable.BACnetObjectType.DefaultValues)
+ self.VariablesGrid.SetDefaultValue(
+ self.ObjTable.BACnetObjectType.DefaultValues)
# self.ObjTable: The table that contains the data displayed in the grid
- # This table was instantiated/created in the initializer for class _BacnetSlavePlug
+ # This table was instantiated/created in the initializer for class _BacnetSlavePlug
self.VariablesGrid.SetTable(self.ObjTable)
self.VariablesGrid.SetEditable(True)
# set the column attributes (width, alignment)
@@ -848,19 +854,19 @@
# (BVObject, BIObject, BOObject, AVObject, AIObject, AOObject, MSVObject, MSIObject, MSOObject)
# which inherit from one of (BinaryObject, AnalogObject, MultiSObject)
ColumnAlignments = self.ObjTable.BACnetObjectType.ColumnAlignments
- ColumnSizes = self.ObjTable.BACnetObjectType.ColumnSizes
- for col in range( self.ObjTable.GetNumberCols()):
+ ColumnSizes = self.ObjTable.BACnetObjectType.ColumnSizes
+ for col in range(self.ObjTable.GetNumberCols()):
attr = wx.grid.GridCellAttr()
attr.SetAlignment(ColumnAlignments[col], wx.ALIGN_CENTRE)
self.VariablesGrid.SetColAttr(col, attr)
self.VariablesGrid.SetColMinimalWidth(col, ColumnSizes[col])
self.VariablesGrid.AutoSizeColumn(col, False)
-
+
# layout the items in all sizers, and show them too.
- self.SetSizer(self.MainSizer) # Have the wondow 'own' the sizer...
- #self.MainSizer.ShowItems(True) # not needed once the window 'owns' the sizer (SetSizer())
- #self.MainSizer.Layout() # not needed once the window 'owns' the sizer (SetSizer())
-
+ self.SetSizer(self.MainSizer) # Have the wondow 'own' the sizer...
+ # self.MainSizer.ShowItems(True) # not needed once the window 'owns' the sizer (SetSizer())
+ # self.MainSizer.Layout() # not needed once the window 'owns' the sizer (SetSizer())
+
# Refresh the view of the grid...
# We ask the table to do that, who in turn will configure the grid for us!!
# It will configure the CellRenderers and CellEditors taking into account the type of
@@ -872,62 +878,57 @@
# (in order to maintain GUI consistency), so we have to adopt their way of doing things.
#
# NOTE: ObjectTable.ResetView() (remember, ObjTable is of class ObjectTable)
- # calls ObjectTable._updateColAttrs(), who will do the configuring.
+ # calls ObjectTable._updateColAttrs(), who will do the configuring.
self.ObjTable.ResetView(self.VariablesGrid)
-
def RefreshView(self):
- #print "ObjectEditor.RefreshView() called!!!"
+ # print "ObjectEditor.RefreshView() called!!!"
# Check for Duplicate Object IDs is only done within same BACnet object type (ID is unique by type).
# The VariablesGrid class can handle it by itself.
self.VariablesGrid.HighlightDuplicateObjectIDs()
# Check for Duplicate Object Names must be done globally (Object Name is unique within bacnet server)
# Only the BacnetSlaveEditorPlug can and will handle this.
- #self.window.HighlightAllDuplicateObjectNames()
- pass
-
- #########################################
+ # self.window.HighlightAllDuplicateObjectNames()
+
+ #
# Event handlers for the Variables Grid #
- #########################################
+ #
def OnVariablesGridCellChange(self, event):
- row, col = event.GetRow(), event.GetCol()
- #print "ObjectEditor.OnVariablesGridCellChange(row=%s, col=%s) called!!!" % (row, col)
+ col = event.GetCol()
+ # print "ObjectEditor.OnVariablesGridCellChange(row=%s, col=%s)
+ # called!!!" % (row, col)
self.ObjTable.ChangesToSave = True
if self.ObjTable.GetColLabelValue(col) == "Object Identifier":
- # an Object ID was changed => must check duplicate object IDs.
+ # an Object ID was changed => must check duplicate object IDs.
self.VariablesGrid.HighlightDuplicateObjectIDs()
if self.ObjTable.GetColLabelValue(col) == "Object Name":
- # an Object Name was changed => must check duplicate object names.
+ # an Object Name was changed => must check duplicate object names.
# Note that this must be done to _all_ BACnet objects, and not just the objects
# of the same BACnet class (Binary Value, Analog Input, ...)
# So we have the BacnetSlaveEditorPlug class do it...
self.window.HighlightAllDuplicateObjectNames()
- # There are changes to save =>
- # udate the enabled/disabled state of the 'save' option in the 'file' menu
+ # There are changes to save =>
+ # udate the enabled/disabled state of the 'save' option in the 'file' menu
self.window.RefreshBeremizWindow()
event.Skip()
def OnVariablesGridCellLeftClick(self, event):
- row = event.GetRow()
+ pass
def OnVariablesGridEditorShown(self, event):
- row, col = event.GetRow(), event.GetCol()
+ pass
def HighlightDuplicateObjectNames(self, AllObjectNamesFreq):
return self.VariablesGrid.HighlightDuplicateObjectNames(AllObjectNamesFreq)
-
-
-
-
class BacnetSlaveEditorPlug(ConfTreeNodeEditor):
# inheritance tree
# wx.SplitterWindow-->EditorPanel-->ConfTreeNodeEditor-->BacnetSlaveEditorPlug
#
# self.Controller -> The object that controls the data displayed in this editor
# In our case, the object of class _BacnetSlavePlug
-
+
CONFNODEEDITOR_TABS = [
(_("Analog Value Objects"), "_create_AV_ObjectEditor"),
(_("Analog Output Objects"), "_create_AO_ObjectEditor"),
@@ -938,53 +939,62 @@
(_("Multi-State Value Objects"), "_create_MSV_ObjectEditor"),
(_("Multi-State Output Objects"), "_create_MSO_ObjectEditor"),
(_("Multi-State Input Objects"), "_create_MSI_ObjectEditor")]
-
+
def _create_AV_ObjectEditor(self, parent):
- self.AV_ObjectEditor = ObjectEditor(parent, self, self.Controler, self.Controler.ObjTables["AV_Obj"])
+ self.AV_ObjectEditor = ObjectEditor(
+ parent, self, self.Controler, self.Controler.ObjTables["AV_Obj"])
return self.AV_ObjectEditor
-
+
def _create_AO_ObjectEditor(self, parent):
- self.AO_ObjectEditor = ObjectEditor(parent, self, self.Controler, self.Controler.ObjTables["AO_Obj"])
+ self.AO_ObjectEditor = ObjectEditor(
+ parent, self, self.Controler, self.Controler.ObjTables["AO_Obj"])
return self.AO_ObjectEditor
-
+
def _create_AI_ObjectEditor(self, parent):
- self.AI_ObjectEditor = ObjectEditor(parent, self, self.Controler, self.Controler.ObjTables["AI_Obj"])
+ self.AI_ObjectEditor = ObjectEditor(
+ parent, self, self.Controler, self.Controler.ObjTables["AI_Obj"])
return self.AI_ObjectEditor
-
+
def _create_BV_ObjectEditor(self, parent):
- self.BV_ObjectEditor = ObjectEditor(parent, self, self.Controler, self.Controler.ObjTables["BV_Obj"])
+ self.BV_ObjectEditor = ObjectEditor(
+ parent, self, self.Controler, self.Controler.ObjTables["BV_Obj"])
return self.BV_ObjectEditor
-
+
def _create_BO_ObjectEditor(self, parent):
- self.BO_ObjectEditor = ObjectEditor(parent, self, self.Controler, self.Controler.ObjTables["BO_Obj"])
+ self.BO_ObjectEditor = ObjectEditor(
+ parent, self, self.Controler, self.Controler.ObjTables["BO_Obj"])
return self.BO_ObjectEditor
-
+
def _create_BI_ObjectEditor(self, parent):
- self.BI_ObjectEditor = ObjectEditor(parent, self, self.Controler, self.Controler.ObjTables["BI_Obj"])
+ self.BI_ObjectEditor = ObjectEditor(
+ parent, self, self.Controler, self.Controler.ObjTables["BI_Obj"])
return self.BI_ObjectEditor
-
+
def _create_MSV_ObjectEditor(self, parent):
- self.MSV_ObjectEditor = ObjectEditor(parent, self, self.Controler, self.Controler.ObjTables["MSV_Obj"])
+ self.MSV_ObjectEditor = ObjectEditor(
+ parent, self, self.Controler, self.Controler.ObjTables["MSV_Obj"])
return self.MSV_ObjectEditor
-
+
def _create_MSO_ObjectEditor(self, parent):
- self.MSO_ObjectEditor = ObjectEditor(parent, self, self.Controler, self.Controler.ObjTables["MSO_Obj"])
+ self.MSO_ObjectEditor = ObjectEditor(
+ parent, self, self.Controler, self.Controler.ObjTables["MSO_Obj"])
return self.MSO_ObjectEditor
-
+
def _create_MSI_ObjectEditor(self, parent):
- self.MSI_ObjectEditor = ObjectEditor(parent, self, self.Controler, self.Controler.ObjTables["MSI_Obj"])
+ self.MSI_ObjectEditor = ObjectEditor(
+ parent, self, self.Controler, self.Controler.ObjTables["MSI_Obj"])
return self.MSI_ObjectEditor
-
+
def __init__(self, parent, controler, window, editable=True):
self.Editable = editable
ConfTreeNodeEditor.__init__(self, parent, controler, window)
-
+
def __del__(self):
self.Controler.OnCloseEditor(self)
-
+
def GetConfNodeMenuItems(self):
return []
-
+
def RefreshConfNodeMenu(self, confnode_menu):
return
@@ -1013,17 +1023,21 @@
self.MSO_ObjectEditor.HighlightDuplicateObjectNames(ObjectNamesCount)
self.MSI_ObjectEditor.HighlightDuplicateObjectNames(ObjectNamesCount)
return None
-
-
+
def RefreshBeremizWindow(self):
- # self.ParentWindow is the top level Beremiz class (object) that
+ # self.ParentWindow is the top level Beremiz class (object) that
# handles the beremiz window and layout
- self.ParentWindow.RefreshTitle() # Refresh the title of the Beremiz window
- # (it changes depending on whether there are
- # changes to save!! )
- self.ParentWindow.RefreshFileMenu() # Refresh the enabled/disabled state of the
- # entries in the main 'file' menu.
- # ('Save' sub-menu should become enabled
- # if there are changes to save! )
- ###self.ParentWindow.RefreshEditMenu()
- ###self.ParentWindow.RefreshPageTitles()
+
+ # Refresh the title of the Beremiz window
+ # (it changes depending on whether there are
+ # changes to save!! )
+ self.ParentWindow.RefreshTitle()
+
+ # Refresh the enabled/disabled state of the
+ # entries in the main 'file' menu.
+ # ('Save' sub-menu should become enabled
+ # if there are changes to save! )
+ self.ParentWindow.RefreshFileMenu()
+
+ # self.ParentWindow.RefreshEditMenu()
+ # self.ParentWindow.RefreshPageTitles()
--- a/bacnet/bacnet.py Wed Aug 01 13:09:45 2018 +0300
+++ b/bacnet/bacnet.py Wed Aug 08 13:46:19 2018 +0200
@@ -19,51 +19,53 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
+#
# This code is made available on the understanding that it will not be
# used in safety-critical situations without a full and competent review.
-
-
-import os, sys
+from __future__ import absolute_import
+
+import os
from collections import Counter
-from datetime import datetime
-
-base_folder = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]
-base_folder = os.path.join(base_folder, "..")
-BacnetPath = os.path.join(base_folder, "BACnet")
-BacnetLibraryPath = os.path.join(BacnetPath, "lib")
-BacnetIncludePath = os.path.join(BacnetPath, "include")
+from datetime import datetime
+import pickle
+
+import wx
+
+from bacnet.BacnetSlaveEditor import *
+from bacnet.BacnetSlaveEditor import ObjectProperties
+from PLCControler import LOCATION_CONFNODE, LOCATION_VAR_MEMORY
+
+base_folder = os.path.split(
+ os.path.dirname(os.path.realpath(__file__)))[0]
+base_folder = os.path.join(base_folder, "..")
+BacnetPath = os.path.join(base_folder, "BACnet")
+BacnetLibraryPath = os.path.join(BacnetPath, "lib")
+BacnetIncludePath = os.path.join(BacnetPath, "include")
BacnetIncludePortPath = os.path.join(BacnetPath, "ports")
BacnetIncludePortPath = os.path.join(BacnetIncludePortPath, "linux")
-import wx
-import pickle
-
-from BacnetSlaveEditor import *
-from BacnetSlaveEditor import ObjectProperties
-from ConfigTreeNode import ConfigTreeNode
-from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
-
# Parameters to be monkey patched in beremiz customizations
-BACNET_VENDOR_ID = 9999
+BACNET_VENDOR_ID = 9999
BACNET_VENDOR_NAME = "Beremiz.org"
BACNET_DEVICE_MODEL_NAME = "Beremiz PLC"
-###################################################
-###################################################
-# #
-# S L A V E D E V I C E #
-# #
-###################################################
-###################################################
+#
+#
+#
+# S L A V E D E V I C E #
+#
+#
+#
# NOTE: Objects of class _BacnetSlavePlug are never instantiated directly.
# The objects are instead instantiated from class FinalCTNClass
# FinalCTNClass inherits from: - ConfigTreeNode
# - The tree node plug (in our case _BacnetSlavePlug)
-#class _BacnetSlavePlug:
-class RootClass:
+# class _BacnetSlavePlug:
+
+
+class RootClass(object):
XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="BACnetServerNode">
@@ -77,7 +79,7 @@
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
- <xsd:attribute name="BACnet_Communication_Control_Password"
+ <xsd:attribute name="BACnet_Communication_Control_Password"
type="xsd:string" use="optional" default="Malba Tahan"/>
<xsd:attribute name="BACnet_Device_ID" use="optional" default="0">
<xsd:simpleType>
@@ -99,8 +101,7 @@
# so the Device instance ID is limited from 0 to 22^2-1 = 4194303
# However, 4194303 is reserved for special use (similar to NULL pointer), so last
# valid ID becomes 4194302
-
-
+
# The class/object that will render the graphical interface to edit the
# BacnetSlavePlug's configuration parameters. The object of class BacnetSlaveEditorPlug
# will be instantiated by the ConfigTreeNode class.
@@ -117,17 +118,17 @@
# of classes ConfigTreeNode as well as FinalCTNClass (since they are always instantiated
# as a FinalCTNClass)
EditorType = BacnetSlaveEditorPlug
-
+
# The following classes follow the model/viewer design pattern
#
# _BacnetSlavePlug - contains the model (i.e. configuration parameters)
- # BacnetSlaveEditorPlug - contains the viewer (and editor, so it includes the 'controller' part of the
+ # BacnetSlaveEditorPlug - contains the viewer (and editor, so it includes the 'controller' part of the
# design pattern which in this case is not separated from the viewer)
#
- # The _BacnetSlavePlug object is 'permanent', i.e. it exists as long as the beremiz project is open
+ # The _BacnetSlavePlug object is 'permanent', i.e. it exists as long as the beremiz project is open
# The BacnetSlaveEditorPlug object is 'transient', i.e. it exists only while the editor is visible/open
# in the editing panel. It is destoryed whenever
- # the user closes the corresponding tab in the
+ # the user closes the corresponding tab in the
# editing panel, and a new object is created when
# the editor is re-opened.
#
@@ -136,9 +137,9 @@
# and are therefore stored to a file)
#
# _BacnetSlavePlug contains: AV_VarEditor, ...
- # (these are the objects that implement a grid table to edit/view the
+ # (these are the objects that implement a grid table to edit/view the
# corresponding mode parameters)
- #
+ #
# Logic:
# - The xx_VarEditor classes inherit from wx.grid.Grid
# - The xx_ObjTable classes inherit from wx.grid.PyGridTableBase
@@ -149,102 +150,117 @@
# Note that wx.grid.Grid is prepared to work with wx.grid.PyGridTableBase as the container of
# data that is displayed and edited in the Grid.
-
ConfNodeMethods = [
- {"bitmap" : "ExportSlave",
- "name" : _("Export slave"),
- "tooltip" : _("Export BACnet slave to EDE file"),
- "method" : "_ExportBacnetSlave"},
+ {"bitmap": "ExportSlave",
+ "name": _("Export slave"),
+ "tooltip": _("Export BACnet slave to EDE file"),
+ "method": "_ExportBacnetSlave"},
]
-
+
def __init__(self):
- # Initialize the dictionary that stores the current configuration for the Analog/Digital/MultiValued Variables
+ # Initialize the dictionary that stores the current configuration for the Analog/Digital/MultiValued Variables
# in this BACnet server.
self.ObjTablesData = {}
- self.ObjTablesData[ "AV_Obj"] = [] # Each list will contain an entry for each row in the xxxxVar grid!!
- self.ObjTablesData[ "AO_Obj"] = [] # Each entry/row will be a dictionary
- self.ObjTablesData[ "AI_Obj"] = [] # Each dictionary will contain all entries/data
- self.ObjTablesData[ "BV_Obj"] = [] # for one row in the grid.
- self.ObjTablesData[ "BO_Obj"] = [] # Same structure as explained above...
- self.ObjTablesData[ "BI_Obj"] = [] # Same structure as explained above...
- self.ObjTablesData["MSV_Obj"] = [] # Same structure as explained above...
- self.ObjTablesData["MSO_Obj"] = [] # Same structure as explained above...
- self.ObjTablesData["MSI_Obj"] = [] # Same structure as explained above...
-
- self.ObjTablesData["EDEfile_parm"] = {"next_EDE_file_version":1}
- # EDE files inlcude extra parameters (ex. file version)
- # We would like to save the parameters the user configures
- # so they are available the next time the user opens the project.
- # Since this plugin is only storing the ObjTablesData[] dict
- # to file, we add that info to this dictionary too.
- # Yes, I know this is kind of a hack.
-
+
+ # Each list will contain an entry for each row in the xxxxVar grid!!
+ # Each entry/row will be a dictionary
+ # Each dictionary will contain all entries/data
+ # for one row in the grid.
+
+ self.ObjTablesData["AV_Obj"] = []
+ self.ObjTablesData["AO_Obj"] = []
+ self.ObjTablesData["AI_Obj"] = []
+ self.ObjTablesData["BV_Obj"] = []
+ self.ObjTablesData["BO_Obj"] = []
+ self.ObjTablesData["BI_Obj"] = []
+ self.ObjTablesData["MSV_Obj"] = []
+ self.ObjTablesData["MSO_Obj"] = []
+ self.ObjTablesData["MSI_Obj"] = []
+
+ self.ObjTablesData["EDEfile_parm"] = {"next_EDE_file_version": 1}
+
+ # EDE files inlcude extra parameters (ex. file version)
+ # We would like to save the parameters the user configures
+ # so they are available the next time the user opens the project.
+ # Since this plugin is only storing the ObjTablesData[] dict
+ # to file, we add that info to this dictionary too.
+ # Yes, I know this is kind of a
+ # hack.
+
filepath = self.GetFileName()
- if(os.path.isfile(filepath)):
+ if os.path.isfile(filepath):
self.LoadFromFile(filepath)
self.ObjTables = {}
- self.ObjTables[ "AV_Obj"] = ObjectTable(self, self.ObjTablesData[ "AV_Obj"], AVObject)
- self.ObjTables[ "AO_Obj"] = ObjectTable(self, self.ObjTablesData[ "AO_Obj"], AOObject)
- self.ObjTables[ "AI_Obj"] = ObjectTable(self, self.ObjTablesData[ "AI_Obj"], AIObject)
- self.ObjTables[ "BV_Obj"] = ObjectTable(self, self.ObjTablesData[ "BV_Obj"], BVObject)
- self.ObjTables[ "BO_Obj"] = ObjectTable(self, self.ObjTablesData[ "BO_Obj"], BOObject)
- self.ObjTables[ "BI_Obj"] = ObjectTable(self, self.ObjTablesData[ "BI_Obj"], BIObject)
- self.ObjTables["MSV_Obj"] = ObjectTable(self, self.ObjTablesData["MSV_Obj"], MSVObject)
- self.ObjTables["MSO_Obj"] = ObjectTable(self, self.ObjTablesData["MSO_Obj"], MSOObject)
- self.ObjTables["MSI_Obj"] = ObjectTable(self, self.ObjTablesData["MSI_Obj"], MSIObject)
- # list containing the data in the table <--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-
- ######################################
+ self.ObjTables["AV_Obj"] = ObjectTable(
+ self, self.ObjTablesData["AV_Obj"], AVObject)
+ self.ObjTables["AO_Obj"] = ObjectTable(
+ self, self.ObjTablesData["AO_Obj"], AOObject)
+ self.ObjTables["AI_Obj"] = ObjectTable(
+ self, self.ObjTablesData["AI_Obj"], AIObject)
+ self.ObjTables["BV_Obj"] = ObjectTable(
+ self, self.ObjTablesData["BV_Obj"], BVObject)
+ self.ObjTables["BO_Obj"] = ObjectTable(
+ self, self.ObjTablesData["BO_Obj"], BOObject)
+ self.ObjTables["BI_Obj"] = ObjectTable(
+ self, self.ObjTablesData["BI_Obj"], BIObject)
+ self.ObjTables["MSV_Obj"] = ObjectTable(
+ self, self.ObjTablesData["MSV_Obj"], MSVObject)
+ self.ObjTables["MSO_Obj"] = ObjectTable(
+ self, self.ObjTablesData["MSO_Obj"], MSOObject)
+ self.ObjTables["MSI_Obj"] = ObjectTable(
+ self, self.ObjTablesData["MSI_Obj"], MSIObject)
+
+ #
# Functions to be called by CTNClass #
- ######################################
+ #
# The following functions would be somewhat equvalent to virtual functions/methods in C++ classes
- # They will be called by the base class (CTNClass) from which this _BacnetSlavePlug class derives.
-
+ # They will be called by the base class (CTNClass) from which this
+ # _BacnetSlavePlug class derives.
+
def GetCurrentNodeName(self):
return self.CTNName()
def GetFileName(self):
return os.path.join(self.CTNPath(), 'bacnet_slave')
-
+
def OnCTNSave(self, from_project_path=None):
- return self.SaveToFile(self.GetFileName())
-
+ return self.SaveToFile(self.GetFileName())
def CTNTestModified(self):
# self.ChangesToSave: Check whether any of the parameters, defined in the XSD above, were changed.
# This is handled by the ConfigTreeNode class
- # (Remember that no objects are ever instantiated from _BacnetSlavePlug.
+ # (Remember that no objects are ever instantiated from _BacnetSlavePlug.
# Objects are instead created from FinalCTNClass, which derives from
# _BacnetSlavePlug and ConfigTreeNode. This means that we can exceptionally
- # consider that all objects of type _BacnetSlavePlug will also be a ConfigTreeNode).
- result = self.ChangesToSave or self.ObjTables[ "AV_Obj"].ChangesToSave \
- or self.ObjTables[ "AO_Obj"].ChangesToSave \
- or self.ObjTables[ "AI_Obj"].ChangesToSave \
- or self.ObjTables[ "BV_Obj"].ChangesToSave \
- or self.ObjTables[ "BO_Obj"].ChangesToSave \
- or self.ObjTables[ "BI_Obj"].ChangesToSave \
- or self.ObjTables["MSV_Obj"].ChangesToSave \
- or self.ObjTables["MSO_Obj"].ChangesToSave \
- or self.ObjTables["MSI_Obj"].ChangesToSave
+ # consider that all objects of type _BacnetSlavePlug will also be a
+ # ConfigTreeNode).
+ result = self.ChangesToSave \
+ or self.ObjTables["AV_Obj"].ChangesToSave \
+ or self.ObjTables["AO_Obj"].ChangesToSave \
+ or self.ObjTables["AI_Obj"].ChangesToSave \
+ or self.ObjTables["BV_Obj"].ChangesToSave \
+ or self.ObjTables["BO_Obj"].ChangesToSave \
+ or self.ObjTables["BI_Obj"].ChangesToSave \
+ or self.ObjTables["MSV_Obj"].ChangesToSave \
+ or self.ObjTables["MSO_Obj"].ChangesToSave \
+ or self.ObjTables["MSI_Obj"].ChangesToSave
return result
- ### Currently not needed. Override _OpenView() in case we need to do some special stuff whenever the editor is opened!
- ##def _OpenView(self, name=None, onlyopened=False):
- ##print "_BacnetSlavePlug._OpenView() Called!!!"
- ##ConfigTreeNode._OpenView(self, name, onlyopened)
- ###print self._View
- #####if self._View is not None:
- #####self._View.SetBusId(self.GetCurrentLocation())
- ##return self._View
-
+ # Currently not needed. Override _OpenView() in case we need to do some special stuff whenever the editor is opened!
+ # def _OpenView(self, name=None, onlyopened=False):
+ # print "_BacnetSlavePlug._OpenView() Called!!!"
+ # ConfigTreeNode._OpenView(self, name, onlyopened)
+ # print self._View
+ # if self._View is not None:
+ # self._View.SetBusId(self.GetCurrentLocation())
+ # return self._View
def GetVariableLocationTree(self):
current_location = self.GetCurrentLocation()
# see comment in CTNGenerate_C regarding identical line of code!
- locstr = ".".join(map(str,current_location))
-
+ locstr = ".".join(map(str, current_location))
+
# IDs used by BACnet to identify object types/class.
# OBJECT_ANALOG_INPUT = 0,
# OBJECT_ANALOG_OUTPUT = 1,
@@ -270,78 +286,84 @@
# Value objects will be mapped onto %M
# Input objects will be mapped onto %I
# Output objects will be mapped onto %Q
-
+
BACnetEntries = []
BACnetEntries.append(self.GetSlaveLocationTree(
- self.ObjTablesData[ "AV_Obj"], 32, 'REAL', 'D', locstr+ '.2', 'Analog Values'))
- BACnetEntries.append(self.GetSlaveLocationTree(
- self.ObjTablesData[ "AO_Obj"], 32, 'REAL', 'D', locstr+ '.1', 'Analog Outputs'))
- BACnetEntries.append(self.GetSlaveLocationTree(
- self.ObjTablesData[ "AI_Obj"], 32, 'REAL', 'D', locstr+ '.0', 'Analog Inputs'))
- BACnetEntries.append(self.GetSlaveLocationTree(
- self.ObjTablesData[ "BV_Obj"], 1, 'BOOL', 'X', locstr+ '.5', 'Binary Values'))
- BACnetEntries.append(self.GetSlaveLocationTree(
- self.ObjTablesData[ "BO_Obj"], 1, 'BOOL', 'X', locstr+ '.4', 'Binary Outputs'))
- BACnetEntries.append(self.GetSlaveLocationTree(
- self.ObjTablesData[ "BI_Obj"], 1, 'BOOL', 'X', locstr+ '.3', 'Binary Inputs'))
- BACnetEntries.append(self.GetSlaveLocationTree(
- self.ObjTablesData["MSV_Obj"], 8, 'BYTE', 'B', locstr+'.19', 'Multi State Values'))
- BACnetEntries.append(self.GetSlaveLocationTree(
- self.ObjTablesData["MSO_Obj"], 8, 'BYTE', 'B', locstr+'.14', 'Multi State Outputs'))
- BACnetEntries.append(self.GetSlaveLocationTree(
- self.ObjTablesData["MSI_Obj"], 8, 'BYTE', 'B', locstr+'.13', 'Multi State Inputs'))
-
- return {"name": self.BaseParams.getName(),
- "type": LOCATION_CONFNODE,
- "location": locstr + ".x",
- "children": BACnetEntries}
-
-
- ############################
+ self.ObjTablesData["AV_Obj"], 32, 'REAL', 'D', locstr + '.2', 'Analog Values'))
+ BACnetEntries.append(self.GetSlaveLocationTree(
+ self.ObjTablesData["AO_Obj"], 32, 'REAL', 'D', locstr + '.1', 'Analog Outputs'))
+ BACnetEntries.append(self.GetSlaveLocationTree(
+ self.ObjTablesData["AI_Obj"], 32, 'REAL', 'D', locstr + '.0', 'Analog Inputs'))
+ BACnetEntries.append(self.GetSlaveLocationTree(
+ self.ObjTablesData["BV_Obj"], 1, 'BOOL', 'X', locstr + '.5', 'Binary Values'))
+ BACnetEntries.append(self.GetSlaveLocationTree(
+ self.ObjTablesData["BO_Obj"], 1, 'BOOL', 'X', locstr + '.4', 'Binary Outputs'))
+ BACnetEntries.append(self.GetSlaveLocationTree(
+ self.ObjTablesData["BI_Obj"], 1, 'BOOL', 'X', locstr + '.3', 'Binary Inputs'))
+ BACnetEntries.append(self.GetSlaveLocationTree(
+ self.ObjTablesData["MSV_Obj"], 8, 'BYTE', 'B', locstr + '.19', 'Multi State Values'))
+ BACnetEntries.append(self.GetSlaveLocationTree(
+ self.ObjTablesData["MSO_Obj"], 8, 'BYTE', 'B', locstr + '.14', 'Multi State Outputs'))
+ BACnetEntries.append(self.GetSlaveLocationTree(
+ self.ObjTablesData["MSI_Obj"], 8, 'BYTE', 'B', locstr + '.13', 'Multi State Inputs'))
+
+ return {"name": self.BaseParams.getName(),
+ "type": LOCATION_CONFNODE,
+ "location": locstr + ".x",
+ "children": BACnetEntries}
+
+ #
# Helper functions/methods #
- ############################
+ #
# a helper function to GetVariableLocationTree()
def GetSlaveLocationTree(self, ObjTablesData, size_in_bits, IECdatatype, location_size, location_str, name):
BACnetObjectEntries = []
- for xx_ObjProp in ObjTablesData:
+ for xx_ObjProp in ObjTablesData:
BACnetObjectEntries.append({
"name": str(xx_ObjProp["Object Identifier"]) + ': ' + xx_ObjProp["Object Name"],
- "type": LOCATION_VAR_MEMORY, # LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, or LOCATION_VAR_MEMORY
- "size": size_in_bits, # 1 or 16
- "IEC_type": IECdatatype, # 'BOOL', 'WORD', ...
- "var_name": "var_name", # seems to be ignored??
+ "type": LOCATION_VAR_MEMORY, # LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, or LOCATION_VAR_MEMORY
+ "size": size_in_bits, # 1 or 16
+ "IEC_type": IECdatatype, # 'BOOL', 'WORD', ...
+ "var_name": "var_name", # seems to be ignored??
"location": location_size + location_str + "." + str(xx_ObjProp["Object Identifier"]),
- "description": "description", # seems to be ignored?
+ "description": "description", # seems to be ignored?
"children": []})
-
- BACnetEntries = []
- return {"name": name,
- "type": LOCATION_CONFNODE,
- "location": location_str + ".x",
- "children": BACnetObjectEntries}
-
-
+
+ return {"name": name,
+ "type": LOCATION_CONFNODE,
+ "location": location_str + ".x",
+ "children": BACnetObjectEntries}
+
# Returns a dictionary with:
# keys: names of BACnet objects
- # value: number of BACnet objects using this same name
+ # value: number of BACnet objects using this same name
# (values larger than 1 indicates an error as BACnet requires unique names)
def GetObjectNamesCount(self):
- # The dictionary is built by first creating a list containing the names of _ALL_
+ # The dictionary is built by first creating a list containing the names of _ALL_
# BACnet objects currently configured by the user (using the GUI)
ObjectNames = []
- ObjectNames.extend(self.ObjTables[ "AV_Obj"].GetAllValuesByName("Object Name"))
- ObjectNames.extend(self.ObjTables[ "AO_Obj"].GetAllValuesByName("Object Name"))
- ObjectNames.extend(self.ObjTables[ "AI_Obj"].GetAllValuesByName("Object Name"))
- ObjectNames.extend(self.ObjTables[ "BV_Obj"].GetAllValuesByName("Object Name"))
- ObjectNames.extend(self.ObjTables[ "BO_Obj"].GetAllValuesByName("Object Name"))
- ObjectNames.extend(self.ObjTables[ "BI_Obj"].GetAllValuesByName("Object Name"))
- ObjectNames.extend(self.ObjTables["MSV_Obj"].GetAllValuesByName("Object Name"))
- ObjectNames.extend(self.ObjTables["MSO_Obj"].GetAllValuesByName("Object Name"))
- ObjectNames.extend(self.ObjTables["MSI_Obj"].GetAllValuesByName("Object Name"))
+ ObjectNames.extend(
+ self.ObjTables["AV_Obj"].GetAllValuesByName("Object Name"))
+ ObjectNames.extend(
+ self.ObjTables["AO_Obj"].GetAllValuesByName("Object Name"))
+ ObjectNames.extend(
+ self.ObjTables["AI_Obj"].GetAllValuesByName("Object Name"))
+ ObjectNames.extend(
+ self.ObjTables["BV_Obj"].GetAllValuesByName("Object Name"))
+ ObjectNames.extend(
+ self.ObjTables["BO_Obj"].GetAllValuesByName("Object Name"))
+ ObjectNames.extend(
+ self.ObjTables["BI_Obj"].GetAllValuesByName("Object Name"))
+ ObjectNames.extend(
+ self.ObjTables["MSV_Obj"].GetAllValuesByName("Object Name"))
+ ObjectNames.extend(
+ self.ObjTables["MSO_Obj"].GetAllValuesByName("Object Name"))
+ ObjectNames.extend(
+ self.ObjTables["MSI_Obj"].GetAllValuesByName("Object Name"))
# This list is then transformed into a collections.Counter class
# Which is then transformed into a dictionary using dict()
return dict(Counter(ObjectNames))
-
+
# Check whether the current configuration contains BACnet objects configured
# with the same identical object name (returns True or False)
def HasDuplicateObjectNames(self):
@@ -354,26 +376,25 @@
# Check whether any object ID is used more than once (not valid in BACnet)
# (returns True or False)
def HasDuplicateObjectIDs(self):
- res = self.ObjTables[ "AV_Obj"].HasDuplicateObjectIDs()
- res = res or self.ObjTables[ "AO_Obj"].HasDuplicateObjectIDs()
- res = res or self.ObjTables[ "AI_Obj"].HasDuplicateObjectIDs()
- res = res or self.ObjTables[ "BV_Obj"].HasDuplicateObjectIDs()
- res = res or self.ObjTables[ "BO_Obj"].HasDuplicateObjectIDs()
- res = res or self.ObjTables[ "BI_Obj"].HasDuplicateObjectIDs()
+ res = self.ObjTables["AV_Obj"].HasDuplicateObjectIDs()
+ res = res or self.ObjTables["AO_Obj"].HasDuplicateObjectIDs()
+ res = res or self.ObjTables["AI_Obj"].HasDuplicateObjectIDs()
+ res = res or self.ObjTables["BV_Obj"].HasDuplicateObjectIDs()
+ res = res or self.ObjTables["BO_Obj"].HasDuplicateObjectIDs()
+ res = res or self.ObjTables["BI_Obj"].HasDuplicateObjectIDs()
res = res or self.ObjTables["MSV_Obj"].HasDuplicateObjectIDs()
res = res or self.ObjTables["MSO_Obj"].HasDuplicateObjectIDs()
res = res or self.ObjTables["MSI_Obj"].HasDuplicateObjectIDs()
return res
-
- #######################################################
+ #
# Methods related to files (saving/loading/exporting) #
- #######################################################
+ #
def SaveToFile(self, filepath):
# Save node data in file
# The configuration data declared in the XSD string will be saved by the ConfigTreeNode class,
# so we only need to save the data that is stored in ObjTablesData objects
- # Note that we do not store the ObjTables objects. ObjTables is of a class that
+ # Note that we do not store the ObjTables objects. ObjTables is of a class that
# contains more stuff we do not need to store. Actually it is a bad idea to store
# this extra stuff (as we would make the files we generate dependent on the actual
# version of the wx library we are using!!! Remember that ObjTables evetually
@@ -383,19 +404,20 @@
fd = open(filepath, "w")
pickle.dump(self.ObjTablesData, fd)
fd.close()
- # On successfull save, reset flags to indicate no more changes that need saving
- self.ObjTables[ "AV_Obj"].ChangesToSave = False
- self.ObjTables[ "AO_Obj"].ChangesToSave = False
- self.ObjTables[ "AI_Obj"].ChangesToSave = False
- self.ObjTables[ "BV_Obj"].ChangesToSave = False
- self.ObjTables[ "BO_Obj"].ChangesToSave = False
- self.ObjTables[ "BI_Obj"].ChangesToSave = False
+ # On successfull save, reset flags to indicate no more changes that
+ # need saving
+ self.ObjTables["AV_Obj"].ChangesToSave = False
+ self.ObjTables["AO_Obj"].ChangesToSave = False
+ self.ObjTables["AI_Obj"].ChangesToSave = False
+ self.ObjTables["BV_Obj"].ChangesToSave = False
+ self.ObjTables["BO_Obj"].ChangesToSave = False
+ self.ObjTables["BI_Obj"].ChangesToSave = False
self.ObjTables["MSV_Obj"].ChangesToSave = False
self.ObjTables["MSO_Obj"].ChangesToSave = False
self.ObjTables["MSI_Obj"].ChangesToSave = False
return True
except:
- return _("Unable to save to file \"%s\"!")%filepath
+ return _("Unable to save to file \"%s\"!") % filepath
def LoadFromFile(self, filepath):
# Load the data that is saved in SaveToFile()
@@ -405,157 +427,181 @@
fd.close()
return True
except:
- return _("Unable to load file \"%s\"!")%filepath
+ return _("Unable to load file \"%s\"!") % filepath
def _ExportBacnetSlave(self):
- dialog = wx.FileDialog(self.GetCTRoot().AppFrame,
- _("Choose a file"),
- os.path.expanduser("~"),
- "%s_EDE.csv" % self.CTNName(),
+ dialog = wx.FileDialog(self.GetCTRoot().AppFrame,
+ _("Choose a file"),
+ os.path.expanduser("~"),
+ "%s_EDE.csv" % self.CTNName(),
_("EDE files (*_EDE.csv)|*_EDE.csv|All files|*.*"),
- wx.SAVE|wx.OVERWRITE_PROMPT)
+ wx.SAVE | wx.OVERWRITE_PROMPT)
if dialog.ShowModal() == wx.ID_OK:
result = self.GenerateEDEFile(dialog.GetPath())
result = False
if result:
- self.GetCTRoot().logger.write_error(_("Error: Export slave failed\n"))
- dialog.Destroy()
-
+ self.GetCTRoot().logger.write_error(
+ _("Error: Export slave failed\n"))
+ dialog.Destroy()
def GenerateEDEFile(self, filename):
- template_file_dir = os.path.join(os.path.split(__file__)[0],"ede_files")
-
- #The BACnetServerNode attribute is added dynamically by ConfigTreeNode._AddParamsMembers()
- # It will be an XML parser object created by GenerateParserFromXSDstring(self.XSD).CreateRoot()
+ template_file_dir = os.path.join(
+ os.path.split(__file__)[0], "ede_files")
+
+ # The BACnetServerNode attribute is added dynamically by ConfigTreeNode._AddParamsMembers()
+ # It will be an XML parser object created by
+ # GenerateParserFromXSDstring(self.XSD).CreateRoot()
BACnet_Device_ID = self.BACnetServerNode.getBACnet_Device_ID()
-
+
# The EDE file contains a header that includes general project data (name, author, ...)
# Instead of asking the user for this data, we get it from the configuration
# of the Beremiz project itself.
# We ask the root Config Tree Node for the data...
ProjProp = {}
FileProp = {}
- CTN_Root = self.GetCTRoot() # this should be an object of class ProjectController
- Project = CTN_Root.Project # this should be an object capable of parsing
- # PLCopen XML files. The parser is created automatically
- # (i.e. using GenerateParserFromXSD() from xmlclass module)
- # using the PLCopen XSD file defining the format of the XML.
- # See the file plcopen/plcopen.py
+
+ # this should be an object of class ProjectController
+ CTN_Root = self.GetCTRoot()
+
+ # this should be an object capable of parsing
+ # PLCopen XML files. The parser is created automatically
+ # (i.e. using GenerateParserFromXSD() from xmlclass module)
+ # using the PLCopen XSD file defining the format of the XML.
+ # See the file plcopen/plcopen.py
+ Project = CTN_Root.Project
if Project is not None:
- # getcontentHeader() and getfileHeader() are functions that are conditionally defined in
- # plcopn/plcopen.py We cannot rely on their existance
- if getattr(Project, "getcontentHeader", None) is not None:
- ProjProp = Project.getcontentHeader()
- # getcontentHeader() returns a dictionary. Available keys are:
- # "projectName", "projectVersion", "modificationDateTime",
- # "organization", "authorName", "language", "pageSize", "scaling"
- if getattr(Project, "getfileHeader", None) is not None:
- FileProp = Project.getfileHeader()
- # getfileHeader() returns a dictionary. Available keys are:
- # "companyName", "companyURL", "productName", "productVersion",
- # "productRelease", "creationDateTime", "contentDescription"
-
- ProjName = ""
+ # getcontentHeader() and getfileHeader() are functions that are conditionally defined in
+ # plcopn/plcopen.py We cannot rely on their existance
+ if getattr(Project, "getcontentHeader", None) is not None:
+ ProjProp = Project.getcontentHeader()
+ # getcontentHeader() returns a dictionary. Available keys are:
+ # "projectName", "projectVersion", "modificationDateTime",
+ # "organization", "authorName", "language", "pageSize", "scaling"
+ if getattr(Project, "getfileHeader", None) is not None:
+ FileProp = Project.getfileHeader()
+ # getfileHeader() returns a dictionary. Available keys are:
+ # "companyName", "companyURL", "productName", "productVersion",
+ # "productRelease", "creationDateTime", "contentDescription"
+
+ ProjName = ""
if "projectName" in ProjProp:
- ProjName = ProjProp["projectName"]
+ ProjName = ProjProp["projectName"]
ProjAuthor = ""
if "companyName" in FileProp:
ProjAuthor += "(" + FileProp["companyName"] + ")"
if "authorName" in ProjProp:
- ProjAuthor = ProjProp["authorName"] + " " + ProjAuthor
-
+ ProjAuthor = ProjProp["authorName"] + " " + ProjAuthor
+
projdata_dict = {}
- projdata_dict["Project Name"] = ProjName
- projdata_dict["Project Author"] = ProjAuthor
- projdata_dict["Current Time"] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- projdata_dict["EDE file version"] = self.ObjTablesData["EDEfile_parm"]["next_EDE_file_version"]
+ projdata_dict["Project Name"] = ProjName
+ projdata_dict["Project Author"] = ProjAuthor
+ projdata_dict["Current Time"] = datetime.now().strftime(
+ '%Y-%m-%d %H:%M:%S')
+ projdata_dict["EDE file version"] = self.ObjTablesData[
+ "EDEfile_parm"]["next_EDE_file_version"]
# Next time we generate an EDE file, use another version!
self.ObjTablesData["EDEfile_parm"]["next_EDE_file_version"] += 1
- AX_params_format = "%(Object Name)s;" + str(BACnet_Device_ID) + ";%(Object Name)s;%(BACnetObjTypeID)s;%(Object Identifier)s;%(Description)s;0;;;%(Settable)s;N;;;;%(Unit ID)s;"
-
- BX_params_format = "%(Object Name)s;" + str(BACnet_Device_ID) + ";%(Object Name)s;%(BACnetObjTypeID)s;%(Object Identifier)s;%(Description)s;0;0;1;%(Settable)s;N;;;;;"
-
- MSX_params_format = "%(Object Name)s;" + str(BACnet_Device_ID) + ";%(Object Name)s;%(BACnetObjTypeID)s;%(Object Identifier)s;%(Description)s;1;1;%(Number of States)s;%(Settable)s;N;;;;;"
-
+ AX_params_format = "%(Object Name)s;" + str(BACnet_Device_ID) + \
+ ";%(Object Name)s;%(BACnetObjTypeID)s;%(Object Identifier)s;%(Description)s;0;;;%(Settable)s;N;;;;%(Unit ID)s;"
+
+ BX_params_format = "%(Object Name)s;" + str(BACnet_Device_ID) + \
+ ";%(Object Name)s;%(BACnetObjTypeID)s;%(Object Identifier)s;%(Description)s;0;0;1;%(Settable)s;N;;;;;"
+
+ MSX_params_format = "%(Object Name)s;" + str(BACnet_Device_ID) + \
+ ";%(Object Name)s;%(BACnetObjTypeID)s;%(Object Identifier)s;%(Description)s;1;1;%(Number of States)s;%(Settable)s;N;;;;;"
+
Objects_List = []
- for ObjType, params_format in [
- ("AV" , AX_params_format ), ("AO" , AX_params_format ), ("AI" , AX_params_format ),
- ("BV" , BX_params_format ), ("BO" , BX_params_format ), ("BI" , BX_params_format ),
- ("MSV", MSX_params_format ), ("MSO", MSX_params_format ), ("MSI", MSX_params_format )
- ]:
+ for ObjType, params_format in [("AV", AX_params_format),
+ ("AO", AX_params_format),
+ ("AI", AX_params_format),
+ ("BV", BX_params_format),
+ ("BO", BX_params_format),
+ ("BI", BX_params_format),
+ ("MSV", MSX_params_format),
+ ("MSO", MSX_params_format),
+ ("MSI", MSX_params_format)]:
self.ObjTables[ObjType + "_Obj"].UpdateAllVirtualProperties()
for ObjProp in self.ObjTablesData[ObjType + "_Obj"]:
Objects_List.append(params_format % ObjProp)
-
+
# Normalize filename
for extension in ["_EDE.csv", "_ObjTypes.csv", "_StateTexts.csv", "_Units.csv"]:
if filename.lower().endswith(extension.lower()):
filename = filename[:-len(extension)]
-
+
# EDE_header
- generate_file_name = filename + "_EDE.csv"
- template_file_name = os.path.join(template_file_dir,"template_EDE.csv")
+ generate_file_name = filename + "_EDE.csv"
+ template_file_name = os.path.join(
+ template_file_dir, "template_EDE.csv")
generate_file_content = open(template_file_name).read() % projdata_dict
- generate_file_handle = open(generate_file_name,'w')
+ generate_file_handle = open(generate_file_name, 'w')
generate_file_handle .write(generate_file_content)
generate_file_handle .write("\n".join(Objects_List))
generate_file_handle .close()
-
- # templates of remaining files do not need changes. They are simply copied unchanged!
+
+ # templates of remaining files do not need changes. They are simply
+ # copied unchanged!
for extension in ["_ObjTypes.csv", "_StateTexts.csv", "_Units.csv"]:
- generate_file_name = filename + extension
- template_file_name = os.path.join(template_file_dir,"template" + extension)
+ generate_file_name = filename + extension
+ template_file_name = os.path.join(
+ template_file_dir, "template" + extension)
generate_file_content = open(template_file_name).read()
- generate_file_handle = open(generate_file_name,'w')
+ generate_file_handle = open(generate_file_name, 'w')
generate_file_handle .write(generate_file_content)
generate_file_handle .close()
-
- #############################
+ #
# Generate the source files #
- #############################
- def CTNGenerate_C(self, buildpath, locations):
- # Determine the current location in Beremiz's project configuration tree
+ #
+ def CTNGenerate_C(self, buildpath, locations):
+ # Determine the current location in Beremiz's project configuration
+ # tree
current_location = self.GetCurrentLocation()
- # The current location of this plugin in Beremiz's configuration tree, separated by underscores
+ # The current location of this plugin in Beremiz's configuration tree, separated by underscores
# NOTE: Since BACnet plugin currently does not use sub-branches in the tree (in other words, this
# _BacnetSlavePlug class was actually renamed as the RootClass), the current_location_dots
# will actually be a single number (e.g.: 0 or 3 or 6, corresponding to the location
# in which the plugin was inserted in the Beremiz configuration tree on Beremiz's left panel).
- locstr = "_".join(map(str,current_location))
-
- # First check whether all the current parameters (inserted by user in the GUI) are valid...
+ locstr = "_".join(map(str, current_location))
+
+ # First check whether all the current parameters (inserted by user in
+ # the GUI) are valid...
if self.HasDuplicateObjectNames():
- self.GetCTRoot().logger.write_warning(_("Error: BACnet server '%s.x: %s' contains objects with duplicate object names.\n")%(locstr, self.CTNName()))
- raise Exception, False
- # TODO: return an error code instead of raising an exception (currently unsupported by Beremiz)
+ self.GetCTRoot().logger.write_warning(
+ _("Error: BACnet server '%s.x: %s' contains objects with duplicate object names.\n") % (locstr, self.CTNName()))
+ raise Exception(False)
+ # TODO: return an error code instead of raising an exception
+ # (currently unsupported by Beremiz)
if self.HasDuplicateObjectIDs():
- self.GetCTRoot().logger.write_warning(_("Error: BACnet server '%s.x: %s' contains objects with duplicate object identifiers.\n")%(locstr, self.CTNName()))
- raise Exception, False
- # TODO: return an error code instead of raising an exception (currently unsupported by Beremiz)
-
- #-------------------------------------------------------------------------------
+ self.GetCTRoot().logger.write_warning(
+ _("Error: BACnet server '%s.x: %s' contains objects with duplicate object identifiers.\n") % (locstr, self.CTNName()))
+ raise Exception(False)
+ # TODO: return an error code instead of raising an exception
+ # (currently unsupported by Beremiz)
+
+ # -------------------------------------------------------------------------------
# Create and populate the loc_dict dictionary with all parameters needed to configure
# the generated source code (.c and .h files)
- #-------------------------------------------------------------------------------
-
+ # ----------------------------------------------------------------------
+
# 1) Create the dictionary (loc_dict = {})
loc_dict = {}
- loc_dict["locstr"] = locstr
-
- #The BACnetServerNode attribute is added dynamically by ConfigTreeNode._AddParamsMembers()
- # It will be an XML parser object created by GenerateParserFromXSDstring(self.XSD).CreateRoot()
- loc_dict["network_interface"] = self.BACnetServerNode.getNetwork_Interface()
- loc_dict["port_number"] = self.BACnetServerNode.getUDP_Port_Number()
- loc_dict["BACnet_Device_ID"] = self.BACnetServerNode.getBACnet_Device_ID()
- loc_dict["BACnet_Device_Name"] = self.BACnetServerNode.getBACnet_Device_Name()
+ loc_dict["locstr"] = locstr
+
+ # The BACnetServerNode attribute is added dynamically by ConfigTreeNode._AddParamsMembers()
+ # It will be an XML parser object created by
+ # GenerateParserFromXSDstring(self.XSD).CreateRoot()
+ loc_dict["network_interface"] = self.BACnetServerNode.getNetwork_Interface()
+ loc_dict["port_number"] = self.BACnetServerNode.getUDP_Port_Number()
+ loc_dict["BACnet_Device_ID"] = self.BACnetServerNode.getBACnet_Device_ID()
+ loc_dict["BACnet_Device_Name"] = self.BACnetServerNode.getBACnet_Device_Name()
loc_dict["BACnet_Comm_Control_Password"] = self.BACnetServerNode.getBACnet_Communication_Control_Password()
- loc_dict["BACnet_Device_Location"] = self.BACnetServerNode.getBACnet_Device_Location()
- loc_dict["BACnet_Device_Description"] = self.BACnetServerNode.getBACnet_Device_Description()
- loc_dict["BACnet_Device_AppSoft_Version"]= self.BACnetServerNode.getBACnet_Device_Application_Software_Version()
+ loc_dict["BACnet_Device_Location"] = self.BACnetServerNode.getBACnet_Device_Location()
+ loc_dict["BACnet_Device_Description"] = self.BACnetServerNode.getBACnet_Device_Description()
+ loc_dict["BACnet_Device_AppSoft_Version"] = self.BACnetServerNode.getBACnet_Device_Application_Software_Version()
loc_dict["BACnet_Vendor_ID"] = BACNET_VENDOR_ID
loc_dict["BACnet_Vendor_Name"] = BACNET_VENDOR_NAME
loc_dict["BACnet_Model_Name"] = BACNET_DEVICE_MODEL_NAME
@@ -563,90 +609,95 @@
# 2) Add the data specific to each BACnet object type
# For each BACnet object type, start off by creating some intermediate helpful lists
# a) parameters_list containing the strings that will
- # be included in the C source code, and which will initialize the struct with the
+ # be included in the C source code, and which will initialize the struct with the
# object (Analog Value, Binary Value, or Multi State Value) parameters
# b) locatedvar_list containing the strings that will
- # declare the memory to store the located variables, as well as the
+ # declare the memory to store the located variables, as well as the
# pointers (required by matiec) that point to that memory.
- # format for delaring IEC 61131-3 variable (and pointer) onto which BACnet object is mapped
+ # format for delaring IEC 61131-3 variable (and pointer) onto which
+ # BACnet object is mapped
locvar_format = '%(Ctype)s ___%(loc)s_%(Object Identifier)s; ' + \
'%(Ctype)s *__%(loc)s_%(Object Identifier)s = &___%(loc)s_%(Object Identifier)s;'
# format for initializing a ANALOG_VALUE_DESCR struct in C code
# also valid for ANALOG_INPUT and ANALOG_OUTPUT
AX_params_format = '{&___%(loc)s_%(Object Identifier)s, ' + \
- '%(Object Identifier)s, "%(Object Name)s", "%(Description)s", %(Unit ID)d}'
+ '%(Object Identifier)s, "%(Object Name)s", "%(Description)s", %(Unit ID)d}'
# format for initializing a BINARY_VALUE_DESCR struct in C code
# also valid for BINARY_INPUT and BINARY_OUTPUT
BX_params_format = '{&___%(loc)s_%(Object Identifier)s, ' + \
- '%(Object Identifier)s, "%(Object Name)s", "%(Description)s"}'
+ '%(Object Identifier)s, "%(Object Name)s", "%(Description)s"}'
# format for initializing a MULTISTATE_VALUE_DESCR struct in C code
# also valid for MULTISTATE_INPUT and MULTISTATE_OUTPUT
MSX_params_format = '{&___%(loc)s_%(Object Identifier)s, ' + \
- '%(Object Identifier)s, "%(Object Name)s", "%(Description)s", %(Number of States)s}'
-
- AV_locstr = 'MD' + locstr+'_2' # see the comment in GetVariableLocationTree() to grok the '_2'
- AO_locstr = 'QD' + locstr+'_1' # see the comment in GetVariableLocationTree() to grok the '_1'
- AI_locstr = 'ID' + locstr+'_0' # see the comment in GetVariableLocationTree() to grok the '_0'
- BV_locstr = 'MX' + locstr+'_5' # see the comment in GetVariableLocationTree() to grok the '_5'
- BO_locstr = 'QX' + locstr+'_4' # see the comment in GetVariableLocationTree() to grok the '_4'
- BI_locstr = 'IX' + locstr+'_3' # see the comment in GetVariableLocationTree() to grok the '_3'
- MSV_locstr = 'MB' + locstr+'_19' # see the comment in GetVariableLocationTree() to grok the '_19'
- MSO_locstr = 'QB' + locstr+'_14' # see the comment in GetVariableLocationTree() to grok the '_14'
- MSI_locstr = 'IB' + locstr+'_13' # see the comment in GetVariableLocationTree() to grok the '_13'
-
-
- for ObjType, ObjLocStr, params_format in [
- ("AV" , AV_locstr, AX_params_format ),
- ("AO" , AO_locstr, AX_params_format ),
- ("AI" , AI_locstr, AX_params_format ),
- ("BV" , BV_locstr, BX_params_format ),
- ("BO" , BO_locstr, BX_params_format ),
- ("BI" , BI_locstr, BX_params_format ),
- ("MSV" , MSV_locstr, MSX_params_format ),
- ("MSO" , MSO_locstr, MSX_params_format ),
- ("MSI" , MSI_locstr, MSX_params_format )
- ]:
+ '%(Object Identifier)s, "%(Object Name)s", "%(Description)s", %(Number of States)s}'
+
+ # see the comment in GetVariableLocationTree()
+ AV_locstr = 'MD' + locstr + '_2'
+ AO_locstr = 'QD' + locstr + '_1'
+ AI_locstr = 'ID' + locstr + '_0'
+ BV_locstr = 'MX' + locstr + '_5'
+ BO_locstr = 'QX' + locstr + '_4'
+ BI_locstr = 'IX' + locstr + '_3'
+ MSV_locstr = 'MB' + locstr + '_19'
+ MSO_locstr = 'QB' + locstr + '_14'
+ MSI_locstr = 'IB' + locstr + '_13'
+
+ for ObjType, ObjLocStr, params_format in [
+ ("AV", AV_locstr, AX_params_format),
+ ("AO", AO_locstr, AX_params_format),
+ ("AI", AI_locstr, AX_params_format),
+ ("BV", BV_locstr, BX_params_format),
+ ("BO", BO_locstr, BX_params_format),
+ ("BI", BI_locstr, BX_params_format),
+ ("MSV", MSV_locstr, MSX_params_format),
+ ("MSO", MSO_locstr, MSX_params_format),
+ ("MSI", MSI_locstr, MSX_params_format)]:
parameters_list = []
locatedvar_list = []
self.ObjTables[ObjType + "_Obj"].UpdateAllVirtualProperties()
for ObjProp in self.ObjTablesData[ObjType + "_Obj"]:
- ObjProp["loc" ] = ObjLocStr
+ ObjProp["loc"] = ObjLocStr
parameters_list.append(params_format % ObjProp)
locatedvar_list.append(locvar_format % ObjProp)
- loc_dict[ ObjType + "_count"] = len( parameters_list )
- loc_dict[ ObjType + "_param"] = ",\n".join( parameters_list )
- loc_dict[ ObjType + "_lvars"] = "\n".join( locatedvar_list )
-
- #----------------------------------------------------------------------
+ loc_dict[ObjType + "_count"] = len(parameters_list)
+ loc_dict[ObjType + "_param"] = ",\n".join(parameters_list)
+ loc_dict[ObjType + "_lvars"] = "\n".join(locatedvar_list)
+
+ # ----------------------------------------------------------------------
# Create the C source files that implement the BACnet server
- #----------------------------------------------------------------------
-
+ # ----------------------------------------------------------------------
+
# Names of the .c files that will be generated, based on a template file with same name
# (names without '.c' --> this will be added later)
# main server.c file is handled separately
Generated_BACnet_c_mainfile = "server"
- Generated_BACnet_c_files = ["ai", "ao", "av", "bi", "bo", "bv", "msi", "mso", "msv", "device"]
+ Generated_BACnet_c_files = [
+ "ai", "ao", "av", "bi", "bo", "bv", "msi", "mso", "msv", "device"]
# Names of the .h files that will be generated, based on a template file with same name
# (names without '.h' --> this will be added later)
- Generated_BACnet_h_files = ["server", "device", "config_bacnet_for_beremiz",
- "ai", "ao", "av", "bi", "bo", "bv", "msi", "mso", "msv"
- ]
+ Generated_BACnet_h_files = [
+ "server", "device", "config_bacnet_for_beremiz",
+ "ai", "ao", "av", "bi", "bo", "bv", "msi", "mso", "msv"
+ ]
# Generate the files with the source code
postfix = "_".join(map(str, current_location))
- template_file_dir = os.path.join(os.path.split(__file__)[0],"runtime")
-
- def generate_file(file_name, extension):
- generate_file_name = os.path.join(buildpath, "%s_%s.%s"%(file_name,postfix,extension))
- template_file_name = os.path.join(template_file_dir,"%s.%s"%(file_name,extension))
+ template_file_dir = os.path.join(
+ os.path.split(__file__)[0], "runtime")
+
+ def generate_file(file_name, extension):
+ generate_file_name = os.path.join(
+ buildpath, "%s_%s.%s" % (file_name, postfix, extension))
+ template_file_name = os.path.join(
+ template_file_dir, "%s.%s" % (file_name, extension))
generate_file_content = open(template_file_name).read() % loc_dict
- generate_file_handle = open(generate_file_name,'w')
- generate_file_handle .write(generate_file_content)
- generate_file_handle .close()
+ generate_file_handle = open(generate_file_name, 'w')
+ generate_file_handle.write(generate_file_content)
+ generate_file_handle.close()
for file_name in Generated_BACnet_c_files:
generate_file(file_name, "c")
@@ -654,44 +705,23 @@
generate_file(file_name, "h")
generate_file(Generated_BACnet_c_mainfile, "c")
Generated_BACnet_c_mainfile_name = \
- os.path.join(buildpath, "%s_%s.%s"%(Generated_BACnet_c_mainfile,postfix,"c"))
-
- #----------------------------------------------------------------------
+ os.path.join(buildpath, "%s_%s.%s" %
+ (Generated_BACnet_c_mainfile, postfix, "c"))
+
+ # ----------------------------------------------------------------------
# Finally, define the compilation and linking commands and flags
- #----------------------------------------------------------------------
-
+ # ----------------------------------------------------------------------
+
LDFLAGS = []
# when using dynamically linked library...
- #LDFLAGS.append(' -lbacnet')
- #LDFLAGS.append(' -L"'+BacnetLibraryPath+'"')
- #LDFLAGS.append(' "-Wl,-rpath,' + BacnetLibraryPath + '"')
+ # LDFLAGS.append(' -lbacnet')
+ # LDFLAGS.append(' -L"'+BacnetLibraryPath+'"')
+ # LDFLAGS.append(' "-Wl,-rpath,' + BacnetLibraryPath + '"')
# when using static library:
- LDFLAGS.append(' "'+os.path.join(BacnetLibraryPath, "libbacnet.a")+'"')
-
- CFLAGS = ' -I"'+BacnetIncludePath+'"'
- CFLAGS += ' -I"'+BacnetIncludePortPath+'"'
-
+ LDFLAGS.append(
+ ' "' + os.path.join(BacnetLibraryPath, "libbacnet.a") + '"')
+
+ CFLAGS = ' -I"' + BacnetIncludePath + '"'
+ CFLAGS += ' -I"' + BacnetIncludePortPath + '"'
+
return [(Generated_BACnet_c_mainfile_name, CFLAGS)], LDFLAGS, True
-
-
-
-###################################################
-###################################################
-# #
-# R O O T C L A S S #
-# #
-###################################################
-###################################################
-#class RootClass:
- #XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
- #<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- #<xsd:element name="BACnetRoot">
- #</xsd:element>
- #</xsd:schema>
- #"""
- #CTNChildrenTypes = [("BacnetSlave", _BacnetSlavePlug, "Bacnet Slave")
- ##,("XXX",_XXXXPlug, "XXX")
- #]
-
- #def CTNGenerate_C(self, buildpath, locations):
- #return [], "", True