mirror of
https://github.com/JoelBender/bacpypes
synced 2025-10-05 22:18:16 +08:00
refactor: Remove tutorials/WhoIsIAm.py
This removes the Tutorial code and updates the old samples/WhoIsIAm.py to match it.
This commit is contained in:
parent
d832f84319
commit
9ec89dbf11
|
@ -3,25 +3,25 @@
|
||||||
Getting Started
|
Getting Started
|
||||||
===============
|
===============
|
||||||
|
|
||||||
Ah, so you are interested in getting started with BACnet and Python. Welcome
|
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
|
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
|
just enough of the basics of BACnet to get a workstation communicating with
|
||||||
another device. We will cover installing the library, downloading and
|
another device. We will cover installing the library, downloading and
|
||||||
configuring the samples applications.
|
configuring the samples applications.
|
||||||
|
|
||||||
Basic Assumptions
|
Basic Assumptions
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
I will assume you are a software developer and it is your job to communicate
|
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
|
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
|
given you a test device and purchased a copy of the BACnet standard. I will
|
||||||
need...
|
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
|
the latest version of Python (2.7 or >3.4) and
|
||||||
`setup tools <https://pypi.python.org/pypi/setuptools#unix-based-systems-including-mac-os-x>`_.
|
`setup tools <https://pypi.python.org/pypi/setuptools#unix-based-systems-including-mac-os-x>`_.
|
||||||
|
|
||||||
- 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.
|
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
|
- a BACnetIP/BACnet-MSTP Router if your mysterious device is an MSTP device (BACpypes is
|
||||||
|
@ -33,7 +33,7 @@ need...
|
||||||
`Anaconda <https://www.continuum.io/downloads>`_ or Enthought
|
`Anaconda <https://www.continuum.io/downloads>`_ or Enthought
|
||||||
`Canopy <https://www.enthought.com/products/canopy/>`_.
|
`Canopy <https://www.enthought.com/products/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::
|
to the internet, install the BACpypes library::
|
||||||
|
|
||||||
$ sudo easy_install bacpypes
|
$ sudo easy_install bacpypes
|
||||||
|
@ -42,7 +42,7 @@ or::
|
||||||
|
|
||||||
$ sudo pip install bacpypes
|
$ 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
|
contains the library source code, sample code, and this documentation. Install
|
||||||
the `Git <https://en.wikipedia.org/wiki/Git>`_ software from
|
the `Git <https://en.wikipedia.org/wiki/Git>`_ software from
|
||||||
`here <https://git-scm.com/downloads>`_, then make a local copy of the
|
`here <https://git-scm.com/downloads>`_, then make a local copy of the
|
||||||
|
@ -50,11 +50,11 @@ repository by cloning it::
|
||||||
|
|
||||||
$ git clone https://github.com/JoelBender/bacpypes.git
|
$ 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 <http://www.wireshark.org/>`_::
|
copy of `Wireshark <http://www.wireshark.org/>`_::
|
||||||
|
|
||||||
$ sudo apt-get install wireshark
|
$ sudo apt-get install wireshark
|
||||||
|
|
||||||
or if you use Windows, `download it here <https://www.wireshark.org/download.html>`_.
|
or if you use Windows, `download it here <https://www.wireshark.org/download.html>`_.
|
||||||
|
|
||||||
.. caution::
|
.. caution::
|
||||||
|
@ -67,15 +67,15 @@ or if you use Windows, `download it here <https://www.wireshark.org/download.htm
|
||||||
Configuring the Workstation
|
Configuring the Workstation
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
The mystery BACnet device you have is going to come with some configuration
|
The mystery BACnet device you have is going to come with some configuration
|
||||||
information by default and sometimes it is easier to set up the test
|
information by default and sometimes it is easier to set up the test
|
||||||
environment with my set of assumptions than come up with a fresh set
|
environment with my set of assumptions than come up with a fresh set
|
||||||
from scratch.
|
from scratch.
|
||||||
|
|
||||||
*IP Address*
|
*IP Address*
|
||||||
The device will probably come with an IP address, let's assume that it
|
The device will probably come with an IP address, let's assume that it
|
||||||
is 192.168.0.10, subnet mask 255.255.0.0, gateway address 192.168.0.1.
|
is 192.168.0.10, subnet mask 255.255.0.0, gateway address 192.168.0.1.
|
||||||
You are going to be joining the same network, so pick 192.168.0.11
|
You are going to be joining the same network, so pick 192.168.0.11
|
||||||
for your workstation address and use the same subnet mask 255.255.0.0.
|
for your workstation address and use the same subnet mask 255.255.0.0.
|
||||||
|
|
||||||
If working with MSTP devices, base your workstation address on the address
|
If working with MSTP devices, base your workstation address on the address
|
||||||
|
@ -84,45 +84,45 @@ from scratch.
|
||||||
*Network Number*
|
*Network Number*
|
||||||
If working with a BACnetIP router and an MSTP device, you will need to know
|
If working with a BACnetIP router and an MSTP device, you will need to know
|
||||||
the network number configured inside the router. Every BACnet network **must**
|
the network number configured inside the router. Every BACnet network **must**
|
||||||
have a unique numeric identifier. You will often see the magical number **2000**
|
have a unique numeric identifier. You will often see the magical number **2000**
|
||||||
but you can choose anything between 1 to 0xFFFE.
|
but you can choose anything between 1 to 0xFFFE.
|
||||||
|
|
||||||
*Device Identifier*
|
*Device Identifier*
|
||||||
Every BACnet device on a BACnet network **must** have a unique numeric
|
Every BACnet device on a BACnet network **must** have a unique numeric
|
||||||
identifier. This number is a 22-bit unsigned non-zero value.
|
identifier. This number is a 22-bit unsigned non-zero value.
|
||||||
It is critical this identifier be unique. Most large customers will have
|
It is critical this identifier be unique. Most large customers will have
|
||||||
someone or some group responsible for maintaining device identifiers across the
|
someone or some group responsible for maintaining device identifiers across the
|
||||||
site. Keep track of the device identifier for the test device. Let's
|
site. Keep track of the device identifier for the test device. Let's
|
||||||
assume that this device is **1000** and you are going to pick **1001**
|
assume that this device is **1000** and you are going to pick **1001**
|
||||||
for your workstation.
|
for your workstation.
|
||||||
|
|
||||||
*Device Name*
|
*Device Name*
|
||||||
Every BACnet device on a BACnet network should also have a unique name, which
|
Every BACnet device on a BACnet network should also have a unique name, which
|
||||||
is a character string. There is nothing on a BACnet network that
|
is a character string. There is nothing on a BACnet network that
|
||||||
enforces this uniqueness, but it is a real headache for integrators
|
enforces this uniqueness, but it is a real headache for integrators
|
||||||
when it isn't followed. You will need to pick a name for your
|
when it isn't followed. You will need to pick a name for your
|
||||||
workstation. My collegues and I use star names, so in the sample
|
workstation. My collegues and I use star names, so in the sample
|
||||||
configuration files you will see the name "Betelgeuse". An actual customer's
|
configuration files you will see the name "Betelgeuse". An actual customer's
|
||||||
site will use a more formal (but less fun) naming convention.
|
site will use a more formal (but less fun) naming convention.
|
||||||
|
|
||||||
|
|
||||||
There are a few more configuration values that you will need, but
|
There are a few more configuration values that you will need, but
|
||||||
you won't need to change the values in the sample configuration file
|
you won't need to change the values in the sample configuration file
|
||||||
until you get deeper into the protocol.
|
until you get deeper into the protocol.
|
||||||
|
|
||||||
*Maximum APDU Length Accepted*
|
*Maximum APDU Length Accepted*
|
||||||
BACnet works on lots of different types of networks, from high
|
BACnet works on lots of different types of networks, from high
|
||||||
speed Ethernet to "slower" and "cheaper" ARCNET or MS/TP (a
|
speed Ethernet to "slower" and "cheaper" ARCNET or MS/TP (a
|
||||||
serial bus protocol used for a field bus defined by BACnet).
|
serial bus protocol used for a field bus defined by BACnet).
|
||||||
For devices to exchange messages they need to know the maximum
|
For devices to exchange messages they need to know the maximum
|
||||||
size message the other device can handle.
|
size message the other device can handle.
|
||||||
|
|
||||||
*Segmentation Supported*
|
*Segmentation Supported*
|
||||||
A vast majority of BACnet communications traffic fits in one
|
A vast majority of BACnet communications traffic fits in one
|
||||||
message, but there are times when larger messages are
|
message, but there are times when larger messages are
|
||||||
convenient and more efficient. Segmentation allows larger
|
convenient and more efficient. Segmentation allows larger
|
||||||
messages to be broken up into segments and spliced back together.
|
messages to be broken up into segments and spliced back together.
|
||||||
It is not unusual for "low power" field devices to not
|
It is not unusual for "low power" field devices to not
|
||||||
support segmentation.
|
support segmentation.
|
||||||
|
|
||||||
There are other configuration parameters in the INI file that are
|
There are other configuration parameters in the INI file that are
|
||||||
|
@ -132,24 +132,24 @@ also used by other applications, just leave them alone for now.
|
||||||
Updating the INI File
|
Updating the INI File
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Now that you know what these values are going to be, you can
|
Now that you know what these values are going to be, you can
|
||||||
configure the BACnet portion of your workstation. Change into the
|
configure the BACnet portion of your workstation. Change into the
|
||||||
bacpypes directory that you checked out earlier, make a copy
|
bacpypes directory that you checked out earlier, make a copy
|
||||||
of the sample configuration file, and edit it for your site::
|
of the sample configuration file, and edit it for your site::
|
||||||
|
|
||||||
$ cd bacpypes
|
$ cd bacpypes
|
||||||
$ cp BACpypes~.ini BACpypes.ini
|
$ cp BACpypes~.ini BACpypes.ini
|
||||||
|
|
||||||
.. tip::
|
.. tip::
|
||||||
|
|
||||||
The sample applications are going to look for this file.
|
The sample applications are going to look for this file.
|
||||||
You can direct the applications to use other INI files on the command line, so it is
|
You can direct the applications to use other INI files on the command line, so it is
|
||||||
simple to keep multiple configurations.
|
simple to keep multiple configurations.
|
||||||
|
|
||||||
At some point you will probably running both "client" and "server"
|
At some point you will probably running both "client" and "server"
|
||||||
applications on your workstation, so you will want separate
|
applications on your workstation, so you will want separate
|
||||||
configuration files for them. Keep in mind that BACnet devices
|
configuration files for them. Keep in mind that BACnet devices
|
||||||
communicate as peers, so it is not unusual for an application to
|
communicate as peers, so it is not unusual for an application to
|
||||||
act as both a client and a server at the same time.
|
act as both a client and a server at the same time.
|
||||||
|
|
||||||
A typical BACpypes.ini file contains::
|
A typical BACpypes.ini file contains::
|
||||||
|
@ -170,41 +170,41 @@ A typical BACpypes.ini file contains::
|
||||||
UDP Communications Issues
|
UDP Communications Issues
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
BACnet devices communicate using UDP rather than TCP. This is so
|
BACnet devices communicate using UDP rather than TCP. This is so
|
||||||
devices do not need to implement a full IP stack (although
|
devices do not need to implement a full IP stack (although
|
||||||
many of them do because they support multiple protocols, including
|
many of them do because they support multiple protocols, including
|
||||||
having embedded web servers).
|
having embedded web servers).
|
||||||
|
|
||||||
There are two types of UDP messages; *unicast* which is a message
|
There are two types of UDP messages; *unicast* which is a message
|
||||||
from one specific IP address (and port) to another device's IP address
|
from one specific IP address (and port) to another device's IP address
|
||||||
(and port); and *broadcast* messages which are sent by one device
|
(and port); and *broadcast* messages which are sent by one device
|
||||||
and received and processed by all other devices that are listening
|
and received and processed by all other devices that are listening
|
||||||
on that port. BACnet uses both types of messages and your workstation
|
on that port. BACnet uses both types of messages and your workstation
|
||||||
will need to receive both types.
|
will need to receive both types.
|
||||||
|
|
||||||
The BACpypes.ini file has an *address* parameter which is an IP
|
The BACpypes.ini file has an *address* parameter which is an IP
|
||||||
address in CIDR notation and can be followed by a port number. For
|
address in CIDR notation and can be followed by a port number. For
|
||||||
example, **192.168.0.11/16** specifies both the IP address and the
|
example, **192.168.0.11/16** specifies both the IP address and the
|
||||||
number of bits in the network portion, which in turn implies a
|
number of bits in the network portion, which in turn implies a
|
||||||
subnet mask, in this case **255.255.0.0**. Unicast messages will
|
subnet mask, in this case **255.255.0.0**. Unicast messages will
|
||||||
be sent to the IP address, and broadcast messages will be sent to
|
be sent to the IP address, and broadcast messages will be sent to
|
||||||
the broadcast address **192.168.255.255** which is the network
|
the broadcast address **192.168.255.255** which is the network
|
||||||
portion of the address with all 1's in the host portion. In this example,
|
portion of the address with all 1's in the host portion. In this example,
|
||||||
the default port 47808 (0xBAC0) is used but you could provide and different
|
the default port 47808 (0xBAC0) is used but you could provide and different
|
||||||
one, **192.168.0.11:47809/16**.
|
one, **192.168.0.11:47809/16**.
|
||||||
|
|
||||||
To receive both unicast and broadcast addresses, BACpypes
|
To receive both unicast and broadcast addresses, BACpypes
|
||||||
opens two sockets, one for unicast traffic and one that only listens
|
opens two sockets, one for unicast traffic and one that only listens
|
||||||
for broadcast messages. The operating system will typically not allow two
|
for broadcast messages. The operating system will typically not allow two
|
||||||
applications to open the same socket at the same time
|
applications to open the same socket at the same time
|
||||||
so to run two BACnet applciations at
|
so to run two BACnet applciations at
|
||||||
the same time they need to be configured with different ports.
|
the same time they need to be configured with different ports.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
The BACnet protocol has been assigned port 47808 (hex 0xBAC0) by
|
The BACnet protocol has been assigned port 47808 (hex 0xBAC0) by
|
||||||
by the `Internet Assigned Numbers Authority <https://www.iana.org/>`_, and sequentially
|
by the `Internet Assigned Numbers Authority <https://www.iana.org/>`_, and sequentially
|
||||||
higher numbers are used in many applications (i.e. 47809, 47810,...).
|
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
|
There are some BACnet routing and networking issues related to using these higher unoffical
|
||||||
ports, but that is a topic for another tutorial.
|
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**
|
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?
|
displays the results it receives. What are these things?
|
||||||
|
|
||||||
As mentioned before, BACnet has unique device identifiers and
|
As mentioned before, BACnet has unique device identifiers and
|
||||||
most applications use these identifiers in their configuration
|
most applications use these identifiers in their configuration
|
||||||
to know who their peers are. Once these identifiers are given
|
to know who their peers are. Once these identifiers are given
|
||||||
to a device they typically do not change, even as the network
|
to a device they typically do not change, even as the network
|
||||||
topology changes.
|
topology changes.
|
||||||
|
|
||||||
BACnet devices use the Who-Is request to translate device
|
BACnet devices use the Who-Is request to translate device
|
||||||
identifiers into network addresses. This is very similar to
|
identifiers into network addresses. This is very similar to
|
||||||
a decentralized DNS service, but the names are unsigned
|
a decentralized DNS service, but the names are unsigned
|
||||||
integers. The request is broadcast on the network and the
|
integers. The request is broadcast on the network and the
|
||||||
client waits around to listen for I-Am messages. The source
|
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.
|
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::
|
session with a BACnet capture filter::
|
||||||
|
|
||||||
udp and port 47808
|
udp and port 47808
|
||||||
|
|
||||||
You might start seeing BACnet traffic from your test device,
|
You might start seeing BACnet traffic from your test device,
|
||||||
and if you wait to power it on after starting your capture
|
and if you wait to power it on after starting your capture
|
||||||
you should see at least a broadcast I-Am message. By looking
|
you should see at least a broadcast I-Am message. By looking
|
||||||
in the I-Am packet decoding you will see some of its
|
in the I-Am packet decoding you will see some of its
|
||||||
configuration parameters that should match what you expected
|
configuration parameters that should match what you expected
|
||||||
them to be.
|
them to be.
|
||||||
|
|
||||||
Now start the simplest tutorial application::
|
Now start the simplest tutorial application::
|
||||||
|
|
||||||
$ python samples/Tutorial/WhoIsIAm.py
|
$ python samples/WhoIsIAm.py
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ BACnet communications traffic. Generate the basic I-Am message::
|
||||||
|
|
||||||
> iam
|
> 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
|
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
|
it but since your test device probably isn't looking for you, it will not
|
||||||
respond to the message.
|
respond to the message.
|
||||||
|
@ -281,27 +281,27 @@ respond to the message.
|
||||||
Binding to the Test Device
|
Binding to the Test Device
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
Next we want to confirm that your workstation can receive the
|
Next we want to confirm that your workstation can receive the
|
||||||
messages the test device sends out. We do this by generating a
|
messages the test device sends out. We do this by generating a
|
||||||
generic Who-Is request. The request will be "unconstrained", meaning
|
generic Who-Is request. The request will be "unconstrained", meaning
|
||||||
every device that hears the message will respond with their corresponding
|
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
|
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
|
a LOT of traffic, which can lead to network problems caused by the resulting
|
||||||
flood of messages.
|
flood of messages.
|
||||||
|
|
||||||
To generate the Who-Is request::
|
To generate the Who-Is request::
|
||||||
|
|
||||||
> whois
|
> whois
|
||||||
|
|
||||||
You should see the Who-Is request captured in Wireshark along with the I-Am
|
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
|
response from your test device, and then the details of the response displayed
|
||||||
on the workstation console.::
|
on the workstation console.::
|
||||||
|
|
||||||
> whois
|
> whois
|
||||||
> pduSource = <RemoteStation 50009:9>
|
> pduSource = <RemoteStation 50009:9>
|
||||||
iAmDeviceIdentifier = ('device', 1000)
|
iAmDeviceIdentifier = ('device', 1000)
|
||||||
maxAPDULengthAccepted = 480
|
maxAPDULengthAccepted = 480
|
||||||
|
@ -309,13 +309,13 @@ on the workstation console.::
|
||||||
vendorID = 8
|
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::
|
simple application. You can see these with the help command::
|
||||||
|
|
||||||
> help whois
|
> help whois
|
||||||
whois [ <addr>] [ <lolimit> <hilimit> ]
|
whois [ <addr>] [ <lolimit> <hilimit> ]
|
||||||
|
|
||||||
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
|
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
|
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
|
request is to look for a specific device given its device
|
||||||
|
@ -329,9 +329,9 @@ building as a group::
|
||||||
|
|
||||||
> whois 203000 203099
|
> 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
|
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::
|
to the specific device and hope that it responds::
|
||||||
|
|
||||||
> whois 192.168.0.10
|
> whois 192.168.0.10
|
||||||
|
@ -349,9 +349,9 @@ but that is a subject of an other tutorial.
|
||||||
What's Next
|
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
|
application can be run, and what the commands can tell you
|
||||||
about how it is working. All of the "console" applications
|
about how it is working. All of the "console" applications
|
||||||
(i.e. those that prompt for commands) use the same basic
|
(i.e. those that prompt for commands) use the same basic
|
||||||
commands and work the same way.
|
commands and work the same way.
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
Running BACpypes Applications
|
Running BACpypes Applications
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
All BACpypes sample applications have the same basic set of command line
|
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
|
options so it is easy to move between applications, turn debugging on and
|
||||||
and use different configurations. There may be additional options and
|
and use different configurations. There may be additional options and
|
||||||
command parameters than just the ones described in this section.
|
command parameters than just the ones described in this section.
|
||||||
|
|
||||||
Getting Help
|
Getting Help
|
||||||
|
@ -14,7 +14,7 @@ Getting Help
|
||||||
Whatever the command line parameters and additional options might be for
|
Whatever the command line parameters and additional options might be for
|
||||||
an application, you can start with help::
|
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]
|
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
|
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
|
Listing Debugging Loggers
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
The BACpypes library and sample applications make extensive use of the
|
The BACpypes library and sample applications make extensive use of the
|
||||||
built-in *logging* module in Python. Every module in the library, along
|
built-in *logging* module in Python. Every module in the library, along
|
||||||
with every class and exported function, has a logging object associated
|
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
|
with it. By attaching a log handler to a logger, the log handler is given
|
||||||
a chance to output the progress of the application.
|
a chance to output the progress of the application.
|
||||||
|
|
||||||
Because BACpypes modules are deeply interconnected, dumping a complete list
|
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
|
of all of the logger names is a long list. Start out focusing on the
|
||||||
components of the WhoIsIAm.py application::
|
components of the WhoIsIAm.py application::
|
||||||
|
|
||||||
$ python Tutorial/WhoIsIAm.py --buggers | grep __main__
|
$ python samples/WhoIsIAm.py --buggers | grep __main__
|
||||||
__main__
|
__main__
|
||||||
__main__.WhoIsIAmApplication
|
__main__.WhoIsIAmApplication
|
||||||
__main__.WhoIsIAmConsoleCmd
|
__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.
|
two classes.
|
||||||
|
|
||||||
Debugging a Module
|
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=<class 'bacpypes.consolelogging.ini'>)
|
DEBUG:__main__: - args: Namespace(buggers=False, debug=['__main__'], ini=<class 'bacpypes.consolelogging.ini'>)
|
||||||
DEBUG:__main__.WhoIsIAmApplication:__init__ (<bacpypes.app.LocalDeviceObject object at 0xb6dd98cc>, '128.253.109.40/24:47808')
|
DEBUG:__main__.WhoIsIAmApplication:__init__ (<bacpypes.app.LocalDeviceObject object at 0xb6dd98cc>, '128.253.109.40/24:47808')
|
||||||
DEBUG:__main__:running
|
DEBUG:__main__:running
|
||||||
>
|
>
|
||||||
|
|
||||||
The output is the severity code of the logger (almost always DEBUG), the name
|
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
|
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,
|
application. From the output above you can see the application initializing,
|
||||||
setting the args variable, creating an instance of the WhoIsIAmApplication class
|
setting the args variable, creating an instance of the WhoIsIAmApplication class
|
||||||
(with some parameters), and then declaring itself - running.
|
(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,
|
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::
|
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__ (<bacpypes.app.LocalDeviceObject object at 0x9bca8ac>, '128.253.109.40/24:47808')
|
DEBUG:__main__.WhoIsIAmApplication:__init__ (<bacpypes.app.LocalDeviceObject object at 0x9bca8ac>, '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::
|
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__ <bacpypes.udp.UDPDirector 128.253.109.255:47808 at 0xb6d40d6c> ('128.253.109.254', 47808)
|
> DEBUG:bacpypes.udp.UDPActor:__init__ <bacpypes.udp.UDPDirector 128.253.109.255:47808 at 0xb6d40d6c> ('128.253.109.254', 47808)
|
||||||
DEBUG:bacpypes.udp.UDPActor:response <bacpypes.comm.PDU object at 0xb6d433cc>
|
DEBUG:bacpypes.udp.UDPActor:response <bacpypes.comm.PDU object at 0xb6d433cc>
|
||||||
<bacpypes.comm.PDU object at 0xb6d433cc>
|
<bacpypes.comm.PDU object at 0xb6d433cc>
|
||||||
pduSource = ('128.253.109.254', 47808)
|
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...'
|
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
|
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
|
function is called with an instance of a PDU as a parameter. Following
|
||||||
the function invocation description, the debugging output continues with the
|
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).
|
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
|
You can debug a function just as easily. Specify as many different
|
||||||
combinations of logger names as necessary. Note, you cannot debug a
|
combinations of logger names as necessary. Note, you cannot debug a
|
||||||
specific function within a class.
|
specific function within a class.
|
||||||
|
|
||||||
Sending Debug Log to a file
|
Sending Debug Log to a file
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
The current --debug command line option takes a list of named debugging access
|
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.
|
points and attaches a StreamHandler which sends the output to sys.stderr.
|
||||||
There is a way to send the debugging output to a
|
There is a way to send the debugging output to a
|
||||||
RotatingFileHandler by providing a file name, and optionally maxBytes and
|
RotatingFileHandler by providing a file name, and optionally maxBytes and
|
||||||
backupCount. For example, this invocation sends the main application debugging
|
backupCount. For example, this invocation sends the main application debugging
|
||||||
to standard error and the debugging output of the bacpypes.udp module to the
|
to standard error and the debugging output of the bacpypes.udp module to the
|
||||||
traffic.txt file::
|
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::
|
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::
|
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::
|
.. caution::
|
||||||
|
|
||||||
|
@ -136,18 +136,18 @@ The definition of debug::
|
||||||
Changing INI Files
|
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.
|
different port numbers or other BACnet communications paramters.
|
||||||
|
|
||||||
Rather than swapping INI files, you can simply provide the INI file on the
|
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::
|
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::
|
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.
|
And I switch back and forth between them.
|
||||||
|
|
||||||
|
|
|
@ -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 [ <addr> ] [ <lolimit> <hilimit> ]"""
|
|
||||||
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 <addr> <net> ... """
|
|
||||||
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()
|
|
83
samples/WhoIsIAm.py
Executable file → Normal file
83
samples/WhoIsIAm.py
Executable file → Normal file
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This application presents a 'console' prompt to the user asking for Who-Is and I-Am
|
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.
|
for incoming traffic and prints out the contents.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -12,8 +12,7 @@ from bacpypes.debugging import bacpypes_debugging, ModuleLogger
|
||||||
from bacpypes.consolelogging import ConfigArgumentParser
|
from bacpypes.consolelogging import ConfigArgumentParser
|
||||||
from bacpypes.consolecmd import ConsoleCmd
|
from bacpypes.consolecmd import ConsoleCmd
|
||||||
|
|
||||||
from bacpypes.core import run, deferred, enable_sleeping
|
from bacpypes.core import run, enable_sleeping
|
||||||
from bacpypes.iocb import IOCB
|
|
||||||
|
|
||||||
from bacpypes.pdu import Address, GlobalBroadcast
|
from bacpypes.pdu import Address, GlobalBroadcast
|
||||||
from bacpypes.apdu import WhoIsRequest, IAmRequest
|
from bacpypes.apdu import WhoIsRequest, IAmRequest
|
||||||
|
@ -23,7 +22,7 @@ from bacpypes.app import BIPSimpleApplication
|
||||||
from bacpypes.local.device import LocalDeviceObject
|
from bacpypes.local.device import LocalDeviceObject
|
||||||
|
|
||||||
# some debugging
|
# some debugging
|
||||||
_debug = 0
|
_debug = 1
|
||||||
_log = ModuleLogger(globals())
|
_log = ModuleLogger(globals())
|
||||||
|
|
||||||
# globals
|
# globals
|
||||||
|
@ -68,10 +67,10 @@ class WhoIsIAmApplication(BIPSimpleApplication):
|
||||||
raise DecodingError("invalid object type")
|
raise DecodingError("invalid object type")
|
||||||
|
|
||||||
if (self._request.deviceInstanceRangeLowLimit is not None) and \
|
if (self._request.deviceInstanceRangeLowLimit is not None) and \
|
||||||
(device_instance < self._request.deviceInstanceRangeLowLimit):
|
(device_instance < self._request.deviceInstanceRangeLowLimit):
|
||||||
pass
|
pass
|
||||||
elif (self._request.deviceInstanceRangeHighLimit is not None) and \
|
elif (self._request.deviceInstanceRangeHighLimit is not None) and \
|
||||||
(device_instance > self._request.deviceInstanceRangeHighLimit):
|
(device_instance > self._request.deviceInstanceRangeHighLimit):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
# print out the contents
|
# print out the contents
|
||||||
|
@ -85,6 +84,7 @@ class WhoIsIAmApplication(BIPSimpleApplication):
|
||||||
# forward it along
|
# forward it along
|
||||||
BIPSimpleApplication.indication(self, apdu)
|
BIPSimpleApplication.indication(self, apdu)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# WhoIsIAmConsoleCmd
|
# WhoIsIAmConsoleCmd
|
||||||
#
|
#
|
||||||
|
@ -93,60 +93,37 @@ class WhoIsIAmApplication(BIPSimpleApplication):
|
||||||
class WhoIsIAmConsoleCmd(ConsoleCmd):
|
class WhoIsIAmConsoleCmd(ConsoleCmd):
|
||||||
|
|
||||||
def do_whois(self, args):
|
def do_whois(self, args):
|
||||||
"""whois [ <addr>] [ <lolimit> <hilimit> ]"""
|
"""whois [ <addr> ] [ <lolimit> <hilimit> ]"""
|
||||||
args = args.split()
|
args = args.split()
|
||||||
if _debug: WhoIsIAmConsoleCmd._debug("do_whois %r", args)
|
if _debug: WhoIsIAmConsoleCmd._debug("do_whois %r", args)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# build a request
|
# gather the parameters
|
||||||
request = WhoIsRequest()
|
|
||||||
if (len(args) == 1) or (len(args) == 3):
|
if (len(args) == 1) or (len(args) == 3):
|
||||||
request.pduDestination = Address(args[0])
|
addr = Address(args[0])
|
||||||
del args[0]
|
del args[0]
|
||||||
else:
|
else:
|
||||||
request.pduDestination = GlobalBroadcast()
|
addr = GlobalBroadcast()
|
||||||
|
|
||||||
if len(args) == 2:
|
if len(args) == 2:
|
||||||
request.deviceInstanceRangeLowLimit = int(args[0])
|
lolimit = int(args[0])
|
||||||
request.deviceInstanceRangeHighLimit = int(args[1])
|
hilimit = int(args[1])
|
||||||
if _debug: WhoIsIAmConsoleCmd._debug(" - request: %r", request)
|
else:
|
||||||
|
lolimit = hilimit = None
|
||||||
|
|
||||||
# make an IOCB
|
# code lives in the device service
|
||||||
iocb = IOCB(request)
|
this_application.who_is(lolimit, hilimit, addr)
|
||||||
if _debug: WhoIsIAmConsoleCmd._debug(" - iocb: %r", iocb)
|
|
||||||
|
|
||||||
# give it to the application
|
except Exception as error:
|
||||||
this_application.request_io(iocb)
|
WhoIsIAmConsoleCmd._exception("exception: %r", error)
|
||||||
|
|
||||||
except Exception as err:
|
|
||||||
WhoIsIAmConsoleCmd._exception("exception: %r", err)
|
|
||||||
|
|
||||||
def do_iam(self, args):
|
def do_iam(self, args):
|
||||||
"""iam"""
|
"""iam"""
|
||||||
args = args.split()
|
args = args.split()
|
||||||
if _debug: WhoIsIAmConsoleCmd._debug("do_iam %r", args)
|
if _debug: WhoIsIAmConsoleCmd._debug("do_iam %r", args)
|
||||||
|
|
||||||
try:
|
# code lives in the device service
|
||||||
# build a request
|
this_application.i_am()
|
||||||
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)
|
|
||||||
|
|
||||||
def do_rtn(self, args):
|
def do_rtn(self, args):
|
||||||
"""rtn <addr> <net> ... """
|
"""rtn <addr> <net> ... """
|
||||||
|
@ -162,11 +139,12 @@ class WhoIsIAmConsoleCmd(ConsoleCmd):
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# main
|
# __main__
|
||||||
#
|
#
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
global this_device, this_application
|
global this_device
|
||||||
|
global this_application
|
||||||
|
|
||||||
# parse the command line arguments
|
# parse the command line arguments
|
||||||
args = ConfigArgumentParser(description=__doc__).parse_args()
|
args = ConfigArgumentParser(description=__doc__).parse_args()
|
||||||
|
@ -175,14 +153,16 @@ def main():
|
||||||
if _debug: _log.debug(" - args: %r", args)
|
if _debug: _log.debug(" - args: %r", args)
|
||||||
|
|
||||||
# make a device object
|
# make a device object
|
||||||
this_device = LocalDeviceObject(ini=args.ini)
|
this_device = LocalDeviceObject(
|
||||||
if _debug: _log.debug(" - this_device: %r", this_device)
|
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
|
# make a simple application
|
||||||
this_application = WhoIsIAmApplication(
|
this_application = WhoIsIAmApplication(this_device, args.ini.address)
|
||||||
this_device, args.ini.address,
|
|
||||||
)
|
|
||||||
if _debug: _log.debug(" - this_application: %r", this_application)
|
|
||||||
|
|
||||||
# make a console
|
# make a console
|
||||||
this_console = WhoIsIAmConsoleCmd()
|
this_console = WhoIsIAmConsoleCmd()
|
||||||
|
@ -197,6 +177,5 @@ def main():
|
||||||
|
|
||||||
_log.debug("fini")
|
_log.debug("fini")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user