JoelBender / bacpypes

BACpypes provides a BACnet application layer and network layer written in Python for daemons, scripting, and graphical interfaces.
MIT License
302 stars 129 forks source link

How to read the priority array of a single point? #456

Closed opsserver closed 2 years ago

opsserver commented 2 years ago

Hi I'm new to bacpypes, I've got stuck of this problem, as we all know BACnet priority level varies from 1 to 16, 1 is the topest, and 16 lowest, I've learned from some of the articles that the priority-value pairs actually exist once a bacnet point is created, which appears like priority1: value1, priority2: value2.... to priority16: value 16. For example, to a certain bacnet point, I set 11 to priority 1 and set 22 to priority 2, the priority array of this point should be: 1:11, 2:22, 3:Null, 4: Null , ... , 16:Null, under this circumstance, the present value of this point should be 11. And then I set Null to priority 1, the priority array should be 1: Null, 2:22, 3: Null, ..., 16: Null, and present value should become 22, because I just released the value of priority 1. The problem I am facing is that : (1) I don't know which method of bacpypes is capable to get the priority array, and actually I don't know what kind of data form the priority array should appears in. (2) How to edit the priority array of a certain point.

can anybody help me? any suggestion and assistance, THANKS IN ADVANCE!!!

JoelBender commented 2 years ago

(1) The priority array of an object is just another property, so you can read it like any other property. For example, in the ReadProperty.py sample application giving it the command read 12.23.34.45 binaryOutput:1 priorityArray will return the entire array and read 12.23.34.45 binaryOutput:1 priorityArray 1 will read just the first entry.

(2) "Editing" the array is writing to a particular entry and you use the Write Property service for that. The ReadWriteProperty.py sample application uses the following write command syntax:

write <addr> <objid> <prop> <value> [ <indx> ] [ <priority> ]

There are two versions of this command that have the same effect. The first writes to the priority array at a specific index, the second writes to the "commandable property" using a specific priority level. So write 12.23.34.45 binaryOutput:1 priorityArray 33 3 will change the priority array entry (but the present value will not change until 2 is released) and write 12.23.34.45 binaryOutput:1 presentValue 44 - 4 skips the array index parameter (because presentValue isn't an array) and changes priority array entry (again, not changing the present value).

The source code for the do_write() command is a little convoluted because with an "Any" datatype there is some additional work wrapping the value, and for things like schedule objects where the presentValue can be anything, there is parser code to extract a prefix to distinguish between integer and unsigned types, for example.

opsserver commented 2 years ago

@JoelBender Thanks Joel! I succeed to get the priority array of a bacnet point by following your guidance above.

I'm having my computre connected to a real bacnet device, and trying to write a priority array back to this point, I imported PriorityArray from bacpypes.basetypes and instantiated it with a variable named 'priorityArray', then edited the 'real' property of the first PriorityValue of priorityArray to 17.5(this would be having edited the value of priority 1 and about to write back into the bacnet device), please find it in the screen shot below, and then I run the code to write priorityArray to the bacnet device, but I got an error said 'writeAccessDenied', I don't know why, is it the possibility that there is some restrictions in the device (hardware)? any suggestions will be so much appreciated!

c5dd0f65fef77aee36643a67f966f5d

Please find my code below.

`addr = "7061:26" # SNET:SADR obj_id = ("analogValue", 0) prop_id = "priorityArray" obj_id = ObjectIdentifier(obj_id).value

priorityArray = PriorityArray()

tarValue = priorityArray[1]

tarValue.null = None setattr(tarValue, "real", 17.5)

request = WritePropertyRequest( objectIdentifier=obj_id, propertyIdentifier=prop_id ) request.pduDestination = Address(addr)

request.propertyValue = Any() try: request.propertyValue.cast_in(priorityArray) except Exception as error: print(error.str())

request.priority = 1

iocb = IOCB(request)

deferred(this_application.request_io, iocb)

iocb.wait()

if iocb.ioResponse:

should be an ack

if not isinstance(iocb.ioResponse, SimpleAckPDU):
    return

sys.stdout.write("ack\n")

if iocb.ioError: print(str(iocb.ioError)) sys.stdout.write(str(iocb.ioError) + '\n')`

And I also tried this, I put the instantiation of PriorityValue into request by cast_in method, but I get the same error of "WriteAccessDenied".

myValue = PriorityValue() myValue.null = None setattr(myValue, "real", 17.5)

request.propertyValue.cast_in(myValue )

JoelBender commented 2 years ago

The error Write Access Denied is exactly that, the WritePropertyRequest is well formed (correct encoding, etc) but being rejected by the server. You need to investigate how the server is configured, maybe there are some settings that you need to set to enable this functionality. It seems unlikely that a device would have a priority array and not allow it to be updated (which would kinda defeat the point of the array for managing local and supervisory control) but it is not required to be writable. Make sure that your request has the priority parameter with an appropriate value (I don't see that in your code snippet) so maybe the value is writable but only by providing a priority, and you cannot rewrite the entire priority array.

opsserver commented 2 years ago

The error Write Access Denied is exactly that, the WritePropertyRequest is well formed (correct encoding, etc) but being rejected by the server. You need to investigate how the server is configured, maybe there are some settings that you need to set to enable this functionality. It seems unlikely that a device would have a priority array and not allow it to be updated (which would kinda defeat the point of the array for managing local and supervisory control) but it is not required to be writable. Make sure that your request has the priority parameter with an appropriate value (I don't see that in your code snippet) so maybe the value is writable but only by providing a priority, and you cannot rewrite the entire priority array.

Understand Joel @JoelBender , thanks again!

opsserver commented 2 years ago

The error Write Access Denied is exactly that, the WritePropertyRequest is well formed (correct encoding, etc) but being rejected by the server. You need to investigate how the server is configured, maybe there are some settings that you need to set to enable this functionality. It seems unlikely that a device would have a priority array and not allow it to be updated (which would kinda defeat the point of the array for managing local and supervisory control) but it is not required to be writable. Make sure that your request has the priority parameter with an appropriate value (I don't see that in your code snippet) so maybe the value is writable but only by providing a priority, and you cannot rewrite the entire priority array.

Hi @Joel, you mentioned that the priority parameter has to be in the request, do you mean by this below:

request = WritePropertyRequest( objectIdentifier=obj_id, propertyIdentifier=prop_id )

request.priority = 1

...

JoelBender commented 2 years ago

Correct, or as a keyword value in the WritePropertyRequest() call because it doesn't need any special wrapper like Any().

opsserver commented 2 years ago

Correct, or as a keyword value in the WritePropertyRequest() call because it doesn't need any special wrapper like Any().

Thanks Joel!