|
|
@@ -13,6 +13,10 @@ BAC0_REGISTERED_WARNING = r"object type .* for vendor identifier 842 already reg
|
|
|
warnings.filterwarnings("ignore", message=BAC0_REGISTERED_WARNING)
|
|
|
|
|
|
import BAC0
|
|
|
+from bacpypes3.apdu import ErrorRejectAbortNack
|
|
|
+from bacpypes3.basetypes import PropertyIdentifier
|
|
|
+from bacpypes3.pdu import Address
|
|
|
+from bacpypes3.primitivedata import ObjectIdentifier
|
|
|
|
|
|
from app.response import response_payload
|
|
|
from app.schemas.bacnet import (
|
|
|
@@ -63,8 +67,23 @@ def bacnet_address(ip: str, port: int) -> str:
|
|
|
return f"{ip}:{port}"
|
|
|
|
|
|
|
|
|
-def property_read_args(address: str, object_type: str, object_id: int, property_name: str) -> str:
|
|
|
- return f"{address} {bac0_object_type(object_type)} {object_id} {property_name}"
|
|
|
+async def read_property_direct(
|
|
|
+ bacnet: Any,
|
|
|
+ address: str,
|
|
|
+ object_type: str,
|
|
|
+ object_id: int,
|
|
|
+ property_name: str,
|
|
|
+ array_index: int | None = None,
|
|
|
+) -> Any:
|
|
|
+ value = await bacnet.this_application.app.read_property(
|
|
|
+ Address(address),
|
|
|
+ ObjectIdentifier((bac0_object_type(object_type), object_id)),
|
|
|
+ PropertyIdentifier(property_name),
|
|
|
+ array_index,
|
|
|
+ )
|
|
|
+ if isinstance(value, ErrorRejectAbortNack):
|
|
|
+ raise BacnetCommunicationError(str(value))
|
|
|
+ return value
|
|
|
|
|
|
|
|
|
def get_local_ip(remote_ip: str, remote_port: int) -> str:
|
|
|
@@ -105,7 +124,7 @@ def json_value(value: Any) -> Any:
|
|
|
|
|
|
async def read_property_or_none(bacnet: Any, address: str, object_type: str, object_id: int, property_name: str) -> Any:
|
|
|
try:
|
|
|
- value = await bacnet.read(property_read_args(address, object_type, object_id, property_name))
|
|
|
+ value = await read_property_direct(bacnet, address, object_type, object_id, property_name)
|
|
|
except Exception:
|
|
|
return None
|
|
|
return json_value(value)
|
|
|
@@ -113,7 +132,7 @@ async def read_property_or_none(bacnet: Any, address: str, object_type: str, obj
|
|
|
|
|
|
async def read_present_value(bacnet: Any, address: str, point: BacnetPointSpec) -> Any:
|
|
|
try:
|
|
|
- value = await bacnet.read(property_read_args(address, point.object_type, point.object_id, "presentValue"))
|
|
|
+ value = await read_property_direct(bacnet, address, point.object_type, point.object_id, "presentValue")
|
|
|
except Exception as exc:
|
|
|
raise BacnetCommunicationError(
|
|
|
f"no response from BACnet device {address} while reading "
|
|
|
@@ -200,15 +219,29 @@ async def search_points_async(request: BacnetPointSearchRequest) -> list[dict[st
|
|
|
warnings.filterwarnings("ignore", message=BAC0_REGISTERED_WARNING)
|
|
|
async with BAC0.start(ip=local_ip, port=local_port, ping=False) as bacnet:
|
|
|
try:
|
|
|
- object_list = await bacnet.read(
|
|
|
- property_read_args(address, "Device", request.bacnet_device_id, "objectList")
|
|
|
+ object_count = await read_property_direct(
|
|
|
+ bacnet,
|
|
|
+ address,
|
|
|
+ "Device",
|
|
|
+ request.bacnet_device_id,
|
|
|
+ "objectList",
|
|
|
+ array_index=0,
|
|
|
)
|
|
|
except Exception as exc:
|
|
|
raise BacnetCommunicationError(
|
|
|
f"no response from BACnet device {address} while reading "
|
|
|
f"Device {request.bacnet_device_id} objectList"
|
|
|
) from exc
|
|
|
- for item in object_list or []:
|
|
|
+
|
|
|
+ for index in range(1, int(object_count) + 1):
|
|
|
+ item = await read_property_direct(
|
|
|
+ bacnet,
|
|
|
+ address,
|
|
|
+ "Device",
|
|
|
+ request.bacnet_device_id,
|
|
|
+ "objectList",
|
|
|
+ array_index=index,
|
|
|
+ )
|
|
|
parsed = split_object_identifier(item)
|
|
|
if parsed is None:
|
|
|
continue
|