Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KeyError exception when reading 'all' properties with show_property_name=True #490

Open
laurentderu opened this issue Oct 14, 2024 · 1 comment

Comments

@laurentderu
Copy link

When I'm doing the following request go read all the properties of an object instance :

network = BAC0.connect(...)
request = f"{self.device.address}:{self.device.port} {object_type} {object_instance} all"
print("REQUEST", request)
network.readMultiple(request, show_property_name=True)

I get a KeyError exception :

REQUEST 10.2.1.1:47808 analogInput 20 all
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:['10.2.1.1:47808', 'analogInput', '20', 'all']
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:###################################
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:# Read Multiple
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:###################################
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:['10.2.1.1:47808', 'analogInput', '20', 'all']
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:###################################
DEBUG:bacpypes.task:FunctionTask > (RuntimeError('timeout'),) {}
DEBUG:bacpypes.task:    - task: ._FunctionTask object at 0x129ea15b0>
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:iocb                 
DEBUG:bacpypes.iocb._statelog:2481.005726 10.2.1.1 idle
DEBUG:bacpypes.iocb._statelog:2481.005856 10.2.1.1 active
DEBUG:bacpypes.iocb._statelog:2481.065153 10.2.1.1 idle
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:==================================================================================================================
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:'analogInput' : 20
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:==================================================================================================================
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:propertyIdentifier   propertyArrayIndex   value                          datatype            
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:------------------------------------------------------------------------------------------------------------------
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:'objectIdentifier'   None                 ('analogInput', 20)            
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:'objectName'         None                 "H'HCMxCrt10'TFl"              
DEBUG:BAC0_Root.BAC0.scripts.Lite.Lite:'objectType'         None                 'analogInput'                  
KeyError: 'AnalogInputObject'
File "/Users/ld/git/mapiu/mapiu-ae/dmway/plugins/bacnet/bacnet.py", line 268, in run
    await action.execute(self.logger)
  File "/Users/ld/git/mapiu/mapiu-ae/dmway/plugins/bacnet/bacnet.py", line 83, in execute
    response = await self.do_execute(logger)
  File "/Users/ld/git/mapiu/mapiu-ae/dmway/plugins/bacnet/bacnet.py", line 216, in do_execute
    object_data = self.device.client.client.readMultiple(request, show_property_name=True)
  File "/Users/ld/git/mapiu/build-env/lib/python3.9/site-packages/BAC0/core/io/Read.py", line 386, in readMultiple
    for k, v in registered_object_types["BAC0"][

If i do instead

request = {'address': '10.2.1.1:47808', 'objects': {'analogInput:20': ['all']}}
network.readMultiple(args=None, request_dict=request)

I get the list of properties with their values

@wasn93
Copy link

wasn93 commented Oct 30, 2024

I was facing the same issue, but I found a workaround. In version 23.7.3 the regarding code snippet is

if show_property_name:
    try:
        int(
            propertyIdentifier
        )  # else it will be a name like maxMaster
        prop_id = "@prop_{}".format(propertyIdentifier)
        _obj, _id = apdu.listOfReadAccessResults[
            0
        ].objectIdentifier
        _key = (str(_obj), vendor_id)
        if _key in registered_object_types.keys():
            _classname = registered_object_types[_key].__name__

            for k, v in registered_object_types["BAC0"][
                _classname
            ].items():
                if v["obj_id"] == propertyIdentifier:
                    prop_id = (k, propertyIdentifier)  # type: ignore
        if isinstance(value, dict):
            value = list(value.items())[0][1]

    except ValueError:
        prop_id = propertyIdentifier
    values.append((value, prop_id))
    dict_values[objectIdentifier].append(
        (_prop_id, (value, prop_id))
    )
else:
    values.append(value)
    dict_values[objectIdentifier].append((_prop_id, value))

The try is only successful, if the property is a proprietary one and is identified by a number instead of a name. So then the problem causing line is reached. I am not really sure what the rest of the code does or should do, but compared to the except block, which is executed if the property is a known one (e. g. maxMaster), we basicly just have to define the prop_id. So for me it worked to just comment out the try block after

prop_id = "@prop_{}".format(propertyIdentifier)

That is also very similar to the current version 2024.09.20. Here the equvilent code is

if show_property_name:
    values.append((property_value, property_identifier))
    dict_values[str(object_identifier)].append(
        (property_identifier, (property_value, property_identifier))
    )
else:
    values.append(property_value)
	dict_values[str(object_identifier)].append(
        (property_identifier, property_value)
    )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants