Implementing "WhoIsIAm" and "WhoHasIHave" services together in a single application
Opened this issue · 4 comments
Hey @JoelBender,
Can you please guide us on how to implement "WhoIsIAm" and "WhoHasIHave" services together in a single application?
We have implemented "WhoIsIAm" services:
- Made a VLAN device object (LocalDevieObject).
vlan_device = LocalDeviceObject(
objectName = 'Sensor <device_instance>'
objectIdentifier = 'Device <device_instance>'
maxApduLengthAccepted=1024,
segmentationSupported='noSegmentation',
vendorIdentifier=,
)
- Made an application and added it to the network.
vlan_app = VLANApplication(vlan_device, vlan_address)
{vlan_device = LocalDeviceObject(), vlan_address = Address(i); where i is the no. of time the loop is being called}
Below is how we have created the VLANApplication Class:
class VLANApplication(
Application,
WhoIsIAmServices,
ReadWritePropertyServices,
):
vlan.add_node(vlan_app.vlan_node)
FYI: After giving the "IAm" response, we add the sensor's (end devices) properties in the VLAN application using "vlan_app.add_object(ravo)", which will get us all the available objectName and objectIdentifier in the end device(sensor). And, we have also confirmed its working using the YABE windows application
So, as per our understanding, We think that for implementing "WhoHasIHave" services we need do the following things:
- Once we get the end device's "objectName and objectIdentifier" we will create another LocalDeviceObject(which will have the objectName and objectIdentifier present in the end_device).
For Ex:
vlan_device2 = LocalDeviceObject(
objectName = ''analogInput"
objectIdentifier = 1
maxApduLengthAccepted=1024,
segmentationSupported='noSegmentation',
vendorIdentifier=,
)
- Then After, we will add this newly created LocalDeviceObject to the already created application and then add it to the network.
vlan_app = VLANApplication(vlan_device2, vlan_address)
vlan.add_node(vlan_app.vlan_node)
If the above approach is incorrect, please guild us further. Else if the above approach is correct, we have some confusion regarding that, which is described below:
i. What should we pass as an address while adding this vlan_device2 into the application,
vlan_app = VLANApplication(vlan_device2, vlan_address)
ii. Let's say we have 3 types of objects in the device (analog input 1, analog input 2, binary input 1). So, firstly, we will create LocalDeviceObject for these 3 object types vlan_device2, vlan_device3, and vlan_device4 respectively.
then after, for each and every object type do we need to write the following line of code? Or, is there any other way to do it all at a time?vlan_app = VLANApplication(vlan_device2, vlan_address)
vlan_app = VLANApplication(vlan_device3, vlan_address)
vlan_app = VLANApplication(vlan_device4, vlan_address)iii. How to cross-verify it with the help of YABE and Wireshark.
We are able to capture "WhoIs" & "IAm" responses through Wireshark. but are unaware of the "WhoHas" & "IHave" responses. We have also tried running the below sample program but are unable to capture any "who-has" or "i-have" responses:python3 bacpypes-master/samples/HandsOnLab/Sample3_WhoHasIHaveApplication.py --ini BACpypes~.ini --debug bacpypes.udp
We Hope, you have understood our issue, please look into this, looking forward to your response.
In case of any confusion please let us know!
The simplest way to get started is to clone the WhoIsIAmVLAN.py sample application and update the parent class list:
class VLANApplication(
ApplicationIOController,
WhoIsIAmServices,
ReadWritePropertyServices,
):
to include the Who-Has and I-Have services by mixing in the WhoHasIHaveServices class:
class VLANApplication(
ApplicationIOController,
WhoIsIAmServices,
WhoHasIHaveServices,
ReadWritePropertyServices,
):
From YABE you should be able to generate a global broadcast Who-Has request for the VLAN device object (the identifier or name that matches the parameters to the LocalDeviceObject
when it was created).
Now to extend the VLAN to include more devices that also have objects, follow the IP2VLANRoute.py sample application that has a loop that creates an application and adds a "random analog value" object to each one. You should then be able to send out a Who-Has for analog value object instance 1 and have all of the VLAN devices respond.
We have already done something similar to this, please look into it and help us further.
Here we have described how we have created the Application class & LocalDeviceObject:
- Make the application
vlan_app = VLANApplication(vlan_device, vlan_address)
> vlan_device = \
LocalDeviceObject(
objectName= "ABCD" + str(device_instance), #name update
objectIdentifier=('device', device_instance),
maxApduLengthAccepted=1024,
segmentationSupported='noSegmentation',
vendorIdentifier= <vendor_id>,
)
> vlan_address = Address(2)
- Application Class
class VLANApplication(
Application,
WhoIsIAmServices,
WhoHasIHaveServices,
ReadWritePropertyServices,
):
def __init__(self, vlan_device, vlan_address, aseID=None):
if _debug: VLANApplication._debug("__init__ %r %r aseID=%r", vlan_device, vlan_address, aseID)
global args
# normal initialization
Application.__init__(self, vlan_device, aseID=aseID)
# optional read property multiple
#if args.rpm:
# self.add_capability(ReadWritePropertyMultipleServices)
# include a application decoder
self.asap = ApplicationServiceAccessPoint()
# pass the device object to the state machine access point so it
# can know if it should support segmentation
self.smap = StateMachineAccessPoint(vlan_device)
# the segmentation state machines need access to the same device
# information cache as the application
self.smap.deviceInfoCache = self.deviceInfoCache
# a network service access point will be needed
self.nsap = NetworkServiceAccessPoint()
# give the NSAP a generic network layer service element
self.nse = NetworkServiceElement()
bind(self.nse, self.nsap)
# bind the top layers
bind(self, self.asap, self.smap, self.nsap)
# create a vlan node at the assigned address
self.vlan_node = Node(vlan_address)
# bind the stack to the node, no network number, no addresss
self.nsap.bind(self.vlan_node)
def request(self, apdu):
if _debug: VLANApplication._debug("[%s]request %r", self.vlan_node.address, apdu)
Application.request(self, apdu)
def indication(self, apdu):
if _debug: VLANApplication._debug("[%s]indication %r", self.vlan_node.address, apdu)
Application.indication(self, apdu)
def response(self, apdu):
if _debug: VLANApplication._debug("[%s]response %r", self.vlan_node.address, apdu)
Application.response(self, apdu)
def confirmation(self, apdu):
if _debug: VLANApplication._debug("[%s]confirmation %r", self.vlan_node.address, apdu)
Application.confirmation(self, apdu)
and also, I don't know why but, we are still not able to find how to generate global broadcast Who-Has request in YABE, we are able to send "who-is" but have not find anything with regards to "who-has". I think if we are doing right in the code, we don't have anything to verify that because we aren't capturing I-have response in the first place and that relies on who-has.
Furthermore, I am concerned about the details to be added in the LocalDeviceObject, because for "WhoHasIHave" we need the deviceIdentifier, objectIdentifier and/or objectName.
for ex:
vlan_device = LocalDeviceObject
(
objectIdentifier = ('device', device_instance), #basically a device id
objectIdentifier = ('analogInput', 1), #object id
objectName= "Liters of water", #object name
)
but in this case, I am not able to understand how to create the proper LocalDeviceObject, as we have same variable "objectIdentifier" for device id and object id.
Also, we noticed that later at the time of making an object, we assign the objectIdentifier and objectName as demanded, and add it to the device. So does the Who-Has gets this details for there?!
currently in use LocalDeviceObject is as shown in step1. are we in need to modify it or its fine?!
Hope you have understood my concern, you might be aware of the correct method so, please provide your valuable suggestion.
@JoelBender Can you please help me with this Issue ticket? Waiting for your response.
You've mixed in the WhoHasIHaveServices
into your application, so it will respond to a Who-Has Request via the do_WhoHasRequest()
method, and incoming I-Have messages that are in response to a Who-Has that you have initiated will be via the do_IHaveRequest()
so you need to provide something specific to your application that can line up your requests and responses. If you can post your application someplace (like a project or gist on GitHub) I might be able to help you.