ChristianTremblay / BAC0

BAC0 - Library depending on BACpypes3 (Python 3) to build automation script for BACnet applications
GNU Lesser General Public License v3.0
174 stars 99 forks source link

how to create virtual bacnet devices and implementing python #146

Closed praveengowda1 closed 5 years ago

praveengowda1 commented 5 years ago

im very new to the bacnet protocol.I'm working in python , so i need help regarding python library called BAC0. i already read BAC0 documentation on the internet and tried their examples but im not able to get the curect output. please help me with some examples like how to create virtual bacnet devices and how to perform read and write operation on which using python programing.Thanks in advance.

praveengowda1 commented 5 years ago

@ChristianTremblay sir, can you please help me with this.

ChristianTremblay commented 5 years ago

Hi @praveengowda1, please have a look here : https://github.com/ChristianTremblay/BAC0/blob/master/tests/conftest.py

I'm using this to test the application. I create BAC0 instances to which I add points then I make the two instances talk to each other.

For example : https://github.com/ChristianTremblay/BAC0/blob/master/tests/test_Read.py

praveengowda1 commented 5 years ago

hi @ChristianTremblay thank you for the replie. im not getting your testing code , actually im not using any bacnet devices . I need to create virtual bacnet device and using that i neet to read and write the object list .I have some sample code plz check once import BAC0 bacnet=BAC0.connect(ip='10.0.0.83') print(bacnet)

mycontroller = BAC0.device('169.254.194.35:47808',481641,bacnet)

print(bacnet.whois()) device=mycontroller.points and iam getting the output like 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data. 2019-07-26 09:21:56,967 - WARNING | Offline: provide database name to load stored data.

also im getting the errors like

File "C:\Users\DELL\Anaconda3\lib\site-packages\BAC0\core\io\Read.py", line 184, in read "APDU Abort Reason : {}".format(reason) BAC0.core.io.IOExceptions.NoResponseFromController: APDU Abort Reason : noResponse

and im using visual test shell software to create the bacnet devices and it acts as slave , so i need the code/script that acts as master to read/write values from that devices pl help me with that

praveengowda1 commented 5 years ago

hi @ChristianTremblay , sir : https://github.com/ChristianTremblay/BAC0/blob/master/tests/conftest.py what above examples will exactly do , can you plz tell me. when i run that code i will not give any output, simply it will run without error and terminates with exit 0 plz help me with that

ChristianTremblay commented 5 years ago

This code shows how you can build your own BACnet device using BAC0. You define an instance, you define some objects that you attach to your device and when BAC0 will start, it will behave as a real BACnet device.

Using this method, you don't need to use VTS (which I don't know and won't support).

Once your BAC0 instance runs, you can fire another one, using a different port (let say 47809). Then you can connect to the first one and ask for data.

Simply running the code in the test folder won't help you as they are unit test for the software. But if you mimic what have been done there, you will have a BACnet device to play with.

praveengowda1 commented 5 years ago

Thank you for the reply , but im not able to understand how i can get the data from another device using above code, can i get more clarity. is above code acts as client / server.

On Mon, Jul 29, 2019 at 8:49 PM Christian Tremblay notifications@github.com wrote:

This code shows how you can build your own BACnet device using BAC0. You define an instance, you define some objects that you attach to your device and when BAC0 will start, it will behave as a real BACnet device.

Using this method, you don't need to use VTS (which I don't know and won't support).

Once your BAC0 instance runs, you can fire another one, using a different port (let say 47809). Then you can connect to the first one and ask for data.

Simply running the code in the test folder won't help you as they are unit test for the software. But if you mimic what have been done there, you will have a BACnet device to play with.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ChristianTremblay/BAC0/issues/146?email_source=notifications&email_token=AMV62UNUBKDUD35QWC4X2HDQB4BIFA5CNFSM4IGAVD7KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3A77YQ#issuecomment-516030434, or mute the thread https://github.com/notifications/unsubscribe-auth/AMV62UI7KC574M7UTSB5F3DQB4BIFANCNFSM4IGAVD7A .

ChristianTremblay commented 5 years ago

BACnet itself works in a way that a device will act as a client and a server.

When you run BAC0.lite() for example, you get a BACnet instance that can be discovered by other BACnet devices and that can discover and interact with others.

What I’m saying is once you started your instance :

bacnet = BAC0.lite()

If you follow the contest code I pointed, you will add let say, an AnalogValue to the thing.

This means that another device could find your instance on the network and ask for the value.

In my test code, I define 3-4 instances. One on port 47808, one on 47809... so on. This way I will be able to share one network card with different instances. Because the way bacnet works, it will always keep the socket open to answer to network request (like a server).

The different instances I created are then able to communicate with the others.

I know it is different than a lot of client server architecture and that can be tricky.

In the example I pointed you need that part where the instance is declared. You need the part where points are added.

Work in the REPL directly for these tests. Or Jupiter Notebook. It will ease your process. Declare 2 bacnet instances :

Bacnet1 = BAC0.lite() Bacnet2 = BAC0.lite(port=47809)

Add points to one of them (let say one analpgValue at address 1 on bacnet2) Then use bacnet1 to read from bacnet2

Bacnet1.read(“IPofbavnet2:47809 analogValue 1 presentValue”)

Clearer ? Let me know.

praveengowda1 commented 5 years ago

what is the syntax for the read() can i get to know that

ChristianTremblay commented 5 years ago

If you dont know nothing about BACnet, I understand it may be a lot to acquire :-) Would have been simpler using a real BACnet device and start playing with BAC0 from there.

I’ll try to simplify so I’ll take shortcuts... hope you will excuse them. BACnet devices are clients and server BAC0 devices get the socket and will keep it forever. BACnet devices are identified by their MAC address (typically an MSTP address or an IP address... we won’t talk about the others and I’ll stick to IP) As BACnet devices may spread across multiple physical networks, the concept of ‘device instance’ is really important to identify devices on the global BACnet network.

Once connected to a network bacnet = BAC0.lite() (for example), it is possible to make a request to know what devices are on the network. This is called by bacnet.whois() The result from whois will tell you the mac and the device instance of the devices connected. You need those information to connect.

Now, BACnet devices contain objects. Objects contain properties. One important object is the ‘device’ object. One important property of the device object is objectList This property will get you the list of all objects in the controller.

This mean that if you know that on your network, there is a bacnet device at mac 192.168.1.2 with instance 100, you could ask this device for its object list. bacnet.read(“192.168.1.2 device 100 objectList”)

See the syntax... : mac...then object.... the instance of object....then property

So if there is only one mode object in this device : (analogValue, 1) You will be able to read

bacnet.read(“192.168.1.2 analogValue 1 presentValue”

For properties of object, if you don’t have access to a copy of the BACnet standard, I recommend you read bacpypes code. See the object.py file.

praveengowda1 commented 5 years ago

hi @ChristianTremblay thank you for your attention , i understood the above discription , when i try to run this code. bacnet.read("192.168.1.2 device 100 objectList") im encountering the errors like Traceback (most recent call last): File "E:/EMS/BACPYPES.py", line 17, in bacnet.read("192.168.1.2 device 100 objectList") File "C:\Users\DELL\Anaconda3\lib\site-packages\BAC0\core\io\Read.py", line 184, in read "APDU Abort Reason : {}".format(reason) BAC0.core.io.IOExceptions.NoResponseFromController: APDU Abort Reason : noResponse i also tried to read the objects from my virtua device also , im not getting it i dont know this but , im using yet another bacnet explorer ...im able to connect to the device and able to send whois() and getting response with im device id but im not able to read the object propertires , im able to send the request and im getting the errors mentioned above please help me with this

ChristianTremblay commented 5 years ago

I need more details. Can you share your code ?

praveengowda1 commented 5 years ago

@ChristianTremblay sure import BAC0

bacnet = BAC0.lite(ip='169.254.194.35/16:63112') print(bacnet)

bacnet.whois()

print(BAC0.version)

read=bacnet.read("169.254.194.35 device 1294418 objectList") print(read) here the device 1294418 is my virtual devide identifier and the software im using is Yet another backnet explorer and room temp simulator and im able to send the read req , i can see that packets cmng in wireshark but the software is not responding to that req but it will responds to who is req.

ChristianTremblay commented 5 years ago

When you define bacnet (BAC0.lite(ip=xxx)) you must give the IP address of the thing running BAC0 (your PC).... so it should be different than the target device you want to read. Also, using port 63112 is not super standard for BACnet... typically, ports 47808 and over are used.

ChristianTremblay commented 5 years ago

Have you make it work ?

praveengowda1 commented 5 years ago

Yes , thank you for your help

On Fri, Aug 9, 2019, 7:38 AM Christian Tremblay notifications@github.com wrote:

Have you make it work ?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ChristianTremblay/BAC0/issues/146?email_source=notifications&email_token=AMV62ULO3NOPVUPXJLJSS3TQDTGSXA5CNFSM4IGAVD7KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD35MF6I#issuecomment-519750393, or mute the thread https://github.com/notifications/unsubscribe-auth/AMV62UJNDSGNJ3AQX2IM5VLQDTGSXANCNFSM4IGAVD7A .

vidyarao123 commented 3 years ago

Hi,

I am new to bacnet. I came across this discussion and used the same code of yours : https://github.com/ChristianTremblay/BAC0/blob/master/tests/conftest.py to understand the concept. My doubts are mostly as similar as @praveengowda1 . When I tried to modify and run your code , I keep getting this error

" IP Address provided (127.0.0.1) already used by BAC0. Check if another software is using port 47808 on this network interface. If so, you can define multiple IP per interface. Or specify another IP using BAC0.lite(ip='IP/mask')" . Fact is that 47808 port number is not used at all in the code. How do I resolve this ?

Also, how do I know what IPs are taken by IP_1 and IP_30 ?

Thanks

NubeDev commented 3 years ago

Have you tried using your host IP address? (as in your PC IP address that your router gave your PC)

vidyarao123 commented 3 years ago

Yes .. Apparently on the wireshark, its detecting an IP address which is not configured in my laptop.

77anS commented 2 years ago

Hi @ChristianTremblay , Could you help me? I try this code below on my workstation

But when I use tool Yabe to discover the virtual devices that create by code below at info: Bacnet/IP over UDP

Network adapter:

Result at terminal: " 2022-05-08 11:23:56,793 - INFO | Changing device state to DeviceDisconnected'> 2022-05-08 11:23:57,056 - INFO | Changing device state to RPMDeviceConnected'> 2022-05-08 11:23:57,260 - INFO | Device 101:[BAC0] found... building points list 2022-05-08 11:23:57,743 - INFO | Ready! 2022-05-08 11:23:57,744 - INFO | Device defined for normal polling with a delay of 10sec 2022-05-08 11:23:57,744 - INFO | Polling started, values read every 10 seconds "

-----------------------------------------------------------------------------------------------------------------------------------

from collections import namedtuple import time

import BAC0

from BAC0.core.devices.local.models import ( analog_input, analog_output, analog_value, binary_input, binary_output, binary_value, multistate_input,](url) multistate_output, multistate_value, date_value, datetime_value, temperature_input, temperature_value, humidity_input, humidity_value, character_string, ) from BAC0.core.devices.local.object import ObjectFactory from BAC0.core.devices.local.models import make_state_text

def add_points(qty_per_type, device):

Start from fresh

ObjectFactory.clear_objects()
basic_qty = qty_per_type - 1
# Analog Inputs
# Default... percent
for _ in range(basic_qty):
    _new_objects = analog_input(presentValue=99.9)
    _new_objects = multistate_value(presentValue=1)

# Supplemental with more details, for demonstration
_new_objects = analog_input(
    name="ZN-T",
    properties={"units": "degreesCelsius"},
    description="Zone Temperature",
    presentValue=21,
)

states = make_state_text(["Normal", "Alarm", "Super Emergency"])
_new_objects = multistate_value(
    description="An Alarm Value",
    properties={"stateText": states},
    name="BIG-ALARM",
    is_commandable=True,
)

# All others using default implementation
for _ in range(qty_per_type):
    _new_objects = analog_output(presentValue=89.9)
    _new_objects = analog_value(presentValue=79.9)
    _new_objects = binary_input()
    _new_objects = binary_output()
    _new_objects = binary_value()
    _new_objects = multistate_input()
    _new_objects = multistate_output()
    _new_objects = date_value()
    _new_objects = datetime_value()
    _new_objects = character_string(presentValue="test")

_new_objects.add_objects_to_application(device)

def main(): bacnet = BAC0.lite(ip = "192.168.0.5",port = 47808, mask = 24, bbmdAddress=None, bbmdTTL=0, bdtable=None, ping=True, ping_delay=300, db_params=None,)

# We'll use 3 devices with our first instance
device_app = BAC0.lite(ip = "192.168.0.11",port=47809, mask = 24, deviceId=101)
device30_app = BAC0.lite(ip = "192.168.0.11",port=47810, mask = 24, deviceId=102)
device300_app = BAC0.lite(ip = "192.168.0.11",port=47811, mask = 24, deviceId=103)

add_points(2, device_app)
add_points(10, device30_app)
add_points(30, device300_app)

ip = device_app.localIPAddr.addrTuple[0]
boid = device_app.Boid

ip_30 = device30_app.localIPAddr.addrTuple[0]
boid_30 = device30_app.Boid

ip_300 = device300_app.localIPAddr.addrTuple[0]
boid_300 = device300_app.Boid

print("ABC:")
print("IP1: ",ip, " BOID: ", boid)

# Connect to test device using main network
test_device = BAC0.device("{}:47809".format(ip), boid, bacnet, poll=10)
# test_device_30 = BAC0.device("{}:47810".format(ip_30), boid_30, bacnet, poll=0)
# test_device_300 = BAC0.device("{}:47811".format(ip_300), boid_300, bacnet, poll=0)

while True:
    time.sleep(0.01)

if name == "main": main()

-----------------------------------------------------------------------------------------------------------------------------------