ChristianTremblay / BAC0

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

issubclass() arg 1 must be a class when writing multiple #262

Closed CPSuperstore closed 3 years ago

CPSuperstore commented 3 years ago

Hi all,

I am attempting to write multiple things to the BACnet network, so I tried the code in the documentation:

r = ['analogValue 1 presentValue 100', 'analogValue 2 presentValue 100', 'analogValue 3 presentValue 100 - 8', '@obj_142 1 @prop_1042 True']
bacnet.writeMultiple(addr='2:5', args=r, vendor_id=842)

But then I get this error:

Traceback (most recent call last):
  ...
  File "... .py", line 234, in broadcast_reads
    bacnet.writeMultiple(addr='2:5', args=r, vendor_id=842)
  File "/usr/local/lib/python3.7/dist-packages/BAC0/core/io/Write.py", line 265, in writeMultiple
    iocb = IOCB(self.build_wpm_request(args, vendor_id=vendor_id, addr=addr))
  File "/usr/local/lib/python3.7/dist-packages/BAC0/core/io/Write.py", line 317, in build_wpm_request
    obj_type, prop_id, indx, vendor_id, value
  File "/usr/local/lib/python3.7/dist-packages/BAC0/core/io/Write.py", line 152, in _validate_value_vs_datatype
    elif issubclass(datatype, Atomic):
TypeError: issubclass() arg 1 must be a class

So I tried removing the last item in r to get:

r = ['analogValue 1 presentValue 100', 'analogValue 2 presentValue 100', 'analogValue 3 presentValue 100 - 8']
bacnet.writeMultiple(addr='2:5', args=r, vendor_id=842)

and even without the vendor_id arg, just in case:

r = ['analogValue 1 presentValue 100', 'analogValue 2 presentValue 100', 'analogValue 3 presentValue 100 - 8']
bacnet.writeMultiple(addr='2:5', args=r)

and in both cases I get the following stacktrace

Traceback (most recent call last):
  File "... .py", line 233, in broadcast_reads
    bacnet.writeMultiple(addr='2:5', args=r)
  File "/usr/local/lib/python3.7/dist-packages/BAC0/core/io/Write.py", line 290, in writeMultiple
    raise NoResponseFromController("APDU Abort Reason : {}".format(reason))
BAC0.core.io.IOExceptions.NoResponseFromController: APDU Abort Reason : Timeout

Any help would be much appreciated.

ChristianTremblay commented 3 years ago

Is this controller reachable on your network ? Does a simple write work ? Does it support write multiple ?

CPSuperstore commented 3 years ago

Yes I was able to connect to the controller I was able to verify with bacnet.discover(). Neither single of multiple write worked. They both returned the BAC0.core.io.IOExceptions.NoResponseFromController: APDU Abort Reason : Timeout error

ChristianTremblay commented 3 years ago

Timeout is typically a "no connection" error... Can you give the output of discover ?

CPSuperstore commented 3 years ago

I ended up creating a VERY hacky workaround which works as intended:

 o = ObjectFactory(
    AnalogValueObject,
    0,
    "SomeName",
    properties={"units": "SomeUnits"},
    presentValue=SomeValue,
    description="SomeDescription",
    is_commandable=True
)

for v in o.objects.values():
    bacnet.this_application.add_object(v)

And then I run this code before the above code if I want to overwrite a value:

for v in o.objects.values():
    bacnet.this_application.delete_object(v)

o.clear_objects()

This works exactly as I need it to. There is probably a better way to do it, but after two straight days of hair pulling, I don't care all that much.

Closing for now, but if you have any questions on my implementation, feel free to leave a comment.

gauravpathak commented 1 year ago

Hi @ChristianTremblay

Unfortunately I am also getting the same error as mentioned in the original post:

Traceback (most recent call last):
  File "C:\Users\h492401\Downloads\BAC0-Tests\writeprop.py", line 34, in <module>
    main()
  File "C:\Users\h492401\Downloads\BAC0-Tests\writeprop.py", line 28, in main
    values = bacnet.writeMultiple(addr='192.168.0.200', args=_wpm, vendor_id=17)
  File "C:\Users\h492401\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\BAC0\core\io\Write.py", line 265, in writeMultiple
    iocb = IOCB(self.build_wpm_request(args, vendor_id=vendor_id, addr=addr))
  File "C:\Users\h492401\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\BAC0\core\io\Write.py", line 321, in build_wpm_request
    value = self._validate_value_vs_datatype(
  File "C:\Users\h492401\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\BAC0\core\io\Write.py", line 152, in _validate_value_vs_datatype
    elif issubclass(datatype, Atomic):
TypeError: issubclass() arg 1 must be a class

Here is how I am trying to use write multiple:

import argparse
from builtins import print
import pprint

import BAC0

IP_ADDR = "192.168.0.5"

def main():
    pp = pprint.PrettyPrinter(indent=2)
    BAC0.log_level('silence')
    parser = argparse.ArgumentParser()
    required = parser.add_argument_group('required arguments')
    required.add_argument("-a", "--addr", type=str, required=True, help="IP Address of Target Controller")
    args = parser.parse_args()
    bacnet = BAC0.connect(IP_ADDR)
    while True:
        resp = bacnet.discover(networks='known', global_broadcast=False, reset=True)
        if len(resp) > 0:
            for addr, inst in bacnet.discoveredDevices:
                if args.addr == addr:
                    print("Sending WPM Req to address: ", addr, "Instance: ", inst)
                    # cmd = addr + ' ' + 'analogInput 1 presentValue statusFlags units description'
                    # @prop_81 is Out-Of-Service which is not defined as string in BAC0
                    _wpm = ['analogInput 1 @prop_81 True', 'analogInput 2 @prop_81 True']
                    # print(cmd)
                    values = bacnet.writeMultiple(addr='192.168.0.200', args=_wpm, vendor_id=17)
                    pp.pprint(values)
                    print("\n")

if __name__ == "__main__":
    main()

I am using BAC0 22.9.21

Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import BAC0
>>> BAC0.version
'22.9.21'
>>>