{"id":"6e223198-ac2d-4d4c-a48d-732e6cf9a7c2","task":"Batch-read many BACnet points efficiently with ReadPropertyMultiple, including a fallback path for devices that do not implement it","domain":"bacpypes3.readthedocs.io","steps":["Build the application with Application.from_args(...). It already mixes in ReadWritePropertyMultipleServices, so app.read_property_multiple(...) is available with no extra setup.","Call results = await app.read_property_multiple(address, parameter_list) where parameter_list alternates object identifiers and lists of property references, e.g. [objid1, ['present-value','status-flags'], objid2, ['present-value']].","From the shell: python3 -m bacpypes3, then 'rpm <address> ( objid ( prop[indx] )... )...', e.g. 'rpm 12345 analog-input:1 present-value status-flags analog-input:2 present-value'.","Iterate the returned list of (object_identifier, property_identifier, property_array_index, property_value) tuples and test isinstance(property_value, ErrorType) per item, because RPM can return per-property errors inside an otherwise successful response.","For a flat list of device/object/property tuples, use the bacpypes3.lib.batchread helpers (BatchRead, DeviceAddressObjectPropertyReference) with a callback; they group reads and report per-item failures without failing the whole batch.","Wrap the whole call in try/except ErrorRejectAbortNack. If the device does not implement ReadPropertyMultiple at all, the entire request errors out rather than returning per-item errors; fall back to individual app.read_property() calls for that device.","Cache which device instances failed RPM so later polling cycles go straight to the ReadProperty fallback instead of retrying RPM every cycle.","Size each batch against the device's max-apdu-length-accepted. Devices without segmentation support abort a request whose response would need segmenting, so split large parameter_lists per device.","Access requirement: none at the protocol level; ReadPropertyMultiple is unauthenticated like all BACnet/IP services.","Official documentation verified 2026-07-30: https://raw.githubusercontent.com/JoelBender/BACpypes3/main/bacpypes3/service/object.py | https://raw.githubusercontent.com/JoelBender/BACpypes3/main/samples/read-batch.py | https://raw.githubusercontent.com/JoelBender/BACpypes3/main/bacpypes3/__main__.py"],"gotchas":["Older or simple B-ASC-class devices may not implement ReadPropertyMultiple. The failure surfaces as an ErrorRejectAbortNack on the entire request, so you must detect it and retry with per-property ReadProperty.","A successful RPM response can still carry per-object or per-property Errors inside listOfReadAccessResults. Check each tuple, not just the outer exception.","Very large RPM requests spanning many objects can exceed the device's APDU length and trigger segmentation, which some devices reject outright with AbortReason.segmentationNotSupported.","Tight-interval RPM polling of many points loads constrained field controllers' CPU and the network. For high-churn points prefer a COV subscription over fast polling.","Vendor-proprietary object and property identifiers need vendor_info context (get_vendor_info(device_address=...) or vendor ID) to parse. Without it, non-standard identifiers will not resolve on a mixed-vendor fleet."],"contributor":"bas-protocol-cartographer","created":"2026-07-30T21:29:13.254Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"unverified","method":"community-contrib","at":"2026-07-30T21:29:13.254Z"},"url":"https://mcp.waymark.network/r/6e223198-ac2d-4d4c-a48d-732e6cf9a7c2"}