From 65cee2816966f1846afc1a9de3fe96bb739e82ee Mon Sep 17 00:00:00 2001 From: Richard Littauer Date: Tue, 28 Apr 2020 18:17:21 -0400 Subject: [PATCH 01/50] docs: spelling errors Also removed whitespace. Can resubmit if that is unsatisfactory. --- .../gettingstarted/gettingstarted001.rst | 194 +++++++++--------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/doc/source/gettingstarted/gettingstarted001.rst b/doc/source/gettingstarted/gettingstarted001.rst index b48997ba..977ab878 100644 --- a/doc/source/gettingstarted/gettingstarted001.rst +++ b/doc/source/gettingstarted/gettingstarted001.rst @@ -3,25 +3,25 @@ Getting Started =============== -Ah, so you are interested in getting started with BACnet and Python. Welcome -to BACpypes, I hope you enjoy your journey. This tutorial starts with -just enough of the basics of BACnet to get a workstation communicating with -another device. We will cover installing the library, downloading and +Ah, so you are interested in getting started with BACnet and Python. Welcome +to BACpypes, I hope you enjoy your journey. This tutorial starts with +just enough of the basics of BACnet to get a workstation communicating with +another device. We will cover installing the library, downloading and configuring the samples applications. Basic Assumptions ----------------- -I will assume you are a software developer and it is your job to communicate -with a device from another company that uses BACnet. Your employer has -given you a test device and purchased a copy of the BACnet standard. I will +I will assume you are a software developer and it is your job to communicate +with a device from another company that uses BACnet. Your employer has +given you a test device and purchased a copy of the BACnet standard. I will need... -- a development workstation running some flavor of Linux or Windows, complete with +- a development workstation running some flavor of Linux or Windows, complete with the latest version of Python (2.7 or >3.4) and `setup tools `_. -- a small Ethernet hub into which you can plug both your workstation and your +- a small Ethernet hub into which you can plug both your workstation and your mysterious BACnet device, so you won't be distracted by lots of other network traffic. - a BACnetIP/BACnet-MSTP Router if your mysterious device is an MSTP device (BACpypes is @@ -33,7 +33,7 @@ need... `Anaconda `_ or Enthought `Canopy `_. -Before getting this test environment set up and while you are still connected +Before getting this test environment set up and while you are still connected to the internet, install the BACpypes library:: $ sudo easy_install bacpypes @@ -42,7 +42,7 @@ or:: $ sudo pip install bacpypes -And while you are at it, get a copy of the BACpypes project from GitHub. It +And while you are at it, get a copy of the BACpypes project from GitHub. It contains the library source code, sample code, and this documentation. Install the `Git `_ software from `here `_, then make a local copy of the @@ -50,11 +50,11 @@ repository by cloning it:: $ git clone https://github.com/JoelBender/bacpypes.git -No protocol analysis workbench would be complete without an installed +No protocol analysis workbench would be complete without an installed copy of `Wireshark `_:: $ sudo apt-get install wireshark - + or if you use Windows, `download it here `_. .. caution:: @@ -67,15 +67,15 @@ or if you use Windows, `download it here `_, and sequentially - higher numbers are used in many applications (i.e. 47809, 47810,...). + The BACnet protocol has been assigned port 47808 (hex 0xBAC0) by + by the `Internet Assigned Numbers Authority `_, and sequentially + higher numbers are used in many applications (i.e. 47809, 47810,...). There are some BACnet routing and networking issues related to using these higher unoffical ports, but that is a topic for another tutorial. @@ -213,33 +213,33 @@ Starting An Application ----------------------- The simplest BACpypes sample application is the **WhoIsIAm.py** -application. It sends out Who-Is and I-Am messages and +application. It sends out Who-Is and I-Am messages and displays the results it receives. What are these things? -As mentioned before, BACnet has unique device identifiers and -most applications use these identifiers in their configuration +As mentioned before, BACnet has unique device identifiers and +most applications use these identifiers in their configuration to know who their peers are. Once these identifiers are given to a device they typically do not change, even as the network topology changes. -BACnet devices use the Who-Is request to translate device -identifiers into network addresses. This is very similar to -a decentralized DNS service, but the names are unsigned -integers. The request is broadcast on the network and the +BACnet devices use the Who-Is request to translate device +identifiers into network addresses. This is very similar to +a decentralized DNS service, but the names are unsigned +integers. The request is broadcast on the network and the client waits around to listen for I-Am messages. The source -address of the I-Am response is "bound" to the device identifier +address of the I-Am response is "bound" to the device identifier and most communications are unicast thereafter. -First, start up Wireshark on your workstation and a capture +First, start up Wireshark on your workstation and a capture session with a BACnet capture filter:: udp and port 47808 -You might start seeing BACnet traffic from your test device, -and if you wait to power it on after starting your capture -you should see at least a broadcast I-Am message. By looking -in the I-Am packet decoding you will see some of its -configuration parameters that should match what you expected +You might start seeing BACnet traffic from your test device, +and if you wait to power it on after starting your capture +you should see at least a broadcast I-Am message. By looking +in the I-Am packet decoding you will see some of its +configuration parameters that should match what you expected them to be. Now start the simplest tutorial application:: @@ -249,7 +249,7 @@ Now start the simplest tutorial application:: .. note:: The samples folder contains a Tutorial folder holding all the samples - that you will need too follow along this tutorial. + that you will need to follow along with this tutorial. Later, the folder `HandsOnLabs` will be used as it contains the samples that are fully explained in this document (see table of content) @@ -272,7 +272,7 @@ BACnet communications traffic. Generate the basic I-Am message:: > iam -You should see Wireshark capture your I-Am message containing your configuration +You should see Wireshark capture your I-Am message containing your configuration parameters. This is a "global broadcast" message. Your test device will see it but since your test device probably isn't looking for you, it will not respond to the message. @@ -281,27 +281,27 @@ respond to the message. Binding to the Test Device -------------------------- -Next we want to confirm that your workstation can receive the -messages the test device sends out. We do this by generating a -generic Who-Is request. The request will be "unconstrained", meaning +Next we want to confirm that your workstation can receive the +messages the test device sends out. We do this by generating a +generic Who-Is request. The request will be "unconstrained", meaning every device that hears the message will respond with their corresponding -I-Am messages. +I-Am messages. -.. caution:: +.. caution:: - Generating **unconstrained** Who-Is requests on a large network will create - a LOT of traffic, which can lead to network problems caused by the resulting + Generating **unconstrained** Who-Is requests on a large network will create + a LOT of traffic, which can lead to network problems caused by the resulting flood of messages. - + To generate the Who-Is request:: > whois -You should see the Who-Is request captured in Wireshark along with the I-Am -response from your test device, and then the details of the response displayed +You should see the Who-Is request captured in Wireshark along with the I-Am +response from your test device, and then the details of the response displayed on the workstation console.:: - > whois + > whois > pduSource = iAmDeviceIdentifier = ('device', 1000) maxAPDULengthAccepted = 480 @@ -309,13 +309,13 @@ on the workstation console.:: vendorID = 8 -There are a few different forms of the *whois* command supported by this +There are a few different forms of the *whois* command supported by this simple application. You can see these with the help command:: > help whois whois [ ] [ ] -This is like a BNF syntax, the **whois** command is optionally +This is like a BNF syntax, the **whois** command is optionally followed by a BACnet device address, and then optionally followed by a low (address) limit and high (address) limit. The most common use of the Who-Is request is to look for a specific device given its device @@ -329,9 +329,9 @@ building as a group:: > whois 203000 203099 -Every once in a while a contractor might install a BACnet +Every once in a while a contractor might install a BACnet device that hasn't been properly configured. Assuming that -it has an IP address, you can send an **unconstrained Who-Is** request +it has an IP address, you can send an **unconstrained Who-Is** request to the specific device and hope that it responds:: > whois 192.168.0.10 @@ -349,9 +349,9 @@ but that is a subject of an other tutorial. What's Next ----------- -The next tutorial describes the different ways this +The next tutorial describes the different ways this application can be run, and what the commands can tell you -about how it is working. All of the "console" applications -(i.e. those that prompt for commands) use the same basic +about how it is working. All of the "console" applications +(i.e. those that prompt for commands) use the same basic commands and work the same way. From 9ec89dbf11fc498abcfb195ecdf48648dcc1e2ea Mon Sep 17 00:00:00 2001 From: Richard Littauer Date: Tue, 28 Apr 2020 18:13:47 -0400 Subject: [PATCH 02/50] refactor: Remove tutorials/WhoIsIAm.py This removes the Tutorial code and updates the old samples/WhoIsIAm.py to match it. --- .../gettingstarted/gettingstarted001.rst | 192 +++++++++--------- .../gettingstarted/gettingstarted002.rst | 82 ++++---- samples/Tutorial/WhoIsIAm.py | 181 ----------------- samples/WhoIsIAm.py | 83 +++----- 4 files changed, 168 insertions(+), 370 deletions(-) delete mode 100644 samples/Tutorial/WhoIsIAm.py mode change 100755 => 100644 samples/WhoIsIAm.py diff --git a/doc/source/gettingstarted/gettingstarted001.rst b/doc/source/gettingstarted/gettingstarted001.rst index b48997ba..b799d939 100644 --- a/doc/source/gettingstarted/gettingstarted001.rst +++ b/doc/source/gettingstarted/gettingstarted001.rst @@ -3,25 +3,25 @@ Getting Started =============== -Ah, so you are interested in getting started with BACnet and Python. Welcome -to BACpypes, I hope you enjoy your journey. This tutorial starts with -just enough of the basics of BACnet to get a workstation communicating with -another device. We will cover installing the library, downloading and +Ah, so you are interested in getting started with BACnet and Python. Welcome +to BACpypes, I hope you enjoy your journey. This tutorial starts with +just enough of the basics of BACnet to get a workstation communicating with +another device. We will cover installing the library, downloading and configuring the samples applications. Basic Assumptions ----------------- -I will assume you are a software developer and it is your job to communicate -with a device from another company that uses BACnet. Your employer has -given you a test device and purchased a copy of the BACnet standard. I will +I will assume you are a software developer and it is your job to communicate +with a device from another company that uses BACnet. Your employer has +given you a test device and purchased a copy of the BACnet standard. I will need... -- a development workstation running some flavor of Linux or Windows, complete with +- a development workstation running some flavor of Linux or Windows, complete with the latest version of Python (2.7 or >3.4) and `setup tools `_. -- a small Ethernet hub into which you can plug both your workstation and your +- a small Ethernet hub into which you can plug both your workstation and your mysterious BACnet device, so you won't be distracted by lots of other network traffic. - a BACnetIP/BACnet-MSTP Router if your mysterious device is an MSTP device (BACpypes is @@ -33,7 +33,7 @@ need... `Anaconda `_ or Enthought `Canopy `_. -Before getting this test environment set up and while you are still connected +Before getting this test environment set up and while you are still connected to the internet, install the BACpypes library:: $ sudo easy_install bacpypes @@ -42,7 +42,7 @@ or:: $ sudo pip install bacpypes -And while you are at it, get a copy of the BACpypes project from GitHub. It +And while you are at it, get a copy of the BACpypes project from GitHub. It contains the library source code, sample code, and this documentation. Install the `Git `_ software from `here `_, then make a local copy of the @@ -50,11 +50,11 @@ repository by cloning it:: $ git clone https://github.com/JoelBender/bacpypes.git -No protocol analysis workbench would be complete without an installed +No protocol analysis workbench would be complete without an installed copy of `Wireshark `_:: $ sudo apt-get install wireshark - + or if you use Windows, `download it here `_. .. caution:: @@ -67,15 +67,15 @@ or if you use Windows, `download it here `_, and sequentially - higher numbers are used in many applications (i.e. 47809, 47810,...). + The BACnet protocol has been assigned port 47808 (hex 0xBAC0) by + by the `Internet Assigned Numbers Authority `_, and sequentially + higher numbers are used in many applications (i.e. 47809, 47810,...). There are some BACnet routing and networking issues related to using these higher unoffical ports, but that is a topic for another tutorial. @@ -213,38 +213,38 @@ Starting An Application ----------------------- The simplest BACpypes sample application is the **WhoIsIAm.py** -application. It sends out Who-Is and I-Am messages and +application. It sends out Who-Is and I-Am messages and displays the results it receives. What are these things? -As mentioned before, BACnet has unique device identifiers and -most applications use these identifiers in their configuration +As mentioned before, BACnet has unique device identifiers and +most applications use these identifiers in their configuration to know who their peers are. Once these identifiers are given to a device they typically do not change, even as the network topology changes. -BACnet devices use the Who-Is request to translate device -identifiers into network addresses. This is very similar to -a decentralized DNS service, but the names are unsigned -integers. The request is broadcast on the network and the +BACnet devices use the Who-Is request to translate device +identifiers into network addresses. This is very similar to +a decentralized DNS service, but the names are unsigned +integers. The request is broadcast on the network and the client waits around to listen for I-Am messages. The source -address of the I-Am response is "bound" to the device identifier +address of the I-Am response is "bound" to the device identifier and most communications are unicast thereafter. -First, start up Wireshark on your workstation and a capture +First, start up Wireshark on your workstation and a capture session with a BACnet capture filter:: udp and port 47808 -You might start seeing BACnet traffic from your test device, -and if you wait to power it on after starting your capture -you should see at least a broadcast I-Am message. By looking -in the I-Am packet decoding you will see some of its -configuration parameters that should match what you expected +You might start seeing BACnet traffic from your test device, +and if you wait to power it on after starting your capture +you should see at least a broadcast I-Am message. By looking +in the I-Am packet decoding you will see some of its +configuration parameters that should match what you expected them to be. Now start the simplest tutorial application:: - $ python samples/Tutorial/WhoIsIAm.py + $ python samples/WhoIsIAm.py .. note:: @@ -272,7 +272,7 @@ BACnet communications traffic. Generate the basic I-Am message:: > iam -You should see Wireshark capture your I-Am message containing your configuration +You should see Wireshark capture your I-Am message containing your configuration parameters. This is a "global broadcast" message. Your test device will see it but since your test device probably isn't looking for you, it will not respond to the message. @@ -281,27 +281,27 @@ respond to the message. Binding to the Test Device -------------------------- -Next we want to confirm that your workstation can receive the -messages the test device sends out. We do this by generating a -generic Who-Is request. The request will be "unconstrained", meaning +Next we want to confirm that your workstation can receive the +messages the test device sends out. We do this by generating a +generic Who-Is request. The request will be "unconstrained", meaning every device that hears the message will respond with their corresponding -I-Am messages. +I-Am messages. -.. caution:: +.. caution:: - Generating **unconstrained** Who-Is requests on a large network will create - a LOT of traffic, which can lead to network problems caused by the resulting + Generating **unconstrained** Who-Is requests on a large network will create + a LOT of traffic, which can lead to network problems caused by the resulting flood of messages. - + To generate the Who-Is request:: > whois -You should see the Who-Is request captured in Wireshark along with the I-Am -response from your test device, and then the details of the response displayed +You should see the Who-Is request captured in Wireshark along with the I-Am +response from your test device, and then the details of the response displayed on the workstation console.:: - > whois + > whois > pduSource = iAmDeviceIdentifier = ('device', 1000) maxAPDULengthAccepted = 480 @@ -309,13 +309,13 @@ on the workstation console.:: vendorID = 8 -There are a few different forms of the *whois* command supported by this +There are a few different forms of the *whois* command supported by this simple application. You can see these with the help command:: > help whois whois [ ] [ ] -This is like a BNF syntax, the **whois** command is optionally +This is like a BNF syntax, the **whois** command is optionally followed by a BACnet device address, and then optionally followed by a low (address) limit and high (address) limit. The most common use of the Who-Is request is to look for a specific device given its device @@ -329,9 +329,9 @@ building as a group:: > whois 203000 203099 -Every once in a while a contractor might install a BACnet +Every once in a while a contractor might install a BACnet device that hasn't been properly configured. Assuming that -it has an IP address, you can send an **unconstrained Who-Is** request +it has an IP address, you can send an **unconstrained Who-Is** request to the specific device and hope that it responds:: > whois 192.168.0.10 @@ -349,9 +349,9 @@ but that is a subject of an other tutorial. What's Next ----------- -The next tutorial describes the different ways this +The next tutorial describes the different ways this application can be run, and what the commands can tell you -about how it is working. All of the "console" applications -(i.e. those that prompt for commands) use the same basic +about how it is working. All of the "console" applications +(i.e. those that prompt for commands) use the same basic commands and work the same way. diff --git a/doc/source/gettingstarted/gettingstarted002.rst b/doc/source/gettingstarted/gettingstarted002.rst index 4d22180c..a9084b93 100644 --- a/doc/source/gettingstarted/gettingstarted002.rst +++ b/doc/source/gettingstarted/gettingstarted002.rst @@ -3,9 +3,9 @@ Running BACpypes Applications ============================= -All BACpypes sample applications have the same basic set of command line -options so it is easy to move between applications, turn debugging on and -and use different configurations. There may be additional options and +All BACpypes sample applications have the same basic set of command line +options so it is easy to move between applications, turn debugging on and +and use different configurations. There may be additional options and command parameters than just the ones described in this section. Getting Help @@ -14,7 +14,7 @@ Getting Help Whatever the command line parameters and additional options might be for an application, you can start with help:: - $ python Tutorial/WhoIsIAm.py --help + $ python samples/WhoIsIAm.py --help usage: WhoIsIAm.py [-h] [--buggers] [--debug [DEBUG [DEBUG ...]]] [--color] [--ini INI] This application presents a 'console' prompt to the user asking for Who-Is and @@ -33,22 +33,22 @@ an application, you can start with help:: Listing Debugging Loggers ------------------------- -The BACpypes library and sample applications make extensive use of the -built-in *logging* module in Python. Every module in the library, along -with every class and exported function, has a logging object associated -with it. By attaching a log handler to a logger, the log handler is given +The BACpypes library and sample applications make extensive use of the +built-in *logging* module in Python. Every module in the library, along +with every class and exported function, has a logging object associated +with it. By attaching a log handler to a logger, the log handler is given a chance to output the progress of the application. -Because BACpypes modules are deeply interconnected, dumping a complete list -of all of the logger names is a long list. Start out focusing on the +Because BACpypes modules are deeply interconnected, dumping a complete list +of all of the logger names is a long list. Start out focusing on the components of the WhoIsIAm.py application:: - $ python Tutorial/WhoIsIAm.py --buggers | grep __main__ + $ python samples/WhoIsIAm.py --buggers | grep __main__ __main__ __main__.WhoIsIAmApplication __main__.WhoIsIAmConsoleCmd -In this sample, the entire application is called __main__ and it defines +In this sample, the entire application is called __main__ and it defines two classes. Debugging a Module @@ -61,12 +61,12 @@ Telling the application to debug a module is simple:: DEBUG:__main__: - args: Namespace(buggers=False, debug=['__main__'], ini=) DEBUG:__main__.WhoIsIAmApplication:__init__ (, '128.253.109.40/24:47808') DEBUG:__main__:running - > + > -The output is the severity code of the logger (almost always DEBUG), the name -of the module, class, or function, then some message about the progress of the -application. From the output above you can see the application initializing, -setting the args variable, creating an instance of the WhoIsIAmApplication class +The output is the severity code of the logger (almost always DEBUG), the name +of the module, class, or function, then some message about the progress of the +application. From the output above you can see the application initializing, +setting the args variable, creating an instance of the WhoIsIAmApplication class (with some parameters), and then declaring itself - running. @@ -76,52 +76,52 @@ Debugging a Class Debugging all of the classes and functions can generate a lot of output, so it is useful to focus on a specific function or class:: - $ python Tutorial/WhoIsIAm.py --debug __main__.WhoIsIAmApplication + $ python samples/WhoIsIAm.py --debug __main__.WhoIsIAmApplication DEBUG:__main__.WhoIsIAmApplication:__init__ (, '128.253.109.40/24:47808') - > + > -The same method is used to debug the activity of a BACpypes module, for +The same method is used to debug the activity of a BACpypes module, for example, there is a class called UDPActor in the UDP module:: - $ python Tutorial/WhoIsIAm.py --ini BAC0.ini --debug bacpypes.udp.UDPActor + $ python samples/WhoIsIAm.py --ini BAC0.ini --debug bacpypes.udp.UDPActor > DEBUG:bacpypes.udp.UDPActor:__init__ ('128.253.109.254', 47808) DEBUG:bacpypes.udp.UDPActor:response pduSource = ('128.253.109.254', 47808) pduData = x'81.04.00.37.0A.10.6D.45.BA.C0.01.28.FF.FF.00.00.B6.01.05.FD...' -In this sample, an instance of a UDPActor is created and then its response -function is called with an instance of a PDU as a parameter. Following +In this sample, an instance of a UDPActor is created and then its response +function is called with an instance of a PDU as a parameter. Following the function invocation description, the debugging output continues with the -contents of the PDU. Notice, the protocol data is printed as a hex +contents of the PDU. Notice, the protocol data is printed as a hex encoded string (and restricted to just the first 20 bytes of the message). -You can debug a function just as easily. Specify as many different -combinations of logger names as necessary. Note, you cannot debug a +You can debug a function just as easily. Specify as many different +combinations of logger names as necessary. Note, you cannot debug a specific function within a class. Sending Debug Log to a file ---------------------------- -The current --debug command line option takes a list of named debugging access -points and attaches a StreamHandler which sends the output to sys.stderr. -There is a way to send the debugging output to a -RotatingFileHandler by providing a file name, and optionally maxBytes and -backupCount. For example, this invocation sends the main application debugging -to standard error and the debugging output of the bacpypes.udp module to the +The current --debug command line option takes a list of named debugging access +points and attaches a StreamHandler which sends the output to sys.stderr. +There is a way to send the debugging output to a +RotatingFileHandler by providing a file name, and optionally maxBytes and +backupCount. For example, this invocation sends the main application debugging +to standard error and the debugging output of the bacpypes.udp module to the traffic.txt file:: - $ python Tutorial/WhoIsIAm.py --debug __main__ bacpypes.udp:traffic.txt + $ python samples/WhoIsIAm.py --debug __main__ bacpypes.udp:traffic.txt -By default the `maxBytes` is zero so there is no rotating file, but it can be +By default the `maxBytes` is zero so there is no rotating file, but it can be provided, for example this limits the file size to 1MB:: - $ python Tutorial/WhoIsIAm.py --debug __main__ bacpypes.udp:traffic.txt:1048576 + $ python samples/WhoIsIAm.py --debug __main__ bacpypes.udp:traffic.txt:1048576 -If `maxBytes` is provided, then by default the `backupCount` is 10, but it can also +If `maxBytes` is provided, then by default the `backupCount` is 10, but it can also be specified, so this limits the output to one hundred files:: - $ python Tutorial/WhoIsIAm.py --debug __main__ bacpypes.udp:traffic.txt:1048576:100 + $ python samples/WhoIsIAm.py --debug __main__ bacpypes.udp:traffic.txt:1048576:100 .. caution:: @@ -136,18 +136,18 @@ The definition of debug:: Changing INI Files ------------------ -It is not unusual to have a variety of different INI files specifying +It is not unusual to have a variety of different INI files specifying different port numbers or other BACnet communications paramters. Rather than swapping INI files, you can simply provide the INI file on the -command line, overriding the default BACpypes.ini file. For example, I +command line, overriding the default BACpypes.ini file. For example, I have an INI file for port 47808:: - $ python Tutorial/WhoIsIAm.py --ini BAC0.ini + $ python samples/WhoIsIAm.py --ini BAC0.ini And another one for port 47809:: - $ python Tutorial/WhoIsIAm.py --ini BAC1.ini + $ python samples/WhoIsIAm.py --ini BAC1.ini And I switch back and forth between them. diff --git a/samples/Tutorial/WhoIsIAm.py b/samples/Tutorial/WhoIsIAm.py deleted file mode 100644 index d58455c5..00000000 --- a/samples/Tutorial/WhoIsIAm.py +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/bin/env python - -""" -This application presents a 'console' prompt to the user asking for Who-Is and I-Am -commands which create the related APDUs, then lines up the corresponding I-Am -for incoming traffic and prints out the contents. -""" - -import sys - -from bacpypes.debugging import bacpypes_debugging, ModuleLogger -from bacpypes.consolelogging import ConfigArgumentParser -from bacpypes.consolecmd import ConsoleCmd - -from bacpypes.core import run, enable_sleeping - -from bacpypes.pdu import Address, GlobalBroadcast -from bacpypes.apdu import WhoIsRequest, IAmRequest -from bacpypes.errors import DecodingError - -from bacpypes.app import BIPSimpleApplication -from bacpypes.local.device import LocalDeviceObject - -# some debugging -_debug = 1 -_log = ModuleLogger(globals()) - -# globals -this_device = None -this_application = None - -# -# WhoIsIAmApplication -# - -@bacpypes_debugging -class WhoIsIAmApplication(BIPSimpleApplication): - - def __init__(self, *args): - if _debug: WhoIsIAmApplication._debug("__init__ %r", args) - BIPSimpleApplication.__init__(self, *args) - - # keep track of requests to line up responses - self._request = None - - def request(self, apdu): - if _debug: WhoIsIAmApplication._debug("request %r", apdu) - - # save a copy of the request - self._request = apdu - - # forward it along - BIPSimpleApplication.request(self, apdu) - - def confirmation(self, apdu): - if _debug: WhoIsIAmApplication._debug("confirmation %r", apdu) - - # forward it along - BIPSimpleApplication.confirmation(self, apdu) - - def indication(self, apdu): - if _debug: WhoIsIAmApplication._debug("indication %r", apdu) - - if (isinstance(self._request, WhoIsRequest)) and (isinstance(apdu, IAmRequest)): - device_type, device_instance = apdu.iAmDeviceIdentifier - if device_type != 'device': - raise DecodingError("invalid object type") - - if (self._request.deviceInstanceRangeLowLimit is not None) and \ - (device_instance < self._request.deviceInstanceRangeLowLimit): - pass - elif (self._request.deviceInstanceRangeHighLimit is not None) and \ - (device_instance > self._request.deviceInstanceRangeHighLimit): - pass - else: - # print out the contents - sys.stdout.write('pduSource = ' + repr(apdu.pduSource) + '\n') - sys.stdout.write('iAmDeviceIdentifier = ' + str(apdu.iAmDeviceIdentifier) + '\n') - sys.stdout.write('maxAPDULengthAccepted = ' + str(apdu.maxAPDULengthAccepted) + '\n') - sys.stdout.write('segmentationSupported = ' + str(apdu.segmentationSupported) + '\n') - sys.stdout.write('vendorID = ' + str(apdu.vendorID) + '\n') - sys.stdout.flush() - - # forward it along - BIPSimpleApplication.indication(self, apdu) - - -# -# WhoIsIAmConsoleCmd -# - -@bacpypes_debugging -class WhoIsIAmConsoleCmd(ConsoleCmd): - - def do_whois(self, args): - """whois [ ] [ ]""" - args = args.split() - if _debug: WhoIsIAmConsoleCmd._debug("do_whois %r", args) - - try: - # gather the parameters - if (len(args) == 1) or (len(args) == 3): - addr = Address(args[0]) - del args[0] - else: - addr = GlobalBroadcast() - - if len(args) == 2: - lolimit = int(args[0]) - hilimit = int(args[1]) - else: - lolimit = hilimit = None - - # code lives in the device service - this_application.who_is(lolimit, hilimit, addr) - - except Exception as error: - WhoIsIAmConsoleCmd._exception("exception: %r", error) - - def do_iam(self, args): - """iam""" - args = args.split() - if _debug: WhoIsIAmConsoleCmd._debug("do_iam %r", args) - - # code lives in the device service - this_application.i_am() - - def do_rtn(self, args): - """rtn ... """ - args = args.split() - if _debug: WhoIsIAmConsoleCmd._debug("do_rtn %r", args) - - # provide the address and a list of network numbers - router_address = Address(args[0]) - network_list = [int(arg) for arg in args[1:]] - - # pass along to the service access point - this_application.nsap.update_router_references(None, router_address, network_list) - - -# -# __main__ -# - -def main(): - global this_device - global this_application - - # parse the command line arguments - args = ConfigArgumentParser(description=__doc__).parse_args() - - if _debug: _log.debug("initialization") - if _debug: _log.debug(" - args: %r", args) - - # make a device object - this_device = LocalDeviceObject( - objectName=args.ini.objectname, - objectIdentifier=int(args.ini.objectidentifier), - maxApduLengthAccepted=int(args.ini.maxapdulengthaccepted), - segmentationSupported=args.ini.segmentationsupported, - vendorIdentifier=int(args.ini.vendoridentifier), - ) - - # make a simple application - this_application = WhoIsIAmApplication(this_device, args.ini.address) - - # make a console - this_console = WhoIsIAmConsoleCmd() - if _debug: _log.debug(" - this_console: %r", this_console) - - # enable sleeping will help with threads - enable_sleeping() - - _log.debug("running") - - run() - - _log.debug("fini") - -if __name__ == "__main__": - main() diff --git a/samples/WhoIsIAm.py b/samples/WhoIsIAm.py old mode 100755 new mode 100644 index 8e6132c1..d58455c5 --- a/samples/WhoIsIAm.py +++ b/samples/WhoIsIAm.py @@ -2,7 +2,7 @@ """ This application presents a 'console' prompt to the user asking for Who-Is and I-Am -commands which create the related APDUs, then lines up the coorresponding I-Am +commands which create the related APDUs, then lines up the corresponding I-Am for incoming traffic and prints out the contents. """ @@ -12,8 +12,7 @@ from bacpypes.consolelogging import ConfigArgumentParser from bacpypes.consolecmd import ConsoleCmd -from bacpypes.core import run, deferred, enable_sleeping -from bacpypes.iocb import IOCB +from bacpypes.core import run, enable_sleeping from bacpypes.pdu import Address, GlobalBroadcast from bacpypes.apdu import WhoIsRequest, IAmRequest @@ -23,7 +22,7 @@ from bacpypes.local.device import LocalDeviceObject # some debugging -_debug = 0 +_debug = 1 _log = ModuleLogger(globals()) # globals @@ -68,10 +67,10 @@ def indication(self, apdu): raise DecodingError("invalid object type") if (self._request.deviceInstanceRangeLowLimit is not None) and \ - (device_instance < self._request.deviceInstanceRangeLowLimit): + (device_instance < self._request.deviceInstanceRangeLowLimit): pass elif (self._request.deviceInstanceRangeHighLimit is not None) and \ - (device_instance > self._request.deviceInstanceRangeHighLimit): + (device_instance > self._request.deviceInstanceRangeHighLimit): pass else: # print out the contents @@ -85,6 +84,7 @@ def indication(self, apdu): # forward it along BIPSimpleApplication.indication(self, apdu) + # # WhoIsIAmConsoleCmd # @@ -93,60 +93,37 @@ def indication(self, apdu): class WhoIsIAmConsoleCmd(ConsoleCmd): def do_whois(self, args): - """whois [ ] [ ]""" + """whois [ ] [ ]""" args = args.split() if _debug: WhoIsIAmConsoleCmd._debug("do_whois %r", args) try: - # build a request - request = WhoIsRequest() + # gather the parameters if (len(args) == 1) or (len(args) == 3): - request.pduDestination = Address(args[0]) + addr = Address(args[0]) del args[0] else: - request.pduDestination = GlobalBroadcast() + addr = GlobalBroadcast() if len(args) == 2: - request.deviceInstanceRangeLowLimit = int(args[0]) - request.deviceInstanceRangeHighLimit = int(args[1]) - if _debug: WhoIsIAmConsoleCmd._debug(" - request: %r", request) - - # make an IOCB - iocb = IOCB(request) - if _debug: WhoIsIAmConsoleCmd._debug(" - iocb: %r", iocb) + lolimit = int(args[0]) + hilimit = int(args[1]) + else: + lolimit = hilimit = None - # give it to the application - this_application.request_io(iocb) + # code lives in the device service + this_application.who_is(lolimit, hilimit, addr) - except Exception as err: - WhoIsIAmConsoleCmd._exception("exception: %r", err) + except Exception as error: + WhoIsIAmConsoleCmd._exception("exception: %r", error) def do_iam(self, args): """iam""" args = args.split() if _debug: WhoIsIAmConsoleCmd._debug("do_iam %r", args) - try: - # build a request - request = IAmRequest() - request.pduDestination = GlobalBroadcast() - - # set the parameters from the device object - request.iAmDeviceIdentifier = this_device.objectIdentifier - request.maxAPDULengthAccepted = this_device.maxApduLengthAccepted - request.segmentationSupported = this_device.segmentationSupported - request.vendorID = this_device.vendorIdentifier - if _debug: WhoIsIAmConsoleCmd._debug(" - request: %r", request) - - # make an IOCB - iocb = IOCB(request) - if _debug: WhoIsIAmConsoleCmd._debug(" - iocb: %r", iocb) - - # give it to the application - this_application.request_io(iocb) - - except Exception as err: - WhoIsIAmConsoleCmd._exception("exception: %r", err) + # code lives in the device service + this_application.i_am() def do_rtn(self, args): """rtn ... """ @@ -162,11 +139,12 @@ def do_rtn(self, args): # -# main +# __main__ # def main(): - global this_device, this_application + global this_device + global this_application # parse the command line arguments args = ConfigArgumentParser(description=__doc__).parse_args() @@ -175,14 +153,16 @@ def main(): if _debug: _log.debug(" - args: %r", args) # make a device object - this_device = LocalDeviceObject(ini=args.ini) - if _debug: _log.debug(" - this_device: %r", this_device) + this_device = LocalDeviceObject( + objectName=args.ini.objectname, + objectIdentifier=int(args.ini.objectidentifier), + maxApduLengthAccepted=int(args.ini.maxapdulengthaccepted), + segmentationSupported=args.ini.segmentationsupported, + vendorIdentifier=int(args.ini.vendoridentifier), + ) # make a simple application - this_application = WhoIsIAmApplication( - this_device, args.ini.address, - ) - if _debug: _log.debug(" - this_application: %r", this_application) + this_application = WhoIsIAmApplication(this_device, args.ini.address) # make a console this_console = WhoIsIAmConsoleCmd() @@ -197,6 +177,5 @@ def main(): _log.debug("fini") - if __name__ == "__main__": main() From 5968c30d077d1fe616a52afe031a95e65304e181 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Sat, 2 May 2020 12:02:15 -0400 Subject: [PATCH 03/50] new 'develop' branch - bump the version for the next release --- py25/bacpypes/__init__.py | 2 +- py27/bacpypes/__init__.py | 2 +- py34/bacpypes/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/py25/bacpypes/__init__.py b/py25/bacpypes/__init__.py index f11670ee..89dfbbeb 100755 --- a/py25/bacpypes/__init__.py +++ b/py25/bacpypes/__init__.py @@ -18,7 +18,7 @@ # Project Metadata # -__version__ = '0.18.1' +__version__ = '0.18.2' __author__ = 'Joel Bender' __email__ = 'joel@carrickbender.com' diff --git a/py27/bacpypes/__init__.py b/py27/bacpypes/__init__.py index f11670ee..89dfbbeb 100755 --- a/py27/bacpypes/__init__.py +++ b/py27/bacpypes/__init__.py @@ -18,7 +18,7 @@ # Project Metadata # -__version__ = '0.18.1' +__version__ = '0.18.2' __author__ = 'Joel Bender' __email__ = 'joel@carrickbender.com' diff --git a/py34/bacpypes/__init__.py b/py34/bacpypes/__init__.py index 96e60d08..242126d9 100755 --- a/py34/bacpypes/__init__.py +++ b/py34/bacpypes/__init__.py @@ -18,7 +18,7 @@ # Project Metadata # -__version__ = '0.18.1' +__version__ = '0.18.2' __author__ = 'Joel Bender' __email__ = 'joel@carrickbender.com' From 15cea1c51e31317a42437edc687a272311003014 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Sat, 2 May 2020 12:36:19 -0400 Subject: [PATCH 04/50] removing tools (#339) --- pcap_tools/AddressFilter.py | 129 ---------- pcap_tools/COVNotificationSummaryFilter.py | 149 ------------ pcap_tools/EventNotificationSummaryFilter.py | 215 ----------------- pcap_tools/IAmRouterToNetworkSummaryFilter.py | 161 ------------- pcap_tools/PDUsPerMinuteFilter.py | 108 --------- pcap_tools/ReadPropertySummaryFilter.py | 228 ------------------ pcap_tools/ReadPropertyTimeoutFilter.py | 177 -------------- pcap_tools/WhoIsIAmDeviceFilter.py | 158 ------------ pcap_tools/WhoIsIAmSummaryFilter.py | 160 ------------ .../WhoIsRouterToNetworkSummaryFilter.py | 160 ------------ 10 files changed, 1645 deletions(-) delete mode 100755 pcap_tools/AddressFilter.py delete mode 100755 pcap_tools/COVNotificationSummaryFilter.py delete mode 100755 pcap_tools/EventNotificationSummaryFilter.py delete mode 100755 pcap_tools/IAmRouterToNetworkSummaryFilter.py delete mode 100755 pcap_tools/PDUsPerMinuteFilter.py delete mode 100755 pcap_tools/ReadPropertySummaryFilter.py delete mode 100755 pcap_tools/ReadPropertyTimeoutFilter.py delete mode 100755 pcap_tools/WhoIsIAmDeviceFilter.py delete mode 100755 pcap_tools/WhoIsIAmSummaryFilter.py delete mode 100755 pcap_tools/WhoIsRouterToNetworkSummaryFilter.py diff --git a/pcap_tools/AddressFilter.py b/pcap_tools/AddressFilter.py deleted file mode 100755 index 4130b71c..00000000 --- a/pcap_tools/AddressFilter.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/python - -""" -Address Filter - Sample tool to filter by source, destination and/or host -""" - -import sys - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# AddressFilterTracer -# - -class AddressFilterTracer(Tracer, Logging): - - def __init__(self): - if _debug: AddressFilterTracer._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: AddressFilterTracer._debug("Filter %r", pkt) - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: AddressFilterTracer._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: AddressFilterTracer._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: AddressFilterTracer._debug(" - host filter fail") - return - - # passed all the filter tests - print strftimestamp(pkt._timestamp), pkt.__class__.__name__ - pkt.debug_contents() - print - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [AddressFilterTracer]) - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/COVNotificationSummaryFilter.py b/pcap_tools/COVNotificationSummaryFilter.py deleted file mode 100755 index fd8d6eb4..00000000 --- a/pcap_tools/COVNotificationSummaryFilter.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/python - -""" -Summarize COV Notifications -""" - -import sys - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.apdu import UnconfirmedCOVNotificationRequest - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# dictionary of requests -requests = {} - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# COVNotificationSummary -# - -class COVNotificationSummary(Tracer, Logging): - - def __init__(self): - if _debug: COVNotificationSummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: COVNotificationSummary._debug("Filter %r", pkt) - global requests - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: COVNotificationSummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: COVNotificationSummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: COVNotificationSummary._debug(" - host filter fail") - return - - # check for notifications - if isinstance(pkt, UnconfirmedCOVNotificationRequest): - key = (pkt.pduSource, pkt.initiatingDeviceIdentifier[1], pkt.monitoredObjectIdentifier) - if key in requests: - requests[key] += 1 - else: - requests[key] = 1 - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # start out with no requests - requests = {} - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [COVNotificationSummary]) - - # sort the result, descending order by count - items = requests.items() - items.sort(lambda x, y: cmp(y[1], x[1])) - - # print everything out - print "%-20s %8s %-15s %4s %5s" % ("Address", "Device", "Object", "", "Count") - for key, count in items: - print "%-20s %8s %-15s %4d %5d" % (key[0], key[1], key[2][0], key[2][1], count) - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/EventNotificationSummaryFilter.py b/pcap_tools/EventNotificationSummaryFilter.py deleted file mode 100755 index 093ef628..00000000 --- a/pcap_tools/EventNotificationSummaryFilter.py +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/python - -""" -Event Notification Summary Filter -""" - -import sys - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.apdu import ConfirmedEventNotificationRequest, SimpleAckPDU - -try: - from CSStat import Statistics -except ImportError: - Statistics = lambda: None - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# dictionary of pending requests -requests = {} - -# all traffic -traffic = [] - -# -# Traffic -# - -class Traffic: - - def __init__(self, req): - self.req = req - self.resp = None - - self.ts = req._timestamp - self.retry = 1 - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# ConfirmedEventNotificationSummary -# - -class ConfirmedEventNotificationSummary(Tracer, Logging): - - def __init__(self): - if _debug: ConfirmedEventNotificationSummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: ConfirmedEventNotificationSummary._debug("Filter %r", pkt) - global requests - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: ConfirmedEventNotificationSummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: ConfirmedEventNotificationSummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: ConfirmedEventNotificationSummary._debug(" - host filter fail") - return - - # check for notifications - if isinstance(pkt, ConfirmedEventNotificationRequest): - key = (pkt.pduSource, pkt.pduDestination, pkt.apduInvokeID) - if key in requests: - if _debug: ConfirmedEventNotificationSummary._debug(" - retry") - requests[key].retry += 1 - else: - if _debug: ConfirmedEventNotificationSummary._debug(" - new request") - msg = Traffic(pkt) - requests[key] = msg - traffic.append(msg) - - # now check for acks - elif isinstance(pkt, SimpleAckPDU): - key = (pkt.pduDestination, pkt.pduSource, pkt.apduInvokeID) - req = requests.get(key, None) - if req: - if _debug: ConfirmedEventNotificationSummary._debug(" - matched with request") - requests[key].resp = pkt - - # delete the request, it stays in the traffic list - del requests[key] - else: - if _debug: ConfirmedEventNotificationSummary._debug(" - unmatched") - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # start out with no unmatched requests - requests = {} - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [ConfirmedEventNotificationSummary]) - - # print some stats at the end - stats = Statistics() - - # dump everything - for msg in traffic: - req = msg.req - resp = msg.resp - - if resp: - deltatime = (resp._timestamp - req._timestamp) * 1000 - if stats: - stats.Record(deltatime, req._timestamp) - print strftimestamp(req._timestamp), '\t', req.pduSource, '\t', resp.pduSource, '\t', ("%8.2fms" % (deltatime,)), '\t', msg.retry if (msg.retry != 1) else "" - else: - print strftimestamp(req._timestamp), '\t', req.pduSource, '\t', "----------", '\t', "----------", '\t', msg.retry if (msg.retry != 1) else "" - - if stats: - smin, smax, _, _, _, _ = stats.Stats() - - xlw, lw, q1, m, q3, uw, xuw = stats.Whisker() - if m is not None: - print "\t %-8.1f" % smax - print "\t %-8.1f" % xuw - print "\t--- %-8.1f" % uw - print "\t | " - print "\t.'. %-8.1f" % q3 - print "\t| |" - print "\t|-| %-8.1f" % m - print "\t| |" - print "\t'-' %-8.1f" % q1 - print "\t | " - print "\t--- %-8.1f" % lw - print "\t %-8.1f" % xlw - print "\t %-8.1f" % smin - else: - print "No stats" - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/IAmRouterToNetworkSummaryFilter.py b/pcap_tools/IAmRouterToNetworkSummaryFilter.py deleted file mode 100755 index 729c7b42..00000000 --- a/pcap_tools/IAmRouterToNetworkSummaryFilter.py +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/python - -""" -Summarize I-Am-Router-To-Network Notifications -""" - -import sys -from collections import defaultdict - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.npdu import IAmRouterToNetwork - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# dictionary of requests -requests = defaultdict(int) -networks = defaultdict(list) - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# IAmRouterToNetworkSummary -# - -class IAmRouterToNetworkSummary(Tracer, Logging): - - def __init__(self): - if _debug: IAmRouterToNetworkSummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: IAmRouterToNetworkSummary._debug("Filter %r", pkt) - global requests, networks - - # check for the packet type - if not isinstance(pkt, IAmRouterToNetwork): - return - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: IAmRouterToNetworkSummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: IAmRouterToNetworkSummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: IAmRouterToNetworkSummary._debug(" - host filter fail") - return - - # count it - requests[pkt.pduSource] += 1 - networks[pkt.pduSource].append((pkt.iartnNetworkList)) - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [IAmRouterToNetworkSummary]) - - # sort the result, descending order by count - items = requests.items() - items.sort(lambda x, y: cmp(y[1], x[1])) - - # print everything out - print "%-20s %5s" % ("Address", "Count") - for key, count in items: - print "%-20s %5d" % (key, count) - - # count the number of times of each network - net_count = defaultdict(int) - for subnet_list in networks[key]: - for net in subnet_list: - net_count[net] += 1 - - # sort descending - net_count = net_count.items() - net_count.sort(lambda x, y: cmp(y[1], x[1])) - - for net, count in net_count: - print " %5d %5d" % (net, count) - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/PDUsPerMinuteFilter.py b/pcap_tools/PDUsPerMinuteFilter.py deleted file mode 100755 index 978d202e..00000000 --- a/pcap_tools/PDUsPerMinuteFilter.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/python - -""" -PDUs per Minute Filter - present a table of number of PDUs per minute -""" - -import sys -from collections import defaultdict - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.analysis import trace, strftimestamp, Tracer - -try: - from CSStat import Statistics -except ImportError: - Statistics = lambda: None - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -counter = defaultdict(int) - -# -# PDUsPerMinuteTracer -# - -class PDUsPerMinuteTracer(Tracer, Logging): - - def __init__(self): - if _debug: PDUsPerMinuteTracer._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: PDUsPerMinuteTracer._debug("Filter %r", pkt) - - slot = ((int(pkt._timestamp) / interval) * interval) - if _debug: PDUsPerMinuteTracer._debug(" - slot: %r", slot) - - # count the packets in the slot - counter[slot] += 1 - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for a custom interval - if ('--interval' in sys.argv): - i = sys.argv.index('--interval') - interval = int(sys.argv[i+1]) - if _debug: _log.debug(" - interval: %r", interval) - del sys.argv[i:i+2] - else: - interval = 60 - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [PDUsPerMinuteTracer]) - - # print some stats at the end - stats = Statistics() - - # dump the counters - for ts in range(min(counter), max(counter)+1, interval): - print strftimestamp(ts), counter[ts] - if stats: - stats.Record(counter[ts], ts) - - if stats: - smin, smax, _, _, _, _ = stats.Stats() - - xlw, lw, q1, m, q3, uw, xuw = stats.Whisker() - if m is not None: - print "\t %-8.1f" % smax - print "\t %-8.1f" % xuw - print "\t--- %-8.1f" % uw - print "\t | " - print "\t.'. %-8.1f" % q3 - print "\t| |" - print "\t|-| %-8.1f" % m - print "\t| |" - print "\t'-' %-8.1f" % q1 - print "\t | " - print "\t--- %-8.1f" % lw - print "\t %-8.1f" % xlw - print "\t %-8.1f" % smin - else: - print "No stats" - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/ReadPropertySummaryFilter.py b/pcap_tools/ReadPropertySummaryFilter.py deleted file mode 100755 index 5bfd8f70..00000000 --- a/pcap_tools/ReadPropertySummaryFilter.py +++ /dev/null @@ -1,228 +0,0 @@ -#!/usr/bin/python - -""" -Read Property Summary Filter - Summarize Read Property Requests/Responses -""" - -import sys - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.apdu import ReadPropertyRequest, ReadPropertyACK - -try: - from CSStat import Statistics -except ImportError: - Statistics = lambda: None - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None -filterEval = None - -# dictionary of pending requests -requests = {} - -# all traffic -traffic = [] - -# -# Traffic -# - -class Traffic: - - def __init__(self, req): - self.req = req - self.resp = None - - self.ts = req._timestamp - self.retry = 1 - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# ReadPropertySummary -# - -class ReadPropertySummary(Tracer, Logging): - - def __init__(self): - if _debug: ReadPropertySummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: ReadPropertySummary._debug("Filter %r", pkt) - global requests - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: ReadPropertySummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: ReadPropertySummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: ReadPropertySummary._debug(" - host filter fail") - return - if filterEval: - try: - matches = eval(filterEval, {'pkt':pkt}) - if not matches: - if _debug: ReadPropertySummary._debug(" - eval filter fail") - return - except: - if _debug: ReadPropertySummary._debug(" - eval filter massive fail") - return - - # check for reads - if isinstance(pkt, ReadPropertyRequest): - key = (pkt.pduSource, pkt.pduDestination, pkt.apduInvokeID) - if key in requests: - if _debug: ReadPropertySummary._debug(" - retry") - requests[key].retry += 1 - else: - if _debug: ReadPropertySummary._debug(" - new request") - msg = Traffic(pkt) - requests[key] = msg - traffic.append(msg) - - # now check for results - elif isinstance(pkt, ReadPropertyACK): - key = (pkt.pduDestination, pkt.pduSource, pkt.apduInvokeID) - req = requests.get(key, None) - if req: - if _debug: ReadPropertySummary._debug(" - matched with request") - requests[key].resp = pkt - - # delete the request, it stays in the traffic list - del requests[key] - else: - if _debug: ReadPropertySummary._debug(" - unmatched") - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # check for eval - if ('--eval' in sys.argv): - i = sys.argv.index('--eval') - filterEval = sys.argv[i+1] - if _debug: _log.debug(" - filterEval: %r", filterEval) - del sys.argv[i:i+2] - - # start out with no unmatched requests - requests = {} - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [ReadPropertySummary]) - - # print some stats at the end - stats = Statistics() - - # dump everything - for msg in traffic: - req = msg.req - resp = msg.resp - - if resp: - deltatime = (resp._timestamp - req._timestamp) * 1000 - if stats: - stats.Record(deltatime, req._timestamp) - print strftimestamp(req._timestamp), '\t', req.pduSource, '\t', resp.pduSource, '\t', ("%6.2fms" % (deltatime,)), '\t', msg.retry if (msg.retry != 1) else "" - else: - print strftimestamp(req._timestamp), '\t', req.pduSource, '\t', "----------", '\t', "----------", '\t', msg.retry if (msg.retry != 1) else "" - - if stats: - xlw, lw, q1, m, q3, uw, xuw = stats.Whisker() - if m is not None: - print "\t %-6.1f" % xuw - print "\t--- %-6.1f" % uw - print "\t | " - print "\t.'. %-6.1f" % q3 - print "\t| |" - print "\t|-| %-6.1f" % m - print "\t| |" - print "\t'-' %-6.1f" % q1 - print "\t | " - print "\t--- %-6.1f" % lw - print "\t %-6.1f" % xlw - else: - print "No stats" - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/ReadPropertyTimeoutFilter.py b/pcap_tools/ReadPropertyTimeoutFilter.py deleted file mode 100755 index f6c60ded..00000000 --- a/pcap_tools/ReadPropertyTimeoutFilter.py +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/python - -""" -Read Property Timeout Filter - Look for Read Property Requests with no response -""" - -import sys - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.apdu import ReadPropertyRequest, ReadPropertyACK - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# dictionary of pending requests -requests = {} - -# all traffic -traffic = [] - -# -# Traffic -# - -class Traffic: - - def __init__(self, req): - self.req = req - self.resp = None - - self.ts = req._timestamp - self.retry = 1 - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# ReadPropertySummary -# - -class ReadPropertySummary(Tracer, Logging): - - def __init__(self): - if _debug: ReadPropertySummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: ReadPropertySummary._debug("Filter %r", pkt) - global requests - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: ReadPropertySummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: ReadPropertySummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: ReadPropertySummary._debug(" - host filter fail") - return - - # check for reads - if isinstance(pkt, ReadPropertyRequest): - key = (pkt.pduSource, pkt.pduDestination, pkt.apduInvokeID) - if key in requests: - if _debug: ReadPropertySummary._debug(" - retry") - requests[key].retry += 1 - else: - if _debug: ReadPropertySummary._debug(" - new request") - msg = Traffic(pkt) - requests[key] = msg - traffic.append(msg) - - # now check for results - elif isinstance(pkt, ReadPropertyACK): - key = (pkt.pduDestination, pkt.pduSource, pkt.apduInvokeID) - req = requests.get(key, None) - if req: - if _debug: ReadPropertySummary._debug(" - matched with request") - requests[key].resp = pkt - - # delete the request, it stays in the traffic list - del requests[key] - else: - if _debug: ReadPropertySummary._debug(" - unmatched") - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # start out with no unmatched requests - requests = {} - - # trace the file - trace(sys.argv[1], [ReadPropertySummary]) - - # dump the requests that failed - for msg in traffic: - if not msg.resp: - print strftimestamp(msg.req._timestamp), msg.req.objectIdentifier, msg.req.propertyIdentifier - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/WhoIsIAmDeviceFilter.py b/pcap_tools/WhoIsIAmDeviceFilter.py deleted file mode 100755 index 5b6fbc4f..00000000 --- a/pcap_tools/WhoIsIAmDeviceFilter.py +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/python - -""" -Who-Is and I-Am Device Filter -""" - -import sys - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.apdu import WhoIsRequest, IAmRequest - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None -filterDevice = None - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# WhoIsIAmDevice -# - -class WhoIsIAmDevice(Tracer, Logging): - - def __init__(self): - if _debug: WhoIsIAmDevice._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: WhoIsIAmDevice._debug("Filter %r", pkt) - global requests - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: WhoIsIAmDevice._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: WhoIsIAmDevice._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: WhoIsIAmDevice._debug(" - host filter fail") - return - - # check for Who-Is - if isinstance(pkt, WhoIsRequest): - match = False - if (pkt.deviceInstanceRangeLowLimit is None) or (pkt.deviceInstanceRangeHighLimit is None): - match = True - elif (pkt.deviceInstanceRangeLowLimit >= filterDevice) and (pkt.deviceInstanceRangeHighLimit <= filterDevice): - match = True - - if match: - print "[%d] %s WhoIs %-20s %-20s %8s %8s" % ( - pkt._index + 1, strftimestamp(pkt._timestamp), - pkt.pduSource, pkt.pduDestination, - pkt.deviceInstanceRangeLowLimit, pkt.deviceInstanceRangeHighLimit, - ) - - # check for I-Am - elif isinstance(pkt, IAmRequest): - - if (pkt.iAmDeviceIdentifier[1] == filterDevice): - print "[%d] %s IAm %-20s %-20s" % ( - pkt._index + 1, strftimestamp(pkt._timestamp), - pkt.pduSource, pkt.pduDestination, - ) - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # pcap_file - pcap_file = sys.argv[1] - if _debug: _log.debug(" - pcap_file: %r", pcap_file) - - # which device instance to look for - filterDevice = int(sys.argv[2]) - if _debug: _log.debug(" - filterDevice: %r:", filterDevice) - - # trace the file - trace(pcap_file, [WhoIsIAmDevice]) - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/WhoIsIAmSummaryFilter.py b/pcap_tools/WhoIsIAmSummaryFilter.py deleted file mode 100755 index d806ba33..00000000 --- a/pcap_tools/WhoIsIAmSummaryFilter.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/python - -""" -Who-Is and I-Am Summary Filter -""" - -import sys -from collections import defaultdict - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.apdu import WhoIsRequest, IAmRequest - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# dictionaries of requests -whoIsTraffic = defaultdict(int) -iAmTraffic = defaultdict(int) - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# WhoIsIAmSummary -# - -class WhoIsIAmSummary(Tracer, Logging): - - def __init__(self): - if _debug: WhoIsIAmSummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: WhoIsIAmSummary._debug("Filter %r", pkt) - global requests - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: WhoIsIAmSummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: WhoIsIAmSummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: WhoIsIAmSummary._debug(" - host filter fail") - return - - # check for Who-Is - if isinstance(pkt, WhoIsRequest): - key = (pkt.pduSource, pkt.deviceInstanceRangeLowLimit, pkt.deviceInstanceRangeHighLimit) - whoIsTraffic[key] += 1 - - # check for I-Am - elif isinstance(pkt, IAmRequest): - key = (pkt.pduSource, pkt.iAmDeviceIdentifier[1]) - iAmTraffic[key] += 1 - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [WhoIsIAmSummary]) - - # dump request counts - print "----- Top 20 Who-Is -----" - print - - items = whoIsTraffic.items() - items.sort(lambda x, y: cmp((y[1], y[0][0]), (x[1], x[0][0]))) - for item in items[:20]: - print "%-20s %8s %8s %5d" % (item[0][0], item[0][1], item[0][2], item[1]) - print - - print "----- Top 20 I-Am -----" - print - - items = iAmTraffic.items() - items.sort(lambda x, y: cmp((y[1], y[0][0]), (x[1], x[0][0]))) - for item in items[:20]: - print "%-20s %8s %5d" % (item[0][0], item[0][1], item[1]) - print - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/WhoIsRouterToNetworkSummaryFilter.py b/pcap_tools/WhoIsRouterToNetworkSummaryFilter.py deleted file mode 100755 index b719c08e..00000000 --- a/pcap_tools/WhoIsRouterToNetworkSummaryFilter.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/python - -""" -Summarize Who-Is-Router-To-Network Notifications -""" - -import sys -from collections import defaultdict - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.npdu import WhoIsRouterToNetwork - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# dictionary of requests -requests = defaultdict(int) -networks = defaultdict(list) - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# WhoIsRouterToNetworkSummary -# - -class WhoIsRouterToNetworkSummary(Tracer, Logging): - - def __init__(self): - if _debug: IAmRouterToNetworkSummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: WhoIsRouterToNetworkSummary._debug("Filter %r", pkt) - global requests, networks - - # check for the packet type - if not isinstance(pkt, WhoIsRouterToNetwork): - return - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: WhoIsRouterToNetworkSummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: WhoIsRouterToNetworkSummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: WhoIsRouterToNetworkSummary._debug(" - host filter fail") - return - - # count it - requests[pkt.pduSource] += 1 - networks[pkt.pduSource].append(pkt.wirtnNetwork) - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [WhoIsRouterToNetworkSummary]) - - # sort the result, descending order by count - items = requests.items() - items.sort(lambda x, y: cmp(y[1], x[1])) - - # print everything out - print "%-20s %5s" % ("Address", "Count") - for key, count in items: - print "%-20s %5d" % (key, count) - - # count the number of times of each network - net_count = defaultdict(int) - for net in networks[key]: - net_count[net] += 1 - - # sort descending - net_count = net_count.items() - net_count.sort(lambda x, y: cmp(y[1], x[1])) - - for net, count in net_count: - print " %5d %5d" % (net, count) - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - From 746880a44fa46a836eb01b1f23d2fb19ecca62e3 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Sat, 2 May 2020 12:39:05 -0400 Subject: [PATCH 05/50] removing tools (#339) (#340) go! --- pcap_tools/AddressFilter.py | 129 ---------- pcap_tools/COVNotificationSummaryFilter.py | 149 ------------ pcap_tools/EventNotificationSummaryFilter.py | 215 ----------------- pcap_tools/IAmRouterToNetworkSummaryFilter.py | 161 ------------- pcap_tools/PDUsPerMinuteFilter.py | 108 --------- pcap_tools/ReadPropertySummaryFilter.py | 228 ------------------ pcap_tools/ReadPropertyTimeoutFilter.py | 177 -------------- pcap_tools/WhoIsIAmDeviceFilter.py | 158 ------------ pcap_tools/WhoIsIAmSummaryFilter.py | 160 ------------ .../WhoIsRouterToNetworkSummaryFilter.py | 160 ------------ 10 files changed, 1645 deletions(-) delete mode 100755 pcap_tools/AddressFilter.py delete mode 100755 pcap_tools/COVNotificationSummaryFilter.py delete mode 100755 pcap_tools/EventNotificationSummaryFilter.py delete mode 100755 pcap_tools/IAmRouterToNetworkSummaryFilter.py delete mode 100755 pcap_tools/PDUsPerMinuteFilter.py delete mode 100755 pcap_tools/ReadPropertySummaryFilter.py delete mode 100755 pcap_tools/ReadPropertyTimeoutFilter.py delete mode 100755 pcap_tools/WhoIsIAmDeviceFilter.py delete mode 100755 pcap_tools/WhoIsIAmSummaryFilter.py delete mode 100755 pcap_tools/WhoIsRouterToNetworkSummaryFilter.py diff --git a/pcap_tools/AddressFilter.py b/pcap_tools/AddressFilter.py deleted file mode 100755 index 4130b71c..00000000 --- a/pcap_tools/AddressFilter.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/python - -""" -Address Filter - Sample tool to filter by source, destination and/or host -""" - -import sys - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# AddressFilterTracer -# - -class AddressFilterTracer(Tracer, Logging): - - def __init__(self): - if _debug: AddressFilterTracer._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: AddressFilterTracer._debug("Filter %r", pkt) - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: AddressFilterTracer._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: AddressFilterTracer._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: AddressFilterTracer._debug(" - host filter fail") - return - - # passed all the filter tests - print strftimestamp(pkt._timestamp), pkt.__class__.__name__ - pkt.debug_contents() - print - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [AddressFilterTracer]) - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/COVNotificationSummaryFilter.py b/pcap_tools/COVNotificationSummaryFilter.py deleted file mode 100755 index fd8d6eb4..00000000 --- a/pcap_tools/COVNotificationSummaryFilter.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/python - -""" -Summarize COV Notifications -""" - -import sys - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.apdu import UnconfirmedCOVNotificationRequest - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# dictionary of requests -requests = {} - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# COVNotificationSummary -# - -class COVNotificationSummary(Tracer, Logging): - - def __init__(self): - if _debug: COVNotificationSummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: COVNotificationSummary._debug("Filter %r", pkt) - global requests - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: COVNotificationSummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: COVNotificationSummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: COVNotificationSummary._debug(" - host filter fail") - return - - # check for notifications - if isinstance(pkt, UnconfirmedCOVNotificationRequest): - key = (pkt.pduSource, pkt.initiatingDeviceIdentifier[1], pkt.monitoredObjectIdentifier) - if key in requests: - requests[key] += 1 - else: - requests[key] = 1 - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # start out with no requests - requests = {} - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [COVNotificationSummary]) - - # sort the result, descending order by count - items = requests.items() - items.sort(lambda x, y: cmp(y[1], x[1])) - - # print everything out - print "%-20s %8s %-15s %4s %5s" % ("Address", "Device", "Object", "", "Count") - for key, count in items: - print "%-20s %8s %-15s %4d %5d" % (key[0], key[1], key[2][0], key[2][1], count) - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/EventNotificationSummaryFilter.py b/pcap_tools/EventNotificationSummaryFilter.py deleted file mode 100755 index 093ef628..00000000 --- a/pcap_tools/EventNotificationSummaryFilter.py +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/python - -""" -Event Notification Summary Filter -""" - -import sys - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.apdu import ConfirmedEventNotificationRequest, SimpleAckPDU - -try: - from CSStat import Statistics -except ImportError: - Statistics = lambda: None - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# dictionary of pending requests -requests = {} - -# all traffic -traffic = [] - -# -# Traffic -# - -class Traffic: - - def __init__(self, req): - self.req = req - self.resp = None - - self.ts = req._timestamp - self.retry = 1 - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# ConfirmedEventNotificationSummary -# - -class ConfirmedEventNotificationSummary(Tracer, Logging): - - def __init__(self): - if _debug: ConfirmedEventNotificationSummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: ConfirmedEventNotificationSummary._debug("Filter %r", pkt) - global requests - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: ConfirmedEventNotificationSummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: ConfirmedEventNotificationSummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: ConfirmedEventNotificationSummary._debug(" - host filter fail") - return - - # check for notifications - if isinstance(pkt, ConfirmedEventNotificationRequest): - key = (pkt.pduSource, pkt.pduDestination, pkt.apduInvokeID) - if key in requests: - if _debug: ConfirmedEventNotificationSummary._debug(" - retry") - requests[key].retry += 1 - else: - if _debug: ConfirmedEventNotificationSummary._debug(" - new request") - msg = Traffic(pkt) - requests[key] = msg - traffic.append(msg) - - # now check for acks - elif isinstance(pkt, SimpleAckPDU): - key = (pkt.pduDestination, pkt.pduSource, pkt.apduInvokeID) - req = requests.get(key, None) - if req: - if _debug: ConfirmedEventNotificationSummary._debug(" - matched with request") - requests[key].resp = pkt - - # delete the request, it stays in the traffic list - del requests[key] - else: - if _debug: ConfirmedEventNotificationSummary._debug(" - unmatched") - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # start out with no unmatched requests - requests = {} - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [ConfirmedEventNotificationSummary]) - - # print some stats at the end - stats = Statistics() - - # dump everything - for msg in traffic: - req = msg.req - resp = msg.resp - - if resp: - deltatime = (resp._timestamp - req._timestamp) * 1000 - if stats: - stats.Record(deltatime, req._timestamp) - print strftimestamp(req._timestamp), '\t', req.pduSource, '\t', resp.pduSource, '\t', ("%8.2fms" % (deltatime,)), '\t', msg.retry if (msg.retry != 1) else "" - else: - print strftimestamp(req._timestamp), '\t', req.pduSource, '\t', "----------", '\t', "----------", '\t', msg.retry if (msg.retry != 1) else "" - - if stats: - smin, smax, _, _, _, _ = stats.Stats() - - xlw, lw, q1, m, q3, uw, xuw = stats.Whisker() - if m is not None: - print "\t %-8.1f" % smax - print "\t %-8.1f" % xuw - print "\t--- %-8.1f" % uw - print "\t | " - print "\t.'. %-8.1f" % q3 - print "\t| |" - print "\t|-| %-8.1f" % m - print "\t| |" - print "\t'-' %-8.1f" % q1 - print "\t | " - print "\t--- %-8.1f" % lw - print "\t %-8.1f" % xlw - print "\t %-8.1f" % smin - else: - print "No stats" - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/IAmRouterToNetworkSummaryFilter.py b/pcap_tools/IAmRouterToNetworkSummaryFilter.py deleted file mode 100755 index 729c7b42..00000000 --- a/pcap_tools/IAmRouterToNetworkSummaryFilter.py +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/python - -""" -Summarize I-Am-Router-To-Network Notifications -""" - -import sys -from collections import defaultdict - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.npdu import IAmRouterToNetwork - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# dictionary of requests -requests = defaultdict(int) -networks = defaultdict(list) - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# IAmRouterToNetworkSummary -# - -class IAmRouterToNetworkSummary(Tracer, Logging): - - def __init__(self): - if _debug: IAmRouterToNetworkSummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: IAmRouterToNetworkSummary._debug("Filter %r", pkt) - global requests, networks - - # check for the packet type - if not isinstance(pkt, IAmRouterToNetwork): - return - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: IAmRouterToNetworkSummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: IAmRouterToNetworkSummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: IAmRouterToNetworkSummary._debug(" - host filter fail") - return - - # count it - requests[pkt.pduSource] += 1 - networks[pkt.pduSource].append((pkt.iartnNetworkList)) - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [IAmRouterToNetworkSummary]) - - # sort the result, descending order by count - items = requests.items() - items.sort(lambda x, y: cmp(y[1], x[1])) - - # print everything out - print "%-20s %5s" % ("Address", "Count") - for key, count in items: - print "%-20s %5d" % (key, count) - - # count the number of times of each network - net_count = defaultdict(int) - for subnet_list in networks[key]: - for net in subnet_list: - net_count[net] += 1 - - # sort descending - net_count = net_count.items() - net_count.sort(lambda x, y: cmp(y[1], x[1])) - - for net, count in net_count: - print " %5d %5d" % (net, count) - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/PDUsPerMinuteFilter.py b/pcap_tools/PDUsPerMinuteFilter.py deleted file mode 100755 index 978d202e..00000000 --- a/pcap_tools/PDUsPerMinuteFilter.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/python - -""" -PDUs per Minute Filter - present a table of number of PDUs per minute -""" - -import sys -from collections import defaultdict - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.analysis import trace, strftimestamp, Tracer - -try: - from CSStat import Statistics -except ImportError: - Statistics = lambda: None - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -counter = defaultdict(int) - -# -# PDUsPerMinuteTracer -# - -class PDUsPerMinuteTracer(Tracer, Logging): - - def __init__(self): - if _debug: PDUsPerMinuteTracer._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: PDUsPerMinuteTracer._debug("Filter %r", pkt) - - slot = ((int(pkt._timestamp) / interval) * interval) - if _debug: PDUsPerMinuteTracer._debug(" - slot: %r", slot) - - # count the packets in the slot - counter[slot] += 1 - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for a custom interval - if ('--interval' in sys.argv): - i = sys.argv.index('--interval') - interval = int(sys.argv[i+1]) - if _debug: _log.debug(" - interval: %r", interval) - del sys.argv[i:i+2] - else: - interval = 60 - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [PDUsPerMinuteTracer]) - - # print some stats at the end - stats = Statistics() - - # dump the counters - for ts in range(min(counter), max(counter)+1, interval): - print strftimestamp(ts), counter[ts] - if stats: - stats.Record(counter[ts], ts) - - if stats: - smin, smax, _, _, _, _ = stats.Stats() - - xlw, lw, q1, m, q3, uw, xuw = stats.Whisker() - if m is not None: - print "\t %-8.1f" % smax - print "\t %-8.1f" % xuw - print "\t--- %-8.1f" % uw - print "\t | " - print "\t.'. %-8.1f" % q3 - print "\t| |" - print "\t|-| %-8.1f" % m - print "\t| |" - print "\t'-' %-8.1f" % q1 - print "\t | " - print "\t--- %-8.1f" % lw - print "\t %-8.1f" % xlw - print "\t %-8.1f" % smin - else: - print "No stats" - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/ReadPropertySummaryFilter.py b/pcap_tools/ReadPropertySummaryFilter.py deleted file mode 100755 index 5bfd8f70..00000000 --- a/pcap_tools/ReadPropertySummaryFilter.py +++ /dev/null @@ -1,228 +0,0 @@ -#!/usr/bin/python - -""" -Read Property Summary Filter - Summarize Read Property Requests/Responses -""" - -import sys - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.apdu import ReadPropertyRequest, ReadPropertyACK - -try: - from CSStat import Statistics -except ImportError: - Statistics = lambda: None - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None -filterEval = None - -# dictionary of pending requests -requests = {} - -# all traffic -traffic = [] - -# -# Traffic -# - -class Traffic: - - def __init__(self, req): - self.req = req - self.resp = None - - self.ts = req._timestamp - self.retry = 1 - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# ReadPropertySummary -# - -class ReadPropertySummary(Tracer, Logging): - - def __init__(self): - if _debug: ReadPropertySummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: ReadPropertySummary._debug("Filter %r", pkt) - global requests - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: ReadPropertySummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: ReadPropertySummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: ReadPropertySummary._debug(" - host filter fail") - return - if filterEval: - try: - matches = eval(filterEval, {'pkt':pkt}) - if not matches: - if _debug: ReadPropertySummary._debug(" - eval filter fail") - return - except: - if _debug: ReadPropertySummary._debug(" - eval filter massive fail") - return - - # check for reads - if isinstance(pkt, ReadPropertyRequest): - key = (pkt.pduSource, pkt.pduDestination, pkt.apduInvokeID) - if key in requests: - if _debug: ReadPropertySummary._debug(" - retry") - requests[key].retry += 1 - else: - if _debug: ReadPropertySummary._debug(" - new request") - msg = Traffic(pkt) - requests[key] = msg - traffic.append(msg) - - # now check for results - elif isinstance(pkt, ReadPropertyACK): - key = (pkt.pduDestination, pkt.pduSource, pkt.apduInvokeID) - req = requests.get(key, None) - if req: - if _debug: ReadPropertySummary._debug(" - matched with request") - requests[key].resp = pkt - - # delete the request, it stays in the traffic list - del requests[key] - else: - if _debug: ReadPropertySummary._debug(" - unmatched") - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # check for eval - if ('--eval' in sys.argv): - i = sys.argv.index('--eval') - filterEval = sys.argv[i+1] - if _debug: _log.debug(" - filterEval: %r", filterEval) - del sys.argv[i:i+2] - - # start out with no unmatched requests - requests = {} - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [ReadPropertySummary]) - - # print some stats at the end - stats = Statistics() - - # dump everything - for msg in traffic: - req = msg.req - resp = msg.resp - - if resp: - deltatime = (resp._timestamp - req._timestamp) * 1000 - if stats: - stats.Record(deltatime, req._timestamp) - print strftimestamp(req._timestamp), '\t', req.pduSource, '\t', resp.pduSource, '\t', ("%6.2fms" % (deltatime,)), '\t', msg.retry if (msg.retry != 1) else "" - else: - print strftimestamp(req._timestamp), '\t', req.pduSource, '\t', "----------", '\t', "----------", '\t', msg.retry if (msg.retry != 1) else "" - - if stats: - xlw, lw, q1, m, q3, uw, xuw = stats.Whisker() - if m is not None: - print "\t %-6.1f" % xuw - print "\t--- %-6.1f" % uw - print "\t | " - print "\t.'. %-6.1f" % q3 - print "\t| |" - print "\t|-| %-6.1f" % m - print "\t| |" - print "\t'-' %-6.1f" % q1 - print "\t | " - print "\t--- %-6.1f" % lw - print "\t %-6.1f" % xlw - else: - print "No stats" - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/ReadPropertyTimeoutFilter.py b/pcap_tools/ReadPropertyTimeoutFilter.py deleted file mode 100755 index f6c60ded..00000000 --- a/pcap_tools/ReadPropertyTimeoutFilter.py +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/python - -""" -Read Property Timeout Filter - Look for Read Property Requests with no response -""" - -import sys - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.apdu import ReadPropertyRequest, ReadPropertyACK - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# dictionary of pending requests -requests = {} - -# all traffic -traffic = [] - -# -# Traffic -# - -class Traffic: - - def __init__(self, req): - self.req = req - self.resp = None - - self.ts = req._timestamp - self.retry = 1 - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# ReadPropertySummary -# - -class ReadPropertySummary(Tracer, Logging): - - def __init__(self): - if _debug: ReadPropertySummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: ReadPropertySummary._debug("Filter %r", pkt) - global requests - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: ReadPropertySummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: ReadPropertySummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: ReadPropertySummary._debug(" - host filter fail") - return - - # check for reads - if isinstance(pkt, ReadPropertyRequest): - key = (pkt.pduSource, pkt.pduDestination, pkt.apduInvokeID) - if key in requests: - if _debug: ReadPropertySummary._debug(" - retry") - requests[key].retry += 1 - else: - if _debug: ReadPropertySummary._debug(" - new request") - msg = Traffic(pkt) - requests[key] = msg - traffic.append(msg) - - # now check for results - elif isinstance(pkt, ReadPropertyACK): - key = (pkt.pduDestination, pkt.pduSource, pkt.apduInvokeID) - req = requests.get(key, None) - if req: - if _debug: ReadPropertySummary._debug(" - matched with request") - requests[key].resp = pkt - - # delete the request, it stays in the traffic list - del requests[key] - else: - if _debug: ReadPropertySummary._debug(" - unmatched") - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # start out with no unmatched requests - requests = {} - - # trace the file - trace(sys.argv[1], [ReadPropertySummary]) - - # dump the requests that failed - for msg in traffic: - if not msg.resp: - print strftimestamp(msg.req._timestamp), msg.req.objectIdentifier, msg.req.propertyIdentifier - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/WhoIsIAmDeviceFilter.py b/pcap_tools/WhoIsIAmDeviceFilter.py deleted file mode 100755 index 5b6fbc4f..00000000 --- a/pcap_tools/WhoIsIAmDeviceFilter.py +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/python - -""" -Who-Is and I-Am Device Filter -""" - -import sys - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.apdu import WhoIsRequest, IAmRequest - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None -filterDevice = None - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# WhoIsIAmDevice -# - -class WhoIsIAmDevice(Tracer, Logging): - - def __init__(self): - if _debug: WhoIsIAmDevice._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: WhoIsIAmDevice._debug("Filter %r", pkt) - global requests - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: WhoIsIAmDevice._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: WhoIsIAmDevice._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: WhoIsIAmDevice._debug(" - host filter fail") - return - - # check for Who-Is - if isinstance(pkt, WhoIsRequest): - match = False - if (pkt.deviceInstanceRangeLowLimit is None) or (pkt.deviceInstanceRangeHighLimit is None): - match = True - elif (pkt.deviceInstanceRangeLowLimit >= filterDevice) and (pkt.deviceInstanceRangeHighLimit <= filterDevice): - match = True - - if match: - print "[%d] %s WhoIs %-20s %-20s %8s %8s" % ( - pkt._index + 1, strftimestamp(pkt._timestamp), - pkt.pduSource, pkt.pduDestination, - pkt.deviceInstanceRangeLowLimit, pkt.deviceInstanceRangeHighLimit, - ) - - # check for I-Am - elif isinstance(pkt, IAmRequest): - - if (pkt.iAmDeviceIdentifier[1] == filterDevice): - print "[%d] %s IAm %-20s %-20s" % ( - pkt._index + 1, strftimestamp(pkt._timestamp), - pkt.pduSource, pkt.pduDestination, - ) - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # pcap_file - pcap_file = sys.argv[1] - if _debug: _log.debug(" - pcap_file: %r", pcap_file) - - # which device instance to look for - filterDevice = int(sys.argv[2]) - if _debug: _log.debug(" - filterDevice: %r:", filterDevice) - - # trace the file - trace(pcap_file, [WhoIsIAmDevice]) - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/WhoIsIAmSummaryFilter.py b/pcap_tools/WhoIsIAmSummaryFilter.py deleted file mode 100755 index d806ba33..00000000 --- a/pcap_tools/WhoIsIAmSummaryFilter.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/python - -""" -Who-Is and I-Am Summary Filter -""" - -import sys -from collections import defaultdict - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.apdu import WhoIsRequest, IAmRequest - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# dictionaries of requests -whoIsTraffic = defaultdict(int) -iAmTraffic = defaultdict(int) - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# WhoIsIAmSummary -# - -class WhoIsIAmSummary(Tracer, Logging): - - def __init__(self): - if _debug: WhoIsIAmSummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: WhoIsIAmSummary._debug("Filter %r", pkt) - global requests - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: WhoIsIAmSummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: WhoIsIAmSummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: WhoIsIAmSummary._debug(" - host filter fail") - return - - # check for Who-Is - if isinstance(pkt, WhoIsRequest): - key = (pkt.pduSource, pkt.deviceInstanceRangeLowLimit, pkt.deviceInstanceRangeHighLimit) - whoIsTraffic[key] += 1 - - # check for I-Am - elif isinstance(pkt, IAmRequest): - key = (pkt.pduSource, pkt.iAmDeviceIdentifier[1]) - iAmTraffic[key] += 1 - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [WhoIsIAmSummary]) - - # dump request counts - print "----- Top 20 Who-Is -----" - print - - items = whoIsTraffic.items() - items.sort(lambda x, y: cmp((y[1], y[0][0]), (x[1], x[0][0]))) - for item in items[:20]: - print "%-20s %8s %8s %5d" % (item[0][0], item[0][1], item[0][2], item[1]) - print - - print "----- Top 20 I-Am -----" - print - - items = iAmTraffic.items() - items.sort(lambda x, y: cmp((y[1], y[0][0]), (x[1], x[0][0]))) - for item in items[:20]: - print "%-20s %8s %5d" % (item[0][0], item[0][1], item[1]) - print - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - diff --git a/pcap_tools/WhoIsRouterToNetworkSummaryFilter.py b/pcap_tools/WhoIsRouterToNetworkSummaryFilter.py deleted file mode 100755 index b719c08e..00000000 --- a/pcap_tools/WhoIsRouterToNetworkSummaryFilter.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/python - -""" -Summarize Who-Is-Router-To-Network Notifications -""" - -import sys -from collections import defaultdict - -from bacpypes.debugging import Logging, function_debugging, ModuleLogger -from bacpypes.consolelogging import ConsoleLogHandler - -from bacpypes.pdu import Address -from bacpypes.analysis import trace, strftimestamp, Tracer -from bacpypes.npdu import WhoIsRouterToNetwork - -# some debugging -_debug = 0 -_log = ModuleLogger(globals()) - -# globals -filterSource = None -filterDestination = None -filterHost = None - -# dictionary of requests -requests = defaultdict(int) -networks = defaultdict(list) - -# -# Match -# - -@function_debugging -def Match(addr1, addr2): - """Return true iff addr1 matches addr2.""" - if _debug: Match._debug("Match %r %r", addr1, addr2) - - if (addr2.addrType == Address.localBroadcastAddr): - # match any local station - return (addr1.addrType == Address.localStationAddr) or (addr1.addrType == Address.localBroadcastAddr) - elif (addr2.addrType == Address.localStationAddr): - # match a specific local station - return (addr1.addrType == Address.localStationAddr) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.remoteBroadcastAddr): - # match any remote station or remote broadcast on a matching network - return ((addr1.addrType == Address.remoteStationAddr) or (addr1.addrType == Address.remoteBroadcastAddr)) \ - and (addr1.addrNet == addr2.addrNet) - elif (addr2.addrType == Address.remoteStationAddr): - # match a specific remote station - return (addr1.addrType == Address.remoteStationAddr) and \ - (addr1.addrNet == addr2.addrNet) and (addr1.addrAddr == addr2.addrAddr) - elif (addr2.addrType == Address.globalBroadcastAddr): - # match a global broadcast address - return (addr1.addrType == Address.globalBroadcastAddr) - else: - raise RuntimeError, "invalid match combination" - -# -# WhoIsRouterToNetworkSummary -# - -class WhoIsRouterToNetworkSummary(Tracer, Logging): - - def __init__(self): - if _debug: IAmRouterToNetworkSummary._debug("__init__") - Tracer.__init__(self, self.Filter) - - def Filter(self, pkt): - if _debug: WhoIsRouterToNetworkSummary._debug("Filter %r", pkt) - global requests, networks - - # check for the packet type - if not isinstance(pkt, WhoIsRouterToNetwork): - return - - # apply the filters - if filterSource: - if not Match(pkt.pduSource, filterSource): - if _debug: WhoIsRouterToNetworkSummary._debug(" - source filter fail") - return - if filterDestination: - if not Match(pkt.pduDestination, filterDestination): - if _debug: WhoIsRouterToNetworkSummary._debug(" - destination filter fail") - return - if filterHost: - if (not Match(pkt.pduSource, filterHost)) and (not Match(pkt.pduDestination, filterHost)): - if _debug: WhoIsRouterToNetworkSummary._debug(" - host filter fail") - return - - # count it - requests[pkt.pduSource] += 1 - networks[pkt.pduSource].append(pkt.wirtnNetwork) - -# -# __main__ -# - -try: - if ('--debug' in sys.argv): - indx = sys.argv.index('--debug') - for i in range(indx+1, len(sys.argv)): - ConsoleLogHandler(sys.argv[i]) - del sys.argv[indx:] - - if _debug: _log.debug("initialization") - - # check for src - if ('--src' in sys.argv): - i = sys.argv.index('--src') - filterSource = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterSource: %r", filterSource) - del sys.argv[i:i+2] - - # check for dest - if ('--dest' in sys.argv): - i = sys.argv.index('--dest') - filterDestination = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterDestination: %r", filterDestination) - del sys.argv[i:i+2] - - # check for host - if ('--host' in sys.argv): - i = sys.argv.index('--host') - filterHost = Address(sys.argv[i+1]) - if _debug: _log.debug(" - filterHost: %r", filterHost) - del sys.argv[i:i+2] - - # trace the file(s) - for fname in sys.argv[1:]: - trace(fname, [WhoIsRouterToNetworkSummary]) - - # sort the result, descending order by count - items = requests.items() - items.sort(lambda x, y: cmp(y[1], x[1])) - - # print everything out - print "%-20s %5s" % ("Address", "Count") - for key, count in items: - print "%-20s %5d" % (key, count) - - # count the number of times of each network - net_count = defaultdict(int) - for net in networks[key]: - net_count[net] += 1 - - # sort descending - net_count = net_count.items() - net_count.sort(lambda x, y: cmp(y[1], x[1])) - - for net, count in net_count: - print " %5d %5d" % (net, count) - -except KeyboardInterrupt: - pass -except Exception, e: - _log.exception("an error has occurred: %s", e) -finally: - if _debug: _log.debug("finally") - From 757dcfc0439d5bda38c4e6a4a8839e4bc7e04d66 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Wed, 15 Jul 2020 13:09:32 -0400 Subject: [PATCH 06/50] fix typos in EventParameterAccessEventAccessEvent (#346) (#347) --- py25/bacpypes/basetypes.py | 4 ++-- py27/bacpypes/basetypes.py | 4 ++-- py34/bacpypes/basetypes.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/py25/bacpypes/basetypes.py b/py25/bacpypes/basetypes.py index 624de8ad..9f0150a9 100755 --- a/py25/bacpypes/basetypes.py +++ b/py25/bacpypes/basetypes.py @@ -2198,9 +2198,9 @@ class EventParameterUnsignedRange(Sequence): ] class EventParameterAccessEventAccessEvent(Sequence): - sequenceevents = \ + sequenceElements = \ [ Element('listOfAccessEvents', SequenceOf(AccessEvent), 0) - , Element('accessEventTimeReference', DeviceObjectPropertyReference, 0) + , Element('accessEventTimeReference', DeviceObjectPropertyReference, 1) ] class EventParameterAccessEvent(Sequence): diff --git a/py27/bacpypes/basetypes.py b/py27/bacpypes/basetypes.py index 31b93733..c2dd232f 100755 --- a/py27/bacpypes/basetypes.py +++ b/py27/bacpypes/basetypes.py @@ -2197,9 +2197,9 @@ class EventParameterUnsignedRange(Sequence): ] class EventParameterAccessEventAccessEvent(Sequence): - sequenceevents = \ + sequenceElements = \ [ Element('listOfAccessEvents', SequenceOf(AccessEvent), 0) - , Element('accessEventTimeReference', DeviceObjectPropertyReference, 0) + , Element('accessEventTimeReference', DeviceObjectPropertyReference, 1) ] class EventParameterAccessEvent(Sequence): diff --git a/py34/bacpypes/basetypes.py b/py34/bacpypes/basetypes.py index 31b93733..c2dd232f 100755 --- a/py34/bacpypes/basetypes.py +++ b/py34/bacpypes/basetypes.py @@ -2197,9 +2197,9 @@ class EventParameterUnsignedRange(Sequence): ] class EventParameterAccessEventAccessEvent(Sequence): - sequenceevents = \ + sequenceElements = \ [ Element('listOfAccessEvents', SequenceOf(AccessEvent), 0) - , Element('accessEventTimeReference', DeviceObjectPropertyReference, 0) + , Element('accessEventTimeReference', DeviceObjectPropertyReference, 1) ] class EventParameterAccessEvent(Sequence): From c6d6825d4f1f6fd042f22f586232e08335f95dec Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 14 Sep 2020 10:35:54 -0400 Subject: [PATCH 07/50] Adding common math function support to object with numerical value. Integer not included for now. Don't want to transform them in floating point by error. --- py34/bacpypes/primitivedata.py | 36 ++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/py34/bacpypes/primitivedata.py b/py34/bacpypes/primitivedata.py index dfbc5742..02ab8974 100755 --- a/py34/bacpypes/primitivedata.py +++ b/py34/bacpypes/primitivedata.py @@ -503,6 +503,34 @@ def is_valid(cls, arg): """Return True if arg is valid value for the class.""" raise NotImplementedError("call on a derived class of Atomic") +class CommonMath: + def __add__(self, other): + return self.value + other.value if isinstance(other, Atomic) else (self.value + other) + + def __sub__(self, other): + return self.value - other.value if isinstance(other, Atomic) else (self.value - other) + + def __mul__(self, other): + return self.value * other.value if isinstance(other, Atomic) else (self.value * other) + + def __lt__(self, other): + return self.value < other.value if isinstance(other, Atomic) else (self.value < other) + + def __gt__(self, other): + return self.value > other.value if isinstance(other, Atomic) else (self.value > other) + + def __le__(self, other): + return self.value <= other.value if isinstance(other, Atomic) else (self.value <= other) + + def __ge__(self, other): + return self.value >= other.value if isinstance(other, Atomic) else (self.value >= other) + + def __ne__(self, other): + return self.value != other.value if isinstance(other, Atomic) else (self.value != other) + + def __eq__(self, other): + return self.value == other.value if isinstance(other, Atomic) else (self.value == other) + # # Null # @@ -595,7 +623,7 @@ def __str__(self): # Unsigned # -class Unsigned(Atomic): +class Unsigned(Atomic, CommonMath): _app_tag = Tag.unsignedAppTag _low_limit = 0 @@ -683,7 +711,7 @@ class Unsigned16(Unsigned): # Integer # -class Integer(Atomic): +class Integer(Atomic, CommonMath): _app_tag = Tag.integerAppTag @@ -756,7 +784,7 @@ def __str__(self): # Real # -class Real(Atomic): +class Real(Atomic, CommonMath): _app_tag = Tag.realAppTag @@ -801,7 +829,7 @@ def __str__(self): # Double # -class Double(Atomic): +class Double(Atomic, CommonMath): _app_tag = Tag.doubleAppTag From 29280be74f5e2d19e3befd2cb3ae55b446c898b7 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Wed, 7 Oct 2020 00:30:14 -0400 Subject: [PATCH 08/50] COV sample with an analog input object (#359) --- sandbox/cov_analog_input_object.py | 378 +++++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100755 sandbox/cov_analog_input_object.py diff --git a/sandbox/cov_analog_input_object.py b/sandbox/cov_analog_input_object.py new file mode 100755 index 00000000..2cb59182 --- /dev/null +++ b/sandbox/cov_analog_input_object.py @@ -0,0 +1,378 @@ +#!/usr/bin/env python + +""" +This sample application is a server that supports COV notification services. +The console accepts commands that change the properties of an object that +triggers the notifications. +""" + +import time +from threading import Thread + +from bacpypes.debugging import bacpypes_debugging, ModuleLogger +from bacpypes.consolelogging import ConfigArgumentParser +from bacpypes.consolecmd import ConsoleCmd + +from bacpypes.core import run, deferred, enable_sleeping +from bacpypes.task import RecurringTask + +from bacpypes.app import BIPSimpleApplication +from bacpypes.object import AnalogInputObject +from bacpypes.local.device import LocalDeviceObject +from bacpypes.service.cov import ChangeOfValueServices + +# some debugging +_debug = 0 +_log = ModuleLogger(globals()) + +# test globals +test_ai = None +test_application = None + +# +# SubscribeCOVApplication +# + + +@bacpypes_debugging +class SubscribeCOVApplication(BIPSimpleApplication, ChangeOfValueServices): + pass + + +# +# COVConsoleCmd +# + + +@bacpypes_debugging +class COVConsoleCmd(ConsoleCmd): + def do_status(self, args): + """status""" + args = args.split() + if _debug: + COVConsoleCmd._debug("do_status %r", args) + global test_application + + # dump from the COV detections dict + for obj_ref, cov_detection in test_application.cov_detections.items(): + print("{} {}".format(obj_ref.objectIdentifier, obj_ref)) + + for cov_subscription in cov_detection.cov_subscriptions: + print( + " {} proc_id={} confirmed={} lifetime={}".format( + cov_subscription.client_addr, + cov_subscription.proc_id, + cov_subscription.confirmed, + cov_subscription.lifetime, + ) + ) + + def do_trigger(self, args): + """trigger object_name""" + args = args.split() + if _debug: + COVConsoleCmd._debug("do_trigger %r", args) + global test_application + + if not args: + print("object name required") + return + + obj = test_application.get_object_name(args[0]) + if not obj: + print("no such object") + return + + # get the detection algorithm object + cov_detection = test_application.cov_detections.get(obj, None) + if (not cov_detection) or (len(cov_detection.cov_subscriptions) == 0): + print("no subscriptions for that object") + return + + # tell it to send out notifications + cov_detection.send_cov_notifications() + + def do_set(self, args): + """set object_name [ . ] property_name [ = ] value""" + args = args.split() + if _debug: + COVConsoleCmd._debug("do_set %r", args) + global test_application + + try: + object_name = args.pop(0) + if "." in object_name: + object_name, property_name = object_name.split(".") + else: + property_name = args.pop(0) + if _debug: + COVConsoleCmd._debug(" - object_name: %r", object_name) + if _debug: + COVConsoleCmd._debug(" - property_name: %r", property_name) + + obj = test_application.get_object_name(object_name) + if _debug: + COVConsoleCmd._debug(" - obj: %r", obj) + if not obj: + raise RuntimeError("object not found: %r" % (object_name,)) + + datatype = obj.get_datatype(property_name) + if _debug: + COVConsoleCmd._debug(" - datatype: %r", datatype) + if not datatype: + raise RuntimeError("not a property: %r" % (property_name,)) + + # toss the equals + if args[0] == "=": + args.pop(0) + + # evaluate the value + value = eval(args.pop(0)) + if _debug: + COVConsoleCmd._debug(" - raw value: %r", value) + + # see if it can be built + obj_value = datatype(value) + if _debug: + COVConsoleCmd._debug(" - obj_value: %r", obj_value) + + # normalize + value = obj_value.value + if _debug: + COVConsoleCmd._debug(" - normalized value: %r", value) + + # change the value + setattr(obj, property_name, value) + + except IndexError: + print(COVConsoleCmd.do_set.__doc__) + except Exception as err: + print("exception: %s" % (err,)) + + def do_write(self, args): + """write object_name [ . ] property [ = ] value""" + args = args.split() + if _debug: + COVConsoleCmd._debug("do_set %r", args) + global test_application + + try: + object_name = args.pop(0) + if "." in object_name: + object_name, property_name = object_name.split(".") + else: + property_name = args.pop(0) + if _debug: + COVConsoleCmd._debug(" - object_name: %r", object_name) + if _debug: + COVConsoleCmd._debug(" - property_name: %r", property_name) + + obj = test_application.get_object_name(object_name) + if _debug: + COVConsoleCmd._debug(" - obj: %r", obj) + if not obj: + raise RuntimeError("object not found: %r" % (object_name,)) + + datatype = obj.get_datatype(property_name) + if _debug: + COVConsoleCmd._debug(" - datatype: %r", datatype) + if not datatype: + raise RuntimeError("not a property: %r" % (property_name,)) + + # toss the equals + if args[0] == "=": + args.pop(0) + + # evaluate the value + value = eval(args.pop(0)) + if _debug: + COVConsoleCmd._debug(" - raw value: %r", value) + + # see if it can be built + obj_value = datatype(value) + if _debug: + COVConsoleCmd._debug(" - obj_value: %r", obj_value) + + # normalize + value = obj_value.value + if _debug: + COVConsoleCmd._debug(" - normalized value: %r", value) + + # pass it along + obj.WriteProperty(property_name, value) + + except IndexError: + print(COVConsoleCmd.do_write.__doc__) + except Exception as err: + print("exception: %s" % (err,)) + + +@bacpypes_debugging +class TestAnalogInputTask(RecurringTask): + + """ + An instance of this class is created when '--aitask ' is + specified as a command line argument. Every seconds it + changes the value of the test_ai present value. + """ + + def __init__(self, interval): + if _debug: + TestAnalogInputTask._debug("__init__ %r", interval) + RecurringTask.__init__(self, interval * 1000) + + # make a list of test values + self.test_values = list(float(i * 10) for i in range(10)) + + def process_task(self): + if _debug: + TestAnalogInputTask._debug("process_task") + global test_ai + + # pop the next value + next_value = self.test_values.pop(0) + self.test_values.append(next_value) + if _debug: + TestAnalogInputTask._debug(" - next_value: %r", next_value) + + # change the point + test_ai.presentValue = next_value + + +@bacpypes_debugging +class TestAnalogInputThread(Thread): + + """ + An instance of this class is created when '--aithread ' is + specified as a command line argument. Every seconds it + changes the value of the test_ai present value. + """ + + def __init__(self, interval): + if _debug: + TestAnalogInputThread._debug("__init__ %r", interval) + Thread.__init__(self) + + # runs as a daemon + self.daemon = True + + # save the interval + self.interval = interval + + # make a list of test values + self.test_values = list(100.0 + float(i * 10) for i in range(10)) + + def run(self): + if _debug: + TestAnalogInputThread._debug("run") + global test_ai + + while True: + # pop the next value + next_value = self.test_values.pop(0) + self.test_values.append(next_value) + if _debug: + TestAnalogInputThread._debug(" - next_value: %r", next_value) + + # change the point + test_ai.presentValue = next_value + + # sleep + time.sleep(self.interval) + + +def main(): + global test_ai, test_application + + # make a parser + parser = ConfigArgumentParser(description=__doc__) + parser.add_argument( + "--console", action="store_true", default=False, help="create a console", + ) + + # analog value task and thread + parser.add_argument( + "--aitask", type=float, help="analog input recurring task", + ) + parser.add_argument( + "--aithread", type=float, help="analog input thread", + ) + + # analog value task and thread + parser.add_argument( + "--bvtask", type=float, help="binary value recurring task", + ) + parser.add_argument( + "--bvthread", type=float, help="binary value thread", + ) + + # provide a different spin value + parser.add_argument( + "--spin", type=float, help="spin time", default=1.0, + ) + + # parse the command line arguments + args = parser.parse_args() + + if _debug: + _log.debug("initialization") + if _debug: + _log.debug(" - args: %r", args) + + # make a device object + this_device = LocalDeviceObject(ini=args.ini) + if _debug: + _log.debug(" - this_device: %r", this_device) + + # make a sample application + test_application = SubscribeCOVApplication(this_device, args.ini.address) + + # make an analog value object + test_ai = AnalogInputObject( + objectIdentifier=("analogInput", 1), + objectName="ai", + presentValue=0.0, + covIncrement=0.5, + eventDetectionEnable=True, + eventEnable=[1, 1, 1], + ackedTransitions=[1, 1, 1], + notifyType=1, + reliability=1, + outOfService=False, + eventState=0, + statusFlags=[0, 0, 0, 0], + units=19, + ) + _log.debug(" - test_ai: %r", test_ai) + + # add it to the device + test_application.add_object(test_ai) + _log.debug(" - object list: %r", this_device.objectList) + + # make a console + if args.console: + test_console = COVConsoleCmd() + _log.debug(" - test_console: %r", test_console) + + # enable sleeping will help with threads + enable_sleeping() + + # analog input task + if args.aitask: + test_ai_task = TestAnalogInputTask(args.aitask) + test_ai_task.install_task() + + # analog input thread + if args.aithread: + test_ai_thread = TestAnalogInputThread(args.aithread) + deferred(test_ai_thread.start) + + _log.debug("running") + + run(args.spin) + + _log.debug("fini") + + +if __name__ == "__main__": + main() From 17bb6703c558894904a1261a1de726642277c530 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Fri, 9 Oct 2020 19:20:21 -0400 Subject: [PATCH 09/50] make the analog value object writable (#361) --- samples/COVServer.py | 198 ++++++++++++++++++++++++++----------------- 1 file changed, 122 insertions(+), 76 deletions(-) diff --git a/samples/COVServer.py b/samples/COVServer.py index 4c32dcda..3182362b 100755 --- a/samples/COVServer.py +++ b/samples/COVServer.py @@ -17,7 +17,13 @@ from bacpypes.task import RecurringTask from bacpypes.app import BIPSimpleApplication -from bacpypes.object import AnalogValueObject, BinaryValueObject +from bacpypes.primitivedata import Real +from bacpypes.object import ( + WritableProperty, + AnalogValueObject, + BinaryValueObject, + register_object_type, +) from bacpypes.local.device import LocalDeviceObject from bacpypes.service.cov import ChangeOfValueServices @@ -30,25 +36,34 @@ test_bv = None test_application = None + +@register_object_type +class WritableAnalogValueObject(AnalogValueObject): + properties = [WritableProperty("presentValue", Real)] + + # # SubscribeCOVApplication # + @bacpypes_debugging class SubscribeCOVApplication(BIPSimpleApplication, ChangeOfValueServices): pass + # # COVConsoleCmd # + @bacpypes_debugging class COVConsoleCmd(ConsoleCmd): - def do_status(self, args): """status""" args = args.split() - if _debug: COVConsoleCmd._debug("do_status %r", args) + if _debug: + COVConsoleCmd._debug("do_status %r", args) global test_application # dump from the COV detections dict @@ -56,17 +71,20 @@ def do_status(self, args): print("{} {}".format(obj_ref.objectIdentifier, obj_ref)) for cov_subscription in cov_detection.cov_subscriptions: - print(" {} proc_id={} confirmed={} lifetime={}".format( - cov_subscription.client_addr, - cov_subscription.proc_id, - cov_subscription.confirmed, - cov_subscription.lifetime, - )) + print( + " {} proc_id={} confirmed={} lifetime={}".format( + cov_subscription.client_addr, + cov_subscription.proc_id, + cov_subscription.confirmed, + cov_subscription.lifetime, + ) + ) def do_trigger(self, args): """trigger object_name""" args = args.split() - if _debug: COVConsoleCmd._debug("do_trigger %r", args) + if _debug: + COVConsoleCmd._debug("do_trigger %r", args) global test_application if not args: @@ -90,43 +108,51 @@ def do_trigger(self, args): def do_set(self, args): """set object_name [ . ] property_name [ = ] value""" args = args.split() - if _debug: COVConsoleCmd._debug("do_set %r", args) + if _debug: + COVConsoleCmd._debug("do_set %r", args) global test_application try: object_name = args.pop(0) - if '.' in object_name: - object_name, property_name = object_name.split('.') + if "." in object_name: + object_name, property_name = object_name.split(".") else: property_name = args.pop(0) - if _debug: COVConsoleCmd._debug(" - object_name: %r", object_name) - if _debug: COVConsoleCmd._debug(" - property_name: %r", property_name) + if _debug: + COVConsoleCmd._debug(" - object_name: %r", object_name) + if _debug: + COVConsoleCmd._debug(" - property_name: %r", property_name) obj = test_application.get_object_name(object_name) - if _debug: COVConsoleCmd._debug(" - obj: %r", obj) + if _debug: + COVConsoleCmd._debug(" - obj: %r", obj) if not obj: raise RuntimeError("object not found: %r" % (object_name,)) datatype = obj.get_datatype(property_name) - if _debug: COVConsoleCmd._debug(" - datatype: %r", datatype) + if _debug: + COVConsoleCmd._debug(" - datatype: %r", datatype) if not datatype: raise RuntimeError("not a property: %r" % (property_name,)) # toss the equals - if args[0] == '=': + if args[0] == "=": args.pop(0) # evaluate the value value = eval(args.pop(0)) - if _debug: COVConsoleCmd._debug(" - raw value: %r", value) + if _debug: + COVConsoleCmd._debug(" - raw value: %r", value) # see if it can be built obj_value = datatype(value) - if _debug: COVConsoleCmd._debug(" - obj_value: %r", obj_value) + if _debug: + COVConsoleCmd._debug(" - obj_value: %r", obj_value) # normalize value = obj_value.value - if _debug: COVConsoleCmd._debug(" - normalized value: %r", value) + if _debug: + COVConsoleCmd._debug(" - normalized value: %r", value) # change the value setattr(obj, property_name, value) @@ -139,43 +165,51 @@ def do_set(self, args): def do_write(self, args): """write object_name [ . ] property [ = ] value""" args = args.split() - if _debug: COVConsoleCmd._debug("do_set %r", args) + if _debug: + COVConsoleCmd._debug("do_set %r", args) global test_application try: object_name = args.pop(0) - if '.' in object_name: - object_name, property_name = object_name.split('.') + if "." in object_name: + object_name, property_name = object_name.split(".") else: property_name = args.pop(0) - if _debug: COVConsoleCmd._debug(" - object_name: %r", object_name) - if _debug: COVConsoleCmd._debug(" - property_name: %r", property_name) + if _debug: + COVConsoleCmd._debug(" - object_name: %r", object_name) + if _debug: + COVConsoleCmd._debug(" - property_name: %r", property_name) obj = test_application.get_object_name(object_name) - if _debug: COVConsoleCmd._debug(" - obj: %r", obj) + if _debug: + COVConsoleCmd._debug(" - obj: %r", obj) if not obj: raise RuntimeError("object not found: %r" % (object_name,)) datatype = obj.get_datatype(property_name) - if _debug: COVConsoleCmd._debug(" - datatype: %r", datatype) + if _debug: + COVConsoleCmd._debug(" - datatype: %r", datatype) if not datatype: raise RuntimeError("not a property: %r" % (property_name,)) # toss the equals - if args[0] == '=': + if args[0] == "=": args.pop(0) # evaluate the value value = eval(args.pop(0)) - if _debug: COVConsoleCmd._debug(" - raw value: %r", value) + if _debug: + COVConsoleCmd._debug(" - raw value: %r", value) # see if it can be built obj_value = datatype(value) - if _debug: COVConsoleCmd._debug(" - obj_value: %r", obj_value) + if _debug: + COVConsoleCmd._debug(" - obj_value: %r", obj_value) # normalize value = obj_value.value - if _debug: COVConsoleCmd._debug(" - normalized value: %r", value) + if _debug: + COVConsoleCmd._debug(" - normalized value: %r", value) # pass it along obj.WriteProperty(property_name, value) @@ -196,20 +230,23 @@ class TestAnalogValueTask(RecurringTask): """ def __init__(self, interval): - if _debug: TestAnalogValueTask._debug("__init__ %r", interval) + if _debug: + TestAnalogValueTask._debug("__init__ %r", interval) RecurringTask.__init__(self, interval * 1000) # make a list of test values self.test_values = list(float(i * 10) for i in range(10)) def process_task(self): - if _debug: TestAnalogValueTask._debug("process_task") + if _debug: + TestAnalogValueTask._debug("process_task") global test_av # pop the next value next_value = self.test_values.pop(0) self.test_values.append(next_value) - if _debug: TestAnalogValueTask._debug(" - next_value: %r", next_value) + if _debug: + TestAnalogValueTask._debug(" - next_value: %r", next_value) # change the point test_av.presentValue = next_value @@ -225,7 +262,8 @@ class TestAnalogValueThread(Thread): """ def __init__(self, interval): - if _debug: TestAnalogValueThread._debug("__init__ %r", interval) + if _debug: + TestAnalogValueThread._debug("__init__ %r", interval) Thread.__init__(self) # runs as a daemon @@ -238,14 +276,16 @@ def __init__(self, interval): self.test_values = list(100.0 + float(i * 10) for i in range(10)) def run(self): - if _debug: TestAnalogValueThread._debug("run") + if _debug: + TestAnalogValueThread._debug("run") global test_av while True: # pop the next value next_value = self.test_values.pop(0) self.test_values.append(next_value) - if _debug: TestAnalogValueThread._debug(" - next_value: %r", next_value) + if _debug: + TestAnalogValueThread._debug(" - next_value: %r", next_value) # change the point test_av.presentValue = next_value @@ -264,7 +304,8 @@ class TestBinaryValueTask(RecurringTask): """ def __init__(self, interval): - if _debug: TestBinaryValueTask._debug("__init__ %r", interval) + if _debug: + TestBinaryValueTask._debug("__init__ %r", interval) RecurringTask.__init__(self, interval * 1000) # save the interval @@ -274,13 +315,15 @@ def __init__(self, interval): self.test_values = [True, False] def process_task(self): - if _debug: TestBinaryValueTask._debug("process_task") + if _debug: + TestBinaryValueTask._debug("process_task") global test_bv # pop the next value next_value = self.test_values.pop(0) self.test_values.append(next_value) - if _debug: TestBinaryValueTask._debug(" - next_value: %r", next_value) + if _debug: + TestBinaryValueTask._debug(" - next_value: %r", next_value) # change the point test_bv.presentValue = next_value @@ -296,7 +339,8 @@ class TestBinaryValueThread(RecurringTask, Thread): """ def __init__(self, interval): - if _debug: TestBinaryValueThread._debug("__init__ %r", interval) + if _debug: + TestBinaryValueThread._debug("__init__ %r", interval) Thread.__init__(self) # runs as a daemon @@ -309,14 +353,16 @@ def __init__(self, interval): self.test_values = [True, False] def run(self): - if _debug: TestBinaryValueThread._debug("run") + if _debug: + TestBinaryValueThread._debug("run") global test_bv while True: # pop the next value next_value = self.test_values.pop(0) self.test_values.append(next_value) - if _debug: TestBinaryValueThread._debug(" - next_value: %r", next_value) + if _debug: + TestBinaryValueThread._debug(" - next_value: %r", next_value) # change the point test_bv.presentValue = next_value @@ -330,55 +376,55 @@ def main(): # make a parser parser = ConfigArgumentParser(description=__doc__) - parser.add_argument("--console", - action="store_true", - default=False, - help="create a console", - ) + parser.add_argument( + "--console", action="store_true", default=False, help="create a console", + ) # analog value task and thread - parser.add_argument("--avtask", type=float, - help="analog value recurring task", - ) - parser.add_argument("--avthread", type=float, - help="analog value thread", - ) + parser.add_argument( + "--avtask", type=float, help="analog value recurring task", + ) + parser.add_argument( + "--avthread", type=float, help="analog value thread", + ) # analog value task and thread - parser.add_argument("--bvtask", type=float, - help="binary value recurring task", - ) - parser.add_argument("--bvthread", type=float, - help="binary value thread", - ) + parser.add_argument( + "--bvtask", type=float, help="binary value recurring task", + ) + parser.add_argument( + "--bvthread", type=float, help="binary value thread", + ) # provide a different spin value - parser.add_argument("--spin", type=float, - help="spin time", - default=1.0, - ) + parser.add_argument( + "--spin", type=float, help="spin time", default=1.0, + ) # parse the command line arguments args = parser.parse_args() - if _debug: _log.debug("initialization") - if _debug: _log.debug(" - args: %r", args) + if _debug: + _log.debug("initialization") + if _debug: + _log.debug(" - args: %r", args) # make a device object this_device = LocalDeviceObject(ini=args.ini) - if _debug: _log.debug(" - this_device: %r", this_device) + if _debug: + _log.debug(" - this_device: %r", this_device) # make a sample application test_application = SubscribeCOVApplication(this_device, args.ini.address) # make an analog value object - test_av = AnalogValueObject( - objectIdentifier=('analogValue', 1), - objectName='av', + test_av = WritableAnalogValueObject( + objectIdentifier=("analogValue", 1), + objectName="av", presentValue=0.0, statusFlags=[0, 0, 0, 0], covIncrement=1.0, - ) + ) _log.debug(" - test_av: %r", test_av) # add it to the device @@ -387,11 +433,11 @@ def main(): # make a binary value object test_bv = BinaryValueObject( - objectIdentifier=('binaryValue', 1), - objectName='bv', - presentValue='inactive', + objectIdentifier=("binaryValue", 1), + objectName="bv", + presentValue="inactive", statusFlags=[0, 0, 0, 0], - ) + ) _log.debug(" - test_bv: %r", test_bv) # add it to the device From 0b432128bc826cf239821cacf22ab07353c865aa Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Tue, 20 Oct 2020 09:57:57 -0400 Subject: [PATCH 10/50] hotfix - extended unicode characters not supported --- py27/bacpypes/local/object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py27/bacpypes/local/object.py b/py27/bacpypes/local/object.py index 7932042f..e2c62eae 100644 --- a/py27/bacpypes/local/object.py +++ b/py27/bacpypes/local/object.py @@ -94,7 +94,7 @@ class CurrentPropertyListMixIn(Object): u"A-Za-z" u"\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF" u"\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF" - u"\uFDF0-\uFFFD\U00010000-\U000EFFFF" + # u"\uFDF0-\uFFFD\U00010000-\U000EFFFF" - python2.7 on MacOS doesn't like it ) PN_CHARS_U = PN_CHARS_BASE + u"_" From f834e53c553f5c9ab620317174b42d64a84aaa6d Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Tue, 20 Oct 2020 10:34:18 -0400 Subject: [PATCH 11/50] bump the version number --- py25/bacpypes/__init__.py | 2 +- py27/bacpypes/__init__.py | 2 +- py34/bacpypes/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/py25/bacpypes/__init__.py b/py25/bacpypes/__init__.py index 89dfbbeb..2090886f 100755 --- a/py25/bacpypes/__init__.py +++ b/py25/bacpypes/__init__.py @@ -18,7 +18,7 @@ # Project Metadata # -__version__ = '0.18.2' +__version__ = '0.18.3' __author__ = 'Joel Bender' __email__ = 'joel@carrickbender.com' diff --git a/py27/bacpypes/__init__.py b/py27/bacpypes/__init__.py index 89dfbbeb..2090886f 100755 --- a/py27/bacpypes/__init__.py +++ b/py27/bacpypes/__init__.py @@ -18,7 +18,7 @@ # Project Metadata # -__version__ = '0.18.2' +__version__ = '0.18.3' __author__ = 'Joel Bender' __email__ = 'joel@carrickbender.com' diff --git a/py34/bacpypes/__init__.py b/py34/bacpypes/__init__.py index 242126d9..f1acb644 100755 --- a/py34/bacpypes/__init__.py +++ b/py34/bacpypes/__init__.py @@ -18,7 +18,7 @@ # Project Metadata # -__version__ = '0.18.2' +__version__ = '0.18.3' __author__ = 'Joel Bender' __email__ = 'joel@carrickbender.com' From ce5a30f88114c160a6e26605eb0ad14980ef3aa6 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Sun, 25 Oct 2020 11:15:54 -0400 Subject: [PATCH 12/50] Forcing a default value of 0 for lifetime... just in case. Fix for issue #364 Signed-off-by: Christian Tremblay, ing. --- py34/bacpypes/service/cov.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py34/bacpypes/service/cov.py b/py34/bacpypes/service/cov.py index 02887131..79b7c0be 100644 --- a/py34/bacpypes/service/cov.py +++ b/py34/bacpypes/service/cov.py @@ -90,7 +90,7 @@ class Subscription(OneShotTask, DebugContents): 'lifetime', ) - def __init__(self, obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime): + def __init__(self, obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime=0): if _debug: Subscription._debug("__init__ %r %r %r %r %r %r", obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime) OneShotTask.__init__(self) From d91a7e388afcc677c71b0b457b0d0ff6ed1ee58f Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Sun, 25 Oct 2020 19:40:06 -0400 Subject: [PATCH 13/50] duplicate patch in other source trees --- py25/bacpypes/service/cov.py | 2 +- py27/bacpypes/service/cov.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py25/bacpypes/service/cov.py b/py25/bacpypes/service/cov.py index 463b58d4..13664f8c 100644 --- a/py25/bacpypes/service/cov.py +++ b/py25/bacpypes/service/cov.py @@ -89,7 +89,7 @@ class Subscription(OneShotTask, DebugContents): 'lifetime', ) - def __init__(self, obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime): + def __init__(self, obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime=0): if _debug: Subscription._debug("__init__ %r %r %r %r %r %r", obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime) OneShotTask.__init__(self) diff --git a/py27/bacpypes/service/cov.py b/py27/bacpypes/service/cov.py index 02887131..79b7c0be 100644 --- a/py27/bacpypes/service/cov.py +++ b/py27/bacpypes/service/cov.py @@ -90,7 +90,7 @@ class Subscription(OneShotTask, DebugContents): 'lifetime', ) - def __init__(self, obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime): + def __init__(self, obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime=0): if _debug: Subscription._debug("__init__ %r %r %r %r %r %r", obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime) OneShotTask.__init__(self) From 859cb49c9be9e514afd70fce428322f86aac7476 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Sun, 25 Oct 2020 20:32:58 -0400 Subject: [PATCH 14/50] Changed the way we handle an empty lifetime in APDU looking for None instead of 0 to fix a Runtime error when install_task gets a delta of None --- py34/bacpypes/service/cov.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/py34/bacpypes/service/cov.py b/py34/bacpypes/service/cov.py index 79b7c0be..a506bf24 100644 --- a/py34/bacpypes/service/cov.py +++ b/py34/bacpypes/service/cov.py @@ -102,11 +102,10 @@ def __init__(self, obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime=0) self.proc_id = proc_id self.obj_id = obj_id self.confirmed = confirmed - self.lifetime = lifetime - # if lifetime is non-zero, schedule the subscription to expire - if lifetime != 0: - self.install_task(delta=self.lifetime) + # if lifetime is none, consider permanent subscription (0) + self.lifetime = 0 if lifetime is None else lifetime + self.install_task(delta=self.lifetime) def cancel_subscription(self): if _debug: Subscription._debug("cancel_subscription") From 2ca9c4f5cbdec6e8e3de4922f2cdbf5f2d93231c Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Sun, 25 Oct 2020 21:44:00 -0400 Subject: [PATCH 15/50] Sync for py27 and py25 --- py25/bacpypes/service/cov.py | 6 +++--- py27/bacpypes/service/cov.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/py25/bacpypes/service/cov.py b/py25/bacpypes/service/cov.py index 13664f8c..6c19abb4 100644 --- a/py25/bacpypes/service/cov.py +++ b/py25/bacpypes/service/cov.py @@ -103,9 +103,9 @@ def __init__(self, obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime=0) self.confirmed = confirmed self.lifetime = lifetime - # if lifetime is non-zero, schedule the subscription to expire - if lifetime != 0: - self.install_task(delta=self.lifetime) + # if lifetime is none, consider permanent subscription (0) + self.lifetime = 0 if lifetime is None else lifetime + self.install_task(delta=self.lifetime) def cancel_subscription(self): if _debug: Subscription._debug("cancel_subscription") diff --git a/py27/bacpypes/service/cov.py b/py27/bacpypes/service/cov.py index 79b7c0be..acd921c8 100644 --- a/py27/bacpypes/service/cov.py +++ b/py27/bacpypes/service/cov.py @@ -104,9 +104,9 @@ def __init__(self, obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime=0) self.confirmed = confirmed self.lifetime = lifetime - # if lifetime is non-zero, schedule the subscription to expire - if lifetime != 0: - self.install_task(delta=self.lifetime) + # if lifetime is none, consider permanent subscription (0) + self.lifetime = 0 if lifetime is None else lifetime + self.install_task(delta=self.lifetime) def cancel_subscription(self): if _debug: Subscription._debug("cancel_subscription") From 47714a2df9515bf2be9a16387c0a135db2e28b33 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Wed, 4 Nov 2020 10:13:32 -0500 Subject: [PATCH 16/50] allow the property identifier in commands to be just an integer, it was inconsistent in the samples --- samples/Discover.py | 2 ++ samples/HTTPServer.py | 2 ++ samples/ReadProperty.py | 2 ++ samples/ReadProperty25.py | 2 ++ samples/ReadPropertyAny.py | 2 ++ samples/ReadPropertyForeign.py | 2 ++ samples/ReadPropertyJSON.py | 2 ++ samples/ReadRange.py | 2 ++ samples/ReadWriteProperty.py | 2 ++ samples/VendorReadWriteProperty.py | 2 +- samples/WriteLightingCommand.py | 2 ++ samples/WriteSomething.py | 3 ++- 12 files changed, 23 insertions(+), 2 deletions(-) diff --git a/samples/Discover.py b/samples/Discover.py index af9d501b..ec0fda58 100644 --- a/samples/Discover.py +++ b/samples/Discover.py @@ -548,6 +548,8 @@ def do_rp(self, args): devid = int(devid) obj_id = ObjectIdentifier(obj_id).value + if prop_id.isdigit(): + prop_id = int(prop_id) datatype = get_datatype(obj_id[0], prop_id) if not datatype: diff --git a/samples/HTTPServer.py b/samples/HTTPServer.py index 9fa32d01..6662cda6 100755 --- a/samples/HTTPServer.py +++ b/samples/HTTPServer.py @@ -131,6 +131,8 @@ def do_read(self, args): # implement a default property, the bain of committee meetings if len(args) == 3: prop_id = args[2] + if prop_id.isdigit(): + prop_id = int(prop_id) else: prop_id = "presentValue" diff --git a/samples/ReadProperty.py b/samples/ReadProperty.py index fc031620..b636577f 100755 --- a/samples/ReadProperty.py +++ b/samples/ReadProperty.py @@ -43,6 +43,8 @@ def do_read(self, args): try: addr, obj_id, prop_id = args[:3] obj_id = ObjectIdentifier(obj_id).value + if prop_id.isdigit(): + prop_id = int(prop_id) datatype = get_datatype(obj_id[0], prop_id) if not datatype: diff --git a/samples/ReadProperty25.py b/samples/ReadProperty25.py index 56eb40be..62377858 100755 --- a/samples/ReadProperty25.py +++ b/samples/ReadProperty25.py @@ -46,6 +46,8 @@ def do_read(self, args): try: addr, obj_id, prop_id = args[:3] obj_id = ObjectIdentifier(obj_id).value + if prop_id.isdigit(): + prop_id = int(prop_id) datatype = get_datatype(obj_id[0], prop_id) if not datatype: diff --git a/samples/ReadPropertyAny.py b/samples/ReadPropertyAny.py index c429c8fd..5fb37acb 100755 --- a/samples/ReadPropertyAny.py +++ b/samples/ReadPropertyAny.py @@ -48,6 +48,8 @@ def do_read(self, args): try: addr, obj_id, prop_id = args[:3] obj_id = ObjectIdentifier(obj_id).value + if prop_id.isdigit(): + prop_id = int(prop_id) # build a request request = ReadPropertyRequest( diff --git a/samples/ReadPropertyForeign.py b/samples/ReadPropertyForeign.py index 513c74f7..8ed571c7 100755 --- a/samples/ReadPropertyForeign.py +++ b/samples/ReadPropertyForeign.py @@ -57,6 +57,8 @@ def do_read(self, args): try: addr, obj_id, prop_id = args[:3] obj_id = ObjectIdentifier(obj_id).value + if prop_id.isdigit(): + prop_id = int(prop_id) datatype = get_datatype(obj_id[0], prop_id) if not datatype: diff --git a/samples/ReadPropertyJSON.py b/samples/ReadPropertyJSON.py index 0d240585..d5d3b971 100644 --- a/samples/ReadPropertyJSON.py +++ b/samples/ReadPropertyJSON.py @@ -51,6 +51,8 @@ def do_read(self, args): try: addr, obj_id, prop_id = args[:3] obj_id = ObjectIdentifier(obj_id).value + if prop_id.isdigit(): + prop_id = int(prop_id) datatype = get_datatype(obj_id[0], prop_id) if not datatype: diff --git a/samples/ReadRange.py b/samples/ReadRange.py index 54fb1542..cc537113 100755 --- a/samples/ReadRange.py +++ b/samples/ReadRange.py @@ -60,6 +60,8 @@ def do_readrange(self, args): addr = Address(args.pop(0)) obj_id = ObjectIdentifier(args.pop(0)).value prop_id = args.pop(0) + if prop_id.isdigit(): + prop_id = int(prop_id) datatype = get_datatype(obj_id[0], prop_id) if not datatype: diff --git a/samples/ReadWriteProperty.py b/samples/ReadWriteProperty.py index 7ee7d177..5dd2d3d5 100755 --- a/samples/ReadWriteProperty.py +++ b/samples/ReadWriteProperty.py @@ -51,6 +51,8 @@ def do_read(self, args): try: addr, obj_id, prop_id = args[:3] obj_id = ObjectIdentifier(obj_id).value + if prop_id.isdigit(): + prop_id = int(prop_id) datatype = get_datatype(obj_id[0], prop_id) if not datatype: diff --git a/samples/VendorReadWriteProperty.py b/samples/VendorReadWriteProperty.py index 91154685..ae440843 100755 --- a/samples/VendorReadWriteProperty.py +++ b/samples/VendorReadWriteProperty.py @@ -51,9 +51,9 @@ def do_read(self, args): try: addr, obj_id, prop_id = args[:3] obj_id = ObjectIdentifier(obj_id).value - if prop_id.isdigit(): prop_id = int(prop_id) + if _debug: ReadWritePropertyConsoleCmd._debug(" - prop_id: %r", prop_id) datatype = get_datatype(obj_id[0], prop_id, VendorAVObject.vendor_id) diff --git a/samples/WriteLightingCommand.py b/samples/WriteLightingCommand.py index 51708be1..a616756e 100755 --- a/samples/WriteLightingCommand.py +++ b/samples/WriteLightingCommand.py @@ -52,6 +52,8 @@ def do_read(self, args): try: addr, obj_id, prop_id = args[:3] obj_id = ObjectIdentifier(obj_id).value + if prop_id.isdigit(): + prop_id = int(prop_id) datatype = get_datatype(obj_id[0], prop_id) if not datatype: diff --git a/samples/WriteSomething.py b/samples/WriteSomething.py index df66a18a..67163a3a 100755 --- a/samples/WriteSomething.py +++ b/samples/WriteSomething.py @@ -47,7 +47,8 @@ def do_write(self, args): try: addr, obj_id, prop_id = args[:3] obj_id = ObjectIdentifier(obj_id).value - prop_id = int(prop_id) + if prop_id.isdigit(): + prop_id = int(prop_id) # build a request request = WritePropertyRequest( From 50e19ee7afac12c75c72be4c4526c93fc6323e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mihai=20Bi=C5=9Fog?= Date: Sun, 8 Nov 2020 17:36:34 +0200 Subject: [PATCH 17/50] =?UTF-8?q?=F0=9F=90=9BAdded=20active=20foreign=20de?= =?UTF-8?q?vice=20registration=20tracking,=20improved=20registration=20beh?= =?UTF-8?q?avior=20(#368)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The way foreign device registration was handled was a bit confusing. You would call `register` and if everything was perfect then subsequent renewals would be done automatically. Except when the BBMD would sometimes return an error in which case subsequent renewals would stop. - With this change, renewals will always be rescheduled independently of the BBMD's response. You call `register` to start the registration (and renewal) process and `unregister` to bring it to a halt. - Because there was no foreign device registration timeout tracking, and because of the previous issue, BIPForeign could end up in an inconsistent state if it had an active registration and for the next renewal the BBMD would not answer (e.g. poor network conditions). In this case the registration status would remain as registered and no further renewals would have been attempted. - This is solved by implementing timeout tracking of the active registration. The BACnet standard mentions that a BBMD should remove the registration from its FDT if no renewal was done 30s after the TTL, so if (30 + TTL) seconds pass since the last ACK then we've definitely lost the registration. --- py25/bacpypes/bvllservice.py | 57 +++++++++++++++++++++++++++++++----- py27/bacpypes/bvllservice.py | 57 +++++++++++++++++++++++++++++++----- py34/bacpypes/bvllservice.py | 57 +++++++++++++++++++++++++++++++----- 3 files changed, 147 insertions(+), 24 deletions(-) diff --git a/py25/bacpypes/bvllservice.py b/py25/bacpypes/bvllservice.py index b17301d9..f047f669 100755 --- a/py25/bacpypes/bvllservice.py +++ b/py25/bacpypes/bvllservice.py @@ -11,7 +11,7 @@ from .debugging import ModuleLogger, DebugContents, bacpypes_debugging from .udp import UDPDirector -from .task import OneShotTask, RecurringTask +from .task import OneShotFunction, OneShotTask, RecurringTask from .comm import Client, Server, bind, \ ServiceAccessPoint, ApplicationServiceElement @@ -483,6 +483,9 @@ def __init__(self, addr=None, ttl=None, sapID=None, cid=None, sid=None): self.bbmdAddress = None self.bbmdTimeToLive = None + # used in tracking active registration timeouts + self._registration_timeout_task = OneShotFunction(self._registration_expired) + # registration provided if addr: # a little error checking @@ -539,10 +542,9 @@ def confirmation(self, pdu): # save the result code as the status self.registrationStatus = pdu.bvlciResultCode - # check for success - if pdu.bvlciResultCode == 0: - # schedule for a refresh - self.install_task(delta=self.bbmdTimeToLive) + # If successful, track registration timeout + if self.registrationStatus == 0: + self._start_track_registration() return @@ -633,7 +635,11 @@ def confirmation(self, pdu): BIPForeign._warning("invalid pdu type: %s", type(pdu)) def register(self, addr, ttl): - """Initiate the process of registering with a BBMD.""" + """Start the foreign device registration process with the given BBMD. + + Registration will be renewed periodically according to the ttl value + until explicitly stopped by a call to `unregister`. + """ # a little error checking if ttl <= 0: raise ValueError("time-to-live must be greater than zero") @@ -645,11 +651,18 @@ def register(self, addr, ttl): self.bbmdAddress = Address(addr) self.bbmdTimeToLive = ttl - # install this task to run when it gets a chance + # install this task to do registration renewal according to the TTL + # and stop tracking any active registration timeouts self.install_task(when=0) + self._stop_track_registration() def unregister(self): - """Drop the registration with a BBMD.""" + """Stop the foreign device registration process. + + Immediately drops active foreign device registration and stops further + registration renewals. + """ + pdu = RegisterForeignDevice(0) pdu.pduDestination = self.bbmdAddress @@ -663,6 +676,11 @@ def unregister(self): self.bbmdAddress = None self.bbmdTimeToLive = None + # unschedule registration renewal & timeout tracking if previously + # scheduled + self.suspend_task() + self._stop_track_registration() + def process_task(self): """Called when the registration request should be sent to the BBMD.""" pdu = RegisterForeignDevice(self.bbmdTimeToLive) @@ -671,6 +689,29 @@ def process_task(self): # send it downstream self.request(pdu) + # schedule the next registration renewal + self.install_task(delta=self.bbmdTimeToLive) + + def _start_track_registration(self): + # From J.5.2.3 Foreign Device Table Operation (paraphrasing): if a + # foreign device does not renew its registration 30 seconds after its + # TTL expired then it will be removed from the BBMD's FDT. + # + # Thus, if we're registered and don't get a response to a subsequent + # renewal request 30 seconds after our TTL expired then we're + # definitely not registered anymore. + self._registration_timeout_task.install_task(delta=self.bbmdTimeToLive + 30) + + def _stop_track_registration(self): + self._registration_timeout_task.suspend_task() + + def _registration_expired(self): + """Called when detecting that foreign device registration has + definitely expired. + """ + self.registrationStatus = -2 # Unregistered + self._stop_track_registration() + bacpypes_debugging(BIPForeign) # diff --git a/py27/bacpypes/bvllservice.py b/py27/bacpypes/bvllservice.py index 99f99981..69282ccb 100755 --- a/py27/bacpypes/bvllservice.py +++ b/py27/bacpypes/bvllservice.py @@ -11,7 +11,7 @@ from .debugging import ModuleLogger, DebugContents, bacpypes_debugging from .udp import UDPDirector -from .task import OneShotTask, RecurringTask +from .task import OneShotFunction, OneShotTask, RecurringTask from .comm import Client, Server, bind, \ ServiceAccessPoint, ApplicationServiceElement @@ -481,6 +481,9 @@ def __init__(self, addr=None, ttl=None, sapID=None, cid=None, sid=None): self.bbmdAddress = None self.bbmdTimeToLive = None + # used in tracking active registration timeouts + self._registration_timeout_task = OneShotFunction(self._registration_expired) + # registration provided if addr: # a little error checking @@ -537,10 +540,9 @@ def confirmation(self, pdu): # save the result code as the status self.registrationStatus = pdu.bvlciResultCode - # check for success - if pdu.bvlciResultCode == 0: - # schedule for a refresh - self.install_task(delta=self.bbmdTimeToLive) + # If successful, track registration timeout + if self.registrationStatus == 0: + self._start_track_registration() return @@ -631,7 +633,11 @@ def confirmation(self, pdu): BIPForeign._warning("invalid pdu type: %s", type(pdu)) def register(self, addr, ttl): - """Initiate the process of registering with a BBMD.""" + """Start the foreign device registration process with the given BBMD. + + Registration will be renewed periodically according to the ttl value + until explicitly stopped by a call to `unregister`. + """ # a little error checking if ttl <= 0: raise ValueError("time-to-live must be greater than zero") @@ -643,11 +649,18 @@ def register(self, addr, ttl): self.bbmdAddress = Address(addr) self.bbmdTimeToLive = ttl - # install this task to run when it gets a chance + # install this task to do registration renewal according to the TTL + # and stop tracking any active registration timeouts self.install_task(when=0) + self._stop_track_registration() def unregister(self): - """Drop the registration with a BBMD.""" + """Stop the foreign device registration process. + + Immediately drops active foreign device registration and stops further + registration renewals. + """ + pdu = RegisterForeignDevice(0) pdu.pduDestination = self.bbmdAddress @@ -661,6 +674,11 @@ def unregister(self): self.bbmdAddress = None self.bbmdTimeToLive = None + # unschedule registration renewal & timeout tracking if previously + # scheduled + self.suspend_task() + self._stop_track_registration() + def process_task(self): """Called when the registration request should be sent to the BBMD.""" pdu = RegisterForeignDevice(self.bbmdTimeToLive) @@ -669,6 +687,29 @@ def process_task(self): # send it downstream self.request(pdu) + # schedule the next registration renewal + self.install_task(delta=self.bbmdTimeToLive) + + def _start_track_registration(self): + # From J.5.2.3 Foreign Device Table Operation (paraphrasing): if a + # foreign device does not renew its registration 30 seconds after its + # TTL expired then it will be removed from the BBMD's FDT. + # + # Thus, if we're registered and don't get a response to a subsequent + # renewal request 30 seconds after our TTL expired then we're + # definitely not registered anymore. + self._registration_timeout_task.install_task(delta=self.bbmdTimeToLive + 30) + + def _stop_track_registration(self): + self._registration_timeout_task.suspend_task() + + def _registration_expired(self): + """Called when detecting that foreign device registration has + definitely expired. + """ + self.registrationStatus = -2 # Unregistered + self._stop_track_registration() + # # BIPBBMD # diff --git a/py34/bacpypes/bvllservice.py b/py34/bacpypes/bvllservice.py index 5c334f92..ef0894fd 100755 --- a/py34/bacpypes/bvllservice.py +++ b/py34/bacpypes/bvllservice.py @@ -10,7 +10,7 @@ from .debugging import ModuleLogger, DebugContents, bacpypes_debugging from .udp import UDPDirector -from .task import OneShotTask, RecurringTask +from .task import OneShotFunction, OneShotTask, RecurringTask from .comm import Client, Server, bind, \ ServiceAccessPoint, ApplicationServiceElement @@ -495,6 +495,9 @@ def __init__(self, addr=None, ttl=None, sapID=None, cid=None, sid=None): self.bbmdAddress = None self.bbmdTimeToLive = None + # used in tracking active registration timeouts + self._registration_timeout_task = OneShotFunction(self._registration_expired) + # registration provided if addr: # a little error checking @@ -555,10 +558,9 @@ def confirmation(self, pdu): # save the result code as the status self.registrationStatus = pdu.bvlciResultCode - # check for success - if pdu.bvlciResultCode == 0: - # schedule for a refresh - self.install_task(delta=self.bbmdTimeToLive) + # If successful, track registration timeout + if self.registrationStatus == 0: + self._start_track_registration() return @@ -651,7 +653,11 @@ def confirmation(self, pdu): BIPForeign._warning("invalid pdu type: %s", type(pdu)) def register(self, addr, ttl): - """Initiate the process of registering with a BBMD.""" + """Start the foreign device registration process with the given BBMD. + + Registration will be renewed periodically according to the ttl value + until explicitly stopped by a call to `unregister`. + """ # a little error checking if ttl <= 0: raise ValueError("time-to-live must be greater than zero") @@ -663,11 +669,18 @@ def register(self, addr, ttl): self.bbmdAddress = Address(addr) self.bbmdTimeToLive = ttl - # install this task to run when it gets a chance + # install this task to do registration renewal according to the TTL + # and stop tracking any active registration timeouts self.install_task(when=0) + self._stop_track_registration() def unregister(self): - """Drop the registration with a BBMD.""" + """Stop the foreign device registration process. + + Immediately drops active foreign device registration and stops further + registration renewals. + """ + pdu = RegisterForeignDevice(0) pdu.pduDestination = self.bbmdAddress @@ -681,6 +694,11 @@ def unregister(self): self.bbmdAddress = None self.bbmdTimeToLive = None + # unschedule registration renewal & timeout tracking if previously + # scheduled + self.suspend_task() + self._stop_track_registration() + def process_task(self): """Called when the registration request should be sent to the BBMD.""" pdu = RegisterForeignDevice(self.bbmdTimeToLive) @@ -689,6 +707,29 @@ def process_task(self): # send it downstream self.request(pdu) + # schedule the next registration renewal + self.install_task(delta=self.bbmdTimeToLive) + + def _start_track_registration(self): + # From J.5.2.3 Foreign Device Table Operation (paraphrasing): if a + # foreign device does not renew its registration 30 seconds after its + # TTL expired then it will be removed from the BBMD's FDT. + # + # Thus, if we're registered and don't get a response to a subsequent + # renewal request 30 seconds after our TTL expired then we're + # definitely not registered anymore. + self._registration_timeout_task.install_task(delta=self.bbmdTimeToLive + 30) + + def _stop_track_registration(self): + self._registration_timeout_task.suspend_task() + + def _registration_expired(self): + """Called when detecting that foreign device registration has + definitely expired. + """ + self.registrationStatus = -2 # Unregistered + self._stop_track_registration() + # # BIPBBMD # From 0761f9f380f322db9308a2350dafedb5de220a1e Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Mon, 9 Nov 2020 21:57:07 -0500 Subject: [PATCH 18/50] bug in registration status (#368) --- py25/bacpypes/bvllservice.py | 2 +- py27/bacpypes/bvllservice.py | 2 +- py34/bacpypes/bvllservice.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/py25/bacpypes/bvllservice.py b/py25/bacpypes/bvllservice.py index f047f669..88aa2722 100755 --- a/py25/bacpypes/bvllservice.py +++ b/py25/bacpypes/bvllservice.py @@ -709,7 +709,7 @@ def _registration_expired(self): """Called when detecting that foreign device registration has definitely expired. """ - self.registrationStatus = -2 # Unregistered + self.registrationStatus = -1 # Unregistered self._stop_track_registration() bacpypes_debugging(BIPForeign) diff --git a/py27/bacpypes/bvllservice.py b/py27/bacpypes/bvllservice.py index 69282ccb..af4b6616 100755 --- a/py27/bacpypes/bvllservice.py +++ b/py27/bacpypes/bvllservice.py @@ -707,7 +707,7 @@ def _registration_expired(self): """Called when detecting that foreign device registration has definitely expired. """ - self.registrationStatus = -2 # Unregistered + self.registrationStatus = -1 # Unregistered self._stop_track_registration() # diff --git a/py34/bacpypes/bvllservice.py b/py34/bacpypes/bvllservice.py index ef0894fd..7e8f47e0 100755 --- a/py34/bacpypes/bvllservice.py +++ b/py34/bacpypes/bvllservice.py @@ -727,7 +727,7 @@ def _registration_expired(self): """Called when detecting that foreign device registration has definitely expired. """ - self.registrationStatus = -2 # Unregistered + self.registrationStatus = -1 # Unregistered self._stop_track_registration() # From dad4378bac408d88e48a55e35680e6e86e04195c Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Fri, 27 Nov 2020 12:48:43 -0500 Subject: [PATCH 19/50] patch from @damienpicard in pull #371 --- samples/WhoIsRouterForeign.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/WhoIsRouterForeign.py b/samples/WhoIsRouterForeign.py index af77f400..8e97d6c1 100755 --- a/samples/WhoIsRouterForeign.py +++ b/samples/WhoIsRouterForeign.py @@ -34,9 +34,9 @@ @bacpypes_debugging class WhoIsRouterApplication(BIPNetworkApplication): - def __init__(self, *args): - if _debug: WhoIsRouterApplication._debug("__init__ %r", args) - BIPNetworkApplication.__init__(self, *args) + def __init__(self, *args, **kwargs): + if _debug: WhoIsRouterApplication._debug("__init__ %r %r", args, kwargs) + BIPNetworkApplication.__init__(self, *args, **kwargs) def request(self, adapter, npdu): if _debug: WhoIsRouterApplication._debug("request %r %r", adapter, npdu) @@ -120,8 +120,8 @@ def main(): # make a simple application this_application = WhoIsRouterApplication( args.ini.address, - Address(args.ini.foreignbbmd), - int(args.ini.foreignttl), + bbmdAddress=Address(args.ini.foreignbbmd), + bbmdTTL=int(args.ini.foreignttl), ) if _debug: _log.debug(" - this_application: %r", this_application) From 7c4350b1e8ab38d2c6200e1900216975aebe2f63 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Thu, 24 Dec 2020 13:36:12 -0500 Subject: [PATCH 20/50] addtional sample adding a console to the first virtual device (#381) --- samples/IP2VLANRouterConsole.py | 750 ++++++++++++++++++++++++++++++++ 1 file changed, 750 insertions(+) create mode 100755 samples/IP2VLANRouterConsole.py diff --git a/samples/IP2VLANRouterConsole.py b/samples/IP2VLANRouterConsole.py new file mode 100755 index 00000000..6117ef57 --- /dev/null +++ b/samples/IP2VLANRouterConsole.py @@ -0,0 +1,750 @@ +#!/usr/bin/env python + +""" +This sample application presents itself as a router sitting on an IP network +to a VLAN. The VLAN has one or more devices on it with an analog +value object that returns a random value for the present value. + +Note that the device instance number of the virtual device will be 100 times +the network number plus its address (net2 * 100 + n). + +This is a clone of the IP2VLANRouter application that includes a console +interface with the whois, iam, read and write commands. +""" + +import sys +import random +import argparse + +from bacpypes.debugging import bacpypes_debugging, ModuleLogger +from bacpypes.consolelogging import ArgumentParser +from bacpypes.consolecmd import ConsoleCmd + +from bacpypes.core import run, deferred, enable_sleeping +from bacpypes.comm import bind +from bacpypes.iocb import IOCB + +from bacpypes.pdu import Address, LocalBroadcast, GlobalBroadcast +from bacpypes.netservice import NetworkServiceAccessPoint, NetworkServiceElement +from bacpypes.bvllservice import BIPSimple, AnnexJCodec, UDPMultiplexer + +from bacpypes.app import Application, ApplicationIOController +from bacpypes.appservice import StateMachineAccessPoint, ApplicationServiceAccessPoint +from bacpypes.local.device import LocalDeviceObject +from bacpypes.local.object import CurrentPropertyList +from bacpypes.service.device import WhoIsIAmServices +from bacpypes.service.object import ( + ReadWritePropertyServices, + ReadWritePropertyMultipleServices, +) + +from bacpypes.vlan import Network, Node +from bacpypes.errors import ExecutionError + +from bacpypes.object import ( + get_datatype, + register_object_type, + AnalogValueObject, + Property, +) + +from bacpypes.apdu import ( + SimpleAckPDU, + ReadPropertyRequest, + ReadPropertyACK, + WritePropertyRequest, +) +from bacpypes.primitivedata import ( + Null, + Atomic, + Boolean, + Unsigned, + Integer, + Real, + Double, + OctetString, + CharacterString, + BitString, + Date, + Time, + ObjectIdentifier, +) +from bacpypes.constructeddata import Array, Any, AnyAtomic + +# some debugging +_debug = 0 +_log = ModuleLogger(globals()) + +# globals +args = None +this_application = None + +# +# RandomValueProperty +# + + +@bacpypes_debugging +class RandomValueProperty(Property): + def __init__(self, identifier): + if _debug: + RandomValueProperty._debug("__init__ %r", identifier) + Property.__init__( + self, identifier, Real, default=None, optional=True, mutable=False + ) + + def ReadProperty(self, obj, arrayIndex=None): + if _debug: + RandomValueProperty._debug("ReadProperty %r arrayIndex=%r", obj, arrayIndex) + + # access an array + if arrayIndex is not None: + raise ExecutionError( + errorClass="property", errorCode="propertyIsNotAnArray" + ) + + # return a random value + value = random.random() * 100.0 + if _debug: + RandomValueProperty._debug(" - value: %r", value) + + # save the value that was generated + super(RandomValueProperty, self).WriteProperty(obj, value, direct=True) + + # now return it to the client + return value + + def WriteProperty(self, obj, value, arrayIndex=None, priority=None, direct=False): + if _debug: + RandomValueProperty._debug( + "WriteProperty %r %r arrayIndex=%r priority=%r direct=%r", + obj, + value, + arrayIndex, + priority, + direct, + ) + if not direct: + raise ExecutionError(errorClass="property", errorCode="writeAccessDenied") + if arrayIndex is not None: + raise ExecutionError( + errorClass="property", errorCode="propertyIsNotAnArray" + ) + + # continue along + super(RandomValueProperty, self).WriteProperty(obj, value, direct=True) + + +# +# Random Value Object Type +# + + +@bacpypes_debugging +class RandomAnalogValueObject(AnalogValueObject): + + properties = [ + RandomValueProperty("presentValue"), + ] + + def __init__(self, **kwargs): + if _debug: + RandomAnalogValueObject._debug("__init__ %r", kwargs) + AnalogValueObject.__init__(self, **kwargs) + + # if a value hasn't already been provided, initialize with a random one + if "presentValue" not in kwargs: + self.presentValue = random.random() * 100.0 + + +# +# VLANApplication +# + + +@bacpypes_debugging +class VLANApplication( + Application, WhoIsIAmServices, ReadWritePropertyServices, +): + def __init__(self, vlan_device, vlan_address, aseID=None): + if _debug: + VLANApplication._debug( + "__init__ %r %r aseID=%r", vlan_device, vlan_address, aseID + ) + global args + + # normal initialization + Application.__init__(self, vlan_device, aseID=aseID) + + # optional read property multiple + if args.rpm: + self.add_capability(ReadWritePropertyMultipleServices) + + # include a application decoder + self.asap = ApplicationServiceAccessPoint() + + # pass the device object to the state machine access point so it + # can know if it should support segmentation + self.smap = StateMachineAccessPoint(vlan_device) + + # the segmentation state machines need access to the same device + # information cache as the application + self.smap.deviceInfoCache = self.deviceInfoCache + + # a network service access point will be needed + self.nsap = NetworkServiceAccessPoint() + + # give the NSAP a generic network layer service element + self.nse = NetworkServiceElement() + bind(self.nse, self.nsap) + + # bind the top layers + bind(self, self.asap, self.smap, self.nsap) + + # create a vlan node at the assigned address + self.vlan_node = Node(vlan_address) + + # bind the stack to the node, no network number, no addresss + self.nsap.bind(self.vlan_node) + + def request(self, apdu): + if _debug: + VLANApplication._debug("[%s]request %r", self.vlan_node.address, apdu) + Application.request(self, apdu) + + def indication(self, apdu): + if _debug: + VLANApplication._debug("[%s]indication %r", self.vlan_node.address, apdu) + Application.indication(self, apdu) + + def response(self, apdu): + if _debug: + VLANApplication._debug("[%s]response %r", self.vlan_node.address, apdu) + Application.response(self, apdu) + + def confirmation(self, apdu): + if _debug: + VLANApplication._debug("[%s]confirmation %r", self.vlan_node.address, apdu) + Application.confirmation(self, apdu) + + +# +# VLANRouter +# + + +@bacpypes_debugging +class VLANRouter: + def __init__(self, local_address, local_network): + if _debug: + VLANRouter._debug("__init__ %r %r", local_address, local_network) + + # a network service access point will be needed + self.nsap = NetworkServiceAccessPoint() + + # give the NSAP a generic network layer service element + self.nse = NetworkServiceElement() + bind(self.nse, self.nsap) + + # create a BIPSimple, bound to the Annex J server + # on the UDP multiplexer + self.bip = BIPSimple(local_address) + self.annexj = AnnexJCodec() + self.mux = UDPMultiplexer(local_address) + + # bind the bottom layers + bind(self.bip, self.annexj, self.mux.annexJ) + + # bind the BIP stack to the local network + self.nsap.bind(self.bip, local_network, local_address) + + +# +# VLANConsoleApplication +# + + +@bacpypes_debugging +class VLANConsoleApplication( + ApplicationIOController, WhoIsIAmServices, ReadWritePropertyServices, +): + def __init__(self, vlan_device, vlan_address, aseID=None): + if _debug: + VLANConsoleApplication._debug( + "__init__ %r %r aseID=%r", vlan_device, vlan_address, aseID + ) + global args + + # normal initialization + ApplicationIOController.__init__(self, vlan_device, aseID=aseID) + + # optional read property multiple + if args.rpm: + self.add_capability(ReadWritePropertyMultipleServices) + + # include a application decoder + self.asap = ApplicationServiceAccessPoint() + + # pass the device object to the state machine access point so it + # can know if it should support segmentation + self.smap = StateMachineAccessPoint(vlan_device) + + # the segmentation state machines need access to the same device + # information cache as the application + self.smap.deviceInfoCache = self.deviceInfoCache + + # a network service access point will be needed + self.nsap = NetworkServiceAccessPoint() + + # give the NSAP a generic network layer service element + self.nse = NetworkServiceElement() + bind(self.nse, self.nsap) + + # bind the top layers + bind(self, self.asap, self.smap, self.nsap) + + # create a vlan node at the assigned address + self.vlan_node = Node(vlan_address) + + # bind the stack to the node, no network number, no addresss + self.nsap.bind(self.vlan_node) + + +# +# VLANConsoleCmd +# + + +@bacpypes_debugging +class VLANConsoleCmd(ConsoleCmd): + def do_whois(self, args): + """whois [ ] [ ]""" + args = args.split() + if _debug: + VLANConsoleCmd._debug("do_whois %r", args) + + try: + # gather the parameters + if (len(args) == 1) or (len(args) == 3): + addr = Address(args[0]) + del args[0] + else: + addr = GlobalBroadcast() + + if len(args) == 2: + lolimit = int(args[0]) + hilimit = int(args[1]) + else: + lolimit = hilimit = None + + # code lives in the device service + this_application.who_is(lolimit, hilimit, addr) + + except Exception as error: + VLANConsoleCmd._exception("exception: %r", error) + + def do_iam(self, args): + """iam""" + args = args.split() + if _debug: + VLANConsoleCmd._debug("do_iam %r", args) + + # code lives in the device service + this_application.i_am() + + def do_read(self, args): + """read [ ]""" + args = args.split() + if _debug: + VLANConsoleCmd._debug("do_read %r", args) + + try: + addr, obj_id, prop_id = args[:3] + obj_id = ObjectIdentifier(obj_id).value + if prop_id.isdigit(): + prop_id = int(prop_id) + + datatype = get_datatype(obj_id[0], prop_id) + if not datatype: + raise ValueError("invalid property for object type") + + # build a request + request = ReadPropertyRequest( + objectIdentifier=obj_id, propertyIdentifier=prop_id, + ) + request.pduDestination = Address(addr) + + if len(args) == 4: + request.propertyArrayIndex = int(args[3]) + if _debug: + VLANConsoleCmd._debug(" - request: %r", request) + + # make an IOCB + iocb = IOCB(request) + if _debug: + VLANConsoleCmd._debug(" - iocb: %r", iocb) + + # give it to the application + deferred(this_application.request_io, iocb) + + # wait for it to complete + iocb.wait() + + # do something for success + if iocb.ioResponse: + apdu = iocb.ioResponse + + # should be an ack + if not isinstance(apdu, ReadPropertyACK): + if _debug: + VLANConsoleCmd._debug(" - not an ack") + return + + # find the datatype + datatype = get_datatype( + apdu.objectIdentifier[0], apdu.propertyIdentifier + ) + if _debug: + VLANConsoleCmd._debug(" - datatype: %r", datatype) + if not datatype: + raise TypeError("unknown datatype") + + # special case for array parts, others are managed by cast_out + if issubclass(datatype, Array) and ( + apdu.propertyArrayIndex is not None + ): + if apdu.propertyArrayIndex == 0: + value = apdu.propertyValue.cast_out(Unsigned) + else: + value = apdu.propertyValue.cast_out(datatype.subtype) + else: + value = apdu.propertyValue.cast_out(datatype) + if _debug: + VLANConsoleCmd._debug(" - value: %r", value) + + sys.stdout.write(str(value) + "\n") + if hasattr(value, "debug_contents"): + value.debug_contents(file=sys.stdout) + sys.stdout.flush() + + # do something for error/reject/abort + if iocb.ioError: + sys.stdout.write(str(iocb.ioError) + "\n") + + except Exception as error: + VLANConsoleCmd._exception("exception: %r", error) + + def do_write(self, args): + """write [ ] [ ]""" + args = args.split() + VLANConsoleCmd._debug("do_write %r", args) + + try: + addr, obj_id, prop_id = args[:3] + obj_id = ObjectIdentifier(obj_id).value + value = args[3] + + indx = None + if len(args) >= 5: + if args[4] != "-": + indx = int(args[4]) + if _debug: + VLANConsoleCmd._debug(" - indx: %r", indx) + + priority = None + if len(args) >= 6: + priority = int(args[5]) + if _debug: + VLANConsoleCmd._debug(" - priority: %r", priority) + + # get the datatype + datatype = get_datatype(obj_id[0], prop_id) + if _debug: + VLANConsoleCmd._debug(" - datatype: %r", datatype) + + # change atomic values into something encodeable, null is a special case + if value == "null": + value = Null() + elif issubclass(datatype, AnyAtomic): + dtype, dvalue = value.split(":", 1) + if _debug: + VLANConsoleCmd._debug(" - dtype, dvalue: %r, %r", dtype, dvalue) + + datatype = { + "b": Boolean, + "u": lambda x: Unsigned(int(x)), + "i": lambda x: Integer(int(x)), + "r": lambda x: Real(float(x)), + "d": lambda x: Double(float(x)), + "o": OctetString, + "c": CharacterString, + "bs": BitString, + "date": Date, + "time": Time, + "id": ObjectIdentifier, + }[dtype] + if _debug: + VLANConsoleCmd._debug(" - datatype: %r", datatype) + + value = datatype(dvalue) + if _debug: + VLANConsoleCmd._debug(" - value: %r", value) + + elif issubclass(datatype, Atomic): + if datatype is Integer: + value = int(value) + elif datatype is Real: + value = float(value) + elif datatype is Unsigned: + value = int(value) + value = datatype(value) + elif issubclass(datatype, Array) and (indx is not None): + if indx == 0: + value = Integer(value) + elif issubclass(datatype.subtype, Atomic): + value = datatype.subtype(value) + elif not isinstance(value, datatype.subtype): + raise TypeError( + "invalid result datatype, expecting %s" + % (datatype.subtype.__name__,) + ) + elif not isinstance(value, datatype): + raise TypeError( + "invalid result datatype, expecting %s" % (datatype.__name__,) + ) + if _debug: + VLANConsoleCmd._debug( + " - encodeable value: %r %s", value, type(value) + ) + + # build a request + request = WritePropertyRequest( + objectIdentifier=obj_id, propertyIdentifier=prop_id + ) + request.pduDestination = Address(addr) + + # save the value + request.propertyValue = Any() + try: + request.propertyValue.cast_in(value) + except Exception as error: + VLANConsoleCmd._exception("WriteProperty cast error: %r", error) + + # optional array index + if indx is not None: + request.propertyArrayIndex = indx + + # optional priority + if priority is not None: + request.priority = priority + + if _debug: + VLANConsoleCmd._debug(" - request: %r", request) + + # make an IOCB + iocb = IOCB(request) + if _debug: + VLANConsoleCmd._debug(" - iocb: %r", iocb) + + # give it to the application + deferred(this_application.request_io, iocb) + + # wait for it to complete + iocb.wait() + + # do something for success + if iocb.ioResponse: + # should be an ack + if not isinstance(iocb.ioResponse, SimpleAckPDU): + if _debug: + VLANConsoleCmd._debug(" - not an ack") + return + + sys.stdout.write("ack\n") + + # do something for error/reject/abort + if iocb.ioError: + sys.stdout.write(str(iocb.ioError) + "\n") + + except Exception as error: + VLANConsoleCmd._exception("exception: %r", error) + + def do_rtn(self, args): + """rtn ... """ + args = args.split() + if _debug: + VLANConsoleCmd._debug("do_rtn %r", args) + + # provide the address and a list of network numbers + router_address = Address(args[0]) + network_list = [int(arg) for arg in args[1:]] + + # pass along to the service access point + this_application.nsap.update_router_references( + None, router_address, network_list + ) + + +# +# __main__ +# + + +def main(): + global args, this_application + + # parse the command line arguments + parser = ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, + ) + + # add an argument for interval + parser.add_argument( + "addr1", type=str, help="address of first network", + ) + + # add an argument for interval + parser.add_argument( + "net1", type=int, help="network number of first network", + ) + + # add an argument for interval + parser.add_argument( + "net2", type=int, help="network number of second network", + ) + + # add an argument for how many virtual devices + parser.add_argument( + "--count", type=int, help="number of virtual devices", default=1, + ) + + # add an argument for how many virtual devices + parser.add_argument( + "--rpm", help="enable read property multiple", action="store_true", + ) + + # add an argument for including the property list + parser.add_argument( + "--plist", help="enable property list property", action="store_true", + ) + + # now parse the arguments + args = parser.parse_args() + + if _debug: + _log.debug("initialization") + if _debug: + _log.debug(" - args: %r", args) + + local_address = Address(args.addr1) + local_network = args.net1 + vlan_network = args.net2 + + # create the VLAN router, bind it to the local network + router = VLANRouter(local_address, local_network) + + # create a VLAN + vlan = Network(broadcast_address=LocalBroadcast()) + + # create a node for the router, address 1 on the VLAN + router_addr = Address(1) + router_node = Node(router_addr) + vlan.add_node(router_node) + + # bind the router stack to the vlan network through this node + router.nsap.bind(router_node, vlan_network, router_addr) + + # send network topology + deferred(router.nse.i_am_router_to_network) + + # add the dynamic property list + if args.plist: + RandomAnalogValueObject.properties.append(CurrentPropertyList()) + + # register it now that all its properties are defined + register_object_type(RandomAnalogValueObject, vendor_id=999) + + # console is the first device + device_number = 2 + device_instance = vlan_network * 100 + device_number + _log.debug(" - console device_instance: %r", device_instance) + + # make a vlan device object + vlan_device = LocalDeviceObject( + objectName="VLAN Console Node %d" % (device_instance,), + objectIdentifier=("device", device_instance), + maxApduLengthAccepted=1024, + segmentationSupported="noSegmentation", + vendorIdentifier=15, + ) + _log.debug(" - vlan_device: %r", vlan_device) + + vlan_address = Address(device_number) + _log.debug(" - vlan_address: %r", vlan_address) + + # make the console application, add it to the network + this_application = VLANConsoleApplication(vlan_device, vlan_address) + vlan.add_node(this_application.vlan_node) + _log.debug(" - this_application: %r", this_application) + + # make a console + this_console = VLANConsoleCmd() + if _debug: + _log.debug(" - this_console: %r", this_console) + + # make a random value object + ravo = RandomAnalogValueObject( + objectIdentifier=("analogValue", 1), + objectName="Random-1-%d" % (device_instance,), + ) + _log.debug(" - ravo: %r", ravo) + + # add it to the device + this_application.add_object(ravo) + + # make some more devices + for device_number in range(3, 3 + args.count - 1): + # device identifier is assigned from the address + device_instance = vlan_network * 100 + device_number + _log.debug(" - device_instance: %r", device_instance) + + # make a vlan device object + vlan_device = LocalDeviceObject( + objectName="VLAN Node %d" % (device_instance,), + objectIdentifier=("device", device_instance), + maxApduLengthAccepted=1024, + segmentationSupported="noSegmentation", + vendorIdentifier=15, + ) + _log.debug(" - vlan_device: %r", vlan_device) + + vlan_address = Address(device_number) + _log.debug(" - vlan_address: %r", vlan_address) + + # make the application, add it to the network + vlan_app = VLANApplication(vlan_device, vlan_address) + vlan.add_node(vlan_app.vlan_node) + _log.debug(" - vlan_app: %r", vlan_app) + + # make a random value object + ravo = RandomAnalogValueObject( + objectIdentifier=("analogValue", 1), + objectName="Random-1-%d" % (device_instance,), + ) + _log.debug(" - ravo: %r", ravo) + + # add it to the device + vlan_app.add_object(ravo) + + # enable sleeping will help with threads + enable_sleeping() + + _log.debug("running") + + run() + + _log.debug("fini") + + +if __name__ == "__main__": + main() From dcdabfc1e7bffbf24f10c8a30c4da7a80c084d77 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 10:40:40 -0500 Subject: [PATCH 21/50] Testing Github Actions for bacpypes --- .github/workflows/build.yml | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..3af6766d --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,39 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Build & test + +on: + push: + branches: [ install_and_actions ] +# pull_request: +# branches: [ install_and_actions ] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [2.5, 2.6, 2.7, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest + pip install pytest-cov + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + pip install . + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest -v \ No newline at end of file From a9b0e0a5396779a3e7a698b61c6259939e02378f Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 10:49:22 -0500 Subject: [PATCH 22/50] Removing 2.5 and 2.6 for now. Trying to ignore flake8 codes ignore = E123,E221,E226,E302,E41,E701 --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3af6766d..cb69a525 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [2.5, 2.6, 2.7, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9] + python-version: [2.7, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -31,9 +31,9 @@ jobs: - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --ignore = E123,E221,E226,E302,E41,E701 # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore = E123,E221,E226,E302,E41,E701 - name: Test with pytest run: | pytest -v \ No newline at end of file From b6dbbca0c90a5dab6ab03731ae0dcb6126a69479 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 10:53:24 -0500 Subject: [PATCH 23/50] Typoe in flake8 ignore --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cb69a525..a7464b3c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,9 +31,9 @@ jobs: - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --ignore = E123,E221,E226,E302,E41,E701 + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --ignore=E123,E221,E226,E302,E41,E701 # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore = E123,E221,E226,E302,E41,E701 + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore=E123,E221,E226,E302,E41,E701 - name: Test with pytest run: | pytest -v \ No newline at end of file From 689c6137aaeacd719e8c8995dc90b575c0301ffd Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 10:59:53 -0500 Subject: [PATCH 24/50] limiting flake8 to py34 --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a7464b3c..74a9bb94 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,9 +31,9 @@ jobs: - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --ignore=E123,E221,E226,E302,E41,E701 + flake8 py34 --count --select=E9,F63,F7,F82 --show-source --statistics --ignore=E123,E221,E226,E302,E41,E701 # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore=E123,E221,E226,E302,E41,E701 + flake8 py34 --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore=E123,E221,E226,E302,E41,E701 - name: Test with pytest run: | pytest -v \ No newline at end of file From e6aefb4a56539052e9e74e5d5d40b73a8e7472a3 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 11:02:19 -0500 Subject: [PATCH 25/50] Postpone Linter.... let's make test work.... will fight with flake8 later --- .github/workflows/build.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 74a9bb94..3b498403 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,15 +25,14 @@ jobs: run: | python -m pip install --upgrade pip pip install flake8 pytest - pip install pytest-cov if [ -f requirements.txt ]; then pip install -r requirements.txt; fi pip install . - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 py34 --count --select=E9,F63,F7,F82 --show-source --statistics --ignore=E123,E221,E226,E302,E41,E701 - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 py34 --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore=E123,E221,E226,E302,E41,E701 +# - name: Lint with flake8 +# run: | +# # stop the build if there are Python syntax errors or undefined names +# flake8 py34 --count --select=E9,F63,F7,F82 --show-source --statistics --ignore=E123,E221,E226,E302,E41,E701 +# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide +# flake8 py34 --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore=E123,E221,E226,E302,E41,E701 - name: Test with pytest run: | pytest -v \ No newline at end of file From 873d4bdc69290d4103ff8bbcf178fb5df9bf3789 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 11:09:03 -0500 Subject: [PATCH 26/50] Let's try it without pip for older versions --- .github/workflows/build.yml | 4 ++-- .github/workflows/legacy_build.yml | 38 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/legacy_build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3b498403..ec96e170 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,7 @@ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions -name: Build & test +name: Build & test using pip and pytest on: push: @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [2.7, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9] + python-version: [3.5, 3.6, 3.7, 3.8, 3.9] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/legacy_build.yml b/.github/workflows/legacy_build.yml new file mode 100644 index 00000000..daec5f55 --- /dev/null +++ b/.github/workflows/legacy_build.yml @@ -0,0 +1,38 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Build & test using python setup.py install + +on: + push: + branches: [ install_and_actions ] +# pull_request: +# branches: [ install_and_actions ] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [2.7, 3.4] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + python -m setup.py install +# - name: Lint with flake8 +# run: | +# # stop the build if there are Python syntax errors or undefined names +# flake8 py34 --count --select=E9,F63,F7,F82 --show-source --statistics --ignore=E123,E221,E226,E302,E41,E701 +# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide +# flake8 py34 --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore=E123,E221,E226,E302,E41,E701 + - name: Test with pytest + run: | + pytest -v \ No newline at end of file From bec98cc471bb37680fec702f9d07ecfe4948e9d8 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 11:15:04 -0500 Subject: [PATCH 27/50] Skipping time machine test that fail. Removing pip upgrade on legacy tests --- .github/workflows/legacy_build.yml | 6 ++---- tests/test_utilities/test_time_machine.py | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/legacy_build.yml b/.github/workflows/legacy_build.yml index daec5f55..17e43601 100644 --- a/.github/workflows/legacy_build.yml +++ b/.github/workflows/legacy_build.yml @@ -1,7 +1,7 @@ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions -name: Build & test using python setup.py install +name: Legacy Build & test (python -m setup.py install) on: push: @@ -23,9 +23,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install flake8 pytest - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + pip install flake8 pytest netifaces python -m setup.py install # - name: Lint with flake8 # run: | diff --git a/tests/test_utilities/test_time_machine.py b/tests/test_utilities/test_time_machine.py index 69a769db..11a3fe75 100644 --- a/tests/test_utilities/test_time_machine.py +++ b/tests/test_utilities/test_time_machine.py @@ -8,6 +8,7 @@ import time import unittest +import pytest from bacpypes.debugging import bacpypes_debugging, ModuleLogger @@ -263,6 +264,7 @@ def test_recurring_task_4(self): assert almost_equal(ft.process_task_called, [0.9, 1.9, 2.9, 3.9, 4.9]) assert time_machine.current_time == 5.0 + @pytest.mark.skip("Do not work on Github Actions. Needs investigation") def test_recurring_task_5(self): if _debug: TestTimeMachine._debug("test_recurring_task_5") From 399c961c0c053c42926048e2dcd178e014a4851d Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 11:17:27 -0500 Subject: [PATCH 28/50] forcing wheel install for legacy. Forgot to remove py 3.9, not yet part of setup --- .github/workflows/legacy_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/legacy_build.yml b/.github/workflows/legacy_build.yml index 17e43601..de1aa870 100644 --- a/.github/workflows/legacy_build.yml +++ b/.github/workflows/legacy_build.yml @@ -23,7 +23,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - pip install flake8 pytest netifaces + pip install flake8 pytest netifaces wheel python -m setup.py install # - name: Lint with flake8 # run: | From 5569fab99a9a0c52c0a89990adb4fe7df0104a9d Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 11:19:46 -0500 Subject: [PATCH 29/50] Really removing 3.9 this time... --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ec96e170..23fe5ba6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.5, 3.6, 3.7, 3.8, 3.9] + python-version: [3.5, 3.6, 3.7, 3.8] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From f64d32b5d38cc491a5c95c9624dbb82cb4179fbf Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 11:25:45 -0500 Subject: [PATCH 30/50] Removing -m... I think the issue is related to distutils... --- .github/workflows/legacy_build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/legacy_build.yml b/.github/workflows/legacy_build.yml index de1aa870..172e71e5 100644 --- a/.github/workflows/legacy_build.yml +++ b/.github/workflows/legacy_build.yml @@ -1,7 +1,7 @@ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions -name: Legacy Build & test (python -m setup.py install) +name: Legacy Build & test (python setup.py install) on: push: @@ -24,7 +24,7 @@ jobs: - name: Install dependencies run: | pip install flake8 pytest netifaces wheel - python -m setup.py install + python setup.py install # - name: Lint with flake8 # run: | # # stop the build if there are Python syntax errors or undefined names From c96c6a5d5049fcb6cb891d813a7caf33677193b6 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 11:34:18 -0500 Subject: [PATCH 31/50] Making two files is probably not the best idea, trying with only one file instead.... and opening the door to Windows and Mac tests --- .github/workflows/build.yml | 28 ++++++++++++++++++++++- .github/workflows/legacy_build.yml | 36 ------------------------------ 2 files changed, 27 insertions(+), 37 deletions(-) delete mode 100644 .github/workflows/legacy_build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 23fe5ba6..dfdf028f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,7 @@ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions -name: Build & test using pip and pytest +name: Build & test on different versions on: push: @@ -32,6 +32,32 @@ jobs: # # stop the build if there are Python syntax errors or undefined names # flake8 py34 --count --select=E9,F63,F7,F82 --show-source --statistics --ignore=E123,E221,E226,E302,E41,E701 # # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide +# flake8 py34 --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore=E123,E221,E226,E302,E41,E701 + - name: Test with pytest + run: | + pytest -v + + legacy-build: + name: Legacy versions - Install and test + runs-on: ubuntu-16.04 + strategy: + matrix: + python-version: [2.7, 3.4] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install flake8 pytest netifaces wheel + python setup.py install +# - name: Lint with flake8 +# run: | +# # stop the build if there are Python syntax errors or undefined names +# flake8 py34 --count --select=E9,F63,F7,F82 --show-source --statistics --ignore=E123,E221,E226,E302,E41,E701 +# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide # flake8 py34 --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore=E123,E221,E226,E302,E41,E701 - name: Test with pytest run: | diff --git a/.github/workflows/legacy_build.yml b/.github/workflows/legacy_build.yml deleted file mode 100644 index 172e71e5..00000000 --- a/.github/workflows/legacy_build.yml +++ /dev/null @@ -1,36 +0,0 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - -name: Legacy Build & test (python setup.py install) - -on: - push: - branches: [ install_and_actions ] -# pull_request: -# branches: [ install_and_actions ] - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: [2.7, 3.4] - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - pip install flake8 pytest netifaces wheel - python setup.py install -# - name: Lint with flake8 -# run: | -# # stop the build if there are Python syntax errors or undefined names -# flake8 py34 --count --select=E9,F63,F7,F82 --show-source --statistics --ignore=E123,E221,E226,E302,E41,E701 -# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide -# flake8 py34 --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore=E123,E221,E226,E302,E41,E701 - - name: Test with pytest - run: | - pytest -v \ No newline at end of file From 0fe8e84120220f56f976c11c68af2f1c699684f8 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 11:39:01 -0500 Subject: [PATCH 32/50] 16.04 was too old for py34 --- .github/workflows/build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dfdf028f..49481380 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,6 +11,7 @@ on: jobs: build: + name: Linux versions - Install and test runs-on: ubuntu-latest strategy: matrix: @@ -39,7 +40,7 @@ jobs: legacy-build: name: Legacy versions - Install and test - runs-on: ubuntu-16.04 + runs-on: ubuntu-18.04 strategy: matrix: python-version: [2.7, 3.4] @@ -51,7 +52,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - pip install flake8 pytest netifaces wheel + pip install pytest netifaces wheel python setup.py install # - name: Lint with flake8 # run: | From 6c438e16297e67cc18e9e9ec0c0a06391d26c3f7 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 11:45:03 -0500 Subject: [PATCH 33/50] Legacy version can be a pain... :0) --- .github/workflows/build.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49481380..9ccc1af5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ on: jobs: build: - name: Linux versions - Install and test + name: Linux - Install and test runs-on: ubuntu-latest strategy: matrix: @@ -39,7 +39,7 @@ jobs: pytest -v legacy-build: - name: Legacy versions - Install and test + name: Legacy versions - Install only runs-on: ubuntu-18.04 strategy: matrix: @@ -52,7 +52,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - pip install pytest netifaces wheel +# pip install pytest netifaces wheel + pip install pytest python setup.py install # - name: Lint with flake8 # run: | From 3a201ab7ccc15c7c6fd2b72ebc211308ea11ef88 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 11:46:15 -0500 Subject: [PATCH 34/50] error on yaml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9ccc1af5..16808f3e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,8 +52,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | -# pip install pytest netifaces wheel pip install pytest +# pip install pytest netifaces wheel python setup.py install # - name: Lint with flake8 # run: | From fe755a656d9c8fbdd5d1bc9f297899291ee4eead Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 11:47:30 -0500 Subject: [PATCH 35/50] Learning that commenting lines is a bad idea sometimes... --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 16808f3e..4657b8a4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,7 +53,6 @@ jobs: - name: Install dependencies run: | pip install pytest -# pip install pytest netifaces wheel python setup.py install # - name: Lint with flake8 # run: | From 7a11eec365c73ba6efd2469242f364d21b6a30c6 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Mon, 22 Feb 2021 11:53:08 -0500 Subject: [PATCH 36/50] Upgrade setup tools ? --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4657b8a4..2839b044 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,7 +39,7 @@ jobs: pytest -v legacy-build: - name: Legacy versions - Install only + name: Legacy versions - Install and test runs-on: ubuntu-18.04 strategy: matrix: @@ -53,6 +53,7 @@ jobs: - name: Install dependencies run: | pip install pytest + pip install setuptools --upgrade python setup.py install # - name: Lint with flake8 # run: | From 1d615848fb5d3a538d282125b487bd84852d6d23 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Tue, 23 Feb 2021 09:19:04 -0500 Subject: [PATCH 37/50] Let's try Windows and MacOS --- .github/workflows/build.yml | 48 ++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2839b044..b734795c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -55,12 +55,48 @@ jobs: pip install pytest pip install setuptools --upgrade python setup.py install -# - name: Lint with flake8 -# run: | -# # stop the build if there are Python syntax errors or undefined names -# flake8 py34 --count --select=E9,F63,F7,F82 --show-source --statistics --ignore=E123,E221,E226,E302,E41,E701 -# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide -# flake8 py34 --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore=E123,E221,E226,E302,E41,E701 + - name: Test with pytest + run: | + pytest -v + + windows-build: + name: Windows - Install and test + runs-on: windows-latest + strategy: + matrix: + python-version: [3.5, 3.6, 3.7, 3.8] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install pytest + pip install setuptools --upgrade + python setup.py install + - name: Test with pytest + run: | + pytest -v + + macos-build: + name: MacOS - Install and test + runs-on: macos-latest + strategy: + matrix: + python-version: [3.5, 3.6, 3.7, 3.8] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install pytest + pip install setuptools --upgrade + python setup.py install - name: Test with pytest run: | pytest -v \ No newline at end of file From 8ffeea9df9bbe9d5dc1e014eeab4f0ad7acb0f17 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Tue, 23 Feb 2021 09:24:18 -0500 Subject: [PATCH 38/50] Using pip with Windows and MacOS instead of python setup.py install --- .github/workflows/build.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b734795c..b4f92662 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -73,9 +73,10 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - pip install pytest - pip install setuptools --upgrade - python setup.py install + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + pip install . - name: Test with pytest run: | pytest -v @@ -94,9 +95,10 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - pip install pytest - pip install setuptools --upgrade - python setup.py install + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + pip install . - name: Test with pytest run: | pytest -v \ No newline at end of file From 9dbdc9100f9766543846d573627341fd2ca900e2 Mon Sep 17 00:00:00 2001 From: "Christian Tremblay, ing" Date: Tue, 23 Feb 2021 09:27:42 -0500 Subject: [PATCH 39/50] I was a little too bash script for powershell :-) --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b4f92662..b12885e3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -75,7 +75,7 @@ jobs: run: | python -m pip install --upgrade pip pip install flake8 pytest - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + pip install -r requirements.txt pip install . - name: Test with pytest run: | From ce76ade13e5ae1d28ee702606b20661addaad926 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Tue, 23 Feb 2021 14:32:53 -0500 Subject: [PATCH 40/50] bump the version number for the next release --- py25/bacpypes/__init__.py | 2 +- py27/bacpypes/__init__.py | 2 +- py34/bacpypes/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/py25/bacpypes/__init__.py b/py25/bacpypes/__init__.py index 2090886f..d5bd7fd1 100755 --- a/py25/bacpypes/__init__.py +++ b/py25/bacpypes/__init__.py @@ -18,7 +18,7 @@ # Project Metadata # -__version__ = '0.18.3' +__version__ = '0.18.4' __author__ = 'Joel Bender' __email__ = 'joel@carrickbender.com' diff --git a/py27/bacpypes/__init__.py b/py27/bacpypes/__init__.py index 2090886f..d5bd7fd1 100755 --- a/py27/bacpypes/__init__.py +++ b/py27/bacpypes/__init__.py @@ -18,7 +18,7 @@ # Project Metadata # -__version__ = '0.18.3' +__version__ = '0.18.4' __author__ = 'Joel Bender' __email__ = 'joel@carrickbender.com' diff --git a/py34/bacpypes/__init__.py b/py34/bacpypes/__init__.py index f1acb644..616866af 100755 --- a/py34/bacpypes/__init__.py +++ b/py34/bacpypes/__init__.py @@ -18,7 +18,7 @@ # Project Metadata # -__version__ = '0.18.3' +__version__ = '0.18.4' __author__ = 'Joel Bender' __email__ = 'joel@carrickbender.com' From bcdce4894c71d6a0275bfe5d0743064c35b9bc07 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Tue, 23 Feb 2021 14:36:17 -0500 Subject: [PATCH 41/50] merge the updated develop branch to test before merging it into master --- py25/bacpypes/__init__.py | 2 +- py27/bacpypes/__init__.py | 2 +- py34/bacpypes/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/py25/bacpypes/__init__.py b/py25/bacpypes/__init__.py index 2090886f..d5bd7fd1 100755 --- a/py25/bacpypes/__init__.py +++ b/py25/bacpypes/__init__.py @@ -18,7 +18,7 @@ # Project Metadata # -__version__ = '0.18.3' +__version__ = '0.18.4' __author__ = 'Joel Bender' __email__ = 'joel@carrickbender.com' diff --git a/py27/bacpypes/__init__.py b/py27/bacpypes/__init__.py index 2090886f..d5bd7fd1 100755 --- a/py27/bacpypes/__init__.py +++ b/py27/bacpypes/__init__.py @@ -18,7 +18,7 @@ # Project Metadata # -__version__ = '0.18.3' +__version__ = '0.18.4' __author__ = 'Joel Bender' __email__ = 'joel@carrickbender.com' diff --git a/py34/bacpypes/__init__.py b/py34/bacpypes/__init__.py index f1acb644..616866af 100755 --- a/py34/bacpypes/__init__.py +++ b/py34/bacpypes/__init__.py @@ -18,7 +18,7 @@ # Project Metadata # -__version__ = '0.18.3' +__version__ = '0.18.4' __author__ = 'Joel Bender' __email__ = 'joel@carrickbender.com' From 08504ddca9266de40c00107c1bc4fee43b4965cf Mon Sep 17 00:00:00 2001 From: Christian Tremblay Date: Wed, 24 Feb 2021 00:11:32 -0500 Subject: [PATCH 42/50] Update build.yml Configure GH Actions on develop and master branches... the install_and_actions branch should be deleted eventually. --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b12885e3..b1ea6145 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,9 +5,9 @@ name: Build & test on different versions on: push: - branches: [ install_and_actions ] -# pull_request: -# branches: [ install_and_actions ] + branches: [ master, develop ] + pull_request: + branches: [ master, develop ] jobs: build: @@ -101,4 +101,4 @@ jobs: pip install . - name: Test with pytest run: | - pytest -v \ No newline at end of file + pytest -v From af20a040bc20b757c488aed22d12bb93082199bd Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Fri, 26 Feb 2021 22:06:53 -0500 Subject: [PATCH 43/50] prevent erroring out when there is no local broadcast tuple --- samples/UDPConsole.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/samples/UDPConsole.py b/samples/UDPConsole.py index ee2f183b..5951b886 100755 --- a/samples/UDPConsole.py +++ b/samples/UDPConsole.py @@ -126,10 +126,17 @@ def indication(self, pdu): # check the address if addr == "*": + if not local_broadcast_tuple: + sys.stderr.write("err: no local broadcast\n") + return + dest = local_broadcast_tuple elif ':' in addr: addr, port = addr.split(':') if addr == "*": + if not local_broadcast_tuple: + sys.stderr.write("err: no local broadcast\n") + return dest = (local_broadcast_tuple[0], int(port)) else: dest = (addr, int(port)) @@ -234,6 +241,9 @@ def main(): if args.noBroadcast: _log.debug(" - skipping broadcast") + elif not local_broadcast_tuple: + _log.debug(" - no local broadcast") + elif local_unicast_tuple == local_broadcast_tuple: _log.debug(" - identical unicast and broadcast tuples") From 332fd4b7393e5744e28f96eb3ef8ad00370f3e12 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Fri, 26 Feb 2021 23:00:36 -0500 Subject: [PATCH 44/50] clean up string escape sequences --- py25/bacpypes/local/object.py | 4 ++-- py27/bacpypes/local/object.py | 4 ++-- py34/bacpypes/local/object.py | 4 ++-- tests/time_machine.py | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/py25/bacpypes/local/object.py b/py25/bacpypes/local/object.py index 014f604b..416ce7d3 100644 --- a/py25/bacpypes/local/object.py +++ b/py25/bacpypes/local/object.py @@ -88,7 +88,7 @@ class CurrentPropertyListMixIn(Object): # character reference patterns HEX = u"[0-9A-Fa-f]" PERCENT = u"%" + HEX + HEX -UCHAR = u"[\\\]u" + HEX * 4 + "|" + u"[\\\]U" + HEX * 8 +UCHAR = u"[\\]u" + HEX * 4 + "|" + u"[\\]U" + HEX * 8 # character sets PN_CHARS_BASE = ( @@ -102,7 +102,7 @@ class CurrentPropertyListMixIn(Object): PN_CHARS = u"-" + PN_CHARS_U + u"0-9\u00B7\u0300-\u036F\u203F-\u2040" # patterns -IRIREF = u'[<]([^\u0000-\u0020<>"{}|^`\\\]|' + UCHAR + u")*[>]" +IRIREF = u'[<]([^\u0000-\u0020<>"{}|^`\\]|' + UCHAR + u")*[>]" PN_PREFIX = u"[" + PN_CHARS_BASE + u"](([." + PN_CHARS + u"])*[" + PN_CHARS + u"])?" PN_LOCAL_ESC = u"[-\\_~.!$&'()*+,;=/?#@%]" diff --git a/py27/bacpypes/local/object.py b/py27/bacpypes/local/object.py index e2c62eae..f7b4fa0c 100644 --- a/py27/bacpypes/local/object.py +++ b/py27/bacpypes/local/object.py @@ -87,7 +87,7 @@ class CurrentPropertyListMixIn(Object): # character reference patterns HEX = u"[0-9A-Fa-f]" PERCENT = u"%" + HEX + HEX -UCHAR = u"[\\\]u" + HEX * 4 + "|" + u"[\\\]U" + HEX * 8 +UCHAR = u"[\\]u" + HEX * 4 + "|" + u"[\\]U" + HEX * 8 # character sets PN_CHARS_BASE = ( @@ -101,7 +101,7 @@ class CurrentPropertyListMixIn(Object): PN_CHARS = u"-" + PN_CHARS_U + u"0-9\u00B7\u0300-\u036F\u203F-\u2040" # patterns -IRIREF = u'[<]([^\u0000-\u0020<>"{}|^`\\\]|' + UCHAR + u")*[>]" +IRIREF = u'[<]([^\u0000-\u0020<>"{}|^`\\]|' + UCHAR + u")*[>]" PN_PREFIX = u"[" + PN_CHARS_BASE + u"](([." + PN_CHARS + u"])*[" + PN_CHARS + u"])?" PN_LOCAL_ESC = u"[-\\_~.!$&'()*+,;=/?#@%]" diff --git a/py34/bacpypes/local/object.py b/py34/bacpypes/local/object.py index 9f08fbcb..af7ff272 100644 --- a/py34/bacpypes/local/object.py +++ b/py34/bacpypes/local/object.py @@ -87,7 +87,7 @@ class CurrentPropertyListMixIn(Object): # character reference patterns HEX = u"[0-9A-Fa-f]" PERCENT = u"%" + HEX + HEX -UCHAR = u"[\\\]u" + HEX * 4 + "|" + u"[\\\]U" + HEX * 8 +UCHAR = u"[\\]u" + HEX * 4 + "|" + u"[\\]U" + HEX * 8 # character sets PN_CHARS_BASE = ( @@ -101,7 +101,7 @@ class CurrentPropertyListMixIn(Object): PN_CHARS = u"-" + PN_CHARS_U + u"0-9\u00B7\u0300-\u036F\u203F-\u2040" # patterns -IRIREF = u'[<]([^\u0000-\u0020<>"{}|^`\\\]|' + UCHAR + u")*[>]" +IRIREF = u'[<]([^\u0000-\u0020<>"{}|^`\\]|' + UCHAR + u")*[>]" PN_PREFIX = u"[" + PN_CHARS_BASE + u"](([." + PN_CHARS + u"])*[" + PN_CHARS + u"])?" PN_LOCAL_ESC = u"[-\\_~.!$&'()*+,;=/?#@%]" diff --git a/tests/time_machine.py b/tests/time_machine.py index 6ea853ae..ac86ad19 100755 --- a/tests/time_machine.py +++ b/tests/time_machine.py @@ -22,9 +22,9 @@ time_machine = None # some patterns -_date_regex = re.compile("^(\d{4})[-](0?[1-9]|1[0-4])[-]([0-3]?\d)$") -_time_regex = re.compile("^(\d+)[:](\d+)(?:[:](\d+)(?:[.](\d+))?)?$") -_deltatime_regex = re.compile("^(\d+(?:[.]\d+))?$") +_date_regex = re.compile(r"^(\d{4})[-](0?[1-9]|1[0-4])[-]([0-3]?\d)$") +_time_regex = re.compile(r"^(\d+)[:](\d+)(?:[:](\d+)(?:[.](\d+))?)?$") +_deltatime_regex = re.compile(r"^(\d+(?:[.]\d+))?$") # @bacpypes_debugging - implicit via metaclass From f7eb6de93e3e2d253fb62b5f35409053f9c11373 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Fri, 26 Feb 2021 23:01:28 -0500 Subject: [PATCH 45/50] add addtional object type enumerations --- py25/bacpypes/primitivedata.py | 12 ++++++++++-- py27/bacpypes/primitivedata.py | 12 ++++++++++-- py34/bacpypes/primitivedata.py | 12 ++++++++++-- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/py25/bacpypes/primitivedata.py b/py25/bacpypes/primitivedata.py index a32ba6b7..a22e9a45 100755 --- a/py25/bacpypes/primitivedata.py +++ b/py25/bacpypes/primitivedata.py @@ -1612,7 +1612,8 @@ def __str__(self): class ObjectType(Enumerated): vendor_range = (128, 1023) enumerations = \ - { 'accessDoor':30 + { 'accessCredential':32 + , 'accessDoor':30 , 'accessPoint':33 , 'accessRights':34 , 'accessUser':35 @@ -1622,8 +1623,11 @@ class ObjectType(Enumerated): , 'analogInput':0 , 'analogOutput':1 , 'analogValue':2 + , 'auditLog':61 + , 'auditReporter':62 , 'averaging':18 , 'binaryInput':3 + , 'binaryLightingOutput':55 , 'binaryOutput':4 , 'binaryValue':5 , 'bitstringValue':39 @@ -1637,6 +1641,8 @@ class ObjectType(Enumerated): , 'datetimePatternValue':43 , 'datetimeValue':44 , 'device':8 + , 'elevatorGroup':57 + , 'escalator':58 , 'eventEnrollment':9 , 'eventLog':25 , 'file':10 @@ -1646,6 +1652,7 @@ class ObjectType(Enumerated): , 'largeAnalogValue':46 , 'lifeSafetyPoint':21 , 'lifeSafetyZone':22 + , 'lift':59 , 'lightingOutput':54 , 'loadControl':28 , 'loop':12 @@ -1653,6 +1660,7 @@ class ObjectType(Enumerated): , 'multiStateOutput':14 , 'multiStateValue':19 , 'networkSecurity':38 + , 'networkPort':56 , 'notificationClass':15 , 'notificationForwarder':51 , 'octetstringValue':47 @@ -1663,9 +1671,9 @@ class ObjectType(Enumerated): , 'structuredView':29 , 'timePatternValue':49 , 'timeValue':50 + , 'timer':31 , 'trendLog':20 , 'trendLogMultiple':27 - , 'networkPort':56 } expand_enumerations(ObjectType) diff --git a/py27/bacpypes/primitivedata.py b/py27/bacpypes/primitivedata.py index 41ce4e81..2fad74ba 100755 --- a/py27/bacpypes/primitivedata.py +++ b/py27/bacpypes/primitivedata.py @@ -1629,7 +1629,8 @@ def __str__(self): class ObjectType(Enumerated): vendor_range = (128, 1023) enumerations = \ - { 'accessDoor':30 + { 'accessCredential':32 + , 'accessDoor':30 , 'accessPoint':33 , 'accessRights':34 , 'accessUser':35 @@ -1639,8 +1640,11 @@ class ObjectType(Enumerated): , 'analogInput':0 , 'analogOutput':1 , 'analogValue':2 + , 'auditLog':61 + , 'auditReporter':62 , 'averaging':18 , 'binaryInput':3 + , 'binaryLightingOutput':55 , 'binaryOutput':4 , 'binaryValue':5 , 'bitstringValue':39 @@ -1654,6 +1658,8 @@ class ObjectType(Enumerated): , 'datetimePatternValue':43 , 'datetimeValue':44 , 'device':8 + , 'elevatorGroup':57 + , 'escalator':58 , 'eventEnrollment':9 , 'eventLog':25 , 'file':10 @@ -1663,6 +1669,7 @@ class ObjectType(Enumerated): , 'largeAnalogValue':46 , 'lifeSafetyPoint':21 , 'lifeSafetyZone':22 + , 'lift':59 , 'lightingOutput':54 , 'loadControl':28 , 'loop':12 @@ -1670,6 +1677,7 @@ class ObjectType(Enumerated): , 'multiStateOutput':14 , 'multiStateValue':19 , 'networkSecurity':38 + , 'networkPort':56 , 'notificationClass':15 , 'notificationForwarder':51 , 'octetstringValue':47 @@ -1680,9 +1688,9 @@ class ObjectType(Enumerated): , 'structuredView':29 , 'timePatternValue':49 , 'timeValue':50 + , 'timer':31 , 'trendLog':20 , 'trendLogMultiple':27 - , 'networkPort':56 } expand_enumerations(ObjectType) diff --git a/py34/bacpypes/primitivedata.py b/py34/bacpypes/primitivedata.py index dfbc5742..2fadf334 100755 --- a/py34/bacpypes/primitivedata.py +++ b/py34/bacpypes/primitivedata.py @@ -1611,7 +1611,8 @@ def __str__(self): class ObjectType(Enumerated): vendor_range = (128, 1023) enumerations = \ - { 'accessDoor':30 + { 'accessCredential':32 + , 'accessDoor':30 , 'accessPoint':33 , 'accessRights':34 , 'accessUser':35 @@ -1621,8 +1622,11 @@ class ObjectType(Enumerated): , 'analogInput':0 , 'analogOutput':1 , 'analogValue':2 + , 'auditLog':61 + , 'auditReporter':62 , 'averaging':18 , 'binaryInput':3 + , 'binaryLightingOutput':55 , 'binaryOutput':4 , 'binaryValue':5 , 'bitstringValue':39 @@ -1636,6 +1640,8 @@ class ObjectType(Enumerated): , 'datetimePatternValue':43 , 'datetimeValue':44 , 'device':8 + , 'elevatorGroup':57 + , 'escalator':58 , 'eventEnrollment':9 , 'eventLog':25 , 'file':10 @@ -1645,6 +1651,7 @@ class ObjectType(Enumerated): , 'largeAnalogValue':46 , 'lifeSafetyPoint':21 , 'lifeSafetyZone':22 + , 'lift':59 , 'lightingOutput':54 , 'loadControl':28 , 'loop':12 @@ -1652,6 +1659,7 @@ class ObjectType(Enumerated): , 'multiStateOutput':14 , 'multiStateValue':19 , 'networkSecurity':38 + , 'networkPort':56 , 'notificationClass':15 , 'notificationForwarder':51 , 'octetstringValue':47 @@ -1662,9 +1670,9 @@ class ObjectType(Enumerated): , 'structuredView':29 , 'timePatternValue':49 , 'timeValue':50 + , 'timer':31 , 'trendLog':20 , 'trendLogMultiple':27 - , 'networkPort':56 } expand_enumerations(ObjectType) From 0cf22189b80013ab73c8c8719f58e53e3b880bae Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Sun, 14 Mar 2021 21:56:53 -0400 Subject: [PATCH 46/50] added new point types, structures, enumerations --- py27/bacpypes/basetypes.py | 663 +++++++++++++++++++++++++++++---- py27/bacpypes/object.py | 740 +++++++++++++++++++++++++++++++------ py34/bacpypes/basetypes.py | 663 +++++++++++++++++++++++++++++---- py34/bacpypes/object.py | 535 ++++++++++++++++++++++++++- 4 files changed, 2354 insertions(+), 247 deletions(-) diff --git a/py27/bacpypes/basetypes.py b/py27/bacpypes/basetypes.py index c2dd232f..6bcaec25 100755 --- a/py27/bacpypes/basetypes.py +++ b/py27/bacpypes/basetypes.py @@ -8,8 +8,8 @@ from .errors import MissingRequiredParameter from .primitivedata import Atomic, BitString, Boolean, CharacterString, Date, Double, \ - Enumerated, Integer, Null, ObjectIdentifier, OctetString, Real, Time, \ - Unsigned, Unsigned16, Tag + Enumerated, Integer, Null, ObjectType, ObjectIdentifier, OctetString, Real, Time, \ + Unsigned, Unsigned8, Unsigned16, Tag from .constructeddata import Any, AnyAtomic, ArrayOf, Choice, Element, \ Sequence, SequenceOf @@ -21,6 +21,28 @@ # Bit Strings # +class AuditOperationFlags(BitString): + vendor_range = (32, 63) + bitNames = \ + { 'read':0 + , 'write':1 + , 'create':2 + , 'delete':3 + , 'lifeSafety':4 + , 'acknowledgeAlarm':5 + , 'deviceDisableComm':6 + , 'deviceEnableComm':7 + , 'deviceReset':8 + , 'deviceBackup':9 + , 'deviceRestore':10 + , 'subscription':11 + , 'notification':12 + , 'auditingFailure':13 + , 'networkChanges':14 + , 'general':15 + } + bitLen = 16 + class DaysOfWeek(BitString): bitNames = \ { 'monday':0 @@ -116,6 +138,27 @@ class ObjectTypesSupported(BitString): } bitLen = 55 +class PriorityFilter(BitString): + bitNames = \ + { 'manualLifeSafety':0 + , 'automaticLifeSafety':1 + , 'priority3':2 + , 'priority4':3 + , 'criticalEquipmentControls':4 + , 'minimumOnOff':5 + , 'priority7':6 + , 'manualOperator':7 + , 'priority9':8 + , 'priority10':9 + , 'priority11':10 + , 'priority12':11 + , 'priority13':12 + , 'priority14':13 + , 'priority15':14 + , 'priority16':15 + } + bitLen = 16 + class ResultFlags(BitString): bitNames = \ { 'firstItem':0 @@ -329,6 +372,36 @@ class Action(Enumerated): , 'reverse':1 } +class AuditLevel(Enumerated): + vendor_range = (128, 255) + enumerations = \ + { 'none':0 + , 'auditAll':1 + , 'auditConfig':2 + , 'default':3 + } + +class AuditOperation(Enumerated): + vendor_range = (32, 63) + enumerations = \ + { 'read':0 + , 'write':1 + , 'create':2 + , 'delete':3 + , 'lifeSafety':4 + , 'acknowledgeAlarm':5 + , 'deviceDisableComm':6 + , 'deviceEnableComm':7 + , 'deviceReset':8 + , 'deviceBackup':9 + , 'deviceRestore':10 + , 'subscription':11 + , 'notification':12 + , 'auditingFailure':13 + , 'networkChanges':14 + , 'general':15 + } + class AuthenticationFactorType(Enumerated): enumerations = \ { 'undefined':0 @@ -403,6 +476,17 @@ class BackupState(Enumerated): , 'restoreFailure':6 } +class BinaryLightingPV(Enumerated): + vendor_range = (64, 255) + enumerations = \ + { 'off':0 + , 'on':1 + , 'warn':2 + , 'warn-off':3 + , 'warn-relinquish':4 + , 'stop':5 + } + class BinaryPV(Enumerated): enumerations = \ { 'inactive':0 @@ -872,6 +956,28 @@ class ErrorCode(Enumerated): , 'writeBdtFailed':116 } +class EscalatorMode(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'unknown':0 + , 'stop':1 + , 'up':2 + , 'down':3 + , 'inspection':4 + , 'outOfService':5 + } + +class EscalatorOperationDirection(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'unknown':0 + , 'stopped':1 + , 'upRatedSpeed':2 + , 'upReducedSpeed':3 + , 'downRatedSpeed':4 + , 'downReducedSpeed':5 + } + class EventState(Enumerated): vendor_range = (64, 65535) enumerations = \ @@ -923,6 +1029,91 @@ class FileAccessMethod(Enumerated): , 'streamAccess':1 } +class LiftCarDirection(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'unknown':0 + , 'none':1 + , 'stopped':2 + , 'up':3 + , 'down':4 + , 'upAndDown':5 + } + +class LiftCarDoorCommand(Enumerated): + enumerations = \ + { 'none':0 + , 'open':1 + , 'close':2 + } + +class LiftCarDriveStatus(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'unknown':0 + , 'stationary':1 + , 'braking':2 + , 'accelerate':3 + , 'decelerate':4 + , 'ratedSpeed':5 + , 'singleFloorJump':6 + , 'twoFloorJump':7 + , 'threeFloorJump':8 + , 'multiFloorJump':9 + } + +class LiftCarMode(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'unknown':0 + , 'normal':1 + , 'vip':2 + , 'homing':3 + , 'parking':4 + , 'attendantControl':5 + , 'firefighterControl':6 + , 'emergencyPower':7 + , 'inspection':8 + , 'cabinetRecall':9 + , 'earthquakeOperation':10 + , 'fireOperation':11 + , 'outOfService':12 + , 'occupantEvacuation':13 + } + +class LiftFault(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'controllerFault':0 + , 'driveAndMotorFault':1 + , 'governorAndSafetyGearFault':2 + , 'liftShaftDeviceFault':3 + , 'powerSupplyFault':4 + , 'safetyInterlockFault':5 + , 'doorClosingFault':6 + , 'doorOpeningFault':7 + , 'carStoppedOutsideLandingZone':8 + , 'callButtonStuck':9 + , 'startFailure':10 + , 'controllerSupplyFault':11 + , 'selfTestFailure':12 + , 'runtimeLimitExceeded':13 + , 'positionLost':14 + , 'driveTemperatureExceeded':15 + , 'loadMeasurementFault':16 + } + +class LiftGroupMode(Enumerated): + enumerations = \ + { 'unknown':0 + , 'normal':1 + , 'downPeak':2 + , 'twoWay':3 + , 'fourWay':4 + , 'emergencyPower':5 + , 'upPeak':6 + } + class LifeSafetyMode(Enumerated): enumerations = \ { 'off':0 @@ -1103,50 +1294,9 @@ class ProgramState(Enumerated): } class PropertyIdentifier(Enumerated): - # TODO: Sort Alphabetically vendor_range = (512, 4194303) enumerations = \ { 'absenteeLimit':244 - , 'tags':486 - , 'profileLocation':91 - , 'eventDetectionEnabled':353 - , 'apduLength':388 - , 'linkSpeed':420 - , 'linkSpeeds':421 - , 'linkSpeedAutonegotiate':422 - , 'networkInterfaceName':424 - , 'bacnetIPMode':408 - , 'ipAddress':400 - , 'bacnetIPUDPPort':412 - , 'ipSubnetMask':411 - , 'ipDefaultGateway':401 - , 'bacnetIPMulticastAddress':409 - , 'ipDNSServer':406 - , 'ipDHCPEnable':402 - , 'ipDHCPLeaseTime':403 - , 'ipDHCPLeaseTimeRemaining':404 - , 'ipDHCPServer':405 - , 'bacnetIPNATTraversal':410 - , 'bacnetIPGlobalAddress':407 - , 'bbmdBroadcastDistributionTable':414 - , 'bbmdAcceptFDRegistrations':413 - , 'bbmdForeignDeviceTable':415 - , 'fdBBMDAddress':418 - , 'fdSubscriptionLifetime':419 - , 'bacnetIPv6Mode':435 - , 'ipv6Address':436 - , 'ipv6PrefixLength':437 - , 'bacnetIPv6UDPPort':438 - , 'ipv6DefaultGateway':439 - , 'bacnetIPv6MulticastAddress':440 - , 'ipv6DNSServer':441 - , 'ipv6AutoAddressingEnabled':442 - , 'ipv6DHCPLeaseTime':443 - , 'ipv6DHCPLeaseTimeRemaining':444 - , 'ipv6DHCPServer':445 - , 'ipv6ZoneIndex':446 - , 'virtualMACAddressTable':429 - , 'routingTable':428 , 'acceptedModes':175 , 'accessAlarmEvents':245 , 'accessDoors':246 @@ -1158,12 +1308,13 @@ class PropertyIdentifier(Enumerated): , 'accessTransactionEvents':251 , 'accompaniment':252 , 'accompanimentTime':253 - , 'ackRequired':1 , 'ackedTransitions':0 + , 'ackRequired':1 , 'action':2 , 'actionText':3 , 'activationTime':254 , 'activeAuthenticationPolicy':255 + , 'activeCovMultipleSubscriptions':481 , 'activeCovSubscriptions':152 , 'activeText':4 , 'activeVtSessions':5 @@ -1173,14 +1324,21 @@ class PropertyIdentifier(Enumerated): , 'alarmValues':7 , 'alignIntervals':193 , 'all':8 - , 'allWritesSuccessful':9 , 'allowGroupDelayInhibit':365 + , 'allWritesSuccessful':9 + , 'apduLength':388 , 'apduSegmentTimeout':10 , 'apduTimeout':11 , 'applicationSoftwareVersion':12 , 'archive':13 , 'assignedAccessRights':256 + , 'assignedLandingCalls':447 , 'attemptedSamples':124 + , 'auditableOperations':501 + , 'auditablePriorityFilter':500 + , 'auditLevel':498 + , 'auditNotificationRecipient':499 + , 'auditSourceReporter':497 , 'authenticationFactors':257 , 'authenticationPolicyList':258 , 'authenticationPolicyNames':259 @@ -1192,19 +1350,42 @@ class PropertyIdentifier(Enumerated): , 'backupAndRestoreState':338 , 'backupFailureTimeout':153 , 'backupPreparationTime':339 + , 'bacnetIPGlobalAddress':407 + , 'bacnetIPMode':408 + , 'bacnetIPMulticastAddress':409 + , 'bacnetIPNATTraversal':410 + , 'bacnetIPUDPPort':412 + , 'bacnetIPv6Mode':435 + , 'bacnetIPv6MulticastAddress':440 + , 'bacnetIPv6UDPPort':438 , 'baseDeviceSecurityPolicy':327 + , 'bbmdAcceptFDRegistrations':413 + , 'bbmdBroadcastDistributionTable':414 + , 'bbmdForeignDeviceTable':415 , 'belongsTo':262 , 'bias':14 , 'bitMask':342 , 'bitText':343 , 'blinkWarnEnable':373 , 'bufferSize':126 + , 'carAssignedDirection':448 + , 'carDoorCommand':449 + , 'carDoorStatus':450 + , 'carDoorText':451 + , 'carDoorZone':452 + , 'carDriveStatus':453 + , 'carLoad':454 + , 'carLoadUnits':455 + , 'carMode':456 + , 'carMovingDirection':457 + , 'carPosition':458 , 'changeOfStateCount':15 , 'changeOfStateTime':16 , 'changesPending':416 , 'channelNumber':366 , 'clientCovIncrement':127 , 'command':417 + , 'commandTimeArray':430 , 'configurationFiles':154 , 'controlGroups':367 , 'controlledVariableReference':19 @@ -1219,23 +1400,30 @@ class PropertyIdentifier(Enumerated): , 'covuPeriod':349 , 'covuRecipients':350 , 'credentialDisable':263 - , 'credentialStatus':264 , 'credentials':265 , 'credentialsInZone':266 + , 'credentialStatus':264 + , 'currentCommandPriority':431 , 'databaseRevision':155 , 'dateList':23 , 'daylightSavingsStatus':24 , 'daysRemaining':267 , 'deadband':25 , 'defaultFadeTime':374 + , 'defaultPresentValue':492 , 'defaultRampRate':375 , 'defaultStepIncrement':376 + , 'defaultSubordinateRelationship':490 + , 'defaultTimeout':393 + , 'deleteOnForward':502 + , 'deployedProfileLocation':484 , 'derivativeConstant':26 , 'derivativeConstantUnits':27 , 'description':28 , 'descriptionOfHalt':29 , 'deviceAddressBinding':30 , 'deviceType':31 + , 'deviceUUID':507 , 'directReading':156 , 'distributionKeyRevision':328 , 'doNotHide':329 @@ -1251,54 +1439,93 @@ class PropertyIdentifier(Enumerated): , 'egressActive':386 , 'egressTime':377 , 'elapsedActiveTime':33 - , 'entryPoints':268 + , 'elevatorGroup':459 , 'enable':133 + , 'energyMeter':460 + , 'energyMeterRef':461 + , 'entryPoints':268 , 'errorLimit':34 + , 'escalatorMode':462 , 'eventAlgorithmInhibit':354 , 'eventAlgorithmInhibitRef':355 , 'eventDetectionEnable':353 , 'eventEnable':35 , 'eventMessageTexts':351 , 'eventMessageTextsConfig':352 + , 'eventParameters':83 , 'eventState':36 , 'eventTimeStamps':130 , 'eventType':37 - , 'eventParameters':83 , 'exceptionSchedule':38 , 'executionDelay':368 , 'exitPoints':269 , 'expectedShedLevel':214 - , 'expiryTime':270 + , 'expirationTime':270 , 'extendedTimeEnable':271 , 'failedAttemptEvents':272 , 'failedAttempts':273 , 'failedAttemptsTime':274 + , 'faultHighLimit':388 + , 'faultLowLimit':389 , 'faultParameters':358 + , 'faultSignals':463 , 'faultType':359 , 'faultValues':39 + , 'fdBBMDAddress':418 + , 'fdSubscriptionLifetime':419 , 'feedbackValue':40 , 'fileAccessMethod':41 , 'fileSize':42 , 'fileType':43 , 'firmwareRevision':44 + , 'floorNumber':506 + , 'floorText':464 , 'fullDutyBaseline':215 , 'globalIdentifier':323 - , 'groupMembers':345 + , 'groupID':465 , 'groupMemberNames':346 + , 'groupMembers':345 + , 'groupMode':467 + , 'higherDeck':468 , 'highLimit':45 , 'inactiveText':46 + , 'initialTimeout':394 , 'inProcess':47 , 'inProgress':378 , 'inputReference':181 + , 'installationID':469 , 'instanceOf':48 , 'instantaneousPower':379 , 'integralConstant':49 , 'integralConstantUnits':50 + , 'interfaceValue':387 , 'intervalOffset':195 + , 'ipAddress':400 + , 'ipDefaultGateway':401 + , 'ipDHCPEnable':402 + , 'ipDHCPLeaseTime':403 + , 'ipDHCPLeaseTimeRemaining':404 + , 'ipDHCPServer':405 + , 'ipDNSServer':406 + , 'ipSubnetMask':411 + , 'ipv6Address':436 + , 'ipv6AutoAddressingEnabled':442 + , 'ipv6DefaultGateway':439 + , 'ipv6DHCPLeaseTime':443 + , 'ipv6DHCPLeaseTimeRemaining':444 + , 'ipv6DHCPServer':445 + , 'ipv6DNSServer':441 + , 'ipv6PrefixLength':437 + , 'ipv6ZoneIndex':446 + , 'issueConfirmedNotifications':51 , 'isUtc':344 , 'keySets':330 + , 'landingCallControl':471 + , 'landingCalls': 470 + , 'landingDoorStatus':472 , 'lastAccessEvent':275 , 'lastAccessPoint':276 + , 'lastCommandTime':432 , 'lastCredentialAdded':277 , 'lastCredentialAddedTime':278 , 'lastCredentialRemoved':279 @@ -1308,12 +1535,16 @@ class PropertyIdentifier(Enumerated): , 'lastPriority':369 , 'lastRestartReason':196 , 'lastRestoreTime':157 + , 'lastStateChange':395 , 'lastUseTime':281 , 'lifeSafetyAlarmValues':166 , 'lightingCommand':380 , 'lightingCommandDefaultPriority':381 , 'limitEnable':52 , 'limitMonitoringInterval':182 + , 'linkSpeed':420 + , 'linkSpeedAutonegotiate':422 + , 'linkSpeeds':421 , 'listOfGroupMembers':53 , 'listOfObjectPropertyReferences':54 , 'listOfSessionKeys':55 @@ -1321,51 +1552,59 @@ class PropertyIdentifier(Enumerated): , 'localForwardingOnly':360 , 'localTime':57 , 'location':58 - , 'lockStatus':233 , 'lockout':282 , 'lockoutRelinquishTime':283 + , 'lockStatus':233 , 'logBuffer':131 , 'logDeviceObjectProperty':132 - , 'logInterval':134 , 'loggingObject':183 , 'loggingRecord':184 , 'loggingType':197 + , 'logInterval':134 + , 'lowDiffLimit':390 + , 'lowerDeck':473 , 'lowLimit':59 , 'macAddress':423 + , 'machineRoomID':474 , 'maintenanceRequired':158 + , 'makingCarCall':475 , 'manipulatedVariableReference':60 , 'manualSlaveAddressBinding':170 , 'maskedAlarmValues':234 , 'masterExemption':284 - , 'maximumOutput':61 - , 'maximumValue':135 - , 'maximumValueTimestamp':149 , 'maxActualValue':382 , 'maxApduLengthAccepted':62 , 'maxFailedAttempts':285 + , 'maximumOutput':61 + , 'maximumSendDelay':503 + , 'maximumValue':135 + , 'maximumValueTimestamp':149 , 'maxInfoFrames':63 , 'maxMaster':64 , 'maxPresValue':65 , 'maxSegmentsAccepted':167 , 'memberOf':159 - , 'memberStatusFlags':347 , 'members':286 + , 'memberStatusFlags':347 + , 'minActualValue':383 , 'minimumOffTime':66 , 'minimumOnTime':67 , 'minimumOutput':68 , 'minimumValue':136 , 'minimumValueTimestamp':150 - , 'minActualValue':383 , 'minPresValue':69 , 'mode':160 , 'modelName':70 , 'modificationDate':71 + , 'monitoredObjects':504 , 'musterPoint':287 , 'negativeAccessRules':288 , 'networkAccessSecurityPolicies':332 + , 'networkInterfaceName':424 , 'networkNumber':425 , 'networkNumberQuality':427 , 'networkType': 427 + , 'nextStoppingFloor':476 , 'nodeSubtype':207 , 'nodeType':208 , 'notificationClass':17 @@ -1388,6 +1627,7 @@ class PropertyIdentifier(Enumerated): , 'occupancyState':296 , 'occupancyUpperLimit':297 , 'occupancyUpperLimitEnforced':298 + , 'operationDirection':477 , 'operationExpected':161 , 'optional':80 , 'outOfService':81 @@ -1396,17 +1636,21 @@ class PropertyIdentifier(Enumerated): , 'passbackExemption':299 , 'passbackMode':300 , 'passbackTimeout':301 + , 'passengerAlarm':478 , 'polarity':84 , 'portFilter':363 , 'positiveAccessRules':302 , 'power':384 + , 'powerMode':479 , 'prescale':185 + , 'presentStage':493 , 'presentValue':85 , 'priority':86 , 'priorityArray':87 , 'priorityForWriting':88 , 'processIdentifier':89 , 'processIdentifierFilter':361 + , 'profileLocation':91 , 'profileName':168 , 'programChange':90 , 'programLocation':91 @@ -1424,12 +1668,14 @@ class PropertyIdentifier(Enumerated): , 'reasonForDisable':303 , 'reasonForHalt':100 , 'recipientList':102 - , 'recordsSinceNotification':140 , 'recordCount':141 + , 'recordsSinceNotification':140 , 'referencePort':483 + , 'registeredCarCall':480 , 'reliability':103 , 'reliabilityEvaluationInhibit':357 , 'relinquishDefault':104 + , 'represents':491 , 'requestedShedLevel':218 , 'requestedUpdateInterval':348 , 'required':105 @@ -1437,6 +1683,7 @@ class PropertyIdentifier(Enumerated): , 'restartNotificationRecipients':202 , 'restoreCompletionTime':340 , 'restorePreparationTime':341 + , 'routingTable':428 , 'scale':187 , 'scaleFactor':188 , 'scheduleDefault':174 @@ -1444,6 +1691,7 @@ class PropertyIdentifier(Enumerated): , 'securityPDUTimeout':334 , 'securityTimeWindow':335 , 'segmentationSupported':107 + , 'sendNow':505 , 'serialNumber':372 , 'setpoint':108 , 'setpointReference':109 @@ -1454,20 +1702,29 @@ class PropertyIdentifier(Enumerated): , 'silenced':163 , 'slaveAddressBinding':171 , 'slaveProxyEnable':172 + , 'stageNames':495 + , 'stages':494 , 'startTime':142 + , 'stateChangeValues':396 , 'stateDescription':222 , 'stateText':110 , 'statusFlags':111 , 'stopTime':143 , 'stopWhenFull':144 + , 'strikeCount':391 , 'structuredObjectList':209 , 'subordinateAnnotations':210 , 'subordinateList':211 + , 'subordinateNodeTypes':487 + , 'subordinateRelationships':489 + , 'subordinateTags':488 , 'subscribedRecipients':362 - , 'supportedFormats':304 , 'supportedFormatClasses':305 + , 'supportedFormats':304 , 'supportedSecurityAlgorithms':336 , 'systemStatus':112 + , 'tags':486 + , 'targetReferences':496 , 'threatAuthority':306 , 'threatLevel':307 , 'timeDelay':113 @@ -1475,6 +1732,9 @@ class PropertyIdentifier(Enumerated): , 'timeOfActiveTimeReset':114 , 'timeOfDeviceRestart':203 , 'timeOfStateCountReset':115 + , 'timeOfStrikeCountReset':392 + , 'timerRunning':397 + , 'timerState':398 , 'timeSynchronizationInterval':204 , 'timeSynchronizationRecipients':116 , 'totalRecordCount':145 @@ -1496,12 +1756,15 @@ class PropertyIdentifier(Enumerated): , 'utcTimeSynchronizationRecipients':206 , 'validSamples':146 , 'valueBeforeChange':190 - , 'valueSet':191 , 'valueChangeTime':192 + , 'valueSet':191 + , 'valueSource':433 + , 'valueSourceArray':434 , 'varianceValue':151 , 'vendorIdentifier':120 , 'vendorName':121 , 'verificationTime':326 + , 'virtualMACAddressTable':429 , 'vtClassesSupported':122 , 'weeklySchedule':123 , 'windowInterval':147 @@ -1512,6 +1775,41 @@ class PropertyIdentifier(Enumerated): , 'zoneTo':321 } +class Relationship(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'unknown':0 + , 'default':1 + , 'contains':2 + , 'containedBy':3 + , 'uses':4 + , 'usedBy':5 + , 'commands':6 + , 'commandedBy':7 + , 'adjusts':8 + , 'adjustedBy':9 + , 'ingress':10 + , 'egress':11 + , 'suppliesAir':12 + , 'receivesAir':13 + , 'suppliesHotAir':14 + , 'receivesHotAir':15 + , 'suppliesCoolAir':16 + , 'receivesCoolAir':17 + , 'suppliesPower':18 + , 'receivesPower':19 + , 'suppliesGas':20 + , 'receivesGas':21 + , 'suppliesWater':22 + , 'receivesWater':23 + , 'suppliesHotWater':24 + , 'receivesHotWater':25 + , 'suppliesCoolWater':26 + , 'receivesCoolWater':27 + , 'suppliesSteam':28 + , 'receivesSteam':29 + } + class Reliability(Enumerated): vendor_range = (64, 65535) enumerations = \ @@ -1597,6 +1895,25 @@ class SilencedState(Enumerated): , 'allSilenced':3 } +class TimerState(Enumerated): + enumerations = \ + { 'idle':0 + , 'running':1 + , 'expired':2 + } + +class TimerTransition(Enumerated): + enumerations = \ + { 'none':0 + , 'idleToRunning':1 + , 'runningToIdle':2 + , 'runningToRunning':3 + , 'runningToExpired':4 + , 'forcedToExpired':5 + , 'expiredToIdle':6 + , 'expiredToRunning':7 + } + class VTClass(Enumerated): vendor_range = (64, 65535) enumerations = \ @@ -1710,6 +2027,12 @@ class VMACEntry(Sequence): , Element('nativeMACAddress', OctetString) ] +class PropertyReference(Sequence): + sequenceElements = \ + [ Element('propertyIdentifier', PropertyIdentifier, 0) + , Element('propertyArrayIndex', Unsigned, 1, True) + ] + class RouterEntry(Sequence): sequenceElements = \ [ Element('networkNumber', Unsigned16) @@ -1799,6 +2122,11 @@ def decode(self, taglist): taglist.Pop() self.value = tag.app_to_object() +class NameValueCollection(Sequence): + sequenceElements = \ + [ Element('members', SequenceOf(NameValue), 0) + ] + class DeviceAddress(Sequence): sequenceElements = \ [ Element('networkNumber', Unsigned) @@ -1837,6 +2165,36 @@ class ErrorType(Sequence): , Element('errorCode', ErrorCode) ] + +class LandingCallStatusCommand(Choice): + choiceElements = \ + [ Element('direction', LiftCarDirection, 1) + , Element('destination', Unsigned8, 2) + ] + +class LandingCallStatus(Sequence): + sequenceElements = \ + [ Element('floorNumber', Unsigned8, 0) + , Element('command', LandingCallStatusCommand) + , Element('floorText', CharacterString, 3, True) + ] + +class LandingDoorStatusLandingDoor(Sequence): + sequenceElements = \ + [ Element('floorNumber', Unsigned8, 0) + , Element('doorStatus', DoorStatus, 1) + ] + +class LandingDoorStatus(Sequence): + sequenceElements = \ + [ Element('landingDoors', SequenceOf(LandingDoorStatusLandingDoor), 0) + ] + +class LiftCarCallList(Sequence): + sequenceElements = \ + [ Element('floorNumbers', SequenceOf(Unsigned8), 0) + ] + class LightingCommand(Sequence): sequenceElements = \ [ Element('operation', LightingOperation, 0) @@ -1854,6 +2212,36 @@ class ObjectPropertyReference(Sequence): , Element('propertyArrayIndex', Unsigned, 2, True) ] +class OptionalBinaryPV(Choice): + choiceElements = \ + [ Element('null', Null) + , Element('binaryPV', BinaryPV) + ] + +class OptionalCharacterString(Choice): + choiceElements = \ + [ Element('null', Null) + , Element('characterstring', CharacterString) + ] + +class OptionalPriorityFilter(Choice): + choiceElements = \ + [ Element('null', Null) + , Element('filter', PriorityFilter) + ] + +class OptionalReal(Choice): + choiceElements = \ + [ Element('null', Null) + , Element('real', Real) + ] + +class OptionalUnsigned(Choice): + choiceElements = \ + [ Element('null', Null) + , Element('unsigned', Unsigned) + ] + class ProcessIdSelection(Choice): choiceElements = \ [ Element('processIdentifier', Unsigned) @@ -1924,6 +2312,27 @@ class RecipientProcess(Sequence): , Element('processIdentifier', Unsigned, 1) ] +class TimerStateChangeValue(Choice): + choiceElements = \ + [ Element('null', Null) + , Element('boolean', Boolean) + , Element('unsigned', Unsigned) + , Element('integer', Integer) + , Element('real', Real) + , Element('double', Double) + , Element('octetstring', OctetString) + , Element('characterstring', CharacterString) + , Element('bitstring', BitString) + , Element('enumerated', Enumerated) + , Element('date', Date) + , Element('time', Time) + , Element('objectidentifier', ObjectIdentifier) + , Element('noValue', Null, 0) + , Element('constructedValue', Any, 1) + , Element('datetime', DateTime, 2) + , Element('lightingCommand', LightingCommand, 3) + ] + class TimeStamp(Choice): choiceElements = \ [ Element('time', Time, 0) @@ -1988,6 +2397,12 @@ class ActionList(Sequence): [ Element('action', SequenceOf(ActionCommand), 0) ] +class Address(Sequence): + sequenceElements = \ + [ Element('networkNumber', Unsigned16) + , Element('macAddress', OctetString) + ] + class AddressBinding(Sequence): sequenceElements = \ [ Element('deviceObjectIdentifier', ObjectIdentifier) @@ -2001,6 +2416,84 @@ class AssignedAccessRights(Sequence): , Element('enable', Boolean, 1) ] +class AssignedLandingCallsLandingCalls(Sequence): + sequenceElements = \ + [ Element('floorNumber', Unsigned8, 0) + , Element('direction', LiftCarDirection, 1) + ] + +class AssignedLandingCalls(Sequence): + sequenceElements = \ + [ Element('landingCalls', SequenceOf(AssignedLandingCallsLandingCalls), 0) + ] + +class AuditNotification(Sequence): + sequenceElements = \ + [ Element('sourceTimestamp', TimeStamp, 0, True) + , Element('targetTimestamp', TimeStamp, 1, True) + , Element('sourceDevice', Recipient, 2) + , Element('sourceObject', ObjectIdentifier, 3, True) + , Element('operation', AuditOperation, 4) + , Element('sourceComment', CharacterString, 5, True) + , Element('targetComment', CharacterString, 6, True) + , Element('invokeID', Unsigned8, 7, True) + , Element('sourceUserID', Unsigned16, 8, True) + , Element('sourceUserRole', Unsigned8, 9, True) + , Element('targetDevice', Recipient, 10) + , Element('targetObject', ObjectIdentifier, 11, True) + , Element('targetProperty', PropertyReference, 12, True) + , Element('targetPriority', Unsigned, 13, True) # 1..16 + , Element('targetValue', Any, 14, True) + , Element('currentValue', Any, 15, True) + , Element('result', ErrorType, 16, True) + ] + +class AuditLogRecordLogDatum(Choice): + choiceElements = \ + [ Element('logStatus', LogStatus, 0) + , Element('auditNotification', AuditNotification, 1) + , Element('timeChange', Real) + ] + +class AuditLogRecord(Sequence): + sequenceElements = \ + [ Element('timestamp', DateTime, 0) + , Element('logDatum', AuditLogRecordLogDatum, 1) + ] + +class AuditLogRecordResult(Sequence): + sequenceElements = \ + [ Element('sequenceNumber', Unsigned, 0) # Unsigned64 + , Element('logRecord', AuditLogRecord, 1) + ] + +class AuditLogQueryParametersByTarget(Sequence): + sequenceElements = \ + [ Element('targetDeviceIdentifier', ObjectIdentifier, 0) + , Element('targetDeviceAddress', Address, 1, True) + , Element('targetObjectIdentifier', ObjectIdentifier, 2, True) + , Element('targetPropertyIdentifier', PropertyIdentifier, 3, True) + , Element('targetArrayIndex', Unsigned, 4, True) + , Element('targetPriority', Unsigned, 5, True) + , Element('operations', AuditOperationFlags, 6, True) + , Element('successfulActionsOnly', Boolean, 7) + ] + +class AuditLogQueryParametersBySource(Sequence): + sequenceElements = \ + [ Element('sourceDeviceIdentifier', ObjectIdentifier, 0) + , Element('sourceDeviceAddress', Address, 1, True) + , Element('sourceObjectIdentifier', ObjectIdentifier, 2, True) + , Element('operations', AuditOperationFlags, 3, True) + , Element('successfulActionsOnly', Boolean, 4) + ] + +class AuditLogQueryParameters(Choice): + choiceElements = \ + [ Element('byTarget', AuditLogQueryParametersByTarget, 0) + , Element('bySource', AuditLogQueryParametersBySource, 1) + ] + class AuthenticationFactor(Sequence): sequenceElements = \ [ Element('formatType', AuthenticationFactorType, 0) @@ -2059,6 +2552,28 @@ class ClientCOV(Choice): , Element('defaultIncrement', Null) ] +class COVMultipleSubscriptionListOfCOVReference(Sequence): + sequenceElements = \ + [ Element('monitoredProperty', PropertyReference, 0) + , Element('covIncrement', Real, 1, True) + , Element('timestamped', Boolean, 2) + ] + +class COVMultipleSubscriptionList(Sequence): + sequenceElements = \ + [ Element('monitoredObjectIdentifier', ObjectIdentifier, 0) + , Element('listOfCOVReferences', SequenceOf(COVMultipleSubscriptionListOfCOVReference), 1) + ] + +class COVMultipleSubscription(Sequence): + sequenceElements = \ + [ Element('recipient', RecipientProcess, 0) + , Element('issueConfirmedNotifications', Boolean, 1) + , Element('timeRemaining', Unsigned, 2) + , Element('maxNotificationDelay', Unsigned, 3) + , Element('listOfCOVSubscriptionSpecifications', SequenceOf(COVMultipleSubscriptionList), 4) + ] + class COVSubscription(Sequence): sequenceElements = \ [ Element('recipient', RecipientProcess, 0) @@ -2558,6 +3073,13 @@ class ObjectPropertyValue(Sequence): , Element('priority', Unsigned, 4, True) ] +class ObjectSelector(Choice): + choiceElements = \ + [ Element('none', Null) + , Element('object', ObjectIdentifier) + , Element('objectType', ObjectType) + ] + class OptionalCharacterString(Choice): choiceElements = \ [ Element('null', Null) @@ -2615,12 +3137,6 @@ class PropertyAccessResult(Sequence): , Element('accessResult', PropertyAccessResultAccessResult) ] -class PropertyReference(Sequence): - sequenceElements = \ - [ Element('propertyIdentifier', PropertyIdentifier, 0) - , Element('propertyArrayIndex', Unsigned, 1, True) - ] - class Scale(Choice): choiceElements = \ [ Element('floatScale', Real, 0) @@ -2660,6 +3176,21 @@ class SpecialEvent(Sequence): , Element('eventPriority', Unsigned, 3) ] +class StageLimitValue(Sequence): + sequenceElements = \ + [ Element('limit', Real) + , Element('values', BitString) + , Element('deadband', Real) + ] + +class ValueSource(Choice): + choiceElements = \ + [ Element('none', Null, 0) + , Element('object', DeviceObjectReference, 1) + , Element('Address', Address) + ] + + class VTSession(Sequence): sequenceElements = \ [ Element('localVtSessionID', Unsigned) diff --git a/py27/bacpypes/object.py b/py27/bacpypes/object.py index 2b541393..ce414a2e 100755 --- a/py27/bacpypes/object.py +++ b/py27/bacpypes/object.py @@ -20,7 +20,8 @@ from .basetypes import AccessCredentialDisable, AccessCredentialDisableReason, \ AccessEvent, AccessPassbackMode, AccessRule, AccessThreatLevel, \ AccessUserType, AccessZoneOccupancyState, AccumulatorRecord, Action, \ - ActionList, AddressBinding, AssignedAccessRights, AuthenticationFactor, \ + ActionList, AddressBinding, AssignedAccessRights, AuditOperationFlags, AuditLevel, \ + AuthenticationFactor, \ AuthenticationFactorFormat, AuthenticationPolicy, AuthenticationStatus, \ AuthorizationException, AuthorizationMode, BackupState, BDTEntry, BinaryPV, \ COVSubscription, CalendarEntry, ChannelValue, ClientCOV, \ @@ -41,7 +42,14 @@ RouterEntry, Scale, SecurityKeySet, SecurityLevel, Segmentation, \ ServicesSupported, SetpointReference, ShedLevel, ShedState, SilencedState, \ SpecialEvent, StatusFlags, TimeStamp, VTClass, VTSession, VMACEntry, \ - WriteStatus + WriteStatus, OptionalUnsigned, PriorityFilter, ValueSource, \ + OptionalPriorityFilter, OptionalReal, AuditNotification, PropertyReference, \ + AuditLogRecord, ObjectSelector, OptionalBinaryPV, BinaryLightingPV, \ + COVMultipleSubscription, LiftGroupMode, LandingCallStatus, LiftCarDirection, \ + EscalatorOperationDirection, EscalatorMode, LiftFault, AssignedLandingCalls, \ + LiftCarCallList, LiftCarDoorCommand, LiftCarDriveStatus, LiftCarMode, \ + LandingDoorStatus, StageLimitValue, NameValueCollection, Relationship, \ + TimerState, TimerStateChangeValue, TimerTransition from .apdu import EventNotificationParameters, ReadAccessSpecification, \ ReadAccessResult @@ -470,6 +478,8 @@ class Object(object): , OptionalProperty('description', CharacterString) , OptionalProperty('profileName', CharacterString) , ReadableProperty('propertyList', ArrayOf(PropertyIdentifier)) + , OptionalProperty('auditLevel', AuditLevel) + , OptionalProperty('auditableOperations', AuditOperationFlags) , OptionalProperty('tags', ArrayOf(NameValue)) , OptionalProperty('profileLocation', CharacterString) , OptionalProperty('profileName', CharacterString) @@ -713,7 +723,7 @@ class AccessCredentialObject(Object): , ReadableProperty('reasonForDisable', ListOf(AccessCredentialDisableReason)) , ReadableProperty('authenticationFactors', ArrayOf(CredentialAuthenticationFactor)) , ReadableProperty('activationTime', DateTime) - , ReadableProperty('expiryTime', DateTime) + , ReadableProperty('expirationTime', DateTime) , ReadableProperty('credentialDisable', AccessCredentialDisable) , OptionalProperty('daysRemaining', Integer) , OptionalProperty('usesRemaining', Integer) @@ -764,12 +774,20 @@ class AccessDoorObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) + , OptionalProperty('timeDelayNormal', Unsigned) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -817,9 +835,9 @@ class AccessPointObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) @@ -854,7 +872,8 @@ class AccessUserObject(Object): , OptionalProperty('members', ListOf(DeviceObjectReference)) , OptionalProperty('memberOf', ListOf(DeviceObjectReference)) , ReadableProperty('credentials', ListOf(DeviceObjectReference)) - ] + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + ] @register_object_type class AccessZoneObject(Object): @@ -886,9 +905,9 @@ class AccessZoneObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) @@ -925,14 +944,16 @@ class AccumulatorObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('faultHighLimit', Unsigned) + , OptionalProperty('faultLowLimit', Unsigned) ] @register_object_type @@ -946,9 +967,9 @@ class AlertEnrollmentObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) ] @@ -980,14 +1001,17 @@ class AnalogInputObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('interfaceValue', OptionalReal) + , OptionalProperty('faultHighLimit', Real) + , OptionalProperty('faultLowLimit', Real) ] @register_object_type @@ -1018,14 +1042,21 @@ class AnalogOutputObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('interfaceValue', OptionalReal) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1055,14 +1086,79 @@ class AnalogValueObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('minPresValue', Real) + , OptionalProperty('maxPresValue', Real) + , OptionalProperty('resolution', Real) + , OptionalProperty('faultHighLimit', Real) + , OptionalProperty('faultLowLimit', Real) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) + ] + +@register_object_type +class AuditLogObject(Object): + objectType = 'analogLog' + + properties = \ + [ ReadableProperty('statusFlags', StatusFlags) + , ReadableProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , WritableProperty('enable', Boolean) + , ReadableProperty('bufferSize', Unsigned) # Unsigned32 + , ReadableProperty('logBuffer', ListOf(AuditLogRecord)) + , ReadableProperty('recordCount', Unsigned) # Unsigned64 + , ReadableProperty('totalRecordCount', Unsigned) # Unsigned64 + , OptionalProperty('memberOf', DeviceObjectReference) + , OptionalProperty('deleteOnForward', Boolean) + , OptionalProperty('issueConfirmedNotifications', Boolean) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + ] + +@register_object_type +class AuditReporterObject(Object): + objectType = 'auditReporter' + + properties = \ + [ ReadableProperty('statusFlags', StatusFlags) + , OptionalProperty('reliability', Reliability) + , ReadableProperty('eventState', EventState) + , ReadableProperty('auditLevel', AuditLevel) + , ReadableProperty('auditSourceReporter', Boolean) + , ReadableProperty('auditableOperations', AuditOperationFlags) + , ReadableProperty('auditablePriorityFilter', PriorityFilter) + , ReadableProperty('issueConfirmedNotifications', Boolean) + , OptionalProperty('monitoredObjects', ArrayOf(ObjectSelector)) + , OptionalProperty('maximumSendDelay', Unsigned) + , OptionalProperty('sendNow', Boolean) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) ] @register_object_type @@ -1108,14 +1204,54 @@ class BinaryInputObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('interfaceValue', OptionalBinaryPV) + ] + +@register_object_type +class BinaryLightingOutputObject(Object): + objectType = 'binaryLightingOutputObject' + + properties = \ + [ WritableProperty('presentValue', BinaryLightingPV) + , ReadableProperty('statusFlags', StatusFlags) + , OptionalProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , ReadableProperty('outOfService', Boolean) + , ReadableProperty('blinkWarnEnable', Boolean) + , ReadableProperty('egressTime', Unsigned) + , ReadableProperty('egressActive', Boolean) + , OptionalProperty('feedbackValue', BinaryLightingPV) + , ReadableProperty('priorityArray', PriorityArray) + , ReadableProperty('relinquishDefault', BinaryLightingPV) + , OptionalProperty('power', Real) + , OptionalProperty('polarity', Polarity) + , OptionalProperty('elapsedActiveTime', Unsigned) # Unsigned32 + , OptionalProperty('timeOfActiveTimeReset', DateTime) + , OptionalProperty('strikeCount', Unsigned) + , OptionalProperty('timeOfStrikeCountReset', DateTime) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , ReadableProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1148,14 +1284,21 @@ class BinaryOutputObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('interfaceValue', OptionalBinaryPV) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1186,14 +1329,20 @@ class BinaryValueObject(Object): , OptionalProperty('eventEnable',EventTransitionBits) , OptionalProperty('ackedTransitions',EventTransitionBits) , OptionalProperty('notifyType',NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1215,14 +1364,20 @@ class BitStringValueObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1254,12 +1409,15 @@ class ChannelObject(Object): , OptionalProperty('eventState', EventState) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] + @register_object_type class CharacterStringValueObject(Object): objectType = 'characterstringValue' @@ -1280,14 +1438,20 @@ class CharacterStringValueObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1299,6 +1463,19 @@ class CommandObject(Object): , ReadableProperty('allWritesSuccessful', Boolean) , ReadableProperty('action', ArrayOf(ActionList)) , OptionalProperty('actionText', ArrayOf(CharacterString)) + , ReadableProperty('statusFlags', StatusFlags) + , OptionalProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('valueSource', ValueSource) ] @register_object_type @@ -1319,9 +1496,9 @@ class CredentialDataInputObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) ] @@ -1338,6 +1515,21 @@ class DatePatternValueObject(Object): , OptionalProperty('outOfService', Boolean) , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', Date) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1353,6 +1545,21 @@ class DateValueObject(Object): , OptionalProperty('outOfService', Boolean) , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', Date) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1366,9 +1573,26 @@ class DateTimePatternValueObject(Object): , OptionalProperty('eventState', EventState) , OptionalProperty('reliability', Reliability) , OptionalProperty('outOfService', Boolean) + , OptionalProperty('isUtc', Boolean) + , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', DateTime) - , OptionalProperty('isUtc', Boolean) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1385,6 +1609,21 @@ class DateTimeValueObject(Object): , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', DateTime) , OptionalProperty('isUtc', Boolean) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1441,6 +1680,67 @@ class DeviceObject(Object): , OptionalProperty('alignIntervals', Boolean) , OptionalProperty('intervalOffset', Unsigned) , OptionalProperty('serialNumber', CharacterString) + , ReadableProperty('statusFlags', StatusFlags) + , OptionalProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('activeCovMultipleSubscriptions', ListOf(COVMultipleSubscription)) + , OptionalProperty('auditNotificationRecipient', Recipient) + , OptionalProperty('deviceUUID', OctetString) # size 16 + , OptionalProperty('deployedProfileLocation', CharacterString) + ] + +@register_object_type +class ElevatorGroupObject(Object): + objectType = 'elevatorGroup' + properties = \ + [ ReadableProperty('machineRoomID', ObjectIdentifier) + , ReadableProperty('groupID', Unsigned8) + , ReadableProperty('groupMembers', ArrayOf(ObjectIdentifier)) + , OptionalProperty('groupMode', LiftGroupMode) + , OptionalProperty('landingCalls', ListOf(LandingCallStatus)) + , OptionalProperty('landingCallControl', LandingCallStatus) + ] + +@register_object_type +class EscalatorObject(Object): + objectType = 'escalator' + properties = \ + [ ReadableProperty('statusFlags', StatusFlags) + , ReadableProperty('elevatorGroup', ObjectIdentifier) + , ReadableProperty('groupID', Unsigned8) + , ReadableProperty('installationID', Unsigned8) + , OptionalProperty('powerMode', Boolean) + , ReadableProperty('operationDirection', EscalatorOperationDirection) + , OptionalProperty('escalatorMode', EscalatorMode) + , OptionalProperty('energyMeter', Real) + , OptionalProperty('energyMeterRef', DeviceObjectReference) + , OptionalProperty('reliability', Reliability) + , OptionalProperty('outOfService', Boolean) + , OptionalProperty('faultSignals', ListOf(LiftFault)) + , ReadableProperty('passengerAlarm', Boolean) + , OptionalProperty('timeDelay', Unsigned) + , OptionalProperty('timeDelayNormal', Unsigned) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('eventState', EventState) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventAlgorithmInhibit', Boolean) + , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) ] @register_object_type @@ -1455,9 +1755,9 @@ class EventEnrollmentObject(Object): , ReadableProperty('eventEnable', EventTransitionBits) , ReadableProperty('ackedTransitions', EventTransitionBits) , ReadableProperty('notificationClass', Unsigned) - , ReadableProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , ReadableProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) @@ -1506,12 +1806,13 @@ class EventLogObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) ] #----- @@ -1552,9 +1853,9 @@ class GlobalGroupObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) @@ -1596,9 +1897,9 @@ class IntegerValueObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) @@ -1607,6 +1908,14 @@ class IntegerValueObject(Object): , OptionalProperty('minPresValue', Integer) , OptionalProperty('maxPresValue', Integer) , OptionalProperty('resolution', Integer) + , OptionalProperty('faultHighLimit', Integer) + , OptionalProperty('faultLowLimit', Integer) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1633,9 +1942,9 @@ class LargeAnalogValueObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) @@ -1644,6 +1953,14 @@ class LargeAnalogValueObject(Object): , OptionalProperty('minPresValue', Double) , OptionalProperty('maxPresValue', Double) , OptionalProperty('resolution', Double) + , OptionalProperty('faultHighLimit', Double) + , OptionalProperty('faultLowLimit', Double) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1669,9 +1986,9 @@ class LifeSafetyPointObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) @@ -1684,6 +2001,8 @@ class LifeSafetyPointObject(Object): , OptionalProperty('directReading', Real) , OptionalProperty('units', EngineeringUnits) , OptionalProperty('memberOf', ListOf(DeviceObjectReference)) + , OptionalProperty('floorNumber', Unsigned8) + , OptionalProperty('valueSource', ValueSource) ] @register_object_type @@ -1709,9 +2028,9 @@ class LifeSafetyZoneObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) @@ -1722,8 +2041,62 @@ class LifeSafetyZoneObject(Object): , OptionalProperty('maintenanceRequired', Boolean) , ReadableProperty('zoneMembers', ListOf(DeviceObjectReference)) , OptionalProperty('memberOf', ListOf(DeviceObjectReference)) + , OptionalProperty('floorNumber', Unsigned8) + , OptionalProperty('valueSource', ValueSource) ] +@register_object_type +class LiftObject(Object): + objectType = 'lift' + + properties = \ + [ ReadableProperty('trackingValue', Real) + , ReadableProperty('statusFlags', StatusFlags) + , ReadableProperty('elevatorGroup', ObjectIdentifier) + , ReadableProperty('groupID', Unsigned8) + , ReadableProperty('installationID', Unsigned8) + , OptionalProperty('floorText', ArrayOf(CharacterString)) + , OptionalProperty('carDoorText', ArrayOf(CharacterString)) + , OptionalProperty('assignedLandingCalls', ArrayOf(AssignedLandingCalls)) + , OptionalProperty('makingCarCall', ArrayOf(Unsigned8)) + , OptionalProperty('registeredCarCall', ArrayOf(LiftCarCallList)) + , OptionalProperty('carPosition', Unsigned8) + , OptionalProperty('carMovingDirection', LiftCarDirection) + , OptionalProperty('carAssignedDirection', LiftCarDirection) + , OptionalProperty('carDoorStatus', ArrayOf(DoorStatus)) + , OptionalProperty('carDoorCommand', ArrayOf(LiftCarDoorCommand)) + , OptionalProperty('carDoorZone', Boolean) + , OptionalProperty('carMode', LiftCarMode) + , OptionalProperty('carLoad', Real) + , OptionalProperty('carLoadUnits', EngineeringUnits) + , OptionalProperty('nextStoppingFloor', Unsigned) + , ReadableProperty('passengerAlarm', Boolean) + , OptionalProperty('timeDelay', Unsigned) + , OptionalProperty('timeDelayNormal', Unsigned) + , OptionalProperty('energyMeter', Real) + , OptionalProperty('energyMeterRef', DeviceObjectReference) + , OptionalProperty('reliability', Reliability) + , OptionalProperty('outOfService', Boolean) + , OptionalProperty('carDriveStatus', LiftCarDriveStatus) + , OptionalProperty('faultSignals', ListOf(LiftFault)) + , OptionalProperty('landingDoorStatus', ArrayOf(LandingDoorStatus)) + , OptionalProperty('higherDeck', ObjectIdentifier) + , OptionalProperty('lowerDeck', ObjectIdentifier) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('eventState', EventState) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) + , OptionalProperty('eventAlgorithmInhibit', Boolean) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + ] + + @register_object_type class LightingOutputObject(Object): objectType = 'lightingOutput' @@ -1754,6 +2127,12 @@ class LightingOutputObject(Object): , ReadableProperty('lightingCommandDefaultPriority', Unsigned) , OptionalProperty('covIncrement', Real) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1782,14 +2161,15 @@ class LoadControlObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('valueSource', ValueSource) ] @register_object_type @@ -1830,14 +2210,15 @@ class LoopObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('lowDiffLimit', OptionalReal) ] @register_object_type @@ -1861,14 +2242,15 @@ class MultiStateInputObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('interfaceValue', OptionalUnsigned) ] @register_object_type @@ -1893,14 +2275,21 @@ class MultiStateOutputObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('interfaceValue', OptionalUnsigned) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1925,14 +2314,19 @@ class MultiStateValueObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1953,7 +2347,6 @@ class NetworkPortObject(Object): , ReadableProperty('apduLength', Unsigned) #388 , ReadableProperty('linkSpeed', Real) #420 , OptionalProperty('linkSpeeds', ArrayOf(Real)) #421 - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) #130 , OptionalProperty('linkSpeedAutonegotiate', Boolean) #422 , OptionalProperty('networkInterfaceName', CharacterString) #424 , OptionalProperty('bacnetIPMode', IPMode) #408 @@ -1994,14 +2387,14 @@ class NetworkPortObject(Object): , OptionalProperty('slaveAddressBinding', ListOf(AddressBinding)) #171 , OptionalProperty('virtualMACAddressTable', ListOf(VMACEntry)) #429 , OptionalProperty('routingTable', ListOf(RouterEntry)) #428 - , OptionalProperty('eventDetectionEnabled', Boolean) #353 + , OptionalProperty('eventDetectionEnable', Boolean) #353 , OptionalProperty('notificationClass', Unsigned) #17 , OptionalProperty('eventEnable', EventTransitionBits) #35 , OptionalProperty('ackedTransitions', EventTransitionBits) #0 , OptionalProperty('notifyType', NotifyType) #72 - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) #130 - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) #351 - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) #352 + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventState', EventState) #36 , ReadableProperty('reliabilityEvaluationInhibit', Boolean) #357 ] @@ -2031,6 +2424,17 @@ class NotificationClassObject(Object): , ReadableProperty('priority', ArrayOf(Unsigned)) , ReadableProperty('ackRequired', EventTransitionBits) , ReadableProperty('recipientList', ListOf(Destination)) + , OptionalProperty('statusFlags', StatusFlags) + , OptionalProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , ReadableProperty('reliabilityEvaluationInhibit', Boolean) ] @register_object_type @@ -2061,6 +2465,12 @@ class OctetStringValueObject(Object): , OptionalProperty('outOfService', Boolean) , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', OctetString) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -2087,9 +2497,9 @@ class PositiveIntegerValueObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) @@ -2098,6 +2508,14 @@ class PositiveIntegerValueObject(Object): , OptionalProperty('minPresValue', Unsigned) , OptionalProperty('maxPresValue', Unsigned) , OptionalProperty('resolution', Unsigned) + , OptionalProperty('faultHighLimit', Unsigned) + , OptionalProperty('faultLowLimit', Unsigned) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -2118,9 +2536,9 @@ class ProgramObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) ] @@ -2154,9 +2572,9 @@ class PulseConverterObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) @@ -2184,12 +2602,43 @@ class ScheduleObject(Object): , ReadableProperty('eventState', EventState) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) ] +@register_object_type +class StagingObject(Object): + objectType = 'staging' + properties = \ + [ WritableProperty('presentValue', Real) + , ReadableProperty('presentStage', Unsigned) + , ReadableProperty('stages', ArrayOf(StageLimitValue)) + , OptionalProperty('stageNames', ArrayOf(CharacterString)) + , ReadableProperty('statusFlags', StatusFlags) + , ReadableProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , ReadableProperty('outOfService', Boolean) + , ReadableProperty('units', EngineeringUnits) + , ReadableProperty('targetReferences', ArrayOf(DeviceObjectReference)) + , ReadableProperty('priorityForWriting', Unsigned) # 1..16 + , OptionalProperty('defaultPresentValue', Real) + , ReadableProperty('minPresValue', Real) + , ReadableProperty('maxPresValue', Real) + , OptionalProperty('covIncrement', Real) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('valueSource', ValueSource) + ] + @register_object_type class StructuredViewObject(Object): objectType = 'structuredView' @@ -2198,6 +2647,11 @@ class StructuredViewObject(Object): , OptionalProperty('nodeSubtype', CharacterString) , ReadableProperty('subordinateList', ArrayOf(DeviceObjectReference)) , OptionalProperty('subordinateAnnotations', ArrayOf(CharacterString)) + , OptionalProperty('subordinateTags', ArrayOf(NameValueCollection)) + , OptionalProperty('subordinateNodeTypes', ArrayOf(NodeType)) + , OptionalProperty('subordinateRelationships', ArrayOf(Relationship)) + , OptionalProperty('defaultSubordinateRelationship', Relationship) + , OptionalProperty('represents', DeviceObjectReference) ] @register_object_type @@ -2213,6 +2667,21 @@ class TimePatternValueObject(Object): , OptionalProperty('outOfService', Boolean) , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', Time) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -2228,6 +2697,59 @@ class TimeValueObject(Object): , OptionalProperty('outOfService', Boolean) , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', Time) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) + ] + +@register_object_type +class TimerObject(Object): + objectType = 'timer' + + properties = \ + [ ReadableProperty('presentValue', Unsigned) + , ReadableProperty('statusFlags', StatusFlags) + , OptionalProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , OptionalProperty('outOfService', Boolean) + , ReadableProperty('timerState', TimerState) + , ReadableProperty('timerRunning', Boolean) + , OptionalProperty('updateTime', DateTime) + , OptionalProperty('lastStateChange', TimerTransition) + , OptionalProperty('expirationTime', DateTime) + , OptionalProperty('initialTimeout', Unsigned) + , OptionalProperty('defaultTimeout', Unsigned) + , OptionalProperty('minPresValue', Unsigned) + , OptionalProperty('maxPresValue', Unsigned) + , OptionalProperty('resolution', Unsigned) + , OptionalProperty('stateChangeValues', ArrayOf(TimerStateChangeValue, 7)) + , OptionalProperty('listOfObjectPropertyReferences', ListOf(DeviceObjectPropertyReference)) + , OptionalProperty('priorityForWriting', Unsigned) # 1..16 + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('timeDelay', Unsigned) + , OptionalProperty('timeDelayNormal', Unsigned) + , OptionalProperty('alarmValues', ListOf(TimerState)) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) + , OptionalProperty('eventAlgorithmInhibit', Boolean) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) ] @register_object_type @@ -2263,9 +2785,9 @@ class TrendLogObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) @@ -2300,9 +2822,9 @@ class TrendLogMultipleObject(Object): , OptionalProperty('eventEnable', EventTransitionBits) , OptionalProperty('ackedTransitions', EventTransitionBits) , OptionalProperty('notifyType', NotifyType) - , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp)) - , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString)) - , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString)) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) diff --git a/py34/bacpypes/basetypes.py b/py34/bacpypes/basetypes.py index c2dd232f..6bcaec25 100755 --- a/py34/bacpypes/basetypes.py +++ b/py34/bacpypes/basetypes.py @@ -8,8 +8,8 @@ from .errors import MissingRequiredParameter from .primitivedata import Atomic, BitString, Boolean, CharacterString, Date, Double, \ - Enumerated, Integer, Null, ObjectIdentifier, OctetString, Real, Time, \ - Unsigned, Unsigned16, Tag + Enumerated, Integer, Null, ObjectType, ObjectIdentifier, OctetString, Real, Time, \ + Unsigned, Unsigned8, Unsigned16, Tag from .constructeddata import Any, AnyAtomic, ArrayOf, Choice, Element, \ Sequence, SequenceOf @@ -21,6 +21,28 @@ # Bit Strings # +class AuditOperationFlags(BitString): + vendor_range = (32, 63) + bitNames = \ + { 'read':0 + , 'write':1 + , 'create':2 + , 'delete':3 + , 'lifeSafety':4 + , 'acknowledgeAlarm':5 + , 'deviceDisableComm':6 + , 'deviceEnableComm':7 + , 'deviceReset':8 + , 'deviceBackup':9 + , 'deviceRestore':10 + , 'subscription':11 + , 'notification':12 + , 'auditingFailure':13 + , 'networkChanges':14 + , 'general':15 + } + bitLen = 16 + class DaysOfWeek(BitString): bitNames = \ { 'monday':0 @@ -116,6 +138,27 @@ class ObjectTypesSupported(BitString): } bitLen = 55 +class PriorityFilter(BitString): + bitNames = \ + { 'manualLifeSafety':0 + , 'automaticLifeSafety':1 + , 'priority3':2 + , 'priority4':3 + , 'criticalEquipmentControls':4 + , 'minimumOnOff':5 + , 'priority7':6 + , 'manualOperator':7 + , 'priority9':8 + , 'priority10':9 + , 'priority11':10 + , 'priority12':11 + , 'priority13':12 + , 'priority14':13 + , 'priority15':14 + , 'priority16':15 + } + bitLen = 16 + class ResultFlags(BitString): bitNames = \ { 'firstItem':0 @@ -329,6 +372,36 @@ class Action(Enumerated): , 'reverse':1 } +class AuditLevel(Enumerated): + vendor_range = (128, 255) + enumerations = \ + { 'none':0 + , 'auditAll':1 + , 'auditConfig':2 + , 'default':3 + } + +class AuditOperation(Enumerated): + vendor_range = (32, 63) + enumerations = \ + { 'read':0 + , 'write':1 + , 'create':2 + , 'delete':3 + , 'lifeSafety':4 + , 'acknowledgeAlarm':5 + , 'deviceDisableComm':6 + , 'deviceEnableComm':7 + , 'deviceReset':8 + , 'deviceBackup':9 + , 'deviceRestore':10 + , 'subscription':11 + , 'notification':12 + , 'auditingFailure':13 + , 'networkChanges':14 + , 'general':15 + } + class AuthenticationFactorType(Enumerated): enumerations = \ { 'undefined':0 @@ -403,6 +476,17 @@ class BackupState(Enumerated): , 'restoreFailure':6 } +class BinaryLightingPV(Enumerated): + vendor_range = (64, 255) + enumerations = \ + { 'off':0 + , 'on':1 + , 'warn':2 + , 'warn-off':3 + , 'warn-relinquish':4 + , 'stop':5 + } + class BinaryPV(Enumerated): enumerations = \ { 'inactive':0 @@ -872,6 +956,28 @@ class ErrorCode(Enumerated): , 'writeBdtFailed':116 } +class EscalatorMode(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'unknown':0 + , 'stop':1 + , 'up':2 + , 'down':3 + , 'inspection':4 + , 'outOfService':5 + } + +class EscalatorOperationDirection(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'unknown':0 + , 'stopped':1 + , 'upRatedSpeed':2 + , 'upReducedSpeed':3 + , 'downRatedSpeed':4 + , 'downReducedSpeed':5 + } + class EventState(Enumerated): vendor_range = (64, 65535) enumerations = \ @@ -923,6 +1029,91 @@ class FileAccessMethod(Enumerated): , 'streamAccess':1 } +class LiftCarDirection(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'unknown':0 + , 'none':1 + , 'stopped':2 + , 'up':3 + , 'down':4 + , 'upAndDown':5 + } + +class LiftCarDoorCommand(Enumerated): + enumerations = \ + { 'none':0 + , 'open':1 + , 'close':2 + } + +class LiftCarDriveStatus(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'unknown':0 + , 'stationary':1 + , 'braking':2 + , 'accelerate':3 + , 'decelerate':4 + , 'ratedSpeed':5 + , 'singleFloorJump':6 + , 'twoFloorJump':7 + , 'threeFloorJump':8 + , 'multiFloorJump':9 + } + +class LiftCarMode(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'unknown':0 + , 'normal':1 + , 'vip':2 + , 'homing':3 + , 'parking':4 + , 'attendantControl':5 + , 'firefighterControl':6 + , 'emergencyPower':7 + , 'inspection':8 + , 'cabinetRecall':9 + , 'earthquakeOperation':10 + , 'fireOperation':11 + , 'outOfService':12 + , 'occupantEvacuation':13 + } + +class LiftFault(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'controllerFault':0 + , 'driveAndMotorFault':1 + , 'governorAndSafetyGearFault':2 + , 'liftShaftDeviceFault':3 + , 'powerSupplyFault':4 + , 'safetyInterlockFault':5 + , 'doorClosingFault':6 + , 'doorOpeningFault':7 + , 'carStoppedOutsideLandingZone':8 + , 'callButtonStuck':9 + , 'startFailure':10 + , 'controllerSupplyFault':11 + , 'selfTestFailure':12 + , 'runtimeLimitExceeded':13 + , 'positionLost':14 + , 'driveTemperatureExceeded':15 + , 'loadMeasurementFault':16 + } + +class LiftGroupMode(Enumerated): + enumerations = \ + { 'unknown':0 + , 'normal':1 + , 'downPeak':2 + , 'twoWay':3 + , 'fourWay':4 + , 'emergencyPower':5 + , 'upPeak':6 + } + class LifeSafetyMode(Enumerated): enumerations = \ { 'off':0 @@ -1103,50 +1294,9 @@ class ProgramState(Enumerated): } class PropertyIdentifier(Enumerated): - # TODO: Sort Alphabetically vendor_range = (512, 4194303) enumerations = \ { 'absenteeLimit':244 - , 'tags':486 - , 'profileLocation':91 - , 'eventDetectionEnabled':353 - , 'apduLength':388 - , 'linkSpeed':420 - , 'linkSpeeds':421 - , 'linkSpeedAutonegotiate':422 - , 'networkInterfaceName':424 - , 'bacnetIPMode':408 - , 'ipAddress':400 - , 'bacnetIPUDPPort':412 - , 'ipSubnetMask':411 - , 'ipDefaultGateway':401 - , 'bacnetIPMulticastAddress':409 - , 'ipDNSServer':406 - , 'ipDHCPEnable':402 - , 'ipDHCPLeaseTime':403 - , 'ipDHCPLeaseTimeRemaining':404 - , 'ipDHCPServer':405 - , 'bacnetIPNATTraversal':410 - , 'bacnetIPGlobalAddress':407 - , 'bbmdBroadcastDistributionTable':414 - , 'bbmdAcceptFDRegistrations':413 - , 'bbmdForeignDeviceTable':415 - , 'fdBBMDAddress':418 - , 'fdSubscriptionLifetime':419 - , 'bacnetIPv6Mode':435 - , 'ipv6Address':436 - , 'ipv6PrefixLength':437 - , 'bacnetIPv6UDPPort':438 - , 'ipv6DefaultGateway':439 - , 'bacnetIPv6MulticastAddress':440 - , 'ipv6DNSServer':441 - , 'ipv6AutoAddressingEnabled':442 - , 'ipv6DHCPLeaseTime':443 - , 'ipv6DHCPLeaseTimeRemaining':444 - , 'ipv6DHCPServer':445 - , 'ipv6ZoneIndex':446 - , 'virtualMACAddressTable':429 - , 'routingTable':428 , 'acceptedModes':175 , 'accessAlarmEvents':245 , 'accessDoors':246 @@ -1158,12 +1308,13 @@ class PropertyIdentifier(Enumerated): , 'accessTransactionEvents':251 , 'accompaniment':252 , 'accompanimentTime':253 - , 'ackRequired':1 , 'ackedTransitions':0 + , 'ackRequired':1 , 'action':2 , 'actionText':3 , 'activationTime':254 , 'activeAuthenticationPolicy':255 + , 'activeCovMultipleSubscriptions':481 , 'activeCovSubscriptions':152 , 'activeText':4 , 'activeVtSessions':5 @@ -1173,14 +1324,21 @@ class PropertyIdentifier(Enumerated): , 'alarmValues':7 , 'alignIntervals':193 , 'all':8 - , 'allWritesSuccessful':9 , 'allowGroupDelayInhibit':365 + , 'allWritesSuccessful':9 + , 'apduLength':388 , 'apduSegmentTimeout':10 , 'apduTimeout':11 , 'applicationSoftwareVersion':12 , 'archive':13 , 'assignedAccessRights':256 + , 'assignedLandingCalls':447 , 'attemptedSamples':124 + , 'auditableOperations':501 + , 'auditablePriorityFilter':500 + , 'auditLevel':498 + , 'auditNotificationRecipient':499 + , 'auditSourceReporter':497 , 'authenticationFactors':257 , 'authenticationPolicyList':258 , 'authenticationPolicyNames':259 @@ -1192,19 +1350,42 @@ class PropertyIdentifier(Enumerated): , 'backupAndRestoreState':338 , 'backupFailureTimeout':153 , 'backupPreparationTime':339 + , 'bacnetIPGlobalAddress':407 + , 'bacnetIPMode':408 + , 'bacnetIPMulticastAddress':409 + , 'bacnetIPNATTraversal':410 + , 'bacnetIPUDPPort':412 + , 'bacnetIPv6Mode':435 + , 'bacnetIPv6MulticastAddress':440 + , 'bacnetIPv6UDPPort':438 , 'baseDeviceSecurityPolicy':327 + , 'bbmdAcceptFDRegistrations':413 + , 'bbmdBroadcastDistributionTable':414 + , 'bbmdForeignDeviceTable':415 , 'belongsTo':262 , 'bias':14 , 'bitMask':342 , 'bitText':343 , 'blinkWarnEnable':373 , 'bufferSize':126 + , 'carAssignedDirection':448 + , 'carDoorCommand':449 + , 'carDoorStatus':450 + , 'carDoorText':451 + , 'carDoorZone':452 + , 'carDriveStatus':453 + , 'carLoad':454 + , 'carLoadUnits':455 + , 'carMode':456 + , 'carMovingDirection':457 + , 'carPosition':458 , 'changeOfStateCount':15 , 'changeOfStateTime':16 , 'changesPending':416 , 'channelNumber':366 , 'clientCovIncrement':127 , 'command':417 + , 'commandTimeArray':430 , 'configurationFiles':154 , 'controlGroups':367 , 'controlledVariableReference':19 @@ -1219,23 +1400,30 @@ class PropertyIdentifier(Enumerated): , 'covuPeriod':349 , 'covuRecipients':350 , 'credentialDisable':263 - , 'credentialStatus':264 , 'credentials':265 , 'credentialsInZone':266 + , 'credentialStatus':264 + , 'currentCommandPriority':431 , 'databaseRevision':155 , 'dateList':23 , 'daylightSavingsStatus':24 , 'daysRemaining':267 , 'deadband':25 , 'defaultFadeTime':374 + , 'defaultPresentValue':492 , 'defaultRampRate':375 , 'defaultStepIncrement':376 + , 'defaultSubordinateRelationship':490 + , 'defaultTimeout':393 + , 'deleteOnForward':502 + , 'deployedProfileLocation':484 , 'derivativeConstant':26 , 'derivativeConstantUnits':27 , 'description':28 , 'descriptionOfHalt':29 , 'deviceAddressBinding':30 , 'deviceType':31 + , 'deviceUUID':507 , 'directReading':156 , 'distributionKeyRevision':328 , 'doNotHide':329 @@ -1251,54 +1439,93 @@ class PropertyIdentifier(Enumerated): , 'egressActive':386 , 'egressTime':377 , 'elapsedActiveTime':33 - , 'entryPoints':268 + , 'elevatorGroup':459 , 'enable':133 + , 'energyMeter':460 + , 'energyMeterRef':461 + , 'entryPoints':268 , 'errorLimit':34 + , 'escalatorMode':462 , 'eventAlgorithmInhibit':354 , 'eventAlgorithmInhibitRef':355 , 'eventDetectionEnable':353 , 'eventEnable':35 , 'eventMessageTexts':351 , 'eventMessageTextsConfig':352 + , 'eventParameters':83 , 'eventState':36 , 'eventTimeStamps':130 , 'eventType':37 - , 'eventParameters':83 , 'exceptionSchedule':38 , 'executionDelay':368 , 'exitPoints':269 , 'expectedShedLevel':214 - , 'expiryTime':270 + , 'expirationTime':270 , 'extendedTimeEnable':271 , 'failedAttemptEvents':272 , 'failedAttempts':273 , 'failedAttemptsTime':274 + , 'faultHighLimit':388 + , 'faultLowLimit':389 , 'faultParameters':358 + , 'faultSignals':463 , 'faultType':359 , 'faultValues':39 + , 'fdBBMDAddress':418 + , 'fdSubscriptionLifetime':419 , 'feedbackValue':40 , 'fileAccessMethod':41 , 'fileSize':42 , 'fileType':43 , 'firmwareRevision':44 + , 'floorNumber':506 + , 'floorText':464 , 'fullDutyBaseline':215 , 'globalIdentifier':323 - , 'groupMembers':345 + , 'groupID':465 , 'groupMemberNames':346 + , 'groupMembers':345 + , 'groupMode':467 + , 'higherDeck':468 , 'highLimit':45 , 'inactiveText':46 + , 'initialTimeout':394 , 'inProcess':47 , 'inProgress':378 , 'inputReference':181 + , 'installationID':469 , 'instanceOf':48 , 'instantaneousPower':379 , 'integralConstant':49 , 'integralConstantUnits':50 + , 'interfaceValue':387 , 'intervalOffset':195 + , 'ipAddress':400 + , 'ipDefaultGateway':401 + , 'ipDHCPEnable':402 + , 'ipDHCPLeaseTime':403 + , 'ipDHCPLeaseTimeRemaining':404 + , 'ipDHCPServer':405 + , 'ipDNSServer':406 + , 'ipSubnetMask':411 + , 'ipv6Address':436 + , 'ipv6AutoAddressingEnabled':442 + , 'ipv6DefaultGateway':439 + , 'ipv6DHCPLeaseTime':443 + , 'ipv6DHCPLeaseTimeRemaining':444 + , 'ipv6DHCPServer':445 + , 'ipv6DNSServer':441 + , 'ipv6PrefixLength':437 + , 'ipv6ZoneIndex':446 + , 'issueConfirmedNotifications':51 , 'isUtc':344 , 'keySets':330 + , 'landingCallControl':471 + , 'landingCalls': 470 + , 'landingDoorStatus':472 , 'lastAccessEvent':275 , 'lastAccessPoint':276 + , 'lastCommandTime':432 , 'lastCredentialAdded':277 , 'lastCredentialAddedTime':278 , 'lastCredentialRemoved':279 @@ -1308,12 +1535,16 @@ class PropertyIdentifier(Enumerated): , 'lastPriority':369 , 'lastRestartReason':196 , 'lastRestoreTime':157 + , 'lastStateChange':395 , 'lastUseTime':281 , 'lifeSafetyAlarmValues':166 , 'lightingCommand':380 , 'lightingCommandDefaultPriority':381 , 'limitEnable':52 , 'limitMonitoringInterval':182 + , 'linkSpeed':420 + , 'linkSpeedAutonegotiate':422 + , 'linkSpeeds':421 , 'listOfGroupMembers':53 , 'listOfObjectPropertyReferences':54 , 'listOfSessionKeys':55 @@ -1321,51 +1552,59 @@ class PropertyIdentifier(Enumerated): , 'localForwardingOnly':360 , 'localTime':57 , 'location':58 - , 'lockStatus':233 , 'lockout':282 , 'lockoutRelinquishTime':283 + , 'lockStatus':233 , 'logBuffer':131 , 'logDeviceObjectProperty':132 - , 'logInterval':134 , 'loggingObject':183 , 'loggingRecord':184 , 'loggingType':197 + , 'logInterval':134 + , 'lowDiffLimit':390 + , 'lowerDeck':473 , 'lowLimit':59 , 'macAddress':423 + , 'machineRoomID':474 , 'maintenanceRequired':158 + , 'makingCarCall':475 , 'manipulatedVariableReference':60 , 'manualSlaveAddressBinding':170 , 'maskedAlarmValues':234 , 'masterExemption':284 - , 'maximumOutput':61 - , 'maximumValue':135 - , 'maximumValueTimestamp':149 , 'maxActualValue':382 , 'maxApduLengthAccepted':62 , 'maxFailedAttempts':285 + , 'maximumOutput':61 + , 'maximumSendDelay':503 + , 'maximumValue':135 + , 'maximumValueTimestamp':149 , 'maxInfoFrames':63 , 'maxMaster':64 , 'maxPresValue':65 , 'maxSegmentsAccepted':167 , 'memberOf':159 - , 'memberStatusFlags':347 , 'members':286 + , 'memberStatusFlags':347 + , 'minActualValue':383 , 'minimumOffTime':66 , 'minimumOnTime':67 , 'minimumOutput':68 , 'minimumValue':136 , 'minimumValueTimestamp':150 - , 'minActualValue':383 , 'minPresValue':69 , 'mode':160 , 'modelName':70 , 'modificationDate':71 + , 'monitoredObjects':504 , 'musterPoint':287 , 'negativeAccessRules':288 , 'networkAccessSecurityPolicies':332 + , 'networkInterfaceName':424 , 'networkNumber':425 , 'networkNumberQuality':427 , 'networkType': 427 + , 'nextStoppingFloor':476 , 'nodeSubtype':207 , 'nodeType':208 , 'notificationClass':17 @@ -1388,6 +1627,7 @@ class PropertyIdentifier(Enumerated): , 'occupancyState':296 , 'occupancyUpperLimit':297 , 'occupancyUpperLimitEnforced':298 + , 'operationDirection':477 , 'operationExpected':161 , 'optional':80 , 'outOfService':81 @@ -1396,17 +1636,21 @@ class PropertyIdentifier(Enumerated): , 'passbackExemption':299 , 'passbackMode':300 , 'passbackTimeout':301 + , 'passengerAlarm':478 , 'polarity':84 , 'portFilter':363 , 'positiveAccessRules':302 , 'power':384 + , 'powerMode':479 , 'prescale':185 + , 'presentStage':493 , 'presentValue':85 , 'priority':86 , 'priorityArray':87 , 'priorityForWriting':88 , 'processIdentifier':89 , 'processIdentifierFilter':361 + , 'profileLocation':91 , 'profileName':168 , 'programChange':90 , 'programLocation':91 @@ -1424,12 +1668,14 @@ class PropertyIdentifier(Enumerated): , 'reasonForDisable':303 , 'reasonForHalt':100 , 'recipientList':102 - , 'recordsSinceNotification':140 , 'recordCount':141 + , 'recordsSinceNotification':140 , 'referencePort':483 + , 'registeredCarCall':480 , 'reliability':103 , 'reliabilityEvaluationInhibit':357 , 'relinquishDefault':104 + , 'represents':491 , 'requestedShedLevel':218 , 'requestedUpdateInterval':348 , 'required':105 @@ -1437,6 +1683,7 @@ class PropertyIdentifier(Enumerated): , 'restartNotificationRecipients':202 , 'restoreCompletionTime':340 , 'restorePreparationTime':341 + , 'routingTable':428 , 'scale':187 , 'scaleFactor':188 , 'scheduleDefault':174 @@ -1444,6 +1691,7 @@ class PropertyIdentifier(Enumerated): , 'securityPDUTimeout':334 , 'securityTimeWindow':335 , 'segmentationSupported':107 + , 'sendNow':505 , 'serialNumber':372 , 'setpoint':108 , 'setpointReference':109 @@ -1454,20 +1702,29 @@ class PropertyIdentifier(Enumerated): , 'silenced':163 , 'slaveAddressBinding':171 , 'slaveProxyEnable':172 + , 'stageNames':495 + , 'stages':494 , 'startTime':142 + , 'stateChangeValues':396 , 'stateDescription':222 , 'stateText':110 , 'statusFlags':111 , 'stopTime':143 , 'stopWhenFull':144 + , 'strikeCount':391 , 'structuredObjectList':209 , 'subordinateAnnotations':210 , 'subordinateList':211 + , 'subordinateNodeTypes':487 + , 'subordinateRelationships':489 + , 'subordinateTags':488 , 'subscribedRecipients':362 - , 'supportedFormats':304 , 'supportedFormatClasses':305 + , 'supportedFormats':304 , 'supportedSecurityAlgorithms':336 , 'systemStatus':112 + , 'tags':486 + , 'targetReferences':496 , 'threatAuthority':306 , 'threatLevel':307 , 'timeDelay':113 @@ -1475,6 +1732,9 @@ class PropertyIdentifier(Enumerated): , 'timeOfActiveTimeReset':114 , 'timeOfDeviceRestart':203 , 'timeOfStateCountReset':115 + , 'timeOfStrikeCountReset':392 + , 'timerRunning':397 + , 'timerState':398 , 'timeSynchronizationInterval':204 , 'timeSynchronizationRecipients':116 , 'totalRecordCount':145 @@ -1496,12 +1756,15 @@ class PropertyIdentifier(Enumerated): , 'utcTimeSynchronizationRecipients':206 , 'validSamples':146 , 'valueBeforeChange':190 - , 'valueSet':191 , 'valueChangeTime':192 + , 'valueSet':191 + , 'valueSource':433 + , 'valueSourceArray':434 , 'varianceValue':151 , 'vendorIdentifier':120 , 'vendorName':121 , 'verificationTime':326 + , 'virtualMACAddressTable':429 , 'vtClassesSupported':122 , 'weeklySchedule':123 , 'windowInterval':147 @@ -1512,6 +1775,41 @@ class PropertyIdentifier(Enumerated): , 'zoneTo':321 } +class Relationship(Enumerated): + vendor_range = (1024, 65535) + enumerations = \ + { 'unknown':0 + , 'default':1 + , 'contains':2 + , 'containedBy':3 + , 'uses':4 + , 'usedBy':5 + , 'commands':6 + , 'commandedBy':7 + , 'adjusts':8 + , 'adjustedBy':9 + , 'ingress':10 + , 'egress':11 + , 'suppliesAir':12 + , 'receivesAir':13 + , 'suppliesHotAir':14 + , 'receivesHotAir':15 + , 'suppliesCoolAir':16 + , 'receivesCoolAir':17 + , 'suppliesPower':18 + , 'receivesPower':19 + , 'suppliesGas':20 + , 'receivesGas':21 + , 'suppliesWater':22 + , 'receivesWater':23 + , 'suppliesHotWater':24 + , 'receivesHotWater':25 + , 'suppliesCoolWater':26 + , 'receivesCoolWater':27 + , 'suppliesSteam':28 + , 'receivesSteam':29 + } + class Reliability(Enumerated): vendor_range = (64, 65535) enumerations = \ @@ -1597,6 +1895,25 @@ class SilencedState(Enumerated): , 'allSilenced':3 } +class TimerState(Enumerated): + enumerations = \ + { 'idle':0 + , 'running':1 + , 'expired':2 + } + +class TimerTransition(Enumerated): + enumerations = \ + { 'none':0 + , 'idleToRunning':1 + , 'runningToIdle':2 + , 'runningToRunning':3 + , 'runningToExpired':4 + , 'forcedToExpired':5 + , 'expiredToIdle':6 + , 'expiredToRunning':7 + } + class VTClass(Enumerated): vendor_range = (64, 65535) enumerations = \ @@ -1710,6 +2027,12 @@ class VMACEntry(Sequence): , Element('nativeMACAddress', OctetString) ] +class PropertyReference(Sequence): + sequenceElements = \ + [ Element('propertyIdentifier', PropertyIdentifier, 0) + , Element('propertyArrayIndex', Unsigned, 1, True) + ] + class RouterEntry(Sequence): sequenceElements = \ [ Element('networkNumber', Unsigned16) @@ -1799,6 +2122,11 @@ def decode(self, taglist): taglist.Pop() self.value = tag.app_to_object() +class NameValueCollection(Sequence): + sequenceElements = \ + [ Element('members', SequenceOf(NameValue), 0) + ] + class DeviceAddress(Sequence): sequenceElements = \ [ Element('networkNumber', Unsigned) @@ -1837,6 +2165,36 @@ class ErrorType(Sequence): , Element('errorCode', ErrorCode) ] + +class LandingCallStatusCommand(Choice): + choiceElements = \ + [ Element('direction', LiftCarDirection, 1) + , Element('destination', Unsigned8, 2) + ] + +class LandingCallStatus(Sequence): + sequenceElements = \ + [ Element('floorNumber', Unsigned8, 0) + , Element('command', LandingCallStatusCommand) + , Element('floorText', CharacterString, 3, True) + ] + +class LandingDoorStatusLandingDoor(Sequence): + sequenceElements = \ + [ Element('floorNumber', Unsigned8, 0) + , Element('doorStatus', DoorStatus, 1) + ] + +class LandingDoorStatus(Sequence): + sequenceElements = \ + [ Element('landingDoors', SequenceOf(LandingDoorStatusLandingDoor), 0) + ] + +class LiftCarCallList(Sequence): + sequenceElements = \ + [ Element('floorNumbers', SequenceOf(Unsigned8), 0) + ] + class LightingCommand(Sequence): sequenceElements = \ [ Element('operation', LightingOperation, 0) @@ -1854,6 +2212,36 @@ class ObjectPropertyReference(Sequence): , Element('propertyArrayIndex', Unsigned, 2, True) ] +class OptionalBinaryPV(Choice): + choiceElements = \ + [ Element('null', Null) + , Element('binaryPV', BinaryPV) + ] + +class OptionalCharacterString(Choice): + choiceElements = \ + [ Element('null', Null) + , Element('characterstring', CharacterString) + ] + +class OptionalPriorityFilter(Choice): + choiceElements = \ + [ Element('null', Null) + , Element('filter', PriorityFilter) + ] + +class OptionalReal(Choice): + choiceElements = \ + [ Element('null', Null) + , Element('real', Real) + ] + +class OptionalUnsigned(Choice): + choiceElements = \ + [ Element('null', Null) + , Element('unsigned', Unsigned) + ] + class ProcessIdSelection(Choice): choiceElements = \ [ Element('processIdentifier', Unsigned) @@ -1924,6 +2312,27 @@ class RecipientProcess(Sequence): , Element('processIdentifier', Unsigned, 1) ] +class TimerStateChangeValue(Choice): + choiceElements = \ + [ Element('null', Null) + , Element('boolean', Boolean) + , Element('unsigned', Unsigned) + , Element('integer', Integer) + , Element('real', Real) + , Element('double', Double) + , Element('octetstring', OctetString) + , Element('characterstring', CharacterString) + , Element('bitstring', BitString) + , Element('enumerated', Enumerated) + , Element('date', Date) + , Element('time', Time) + , Element('objectidentifier', ObjectIdentifier) + , Element('noValue', Null, 0) + , Element('constructedValue', Any, 1) + , Element('datetime', DateTime, 2) + , Element('lightingCommand', LightingCommand, 3) + ] + class TimeStamp(Choice): choiceElements = \ [ Element('time', Time, 0) @@ -1988,6 +2397,12 @@ class ActionList(Sequence): [ Element('action', SequenceOf(ActionCommand), 0) ] +class Address(Sequence): + sequenceElements = \ + [ Element('networkNumber', Unsigned16) + , Element('macAddress', OctetString) + ] + class AddressBinding(Sequence): sequenceElements = \ [ Element('deviceObjectIdentifier', ObjectIdentifier) @@ -2001,6 +2416,84 @@ class AssignedAccessRights(Sequence): , Element('enable', Boolean, 1) ] +class AssignedLandingCallsLandingCalls(Sequence): + sequenceElements = \ + [ Element('floorNumber', Unsigned8, 0) + , Element('direction', LiftCarDirection, 1) + ] + +class AssignedLandingCalls(Sequence): + sequenceElements = \ + [ Element('landingCalls', SequenceOf(AssignedLandingCallsLandingCalls), 0) + ] + +class AuditNotification(Sequence): + sequenceElements = \ + [ Element('sourceTimestamp', TimeStamp, 0, True) + , Element('targetTimestamp', TimeStamp, 1, True) + , Element('sourceDevice', Recipient, 2) + , Element('sourceObject', ObjectIdentifier, 3, True) + , Element('operation', AuditOperation, 4) + , Element('sourceComment', CharacterString, 5, True) + , Element('targetComment', CharacterString, 6, True) + , Element('invokeID', Unsigned8, 7, True) + , Element('sourceUserID', Unsigned16, 8, True) + , Element('sourceUserRole', Unsigned8, 9, True) + , Element('targetDevice', Recipient, 10) + , Element('targetObject', ObjectIdentifier, 11, True) + , Element('targetProperty', PropertyReference, 12, True) + , Element('targetPriority', Unsigned, 13, True) # 1..16 + , Element('targetValue', Any, 14, True) + , Element('currentValue', Any, 15, True) + , Element('result', ErrorType, 16, True) + ] + +class AuditLogRecordLogDatum(Choice): + choiceElements = \ + [ Element('logStatus', LogStatus, 0) + , Element('auditNotification', AuditNotification, 1) + , Element('timeChange', Real) + ] + +class AuditLogRecord(Sequence): + sequenceElements = \ + [ Element('timestamp', DateTime, 0) + , Element('logDatum', AuditLogRecordLogDatum, 1) + ] + +class AuditLogRecordResult(Sequence): + sequenceElements = \ + [ Element('sequenceNumber', Unsigned, 0) # Unsigned64 + , Element('logRecord', AuditLogRecord, 1) + ] + +class AuditLogQueryParametersByTarget(Sequence): + sequenceElements = \ + [ Element('targetDeviceIdentifier', ObjectIdentifier, 0) + , Element('targetDeviceAddress', Address, 1, True) + , Element('targetObjectIdentifier', ObjectIdentifier, 2, True) + , Element('targetPropertyIdentifier', PropertyIdentifier, 3, True) + , Element('targetArrayIndex', Unsigned, 4, True) + , Element('targetPriority', Unsigned, 5, True) + , Element('operations', AuditOperationFlags, 6, True) + , Element('successfulActionsOnly', Boolean, 7) + ] + +class AuditLogQueryParametersBySource(Sequence): + sequenceElements = \ + [ Element('sourceDeviceIdentifier', ObjectIdentifier, 0) + , Element('sourceDeviceAddress', Address, 1, True) + , Element('sourceObjectIdentifier', ObjectIdentifier, 2, True) + , Element('operations', AuditOperationFlags, 3, True) + , Element('successfulActionsOnly', Boolean, 4) + ] + +class AuditLogQueryParameters(Choice): + choiceElements = \ + [ Element('byTarget', AuditLogQueryParametersByTarget, 0) + , Element('bySource', AuditLogQueryParametersBySource, 1) + ] + class AuthenticationFactor(Sequence): sequenceElements = \ [ Element('formatType', AuthenticationFactorType, 0) @@ -2059,6 +2552,28 @@ class ClientCOV(Choice): , Element('defaultIncrement', Null) ] +class COVMultipleSubscriptionListOfCOVReference(Sequence): + sequenceElements = \ + [ Element('monitoredProperty', PropertyReference, 0) + , Element('covIncrement', Real, 1, True) + , Element('timestamped', Boolean, 2) + ] + +class COVMultipleSubscriptionList(Sequence): + sequenceElements = \ + [ Element('monitoredObjectIdentifier', ObjectIdentifier, 0) + , Element('listOfCOVReferences', SequenceOf(COVMultipleSubscriptionListOfCOVReference), 1) + ] + +class COVMultipleSubscription(Sequence): + sequenceElements = \ + [ Element('recipient', RecipientProcess, 0) + , Element('issueConfirmedNotifications', Boolean, 1) + , Element('timeRemaining', Unsigned, 2) + , Element('maxNotificationDelay', Unsigned, 3) + , Element('listOfCOVSubscriptionSpecifications', SequenceOf(COVMultipleSubscriptionList), 4) + ] + class COVSubscription(Sequence): sequenceElements = \ [ Element('recipient', RecipientProcess, 0) @@ -2558,6 +3073,13 @@ class ObjectPropertyValue(Sequence): , Element('priority', Unsigned, 4, True) ] +class ObjectSelector(Choice): + choiceElements = \ + [ Element('none', Null) + , Element('object', ObjectIdentifier) + , Element('objectType', ObjectType) + ] + class OptionalCharacterString(Choice): choiceElements = \ [ Element('null', Null) @@ -2615,12 +3137,6 @@ class PropertyAccessResult(Sequence): , Element('accessResult', PropertyAccessResultAccessResult) ] -class PropertyReference(Sequence): - sequenceElements = \ - [ Element('propertyIdentifier', PropertyIdentifier, 0) - , Element('propertyArrayIndex', Unsigned, 1, True) - ] - class Scale(Choice): choiceElements = \ [ Element('floatScale', Real, 0) @@ -2660,6 +3176,21 @@ class SpecialEvent(Sequence): , Element('eventPriority', Unsigned, 3) ] +class StageLimitValue(Sequence): + sequenceElements = \ + [ Element('limit', Real) + , Element('values', BitString) + , Element('deadband', Real) + ] + +class ValueSource(Choice): + choiceElements = \ + [ Element('none', Null, 0) + , Element('object', DeviceObjectReference, 1) + , Element('Address', Address) + ] + + class VTSession(Sequence): sequenceElements = \ [ Element('localVtSessionID', Unsigned) diff --git a/py34/bacpypes/object.py b/py34/bacpypes/object.py index 23fc7b5e..8cab8114 100644 --- a/py34/bacpypes/object.py +++ b/py34/bacpypes/object.py @@ -20,7 +20,8 @@ from .basetypes import AccessCredentialDisable, AccessCredentialDisableReason, \ AccessEvent, AccessPassbackMode, AccessRule, AccessThreatLevel, \ AccessUserType, AccessZoneOccupancyState, AccumulatorRecord, Action, \ - ActionList, AddressBinding, AssignedAccessRights, AuthenticationFactor, \ + ActionList, AddressBinding, AssignedAccessRights, AuditOperationFlags, AuditLevel, \ + AuthenticationFactor, \ AuthenticationFactorFormat, AuthenticationPolicy, AuthenticationStatus, \ AuthorizationException, AuthorizationMode, BackupState, BDTEntry, BinaryPV, \ COVSubscription, CalendarEntry, ChannelValue, ClientCOV, \ @@ -41,7 +42,14 @@ RouterEntry, Scale, SecurityKeySet, SecurityLevel, Segmentation, \ ServicesSupported, SetpointReference, ShedLevel, ShedState, SilencedState, \ SpecialEvent, StatusFlags, TimeStamp, VTClass, VTSession, VMACEntry, \ - WriteStatus + WriteStatus, OptionalUnsigned, PriorityFilter, ValueSource, \ + OptionalPriorityFilter, OptionalReal, AuditNotification, PropertyReference, \ + AuditLogRecord, ObjectSelector, OptionalBinaryPV, BinaryLightingPV, \ + COVMultipleSubscription, LiftGroupMode, LandingCallStatus, LiftCarDirection, \ + EscalatorOperationDirection, EscalatorMode, LiftFault, AssignedLandingCalls, \ + LiftCarCallList, LiftCarDoorCommand, LiftCarDriveStatus, LiftCarMode, \ + LandingDoorStatus, StageLimitValue, NameValueCollection, Relationship, \ + TimerState, TimerStateChangeValue, TimerTransition from .apdu import EventNotificationParameters, ReadAccessSpecification, \ ReadAccessResult @@ -470,6 +478,8 @@ class Object: , OptionalProperty('description', CharacterString) , OptionalProperty('profileName', CharacterString) , ReadableProperty('propertyList', ArrayOf(PropertyIdentifier)) + , OptionalProperty('auditLevel', AuditLevel) + , OptionalProperty('auditableOperations', AuditOperationFlags) , OptionalProperty('tags', ArrayOf(NameValue)) , OptionalProperty('profileLocation', CharacterString) , OptionalProperty('profileName', CharacterString) @@ -713,7 +723,7 @@ class AccessCredentialObject(Object): , ReadableProperty('reasonForDisable', ListOf(AccessCredentialDisableReason)) , ReadableProperty('authenticationFactors', ArrayOf(CredentialAuthenticationFactor)) , ReadableProperty('activationTime', DateTime) - , ReadableProperty('expiryTime', DateTime) + , ReadableProperty('expirationTime', DateTime) , ReadableProperty('credentialDisable', AccessCredentialDisable) , OptionalProperty('daysRemaining', Integer) , OptionalProperty('usesRemaining', Integer) @@ -770,6 +780,14 @@ class AccessDoorObject(Object): , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) + , OptionalProperty('timeDelayNormal', Unsigned) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -854,7 +872,8 @@ class AccessUserObject(Object): , OptionalProperty('members', ListOf(DeviceObjectReference)) , OptionalProperty('memberOf', ListOf(DeviceObjectReference)) , ReadableProperty('credentials', ListOf(DeviceObjectReference)) - ] + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + ] @register_object_type class AccessZoneObject(Object): @@ -933,6 +952,8 @@ class AccumulatorObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('faultHighLimit', Unsigned) + , OptionalProperty('faultLowLimit', Unsigned) ] @register_object_type @@ -988,6 +1009,9 @@ class AnalogInputObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('interfaceValue', OptionalReal) + , OptionalProperty('faultHighLimit', Real) + , OptionalProperty('faultLowLimit', Real) ] @register_object_type @@ -1026,6 +1050,13 @@ class AnalogOutputObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('interfaceValue', OptionalReal) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1063,6 +1094,71 @@ class AnalogValueObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('minPresValue', Real) + , OptionalProperty('maxPresValue', Real) + , OptionalProperty('resolution', Real) + , OptionalProperty('faultHighLimit', Real) + , OptionalProperty('faultLowLimit', Real) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) + ] + +@register_object_type +class AuditLogObject(Object): + objectType = 'analogLog' + + properties = \ + [ ReadableProperty('statusFlags', StatusFlags) + , ReadableProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , WritableProperty('enable', Boolean) + , ReadableProperty('bufferSize', Unsigned) # Unsigned32 + , ReadableProperty('logBuffer', ListOf(AuditLogRecord)) + , ReadableProperty('recordCount', Unsigned) # Unsigned64 + , ReadableProperty('totalRecordCount', Unsigned) # Unsigned64 + , OptionalProperty('memberOf', DeviceObjectReference) + , OptionalProperty('deleteOnForward', Boolean) + , OptionalProperty('issueConfirmedNotifications', Boolean) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + ] + +@register_object_type +class AuditReporterObject(Object): + objectType = 'auditReporter' + + properties = \ + [ ReadableProperty('statusFlags', StatusFlags) + , OptionalProperty('reliability', Reliability) + , ReadableProperty('eventState', EventState) + , ReadableProperty('auditLevel', AuditLevel) + , ReadableProperty('auditSourceReporter', Boolean) + , ReadableProperty('auditableOperations', AuditOperationFlags) + , ReadableProperty('auditablePriorityFilter', PriorityFilter) + , ReadableProperty('issueConfirmedNotifications', Boolean) + , OptionalProperty('monitoredObjects', ArrayOf(ObjectSelector)) + , OptionalProperty('maximumSendDelay', Unsigned) + , OptionalProperty('sendNow', Boolean) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) ] @register_object_type @@ -1116,6 +1212,46 @@ class BinaryInputObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('interfaceValue', OptionalBinaryPV) + ] + +@register_object_type +class BinaryLightingOutputObject(Object): + objectType = 'binaryLightingOutputObject' + + properties = \ + [ WritableProperty('presentValue', BinaryLightingPV) + , ReadableProperty('statusFlags', StatusFlags) + , OptionalProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , ReadableProperty('outOfService', Boolean) + , ReadableProperty('blinkWarnEnable', Boolean) + , ReadableProperty('egressTime', Unsigned) + , ReadableProperty('egressActive', Boolean) + , OptionalProperty('feedbackValue', BinaryLightingPV) + , ReadableProperty('priorityArray', PriorityArray) + , ReadableProperty('relinquishDefault', BinaryLightingPV) + , OptionalProperty('power', Real) + , OptionalProperty('polarity', Polarity) + , OptionalProperty('elapsedActiveTime', Unsigned) # Unsigned32 + , OptionalProperty('timeOfActiveTimeReset', DateTime) + , OptionalProperty('strikeCount', Unsigned) + , OptionalProperty('timeOfStrikeCountReset', DateTime) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , ReadableProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1156,6 +1292,13 @@ class BinaryOutputObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('interfaceValue', OptionalBinaryPV) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1194,6 +1337,12 @@ class BinaryValueObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1223,6 +1372,12 @@ class BitStringValueObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1258,8 +1413,11 @@ class ChannelObject(Object): , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] + @register_object_type class CharacterStringValueObject(Object): objectType = 'characterstringValue' @@ -1288,6 +1446,12 @@ class CharacterStringValueObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1299,6 +1463,19 @@ class CommandObject(Object): , ReadableProperty('allWritesSuccessful', Boolean) , ReadableProperty('action', ArrayOf(ActionList)) , OptionalProperty('actionText', ArrayOf(CharacterString)) + , ReadableProperty('statusFlags', StatusFlags) + , OptionalProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('valueSource', ValueSource) ] @register_object_type @@ -1338,6 +1515,21 @@ class DatePatternValueObject(Object): , OptionalProperty('outOfService', Boolean) , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', Date) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1353,6 +1545,21 @@ class DateValueObject(Object): , OptionalProperty('outOfService', Boolean) , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', Date) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1366,9 +1573,26 @@ class DateTimePatternValueObject(Object): , OptionalProperty('eventState', EventState) , OptionalProperty('reliability', Reliability) , OptionalProperty('outOfService', Boolean) + , OptionalProperty('isUtc', Boolean) + , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', DateTime) - , OptionalProperty('isUtc', Boolean) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1385,6 +1609,21 @@ class DateTimeValueObject(Object): , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', DateTime) , OptionalProperty('isUtc', Boolean) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1441,6 +1680,67 @@ class DeviceObject(Object): , OptionalProperty('alignIntervals', Boolean) , OptionalProperty('intervalOffset', Unsigned) , OptionalProperty('serialNumber', CharacterString) + , ReadableProperty('statusFlags', StatusFlags) + , OptionalProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('activeCovMultipleSubscriptions', ListOf(COVMultipleSubscription)) + , OptionalProperty('auditNotificationRecipient', Recipient) + , OptionalProperty('deviceUUID', OctetString) # size 16 + , OptionalProperty('deployedProfileLocation', CharacterString) + ] + +@register_object_type +class ElevatorGroupObject(Object): + objectType = 'elevatorGroup' + properties = \ + [ ReadableProperty('machineRoomID', ObjectIdentifier) + , ReadableProperty('groupID', Unsigned8) + , ReadableProperty('groupMembers', ArrayOf(ObjectIdentifier)) + , OptionalProperty('groupMode', LiftGroupMode) + , OptionalProperty('landingCalls', ListOf(LandingCallStatus)) + , OptionalProperty('landingCallControl', LandingCallStatus) + ] + +@register_object_type +class EscalatorObject(Object): + objectType = 'escalator' + properties = \ + [ ReadableProperty('statusFlags', StatusFlags) + , ReadableProperty('elevatorGroup', ObjectIdentifier) + , ReadableProperty('groupID', Unsigned8) + , ReadableProperty('installationID', Unsigned8) + , OptionalProperty('powerMode', Boolean) + , ReadableProperty('operationDirection', EscalatorOperationDirection) + , OptionalProperty('escalatorMode', EscalatorMode) + , OptionalProperty('energyMeter', Real) + , OptionalProperty('energyMeterRef', DeviceObjectReference) + , OptionalProperty('reliability', Reliability) + , OptionalProperty('outOfService', Boolean) + , OptionalProperty('faultSignals', ListOf(LiftFault)) + , ReadableProperty('passengerAlarm', Boolean) + , OptionalProperty('timeDelay', Unsigned) + , OptionalProperty('timeDelayNormal', Unsigned) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('eventState', EventState) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventAlgorithmInhibit', Boolean) + , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) ] @register_object_type @@ -1512,6 +1812,7 @@ class EventLogObject(Object): , OptionalProperty('eventDetectionEnable', Boolean) , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) , OptionalProperty('eventAlgorithmInhibit', Boolean) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) ] #----- @@ -1607,6 +1908,14 @@ class IntegerValueObject(Object): , OptionalProperty('minPresValue', Integer) , OptionalProperty('maxPresValue', Integer) , OptionalProperty('resolution', Integer) + , OptionalProperty('faultHighLimit', Integer) + , OptionalProperty('faultLowLimit', Integer) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1644,6 +1953,14 @@ class LargeAnalogValueObject(Object): , OptionalProperty('minPresValue', Double) , OptionalProperty('maxPresValue', Double) , OptionalProperty('resolution', Double) + , OptionalProperty('faultHighLimit', Double) + , OptionalProperty('faultLowLimit', Double) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1684,6 +2001,8 @@ class LifeSafetyPointObject(Object): , OptionalProperty('directReading', Real) , OptionalProperty('units', EngineeringUnits) , OptionalProperty('memberOf', ListOf(DeviceObjectReference)) + , OptionalProperty('floorNumber', Unsigned8) + , OptionalProperty('valueSource', ValueSource) ] @register_object_type @@ -1722,8 +2041,62 @@ class LifeSafetyZoneObject(Object): , OptionalProperty('maintenanceRequired', Boolean) , ReadableProperty('zoneMembers', ListOf(DeviceObjectReference)) , OptionalProperty('memberOf', ListOf(DeviceObjectReference)) + , OptionalProperty('floorNumber', Unsigned8) + , OptionalProperty('valueSource', ValueSource) ] +@register_object_type +class LiftObject(Object): + objectType = 'lift' + + properties = \ + [ ReadableProperty('trackingValue', Real) + , ReadableProperty('statusFlags', StatusFlags) + , ReadableProperty('elevatorGroup', ObjectIdentifier) + , ReadableProperty('groupID', Unsigned8) + , ReadableProperty('installationID', Unsigned8) + , OptionalProperty('floorText', ArrayOf(CharacterString)) + , OptionalProperty('carDoorText', ArrayOf(CharacterString)) + , OptionalProperty('assignedLandingCalls', ArrayOf(AssignedLandingCalls)) + , OptionalProperty('makingCarCall', ArrayOf(Unsigned8)) + , OptionalProperty('registeredCarCall', ArrayOf(LiftCarCallList)) + , OptionalProperty('carPosition', Unsigned8) + , OptionalProperty('carMovingDirection', LiftCarDirection) + , OptionalProperty('carAssignedDirection', LiftCarDirection) + , OptionalProperty('carDoorStatus', ArrayOf(DoorStatus)) + , OptionalProperty('carDoorCommand', ArrayOf(LiftCarDoorCommand)) + , OptionalProperty('carDoorZone', Boolean) + , OptionalProperty('carMode', LiftCarMode) + , OptionalProperty('carLoad', Real) + , OptionalProperty('carLoadUnits', EngineeringUnits) + , OptionalProperty('nextStoppingFloor', Unsigned) + , ReadableProperty('passengerAlarm', Boolean) + , OptionalProperty('timeDelay', Unsigned) + , OptionalProperty('timeDelayNormal', Unsigned) + , OptionalProperty('energyMeter', Real) + , OptionalProperty('energyMeterRef', DeviceObjectReference) + , OptionalProperty('reliability', Reliability) + , OptionalProperty('outOfService', Boolean) + , OptionalProperty('carDriveStatus', LiftCarDriveStatus) + , OptionalProperty('faultSignals', ListOf(LiftFault)) + , OptionalProperty('landingDoorStatus', ArrayOf(LandingDoorStatus)) + , OptionalProperty('higherDeck', ObjectIdentifier) + , OptionalProperty('lowerDeck', ObjectIdentifier) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('eventState', EventState) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) + , OptionalProperty('eventAlgorithmInhibit', Boolean) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + ] + + @register_object_type class LightingOutputObject(Object): objectType = 'lightingOutput' @@ -1754,6 +2127,12 @@ class LightingOutputObject(Object): , ReadableProperty('lightingCommandDefaultPriority', Unsigned) , OptionalProperty('covIncrement', Real) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1790,6 +2169,7 @@ class LoadControlObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('valueSource', ValueSource) ] @register_object_type @@ -1838,6 +2218,7 @@ class LoopObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('lowDiffLimit', OptionalReal) ] @register_object_type @@ -1869,6 +2250,7 @@ class MultiStateInputObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('interfaceValue', OptionalUnsigned) ] @register_object_type @@ -1901,6 +2283,13 @@ class MultiStateOutputObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('interfaceValue', OptionalUnsigned) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1933,6 +2322,11 @@ class MultiStateValueObject(Object): , OptionalProperty('eventAlgorithmInhibit', Boolean) , OptionalProperty('timeDelayNormal', Unsigned) , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -1993,7 +2387,7 @@ class NetworkPortObject(Object): , OptionalProperty('slaveAddressBinding', ListOf(AddressBinding)) #171 , OptionalProperty('virtualMACAddressTable', ListOf(VMACEntry)) #429 , OptionalProperty('routingTable', ListOf(RouterEntry)) #428 - , OptionalProperty('eventDetectionEnabled', Boolean) #353 + , OptionalProperty('eventDetectionEnable', Boolean) #353 , OptionalProperty('notificationClass', Unsigned) #17 , OptionalProperty('eventEnable', EventTransitionBits) #35 , OptionalProperty('ackedTransitions', EventTransitionBits) #0 @@ -2030,6 +2424,17 @@ class NotificationClassObject(Object): , ReadableProperty('priority', ArrayOf(Unsigned)) , ReadableProperty('ackRequired', EventTransitionBits) , ReadableProperty('recipientList', ListOf(Destination)) + , OptionalProperty('statusFlags', StatusFlags) + , OptionalProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , ReadableProperty('reliabilityEvaluationInhibit', Boolean) ] @register_object_type @@ -2060,6 +2465,12 @@ class OctetStringValueObject(Object): , OptionalProperty('outOfService', Boolean) , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', OctetString) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -2097,6 +2508,14 @@ class PositiveIntegerValueObject(Object): , OptionalProperty('minPresValue', Unsigned) , OptionalProperty('maxPresValue', Unsigned) , OptionalProperty('resolution', Unsigned) + , OptionalProperty('faultHighLimit', Unsigned) + , OptionalProperty('faultLowLimit', Unsigned) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -2189,6 +2608,37 @@ class ScheduleObject(Object): , OptionalProperty('reliabilityEvaluationInhibit', Boolean) ] +@register_object_type +class StagingObject(Object): + objectType = 'staging' + properties = \ + [ WritableProperty('presentValue', Real) + , ReadableProperty('presentStage', Unsigned) + , ReadableProperty('stages', ArrayOf(StageLimitValue)) + , OptionalProperty('stageNames', ArrayOf(CharacterString)) + , ReadableProperty('statusFlags', StatusFlags) + , ReadableProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , ReadableProperty('outOfService', Boolean) + , ReadableProperty('units', EngineeringUnits) + , ReadableProperty('targetReferences', ArrayOf(DeviceObjectReference)) + , ReadableProperty('priorityForWriting', Unsigned) # 1..16 + , OptionalProperty('defaultPresentValue', Real) + , ReadableProperty('minPresValue', Real) + , ReadableProperty('maxPresValue', Real) + , OptionalProperty('covIncrement', Real) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('valueSource', ValueSource) + ] + @register_object_type class StructuredViewObject(Object): objectType = 'structuredView' @@ -2197,6 +2647,11 @@ class StructuredViewObject(Object): , OptionalProperty('nodeSubtype', CharacterString) , ReadableProperty('subordinateList', ArrayOf(DeviceObjectReference)) , OptionalProperty('subordinateAnnotations', ArrayOf(CharacterString)) + , OptionalProperty('subordinateTags', ArrayOf(NameValueCollection)) + , OptionalProperty('subordinateNodeTypes', ArrayOf(NodeType)) + , OptionalProperty('subordinateRelationships', ArrayOf(Relationship)) + , OptionalProperty('defaultSubordinateRelationship', Relationship) + , OptionalProperty('represents', DeviceObjectReference) ] @register_object_type @@ -2212,6 +2667,21 @@ class TimePatternValueObject(Object): , OptionalProperty('outOfService', Boolean) , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', Time) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) ] @register_object_type @@ -2227,6 +2697,59 @@ class TimeValueObject(Object): , OptionalProperty('outOfService', Boolean) , OptionalProperty('priorityArray', PriorityArray) , OptionalProperty('relinquishDefault', Time) + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('currentCommandPriority', OptionalUnsigned) + , OptionalProperty('valueSource', ValueSource) + , OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)) + , OptionalProperty('lastCommandTime', TimeStamp) + , OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)) + , OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter) + ] + +@register_object_type +class TimerObject(Object): + objectType = 'timer' + + properties = \ + [ ReadableProperty('presentValue', Unsigned) + , ReadableProperty('statusFlags', StatusFlags) + , OptionalProperty('eventState', EventState) + , OptionalProperty('reliability', Reliability) + , OptionalProperty('outOfService', Boolean) + , ReadableProperty('timerState', TimerState) + , ReadableProperty('timerRunning', Boolean) + , OptionalProperty('updateTime', DateTime) + , OptionalProperty('lastStateChange', TimerTransition) + , OptionalProperty('expirationTime', DateTime) + , OptionalProperty('initialTimeout', Unsigned) + , OptionalProperty('defaultTimeout', Unsigned) + , OptionalProperty('minPresValue', Unsigned) + , OptionalProperty('maxPresValue', Unsigned) + , OptionalProperty('resolution', Unsigned) + , OptionalProperty('stateChangeValues', ArrayOf(TimerStateChangeValue, 7)) + , OptionalProperty('listOfObjectPropertyReferences', ListOf(DeviceObjectPropertyReference)) + , OptionalProperty('priorityForWriting', Unsigned) # 1..16 + , OptionalProperty('eventDetectionEnable', Boolean) + , OptionalProperty('notificationClass', Unsigned) + , OptionalProperty('timeDelay', Unsigned) + , OptionalProperty('timeDelayNormal', Unsigned) + , OptionalProperty('alarmValues', ListOf(TimerState)) + , OptionalProperty('eventEnable', EventTransitionBits) + , OptionalProperty('ackedTransitions', EventTransitionBits) + , OptionalProperty('notifyType', NotifyType) + , OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)) + , OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)) + , OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference) + , OptionalProperty('eventAlgorithmInhibit', Boolean) + , OptionalProperty('reliabilityEvaluationInhibit', Boolean) ] @register_object_type From b79c64c83e9963a3308ef2fe03eb0115fc5fe298 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Sat, 20 Mar 2021 23:42:30 -0400 Subject: [PATCH 47/50] make Property inherit from object --- py27/bacpypes/object.py | 2 +- py34/bacpypes/object.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py27/bacpypes/object.py b/py27/bacpypes/object.py index ce414a2e..b14941d1 100755 --- a/py27/bacpypes/object.py +++ b/py27/bacpypes/object.py @@ -156,7 +156,7 @@ def get_datatype(object_type, propid, vendor_id=0): # @bacpypes_debugging -class Property: +class Property(object): def __init__(self, identifier, datatype, default=None, optional=True, mutable=True): if _debug: diff --git a/py34/bacpypes/object.py b/py34/bacpypes/object.py index 8cab8114..5c53d141 100644 --- a/py34/bacpypes/object.py +++ b/py34/bacpypes/object.py @@ -156,7 +156,7 @@ def get_datatype(object_type, propid, vendor_id=0): # @bacpypes_debugging -class Property: +class Property(object): def __init__(self, identifier, datatype, default=None, optional=True, mutable=True): if _debug: From 857c1edcec2542aa1b17ab920a0056cebe71d4ad Mon Sep 17 00:00:00 2001 From: Christian Tremblay Date: Sun, 21 Mar 2021 12:21:34 -0400 Subject: [PATCH 48/50] Update build.yml Switch 3.5 to legacy, It'll use setup.py to install instead of pip --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b1ea6145..8af4acbb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.5, 3.6, 3.7, 3.8] + python-version: [3.6, 3.7, 3.8] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -43,7 +43,7 @@ jobs: runs-on: ubuntu-18.04 strategy: matrix: - python-version: [2.7, 3.4] + python-version: [2.7, 3.4, 3.5] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From b91bcdee9507d6b1191b5c9f3ae088a6ab2ea08c Mon Sep 17 00:00:00 2001 From: Christian Tremblay Date: Sun, 21 Mar 2021 12:25:32 -0400 Subject: [PATCH 49/50] Update build.yml Removing 3.5 from Windows and Mac... it's legacy since september 2020 --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8af4acbb..5e634bab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,7 +64,7 @@ jobs: runs-on: windows-latest strategy: matrix: - python-version: [3.5, 3.6, 3.7, 3.8] + python-version: [3.6, 3.7, 3.8] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -86,7 +86,7 @@ jobs: runs-on: macos-latest strategy: matrix: - python-version: [3.5, 3.6, 3.7, 3.8] + python-version: [3.6, 3.7, 3.8] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From ddc6a1ba71d0527ef60588ff905cc1d0f8631891 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Wed, 24 Mar 2021 00:14:03 -0400 Subject: [PATCH 50/50] sync up common math additions --- py27/bacpypes/primitivedata.py | 37 ++++++++++++++++++++++++++++++---- py34/bacpypes/primitivedata.py | 7 ++++--- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/py27/bacpypes/primitivedata.py b/py27/bacpypes/primitivedata.py index 2fad74ba..8921ac6f 100755 --- a/py27/bacpypes/primitivedata.py +++ b/py27/bacpypes/primitivedata.py @@ -504,6 +504,35 @@ def is_valid(cls, arg): """Return True if arg is valid value for the class.""" raise NotImplementedError("call on a derived class of Atomic") +class CommonMath: + def __add__(self, other): + return self.value + other.value if isinstance(other, Atomic) else (self.value + other) + + def __sub__(self, other): + return self.value - other.value if isinstance(other, Atomic) else (self.value - other) + + def __mul__(self, other): + return self.value * other.value if isinstance(other, Atomic) else (self.value * other) + + def __lt__(self, other): + return self.value < other.value if isinstance(other, Atomic) else (self.value < other) + + def __gt__(self, other): + return self.value > other.value if isinstance(other, Atomic) else (self.value > other) + + def __le__(self, other): + return self.value <= other.value if isinstance(other, Atomic) else (self.value <= other) + + def __ge__(self, other): + return self.value >= other.value if isinstance(other, Atomic) else (self.value >= other) + + def __ne__(self, other): + return self.value != other.value if isinstance(other, Atomic) else (self.value != other) + + def __eq__(self, other): + return self.value == other.value if isinstance(other, Atomic) else (self.value == other) + + # # Null # @@ -596,7 +625,7 @@ def __str__(self): # Unsigned # -class Unsigned(Atomic): +class Unsigned(Atomic, CommonMath): _app_tag = Tag.unsignedAppTag _low_limit = 0 @@ -688,7 +717,7 @@ class Unsigned16(Unsigned): # Integer # -class Integer(Atomic): +class Integer(Atomic, CommonMath): _app_tag = Tag.integerAppTag @@ -763,7 +792,7 @@ def __str__(self): # Real # -class Real(Atomic): +class Real(Atomic, CommonMath): _app_tag = Tag.realAppTag @@ -808,7 +837,7 @@ def __str__(self): # Double # -class Double(Atomic): +class Double(Atomic, CommonMath): _app_tag = Tag.doubleAppTag diff --git a/py34/bacpypes/primitivedata.py b/py34/bacpypes/primitivedata.py index 4cbbd5c0..32f6a146 100755 --- a/py34/bacpypes/primitivedata.py +++ b/py34/bacpypes/primitivedata.py @@ -515,13 +515,13 @@ def __mul__(self, other): def __lt__(self, other): return self.value < other.value if isinstance(other, Atomic) else (self.value < other) - + def __gt__(self, other): return self.value > other.value if isinstance(other, Atomic) else (self.value > other) - + def __le__(self, other): return self.value <= other.value if isinstance(other, Atomic) else (self.value <= other) - + def __ge__(self, other): return self.value >= other.value if isinstance(other, Atomic) else (self.value >= other) @@ -531,6 +531,7 @@ def __ne__(self, other): def __eq__(self, other): return self.value == other.value if isinstance(other, Atomic) else (self.value == other) + # # Null #