Last active
February 9, 2024 17:15
-
-
Save bbartling/573030a2facc97e178b2362606b9cdda to your computer and use it in GitHub Desktop.
bacpypes3 example of a BACnet server ran Docker on rasp pi hardware with Alpine Linux. App is a make over of legacy bacpypes mini_device.py from repo samples directory but in bacpypes3 asyncio version
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Use an Alpine Linux base image for Raspberry Pi | |
FROM arm32v7/alpine:latest | |
# Set the working directory in the container | |
WORKDIR /app | |
# Install necessary packages and dependencies | |
RUN apk --no-cache add python3 python3-dev py3-pip | |
# Install BACpypes and any other required dependencies | |
RUN pip3 install bacpypes3 | |
# Copy your Python application into the container | |
COPY mini_device_revisited.py /app/mini_device_revisited.py | |
# Expose the UDP port 47808 | |
EXPOSE 47808/udp | |
# Define the command to run your BACpypes application | |
# CMD ["python3", "/app/mini_device_revisited.py", "--debug", "bacpypes3.ipv4.IPv4DatagramProtocol"] | |
CMD ["python3", "/app/mini_device_revisited.py", "--debug"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import asyncio | |
from bacpypes3.debugging import ModuleLogger | |
from bacpypes3.argparse import SimpleArgumentParser | |
from bacpypes3.app import Application | |
from bacpypes3.local.analog import AnalogValueObject | |
from bacpypes3.local.binary import BinaryValueObject | |
from bacpypes3.local.analog import AnalogValueObject | |
from bacpypes3.local.cmd import Commandable | |
class CommandableAnalogValueObject(Commandable, AnalogValueObject): | |
""" | |
Commandable Analog Value Object | |
""" | |
_debug = 0 | |
_log = ModuleLogger(globals()) | |
INTERVAL = 1.0 | |
class SampleApplication: | |
def __init__(self, args, test_bv, test_av, commandable_analog_value): | |
# embed an application | |
self.app = Application.from_args(args) | |
# extract the kwargs that are special to this application | |
self.test_bv = test_bv | |
self.app.add_object(test_bv) | |
self.test_av = test_av | |
self.app.add_object(test_av) | |
self.commandable_analog_value = commandable_analog_value | |
self.app.add_object(commandable_analog_value) | |
# create a task to update the values | |
asyncio.create_task(self.update_values()) | |
async def update_values(self): | |
test_values = [ | |
("active", 1.0), | |
("inactive", 2.0), | |
("active", 3.0), | |
("inactive", 4.0), | |
] | |
while True: | |
await asyncio.sleep(INTERVAL) | |
next_value = test_values.pop(0) | |
test_values.append(next_value) | |
if _debug: | |
_log.debug(" - next_value: %r", next_value) | |
_log.debug( | |
"commandable_analog_value: %r", | |
self.commandable_analog_value.presentValue, | |
) | |
self.test_av.presentValue = next_value[1] | |
self.test_bv.presentValue = next_value[0] | |
async def main(): | |
args = SimpleArgumentParser().parse_args() | |
if _debug: | |
_log.debug("args: %r", args) | |
# define BACnet objects | |
test_av = AnalogValueObject( | |
objectIdentifier=("analogValue", 1), | |
objectName="av", | |
presentValue=0.0, | |
statusFlags=[0, 0, 0, 0], | |
covIncrement=1.0, | |
) | |
_log.debug(" - test_av: %r", test_av) | |
test_bv = BinaryValueObject( | |
objectIdentifier=("binaryValue", 1), | |
objectName="bv", | |
presentValue="inactive", | |
statusFlags=[0, 0, 0, 0], | |
) | |
_log.debug(" - test_bv: %r", test_bv) | |
# Create an instance of your commandable object | |
commandable_analog_value = CommandableAnalogValueObject( | |
objectIdentifier=("analogValue", 3), | |
objectName="commandable-av", | |
presentValue=-1.0, | |
statusFlags=[0, 0, 0, 0], | |
covIncrement=1.0, | |
description="Commandable analog value object", | |
) | |
# instantiate the SampleApplication with test_av and test_bv | |
app = SampleApplication( | |
args, | |
test_av=test_av, | |
test_bv=test_bv, | |
commandable_analog_value=commandable_analog_value, | |
) | |
if _debug: | |
_log.debug("app: %r", app) | |
await asyncio.Future() | |
if __name__ == "__main__": | |
try: | |
asyncio.run(main()) | |
except KeyboardInterrupt: | |
if _debug: | |
_log.debug("keyboard interrupt") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# build docker file with: | |
sudo docker build -t bacpypes-three-mini-device-revisited . | |
# run docker file: | |
sudo docker run -d -p 47808:47808/udp --name my-bacpypes-container bacpypes-three-mini-device-revisited | |
sudo docker run -d --network="host" --name my-bacpypes-container bacnet-server | |
# stop docker container: | |
sudo docker stop my-bacpypes-container | |
# remove docker container if you want to make change to .py file rebuild and run again: | |
sudo docker rm my-bacpypes-container | |
# view logs: | |
sudo docker logs my-bacpypes-container | |
# tail logs: | |
sudo docker logs -f my-bacpypes-container | |
# pipe logs to less: | |
sudo docker logs my-bacpypes-container | less | |
# pip install ifaddr | |
# verify app is listening on port 47808 | |
$ ss --listening --udp --process | grep 47808 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment