### Install BACpypes3 to Local User Path Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/setup.md Install the library to the local user path, which does not require write access to the system Python installation. ```bash pip install bacpypes3 --user ``` -------------------------------- ### Install BACpypes3 to System Path (Not Recommended) Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/setup.md Install the library to the system path. This method is generally not recommended due to potential permission issues and conflicts. ```bash sudo pip install bacpypes3 ``` -------------------------------- ### Install BACpypes3 using pip Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/index.md Install the latest released version of BACpypes3 from PyPI. ```bash pip install bacpypes3 ``` -------------------------------- ### Set up development environment with uv Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/index.md Use the uv utility to create a virtual environment and install all developer tools. ```bash uv sync --all-extras pipenv shell ``` -------------------------------- ### Install BACpypes3 from Source with pipenv Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/setup.md Clone the BACpypes3 repository and install the developer version using pipenv, including optional packages and development tools. ```bash git clone https://github.com/JoelBender/BACpypes3.git cd BACpypes3 pipenv install --dev pipenv shell ... exit ``` -------------------------------- ### Install BACpypes3 from PyPI Source: https://github.com/joelbender/bacpypes3/blob/main/samples/docker/README.md Use this statement to install the latest release version of bacpypes3 from PyPI. ```dockerfile RUN pip install bacpypes3 ``` -------------------------------- ### Create and Activate Virtual Environment with pip Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/setup.md Use this command to create a virtual environment, activate it, and install the bacpypes3 library. ```bash python3 -m venv myenv cd myenv source bin/activate pip install bacpypes3 ... deactivate ``` -------------------------------- ### Run bacpypes3 Module Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Execute the bacpypes3 module directly to start a BACnet device stack with a shell prompt. ```bash $ python3 -m bacpypes3 > ``` -------------------------------- ### Install Wireshark on Debian/Ubuntu Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/setup.md Install Wireshark on Debian-based Linux distributions using the apt-get package manager. ```bash sudo apt-get install wireshark ``` -------------------------------- ### Create and Activate Virtual Environment with pipenv Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/setup.md Use pipenv to manage your virtual environment and install bacpypes3. ```bash pipenv --python `which python3` pipenv install bacpypes3 pipenv shell ... exit ``` -------------------------------- ### Install Latest Test Version of BACpypes3 from PyPI Source: https://github.com/joelbender/bacpypes3/blob/main/samples/docker/README.md Install the latest test version of bacpypes3, which may have issues but should pass unit tests. Requires upgrading pip and specifying index URLs. ```dockerfile RUN pip install --upgrade --index-url https://test.pypi.org/simple/ \ --extra-index-url https://pypi.org/simple/ \ bacpypes3 ``` -------------------------------- ### Get help for BACpypes3 module Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/index.md Display the help message for the bacpypes3 module, showing configuration options for the communications stack. ```bash python3 -m bacpypes3 --help ``` -------------------------------- ### Dockerfile Run Command Source: https://github.com/joelbender/bacpypes3/blob/main/samples/docker/README.md Specifies the command to execute when the Docker container starts. ```dockerfile CMD python bacpypes-greetings.py ``` -------------------------------- ### Application.from_args() Source: https://context7.com/joelbender/bacpypes3/llms.txt Creates a BACnet application from command-line arguments. This method handles the creation of the DeviceObject, NetworkPortObject, and binds all protocol layers, making it the easiest way to start a local BACnet node. ```APIDOC ## Application.from_args() ### Description Creates a fully wired BACnet application directly from parsed `argparse.Namespace` arguments, handling device object creation, network port setup (normal, foreign-device, BBMD modes), and layer binding in one call. This is the simplest way to spin up a local BACnet node for scripting. ### Method Signature `Application.from_args(args)` ### Parameters - **args** (`argparse.Namespace`): Parsed command-line arguments. ### Request Example ```python import asyncio from bacpypes3.argparse import SimpleArgumentParser from bacpypes3.app import Application async def main(): # CLI: python script.py --name MyDevice --instance 1001 --address 192.168.1.50/24 args = SimpleArgumentParser().parse_args() # Builds DeviceObject + NetworkPortObject, binds all protocol layers app = Application.from_args(args) try: # Keep running until interrupted await asyncio.Future() finally: app.close() asyncio.run(main()) ``` ### Response - **app** (`Application`): An instantiated and configured BACpypes3 Application object. ### Notes The device becomes reachable on the BACnet network with the specified instance number. ``` -------------------------------- ### Create BACnet Application from CLI Arguments Source: https://context7.com/joelbender/bacpypes3/llms.txt Use `Application.from_args()` to create a BACnet application directly from parsed command-line arguments. This method handles device and network port setup, making it ideal for simple scripting. ```python import asyncio from bacpypes3.argparse import SimpleArgumentParser from bacpypes3.app import Application async def main(): # CLI: python script.py --name MyDevice --instance 1001 --address 192.168.1.50/24 args = SimpleArgumentParser().parse_args() # Builds DeviceObject + NetworkPortObject, binds all protocol layers app = Application.from_args(args) try: # Keep running until interrupted await asyncio.Future() finally: app.close() asyncio.run(main()) # The device is now reachable on the BACnet network as instance 1001 ``` -------------------------------- ### Console Output Debugging Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/samples/console.md This example shows the processed output from the console application after input has been handled. ```text HI THERE! ``` -------------------------------- ### Read Property Example Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Reads a property from a BACnet device. The address must be a local or remote station. Property can include an array index. ```bash > read address objid prop[indx] ``` ```bash > read 192.168.0.18 analog-value,2 present-value ``` ```bash > read 192.168.0.19 analog-output,3 priority-array ``` ```bash > read 192.168.0.20 device,1001 object-list[0] ``` ```bash > read 192.168.0.21 device,1002 object-list[3] ``` -------------------------------- ### Configure Interface Name Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md If ifaddr is installed, use the --address option with an interface name to bind the device to a specific network interface. ```bash $ python3 -m bacpypes3 --address enp0s25 ``` -------------------------------- ### Read Property Multiple Example Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Sends a Read Property Multiple Request to a device to read multiple properties. Supports reading all, required, or optional properties. ```bash > rpm address ( objid ( prop[indx] )... )... ``` ```bash > rpm 192.168.0.20 binary-value,12 all ``` -------------------------------- ### Write Property Example Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Writes a value to a property of a BACnet object. Supports optional priority level. Primitive values can be written from the shell. ```bash > write address objid prop[indx] value [ priority ] ``` ```bash > write 192.168.0.18 analog-value,2 present-value 75.3 ``` ```bash > write 192.168.0.19 analog-output,3 present-value 80.2 10 ``` ```bash > write 192.168.0.19 analog-output,3 present-value null 10 ``` -------------------------------- ### Configure Device Name and Instance Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Set the device name and instance number using the --name and --instance options. ```bash $ python3 -m bacpypes3 --name Intrepid --instance 998 ``` -------------------------------- ### Build BACpypes3 Egg Source: https://github.com/joelbender/bacpypes3/blob/main/samples/docker/README.md Build a Python egg for bacpypes3 using setup.py. This is useful when developing BACpypes locally. ```bash $ python3 setup.py bdist_egg ``` -------------------------------- ### Build BACpypes3 Application Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/samples/start-here.md Creates an application instance from parsed arguments using `Application.from_args()`. This method sets up the core BACpypes3 application stack. ```python # build an application app = Application.from_args(args) if _debug: _log.debug("app: %r", app) ``` -------------------------------- ### Running the Application with Custom Prompt and Debugging Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/samples/console-prompt.md Illustrates how to run the console-prompt application with a custom prompt ('? ') and enable debugging. The output shows the parsed arguments, including the custom prompt, and the new prompt symbol in action. ```bash $ python3 console-prompt.py --prompt '? ' --debug DEBUG:__main__:args: Namespace(..., prompt='? ') DEBUG:__main__:settings: {'debug': ['__main__'], 'color': False, ... } ? ``` -------------------------------- ### Instantiate and Bind Console Objects Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/samples/console.md Creates instances of the Console and Echo server, binds them together to form a communication stack, and initiates the application's main loop using asyncio. ```python # build a very small stack console = Console() echo = Echo() # bind the two objects together, top down bind(console, echo) # run until the console is done, canceled or EOF await console.fini.wait() ``` -------------------------------- ### Build Docker Image with Local Egg Source: https://github.com/joelbender/bacpypes3/blob/main/samples/docker/README.md Build a Docker image for the bacpypes-greetings application, passing the local egg file as a build argument. ```bash # the script needs to be run from its directory DIR=`dirname $0` pushd $DIR > /dev/null # find the latest egg in the dist directory BACPYPES_EGG=`ls -1 ../../dist/bacpypes3-*-py3.x.egg | tail -n 1` # copy it into this build directory cp -v $BACPYPES_EGG . # build the image passing in the file name docker build --tag bacpypes-greetings \ --file bacpypes-greetings.dockerfile \ --build-arg BACPYPES_EGG=`basename $BACPYPES_EGG` \ . popd ``` -------------------------------- ### Application.from_object_list() Source: https://context7.com/joelbender/bacpypes3/llms.txt Constructs an `Application` from an explicit list of `Object` instances. This method provides full programmatic control over the device object and any additional BACnet objects hosted locally, serving as the foundation for building servers. ```APIDOC ## Application.from_object_list() ### Description Constructs an `Application` from an explicit list of `Object` instances. This gives full programmatic control over the device object and any additional BACnet objects that should be hosted locally, and is the foundation for building servers. ### Method Signature `Application.from_object_list(object_list)` ### Parameters - **object_list** (list): A list of `Object` instances (e.g., `DeviceObject`, `NetworkPortObject`). ### Request Example ```python import asyncio from bacpypes3.app import Application from bacpypes3.local.device import DeviceObject from bacpypes3.local.networkport import NetworkPortObject async def main(): device_object = DeviceObject( objectIdentifier=("device", 599), objectName="BuildingController", vendorIdentifier=999, description="HVAC controller for building A", ) network_port_object = NetworkPortObject( "192.168.0.10/24", objectIdentifier=("network-port", 1), objectName="NetworkPort-1", ) app = Application.from_object_list([device_object, network_port_object]) try: await asyncio.Future() finally: app.close() asyncio.run(main()) ``` ### Response - **app** (`Application`): An instantiated and configured BACpypes3 Application object. ### Notes This method is ideal for scenarios requiring fine-grained control over the BACnet device's objects and configuration. ``` -------------------------------- ### Enable Basic Console Debugging Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/samples/console.md Run the console application with the --debug flag to see initialization logs. This provides insight into the application's startup process and initial settings. ```bash $ python3 console.py --debug ``` ```log DEBUG:__main__:args: Namespace(loggers=False, debug=[], color=None, route_aware=None) DEBUG:__main__:settings: {'debug': ['__main__'], 'color': False, 'debug_file': '', 'max_bytes': 1048576, 'backup_count': 5, 'route_aware': False, 'cov_lifetime': 60, 'config': {} } DEBUG:__main__:console, echo: , <__main__.Echo object at 0x7f3c35cfae00> ``` -------------------------------- ### Run BACpypes Docker Image Source: https://github.com/joelbender/bacpypes3/blob/main/samples/docker/README.md Executes the 'bacpypes-greetings' Docker image interactively and removes the container upon exit. ```bash docker run -it --rm bacpypes-greetings ``` -------------------------------- ### Create BACnet Application from JSON Configuration Source: https://context7.com/joelbender/bacpypes3/llms.txt Use `Application.from_json()` to instantiate a BACnet application from a list of JSON-serializable dictionaries representing BACnet objects. Vendor-specific types are resolved automatically. ```python import asyncio from bacpypes3.app import Application object_list = [ { "object-identifier": "device,1001", "object-name": "JSONDevice", "vendor-identifier": 999, }, { "object-identifier": "network-port,1", "object-name": "NetworkPort-1", "ip-address": "192.168.1.50/24", }, ] async def main(): app = Application.from_json(object_list) try: await asyncio.Future() finally: app.close() asyncio.run(main()) ``` -------------------------------- ### DeviceObject and BACnet Object Types Source: https://context7.com/joelbender/bacpypes3/llms.txt Demonstrates the creation and usage of `DeviceObject`, the mandatory root object for BACnet devices, and other standard object types like `AnalogValueObject` and `BinaryValueObject`. Shows how to instantiate objects and serialize/deserialize them to JSON. ```APIDOC ## `DeviceObject` and BACnet Object Types `DeviceObject` is the mandatory root object for any BACnet device. Additional standard object types (`AnalogValueObject`, `BinaryValueObject`, `ScheduleObject`, etc.) live in `bacpypes3.local.*` and can be instantiated with keyword arguments matching BACnet property names (camelCase to hyphenated-lowercase mapping is automatic). ```python from bacpypes3.local.device import DeviceObject from bacpypes3.local.analog import AnalogValueObject from bacpypes3.local.binary import BinaryValueObject from bacpypes3.json import sequence_to_json, json_to_sequence # Create a device object dev = DeviceObject( objectIdentifier=("device", 5001), objectName="PLC-5001", vendorIdentifier=999, modelName="BACpypes3 Demo", description="Sample BACnet device", ) # Create an analog value object av = AnalogValueObject( objectIdentifier=("analog-value", 1), objectName="SetpointTemp", presentValue=22.5, units="degrees-celsius", covIncrement=0.5, ) # Create a binary value object bv = BinaryValueObject( objectIdentifier=("binary-value", 1), objectName="OccupancyOverride", presentValue="active", ) # Serialise to JSON and round-trip json_data = sequence_to_json(av) print(json_data) # {'object-identifier': 'analog-value,1', 'object-name': 'SetpointTemp', # 'present-value': 22.5, 'units': 'degrees-celsius', ...} av2 = json_to_sequence(json_data, AnalogValueObject) print(av2.presentValue) # 22.5 ``` ``` -------------------------------- ### Run BACpypes3 module Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/index.md Run the bacpypes3 module directly to create a small stack of communications objects and present a shell prompt. ```bash python3 -m bacpypes3 > ``` -------------------------------- ### Application.from_json() Source: https://context7.com/joelbender/bacpypes3/llms.txt Instantiates an `Application` from a list of JSON-serialisable dictionaries representing BACnet objects. Vendor-specific object and property types are automatically resolved using the `vendor-identifier` from the device object entry. ```APIDOC ## Application.from_json() ### Description Instantiates an `Application` from a list of JSON-serialisable dictionaries that represent BACnet objects. Vendor-specific object and property types are resolved automatically using the `vendor-identifier` found in the device object entry. ### Method Signature `Application.from_json(object_list)` ### Parameters - **object_list** (list): A list of dictionaries, where each dictionary represents a BACnet object and its properties. ### Request Example ```python import asyncio from bacpypes3.app import Application object_list = [ { "object-identifier": "device,1001", "object-name": "JSONDevice", "vendor-identifier": 999, }, { "object-identifier": "network-port,1", "object-name": "NetworkPort-1", "ip-address": "192.168.1.50/24", }, ] async def main(): app = Application.from_json(object_list) try: await asyncio.Future() finally: app.close() asyncio.run(main()) ``` ### Response - **app** (`Application`): An instantiated and configured BACpypes3 Application object. ### Notes This method simplifies application setup when object configurations are stored in a JSON format. ``` -------------------------------- ### Configure Foreign Device Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Register as a foreign device with a specified IP address and time-to-live using the --foreign and --ttl options. ```bash $ python3 -m bacpypes3 --foreign 192.168.1.11 --ttl 30 ``` -------------------------------- ### Create BACnet Application from Object List Source: https://context7.com/joelbender/bacpypes3/llms.txt Use `Application.from_object_list()` to construct a BACnet application from a list of explicit `Object` instances. This provides full programmatic control and is suitable for building servers. ```python import asyncio from bacpypes3.app import Application from bacpypes3.local.device import DeviceObject from bacpypes3.local.networkport import NetworkPortObject async def main(): device_object = DeviceObject( objectIdentifier=("device", 599), objectName="BuildingController", vendorIdentifier=999, description="HVAC controller for building A", ) network_port_object = NetworkPortObject( "192.168.0.10/24", objectIdentifier=("network-port", 1), objectName="NetworkPort-1", ) app = Application.from_object_list([device_object, network_port_object]) try: await asyncio.Future() finally: app.close() asyncio.run(main()) ``` -------------------------------- ### Configure IPv4 Address and Subnet Mask (Notation) Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Use the --address option with subnet mask notation to specify the IPv4 address and subnet mask for the device. ```bash $ python3 -m bacpypes3 --address 192.168.0.10/255.255.255.0 ``` -------------------------------- ### Create BACnet Device and Value Objects Source: https://context7.com/joelbender/bacpypes3/llms.txt Instantiate BACnet objects like `DeviceObject`, `AnalogValueObject`, and `BinaryValueObject` using keyword arguments that map to BACnet property names. The library handles camelCase to hyphenated-lowercase conversion. JSON serialization and deserialization are also demonstrated. ```python from bacpypes3.local.device import DeviceObject from bacpypes3.local.analog import AnalogValueObject from bacpypes3.local.binary import BinaryValueObject from bacpypes3.json import sequence_to_json, json_to_sequence # Create a device object dev = DeviceObject( objectIdentifier=("device", 5001), objectName="PLC-5001", vendorIdentifier=999, modelName="BACpypes3 Demo", description="Sample BACnet device", ) # Create an analog value object av = AnalogValueObject( objectIdentifier=("analog-value", 1), objectName="SetpointTemp", presentValue=22.5, units="degrees-celsius", covIncrement=0.5, ) # Create a binary value object bv = BinaryValueObject( objectIdentifier=("binary-value", 1), objectName="OccupancyOverride", presentValue="active", ) # Serialise to JSON and round-trip json_data = sequence_to_json(av) print(json_data) # {'object-identifier': 'analog-value,1', 'object-name': 'SetpointTemp', # 'present-value': 22.5, 'units': 'degrees-celsius', ...} av2 = json_to_sequence(json_data, AnalogValueObject) print(av2.presentValue) # 22.5 ``` -------------------------------- ### Console Initialization Debugging with Module Specificity Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/samples/console.md Examine the initialization logs for the Console class when specific modules are targeted for debugging. This includes details about the prompt and history file. ```log DEBUG:bacpypes3.console.Console:__init__ '> ' 'console.py.history' None ``` -------------------------------- ### Enable General Debugging Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/debugging.md Enable general debugging for the BACpypes3 application to see detailed output about its execution flow. This is useful for understanding the application's startup process and object instantiation. ```text $ python3 -m bacpypes3 --debug DEBUG:__main__:args: Namespace(loggers=False, debug=[], ...) DEBUG:__main__:app: DEBUG:__main__:local_adapter: adapterSAP = adapterAddr = adapterNetConfigured = 0 DEBUG:__main__:bvll_sap: DEBUG:__main__:bvll_ase: > ``` -------------------------------- ### Application.who_is() / Application.i_am() Source: https://context7.com/joelbender/bacpypes3/llms.txt Discovers devices on the network by broadcasting a Who-Is request and collecting I-Am responses. The `i_am()` method sends a local device announcement. ```APIDOC ## Application.who_is() / Application.i_am() ### Description Broadcasts a **Who-Is** unconfirmed request and collects **I-Am** responses within a configurable timeout window. Returns a list of `IAmRequest` APDUs. Narrowing by device instance range or a specific address terminates early on the first match. `i_am()` sends a local device announcement. ### Method `await app.who_is(low_limit=None, high_limit=None, timeout=None)` `app.i_am()` ### Parameters for `who_is()` - **low_limit** (int, optional) - The lower bound of the device instance range to discover. - **high_limit** (int, optional) - The upper bound of the device instance range to discover. - **timeout** (int, optional) - The maximum time in seconds to wait for I-Am responses. ### Response for `who_is()` Returns a list of `IAmRequest` APDUs, each containing information about a discovered device. ### Request Example for `who_is()` ```python # Discover all devices in instance range 0–4194303 i_ams = await app.who_is() # Discover devices in a specific range with a timeout i_ams = await app.who_is(low_limit=1000, high_limit=1999, timeout=5) ``` ### Response Example for `who_is()` ```python # Example output: # Device 123 at 192.168.1.100:47808 # Found 5 devices in range 1000-1999 ``` ### Request Example for `i_am()` ```python # Send our own I-Am announcement app.i_am() ``` ``` -------------------------------- ### Access BACpypes3 shell commands Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/index.md Type 'help' in the BACpypes3 shell to view available commands for examining the local BACnet internetwork. ```bash > help ``` -------------------------------- ### Initialize Console with Custom Prompt Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/samples/console-prompt.md Initializes the Console object with a custom prompt obtained from command-line arguments. This allows the application to use the user-defined prompt instead of the default one. ```python console = Console() ``` ```python console = Console(prompt=args.prompt) ``` -------------------------------- ### Import Core BACpypes3 Modules Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/samples/console.md Imports necessary modules for asyncio, typing, settings, debugging, argument parsing, and console interaction. ```python import asyncio from typing import Callable from bacpypes3.settings import settings ``` ```python from bacpypes3.debugging import ModuleLogger ... # some debugging _debug = 0 _log = ModuleLogger(globals()) ``` ```python from bacpypes3.argparse import ArgumentParser ``` ```python from bacpypes3.console import Console, ConsolePDU ``` -------------------------------- ### Clone BACpypes3 from GitHub Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/index.md Clone the latest version of BACpypes3 from its GitHub repository. ```bash git clone https://github.com/JoelBender/BACpypes3.git cd BACpypes3 ``` -------------------------------- ### Discover BACnet Devices with Who-Is and I-Am Source: https://context7.com/joelbender/bacpypes3/llms.txt Broadcasts a Who-Is request to discover devices on the network and collects I-Am responses. Can narrow discovery by device instance range for faster results. Also includes functionality to send a local device announcement using i_am(). ```python import asyncio from bacpypes3.argparse import SimpleArgumentParser from bacpypes3.app import Application async def main(): app = Application.from_args(SimpleArgumentParser().parse_args()) try: # Discover all devices in instance range 0–4194303 i_ams = await app.who_is() for i_am in i_ams: inst = i_am.iAmDeviceIdentifier[1] addr = i_am.pduSource print(f"Device {inst} at {addr}") # Narrow to a specific range (returns faster) i_ams = await app.who_is(low_limit=1000, high_limit=1999, timeout=5) print(f"Found {len(i_ams)} devices in range 1000-1999") # Send our own I-Am announcement app.i_am() finally: app.close() asyncio.run(main()) ``` -------------------------------- ### Dockerfile Copy Application and Egg Source: https://github.com/joelbender/bacpypes3/blob/main/samples/docker/README.md Copies the Python application script and the BACpypes3 egg file into the container's working directory. ```dockerfile ARG BACPYPES_EGG COPY ${BACPYPES_EGG} . ENV PYTHONPATH ${BACPYPES_EGG} ``` -------------------------------- ### Dockerfile Base and Working Directory Source: https://github.com/joelbender/bacpypes3/blob/main/samples/docker/README.md Sets the base Python image and defines the working directory within the container. ```dockerfile FROM python:3.x-slim WORKDIR /app ``` -------------------------------- ### SimpleArgumentParser for CLI Arguments Source: https://context7.com/joelbender/bacpypes3/llms.txt Wraps argparse.ArgumentParser to provide standard BACnet device arguments and integrated logging configuration. Defaults can be set via environment variables. ```python from bacpypes3.argparse import SimpleArgumentParser import asyncio from bacpypes3.app import Application async def main(): # Automatically adds: --name, --instance, --address, --vendoridentifier, # --network, --foreign, --ttl, --bbmd, --debug parser = SimpleArgumentParser() parser.add_argument("target", help="BACnet device address to poll") args = parser.parse_args() # args.name, args.instance, args.address, args.vendoridentifier ... app = Application.from_args(args) result = await app.read_property(args.target, "device,1", "object-name") print(result) app.close() # CLI usage: # python script.py --name Tester --instance 999 --address host 192.168.1.100 asyncio.run(main()) ``` -------------------------------- ### Run Docker Container with Host Networking Source: https://github.com/joelbender/bacpypes3/blob/main/samples/docker/README.md Use this command to run a Docker container interactively, remove it when finished, and map its network to the host's network. This is crucial for BACnet applications that need to communicate with devices outside the container. ```bash docker run -it --rm \ --network host \ --env BBMD_ADDRESS \ --env TTL \ who-is-console:latest ``` -------------------------------- ### Send Initialize-Routing-Table Command Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md This command sends an Initialize-Routing-Table message to a router to request its current routing table. The address is typically a local station address. ```bash irt [ address ] ``` -------------------------------- ### Configure IPv4 Address and Subnet Mask (CIDR) Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Use the --address option with CIDR notation to specify the IPv4 address and subnet mask for the device. ```bash $ python3 -m bacpypes3 --address 192.168.0.10/24 ``` -------------------------------- ### Send Who-Has Request Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Sends a Who-Has Request to discover devices on the network. Optional parameters include device object ID, object name, and address. ```bash > whohas [ low_limit high_limit ] [ objid ] [ objname ] [ address ] ``` -------------------------------- ### Define Build Arguments in Dockerfile Source: https://github.com/joelbender/bacpypes3/blob/main/samples/docker/README.md Define ARG statements in your Dockerfile to accept build-time variables. These correspond to environment variables passed during the `docker run` command. ```dockerfile ARG BBMD_ADDRESS ARG TTL ``` -------------------------------- ### Configure Vendor Identifier Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Set the vendor identifier property for the device object using the --vendor-identifier option. ```bash $ python3 -m bacpypes3 --vendor-identifier 888 ``` -------------------------------- ### Define Echo Server Class Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/samples/console.md Defines a simple Echo server that inherits from Server and processes ConsolePDU objects. It converts received PDU content to uppercase and sends it back as a response. ```python from bacpypes3.comm import Server, ... @bacpypes_debugging class Echo(Server[ConsolePDU]): async def indication(self, pdu: ConsolePDU) -> None: ... if pdu is None: return # send the uppercase content back up the stack await self.response(pdu.upper()) ``` -------------------------------- ### Who-Has Command Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Initiates a Who-Has request to discover devices on the network. It can optionally filter by device instance range, object ID, object name, and target address. ```APIDOC ## Who-Has ### Description This is a long line of text. ### Usage ```default > whohas [ low_limit high_limit ] [ objid ] [ objname ] [ address ] ``` ``` -------------------------------- ### Save BACpypes3 Configuration to JSON Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md This command generates the BACpypes3 configuration in JSON format. The output can be redirected to a file for use by other applications. ```bash $ echo "config json" | python3 -m bacpypes3 > sample-config.json ``` -------------------------------- ### Parse Command Line Arguments Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/samples/start-here.md Parses command-line arguments using the SimpleArgumentParser. This is a common first step for BACpypes3 applications. ```python args = SimpleArgumentParser().parse_args() if _debug: _log.debug("args: %r", args) ``` -------------------------------- ### Debug Specific Class Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/debugging.md Debug a specific class, like 'bacpypes3.ipv4.IPv4DatagramServer', to observe its initialization and method calls. This provides granular insight into how a particular class handles network communication and messages. ```text $ python3 -m bacpypes3 --debug bacpypes3.ipv4.IPv4DatagramServer DEBUG:bacpypes3.ipv4.IPv4DatagramServer:__init__ no_broadcast=False DEBUG:bacpypes3.ipv4.IPv4DatagramServer: - local_address: ('10.0.1.90', 47808) DEBUG:bacpypes3.ipv4.IPv4DatagramServer: - local_endpoint_task: ... DEBUG:bacpypes3.ipv4.IPv4DatagramServer:set_local_transport_protocol ... ... > whois DEBUG:bacpypes3.ipv4.IPv4DatagramServer:indication pduDestination = pduExpectingReply = False pduNetworkPriority = 0 pduData = x'81.0b.00.0c.01.20.ff.ff.00.ff.10.08' ... > ``` -------------------------------- ### Execute Who-Is Shell Command Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Send a Who-Is Request from the bacpypes3 shell prompt. Optionally specify an address and a range of device instance limits. ```bash > whois [ address [ low_limit high_limit ] ] ``` -------------------------------- ### I-Have Command Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Sends an I-Have Request to announce the availability of an object. Requires the object ID, object name, and optionally a target address. ```APIDOC ## I-Have ### Description This command sends an I-Have Request (Clause 16.9.3) The *objid* is an object identifier. For object identifier syntax see [Object and Property Identifiers](objectidentifiers.md). The *objname* is an object name. The *address* can be any of the five types of addresses; local station, local broadcast, remote station, remote broadcast, or global broadcast. For address syntax patterns see [BACpypes3 Addresses](addresses.md). ### Usage ```default > ihave objid objname [ address ] ``` ``` -------------------------------- ### Console Input and Echo Debugging Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/samples/console.md Observe the debugging output when user input is provided to the console. This shows the 'indication' method being called with the input content. ```text > Hi there! ``` ```log DEBUG:__main__.Echo:indication 'Hi there!' ``` -------------------------------- ### Configure BBMD with BDT Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Configure the workstation as a BACnet Broadcast Management Device (BBMD) by providing a Broadcast Distribution Table (BDT) with the --bbmd option. ```bash $ python3 -m bacpypes3 --address 192.168.0.10/24 --bbmd 192.168.0.10 192.168.1.11 ``` -------------------------------- ### Expand Environment Variables in Docker CMD Source: https://github.com/joelbender/bacpypes3/blob/main/samples/docker/README.md Use variable expansion within the CMD instruction in your Dockerfile to pass environment variables to your application. This allows dynamic configuration of the application at runtime. ```dockerfile CMD python3 who-is-console.py --foreign ${BBMD_ADDRESS} --ttl ${TTL} ``` -------------------------------- ### List Available Loggers Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/debugging.md Use the --loggers option to display a list of all available loggers in the BACpypes3 application. This helps in identifying which modules or classes can be targeted for debugging. ```default $ python3 -m bacpypes3 --loggers ``` -------------------------------- ### Application.write_property() Source: https://context7.com/joelbender/bacpypes3/llms.txt Sends a BACnet WriteProperty confirmed service request. Accepts priority (1–16 for commandable objects) and an optional array index. Returns None on success or raises ErrorRejectAbortNack. ```APIDOC ## `Application.write_property()` ### Description Sends a BACnet **WriteProperty** confirmed service request. Accepts priority (1–16 for commandable objects) and an optional array index. Returns `None` on success or raises `ErrorRejectAbortNack`. ### Method Signature ```python async def write_property(self, address: str, object_id: str, property_id: str, value: Any, instance: Optional[int] = None, priority: Optional[int] = None) ``` ### Parameters - **address** (`str`): The network address of the remote device. - **object_id** (`str`): The identifier of the object (e.g., `"analog-output,1"`). - **property_id** (`str`): The identifier of the property to write (e.g., `"present-value"`). - **value** (`Any`): The value to write to the property. Use `None` to relinquish priority. - **instance** (`Optional[int]`): The instance number of the object (used for array elements). - **priority** (`Optional[int]`): The priority level for the write operation (1-16). ### Request Example ```python import asyncio from bacpypes3.argparse import SimpleArgumentParser from bacpypes3.app import Application from bacpypes3.apdu import ErrorRejectAbortNack async def main(): app = Application.from_args(SimpleArgumentParser().parse_args()) try: # Write present-value at priority 8 await app.write_property( "192.168.1.100", "analog-output,1", "present-value", 72.0, # value None, # array_index 8, # priority ) print("Write succeeded") # Relinquish (write Null) to release priority await app.write_property( "192.168.1.100", "analog-output,1", "present-value", None, # Null relinquishes the priority None, 8, ) except ErrorRejectAbortNack as err: print(f"Write failed: {err}") finally: app.close() asyncio.run(main()) ``` ``` -------------------------------- ### Configure Alternate Port Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md Specify an alternate port number using the --address option when the standard port is in use. ```bash $ python3 -m bacpypes3 --address 192.168.0.10/24:47809 ``` -------------------------------- ### Register Vendor-Specific Information Source: https://context7.com/joelbender/bacpypes3/llms.txt Use `VendorInfo` to register vendor identifiers and extend the BACnet type system with proprietary object types and property identifiers. This information is automatically used by `Application` for encoding and decoding. ```python from bacpypes3.vendor import VendorInfo from bacpypes3.primitivedata import ObjectType, PropertyIdentifier from bacpypes3.object import Object from bacpypes3.constructeddata import Sequence from bacpypes3.primitivedata import Real, CharacterString # Example usage would follow here, but the provided snippet is incomplete. ``` -------------------------------- ### Send Read-Foreign-Device-Table Request Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/running.md This command fetches the foreign device table from a BBMD, which includes registered devices and their time-to-live. The IP address can be IPv4 or IPv6. ```bash rfdt ip-address ``` -------------------------------- ### Run BACpypes3 Application Indefinitely Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/samples/start-here.md Keeps the application running indefinitely using `asyncio.Future()`. This is typical for server-like applications or gateways that need to remain active. ```python # like running forever await asyncio.Future() ``` -------------------------------- ### Debug Specific Module Source: https://github.com/joelbender/bacpypes3/blob/main/doc/source/gettingstarted/debugging.md Focus debugging efforts on a specific module, such as 'bacpypes3.netservice.NetworkAdapter', to reduce log verbosity and pinpoint issues within that module. This is useful for understanding the internal workings of particular components. ```text $ python3 -m bacpypes3 --debug bacpypes3.netservice.NetworkAdapter DEBUG:bacpypes3.netservice.NetworkAdapter:__init__ ... adapters = {} router_info_cache = > ```