ChristianTremblay / BAC0

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

Issue writing to LAVs #455

Open michael-senva opened 3 months ago

michael-senva commented 3 months ago

I'm having some trouble writing to an LAV. I am able to read out a value correctly but get hit with an 'Invalid Constructor Datatype' error when attempting to write the value back.

Here's a snippet to illustrate what I mean:

import BAC0
network = BAC0.connect()
network.read('X.X.X.X largeAnalogValue 1 presentValue')
>>> 0.0
network.write('X.X.X.X largeAnalogValue 1 presentValue 0.0 - 1')
>>> Error (Invalid Constructor Datatype)

I've dug through the library/docs, and it looks like it's expecting the Double object type where the error is raised.

Am I querying correctly? Any recommendations on getting it working?

I've read a bit about creating custom constructors but hit a wall with getting that working. Any help or direction is appreciated! :)

bbartling commented 2 months ago

i dont think i have ever heard of a LAV? Large Analog Value? Is that in the BACnet spec?

michael-senva commented 2 months ago

Large Analog Value, that's correct. It's effectively BACnet's Double type. BAC0 doesn't have trouble with reads, but it doesn't appear to detect a written double and throws an incorrect data type error. I've tried a variety of permutations without success.

It looks like bacpypes supports the Double type under the hood, so the solution may just be creating a new class to handle it (similar to this one for writing text with spaces), but no success so far- I don't have much experience in how Python class structures work, so it may be a fairly straightforward fix I'm just not seeing.

bbartling commented 2 months ago

Gosh interesting, i have yet to run across a Large Analog Value in the wild.

What does your code look like so far? I am fairly handy in bacpypes too.

ChristianTremblay commented 2 months ago

I've never had to write to a LAV in the past, but it is probably feasable.

Please note that any development on my side will be done on the async branch (https://github.com/ChristianTremblay/BAC0/tree/async) using BACpypes3 as I'm slowly migrating BAC0 to asyncio as legacy bacpypes is not supported by python 3.12+

I don't plan to support legacy BAC0 in the future.

I will look at LAV and see what is missing

ChristianTremblay commented 2 months ago

@michael-senva I actually don't have access to a device with LAV objects. I would be grateful if you could try the async branch and tell me what is happening with this version. BACpypes3 now does a lot of the work under the hood and I wouldn't be surprised it works without anything from BAC0's side (or very few work)

michael-senva commented 2 months ago

@bbartling apologies, I missed the notification for your response. The code I had was just making some modifications to the library functions manually, but I couldn't get it to run.

@ChristianTremblay No problem at all, I'll try out that branch and report back.

michael-senva commented 2 months ago

It appears the functions have changed, but gleaning from the sample I'm encountering errors trying to initialize the network-

`

import BAC0 bacnet = BAC0.lite() 2024-07-09 08:36:42,064 - INFO | Starting BAC0 version 2024 (Lite) 2024-07-09 08:36:42,064 - INFO | Use BAC0.log_level to adjust verbosity of the app. 2024-07-09 08:36:42,064 - INFO | Ex. BAC0.log_level('silence') or BAC0.log_level('error') Traceback (most recent call last): File "", line 1, in File "C:\Users...\AppData\Roaming\Python\Python311\site-packages\BAC0\BAC0\scripts\Lite.py", line 142, in init self._ping_task.start() File "C:\Users...\AppData\Roaming\Python\Python311\site-packages\BAC0\BAC0\tasks\TaskManager.py", line 133, in start self.aio_task = asyncio.create_task(self.execute(), name=f"aio{self.name}") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Program Files\Python311\Lib\asyncio\tasks.py", line 381, in create_task loop = events.get_running_loop() ^^^^^^^^^^^^^^^^^^^^^^^^^ RuntimeError: no running event loop`

Not sure if I'm missing a piece or not with the changes, do you have an example I could run?

ChristianTremblay commented 2 months ago

asyncio is a weird beast. If possible, run this code in a Jupyter Notebook. For now, it is the easiest way to run asyncio code I found. There is a event loop already running and it works out of the box.

To run scripts, there are some rules to follow to start a event loop and run the code with it...

I haven't yet found an elegant way to use the REPL... at least with ipython it doesn't work... I saw somwthing with basic python REPL with a dash something option... but as I said, for now, I'm using Notebook (in VSCode , a .ipynb file)

michael-senva commented 2 months ago

@ChristianTremblay

import BAC0
network = BAC0.lite()
await network.read('X.X.X.X largeAnalogValue 1 presentValue')
await network._write('X.X.X.X largeAnalogValue 1 presentValue 0.0')

Took a bit of trial and error but I was able to succeed with the notebook + your async branch, the read dumps 0.0 and the write gives writeAccessDenied as expected (for my DUT).

ChristianTremblay commented 2 months ago

Write access denied comes from the device normally. Are you sure you can write to it ? Or was that accompanied by another error, more specific about the format ?

ChristianTremblay commented 2 months ago

If you start the REPL using python -m asyncio

It works (I knew there was a way.... too much things on my plate lately)

image

michael-senva commented 2 months ago

@ChristianTremblay

Nice! that python entry was much easier to test with.

I added some write-enabled test LAV's on my DUT and both the read and write functions work correctly using the code in my previous comment, without any error.

github-actions[bot] commented 1 day ago

This issue had no activity for a long period of time. If this issue is still required, please update the status or else, it will be closed. Please note that an issue can be reopened if required.