async def discover_properties(app, device_id, addr): objects = await app.execute_request( ReadPropertyRequest(objectIdentifier=('device', device_id), propertyIdentifier='objectList', destination=Address(addr))) result = {} for object_identifier in objects: _logger.info(object_identifier) read_access_specs = [ ReadAccessSpecification( objectIdentifier=object_identifier, listOfPropertyReferences=[ PropertyReference(propertyIdentifier='presentValue'), PropertyReference(propertyIdentifier='objectName'), PropertyReference(propertyIdentifier='objectType'), PropertyReference(propertyIdentifier='description'), PropertyReference(propertyIdentifier='units'), ], ), ] result.update(await app.execute_request( ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_specs, destination=Address(addr)), )) global properties properties = result asyncio.get_event_loop().stop()
async def read_prop_values(app, addr): read_access_specs = [] for i in range(40): read_access_specs.append( ReadAccessSpecification( objectIdentifier=('analogInput', i), listOfPropertyReferences=[ PropertyReference(propertyIdentifier='presentValue') ], )) return await app.execute_request( ReadPropertyMultipleRequest(listOfReadAccessSpecs=read_access_specs, destination=Address(addr)), )
def read_properties(self, target_address, point_map, max_per_request=None, use_read_multiple=True): """ Read a set of points and return the results """ if not use_read_multiple: return self.read_using_single_request(target_address, point_map) # Set max_per_request really high if not set. if max_per_request is None: max_per_request = self._max_per_request _log.debug("Reading {count} points on {target}, max per scrape: {max}".format( count=len(point_map), target=target_address, max=max_per_request)) # process point map and populate object_property_map and # reverse_point_map (object_property_map, reverse_point_map) = self._get_object_properties(point_map, target_address) result_dict = {} finished = False while not finished: read_access_spec_list = [] count = 0 for _ in range(max_per_request): try: obj_data, properties = object_property_map.popitem() except KeyError: finished = True break (spec_list, spec_count) = self._get_access_spec(obj_data, properties) count += spec_count read_access_spec_list.append(spec_list) if read_access_spec_list: _log.debug("Requesting {count} properties from {target}".format(count=count, target=target_address)) request = ReadPropertyMultipleRequest(listOfReadAccessSpecs=read_access_spec_list) request.pduDestination = Address(target_address) iocb = self.iocb_class(request) self.bacnet_application.submit_request(iocb) bacnet_results = iocb.ioResult.get(10) _log.debug("Received read response from {target} count: {count}".format( count=count, target=target_address)) for prop_tuple, value in bacnet_results.items(): name = reverse_point_map[prop_tuple] result_dict[name] = value return result_dict
def simple_read(self, target_address, obj_inst, propertylist, obj_type="device", index=0): try: reverse_point_map = {} result_dict = [] read_access_spec_list = [] count = 0 prop_ref_list = [] for prop in propertylist: prop_ref = PropertyReference(propertyIdentifier=prop) prop_ref_list.append(prop_ref) count += 1 read_access_spec = ReadAccessSpecification( objectIdentifier=(obj_type, obj_inst), listOfPropertyReferences=prop_ref_list) read_access_spec_list.append(read_access_spec) if read_access_spec_list: if count == 1: _log.debug( "Requesting {property} properties from {target}". format(property=prop, target=target_address)) else: _log.debug( "Requesting {count} properties from {target}".format( count=count, target=target_address)) request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list) request.pduDestination = Address(target_address) iocb = IOCB(request, self.async_call) self.this_application.submit_request(iocb) print "bacnet request sent" bacnet_results = tuple bacnet_results = iocb.ioResult.get(35) print "bacnet data fetched" for prop_tuple, value in bacnet_results.iteritems(): result_dict.append(value) print result_dict return result_dict except Exception as e: print e return None
def read_properties(self, target_address, point_map, max_per_request=None): """Read a set of points and return the results""" #This will be used to get the results mapped # back on the the names reverse_point_map = {} #Used to group properties together for the request. object_property_map = defaultdict(list) for name, properties in point_map.iteritems(): object_type, instance_number, property_name = properties reverse_point_map[object_type, instance_number, property_name] = name object_property_map[object_type, instance_number].append(property_name) read_access_spec_list = [] for obj_data, properties in object_property_map.iteritems(): obj_type, obj_inst = obj_data prop_ref_list = [] for prop in properties: prop_ref = PropertyReference(propertyIdentifier=prop) prop_ref_list.append(prop_ref) read_access_spec = ReadAccessSpecification( objectIdentifier=(obj_type, obj_inst), listOfPropertyReferences=prop_ref_list) read_access_spec_list.append(read_access_spec) request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list) request.pduDestination = Address(target_address) iocb = IOCB(request, self.async_call) self.this_application.submit_request(iocb) bacnet_results = iocb.ioResult.get(10) result_dict = {} for prop_tuple, value in bacnet_results.iteritems(): name = reverse_point_map[prop_tuple] result_dict[name] = value return result_dict
def build_rpm_request_from_dict(self, request_dict, vendor_id): """ Read property multiple allow to read a lot of properties with only one request The existing RPM function is made using a string that must be created using bacpypes console style and is hard to automate. This new version will be an attempt to improve that:: _rpm = {'address': '11:2', 'objects': {'analogInput:1': ['presentValue', 'description', 'unit', 'objectList@idx:0'], 'analogInput:2': ['presentValue', 'description', 'unit', 'objectList@idx:0'], }, vendor_id: 842 } """ vendor_id = 842 addr = request_dict["address"] objects = request_dict["objects"] if "vendor_id" in request_dict.keys(): vendor_id = int(request_dict["vendor_id"]) read_access_spec_list = [] for obj, list_of_properties in objects.items(): obj_type, obj_instance = obj.split(":") obj_type = validate_object_type(obj_type, vendor_id=vendor_id) obj_instance = int(obj_instance) property_reference_list = build_property_reference_list( obj_type, list_of_properties ) read_acces_spec = build_read_access_spec( obj_type, obj_instance, property_reference_list ) read_access_spec_list.append(read_acces_spec) if not read_access_spec_list: raise RuntimeError("at least one read access specification required") # build the request request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list ) request.pduDestination = Address(addr) return request
def request_values( self, device_address_str: str, objects: Sequence[Tuple[Union[int, str], int]], chunk_size: Optional[int] = None, request_timeout: Optional[Timedelta] = None, ): device_address = Address(device_address_str) device_info: DeviceInfo = self.deviceInfoCache.get_device_info( device_address) # we adjusted chunking for object property request, which requested 3 properties per object # here we request only 1 property so scale chunk_scale = 3 if not chunk_size: chunk_size = 20 * chunk_scale if device_info and device_info.segmentationSupported == "noSegmentation": chunk_size = 4 * chunk_scale logger.debug( f"Chunking for device {device_address_str} is {chunk_size}") for objects_chunk in chunks(objects, chunk_size): prop_reference_list = [ PropertyReference(propertyIdentifier="presentValue") ] read_access_specs = [ ReadAccessSpecification( objectIdentifier=ObjectIdentifier(object_identifier), listOfPropertyReferences=prop_reference_list, ) for object_identifier in objects_chunk ] request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_specs) request.pduDestination = device_address iocb = IOCB(request) iocb.add_callback(self._iocb_callback) if request_timeout: iocb.set_timeout(request_timeout.s) deferred(self.request_io, iocb)
def scrape_all(self): read_access_spec_list = [] for obj_data, properties in self.object_property_map.iteritems(): obj_type, obj_inst = obj_data prop_ref_list = [] for prop in properties: prop_ref = PropertyReference(propertyIdentifier=prop) prop_ref_list.append(prop_ref) read_access_spec = ReadAccessSpecification(objectIdentifier=(obj_type, obj_inst), listOfPropertyReferences=prop_ref_list) read_access_spec_list.append(read_access_spec) request = ReadPropertyMultipleRequest(listOfReadAccessSpecs=read_access_spec_list) request.pduDestination = self.target_address iocb = IOCB(request) this_application.submit_request(iocb) iocb.ioDefered.addCallback(self.scrape_all_callback) return iocb.ioDefered
def _get_prop_for_obj(self, obj_id): props_to_get = ['objectName', 'description', 'presentValue', 'units'] prop_ref_list = [] for prop in props_to_get: ref = PropertyReference(propertyIdentifier=prop) prop_ref_list.append(ref) read_access_spec = ReadAccessSpecification( objectIdentifier=obj_id, listOfPropertyReferences=prop_ref_list, ) request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=[read_access_spec], destination=self.device.source) iocb = IOCB(request) iocb.add_callback(self._got_properties_for_object, obj_id) self.bacnet_adapter.request_io(iocb)
def read_properties(self, target_address, point_map, max_per_request=None): """Read a set of points and return the results""" # Set max_per_request really high if not set. if max_per_request is None: max_per_request = 1000000 _log.debug( "Reading {count} points on {target}, max per scrape: {max}".format( count=len(point_map), target=target_address, max=max_per_request)) # This will be used to get the results mapped # back on the the names reverse_point_map = {} # TODO Support rading an index of an Array. # Used to group properties together for the request. object_property_map = defaultdict(list) for name, properties in point_map.iteritems(): object_type, instance_number, property_name = properties reverse_point_map[object_type, instance_number, property_name] = name object_property_map[object_type, instance_number].append(property_name) result_dict = {} finished = False while not finished: read_access_spec_list = [] count = 0 for _ in xrange(max_per_request): try: obj_data, properties = object_property_map.popitem() except KeyError: finished = True break obj_type, obj_inst = obj_data prop_ref_list = [] for prop in properties: prop_ref = PropertyReference(propertyIdentifier=prop) prop_ref_list.append(prop_ref) count += 1 read_access_spec = ReadAccessSpecification( objectIdentifier=(obj_type, obj_inst), listOfPropertyReferences=prop_ref_list) read_access_spec_list.append(read_access_spec) if read_access_spec_list: _log.debug( "Requesting {count} properties from {target}".format( count=count, target=target_address)) request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list) request.pduDestination = Address(target_address) iocb = IOCB(request, self.async_call) self.this_application.submit_request(iocb) bacnet_results = iocb.ioResult.get(10) _log.debug("Received read response from {target}".format( count=count, target=target_address)) for prop_tuple, value in bacnet_results.iteritems(): name = reverse_point_map[prop_tuple] result_dict[name] = value return result_dict
def do_read(self, addr, properties): """read <addr> ( <type> <inst> ( <prop> [ <indx> ] )... )...""" read_access_spec_list = [] try: for obj_type, obj_inst, props in properties: if type(obj_type) is int: pass elif obj_type.isdigit(): obj_type = int(obj_type) elif not get_object_class(obj_type): raise ValueError("unknown object type") prop_reference_list = [] for prop_id, idx in props: if prop_id not in PropertyIdentifier.enumerations: break if prop_id in ('all', 'required', 'optional'): pass else: datatype = get_datatype(obj_type, prop_id) if not datatype: raise ValueError( "invalid property for object type") # build a property reference prop_reference = PropertyReference( propertyIdentifier=prop_id, ) # check for an array index if idx is not None: prop_reference.propertyArrayIndex = int(idx) # add it to the list prop_reference_list.append(prop_reference) # check for at least one property if not prop_reference_list: raise ValueError("provide at least one property") # build a read access specification read_access_spec = ReadAccessSpecification( objectIdentifier=(obj_type, obj_inst), listOfPropertyReferences=prop_reference_list, ) # add it to the list read_access_spec_list.append(read_access_spec) # check for at least one if not read_access_spec_list: raise RuntimeError( "at least one read access specification required") # build the request request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list, ) request.pduDestination = Address(addr) if _debug: logger.debug(" - request: %r", request) self._request = request # make an IOCB iocb = IOCB(request) if _debug: logger.debug(" - iocb: %r", iocb) # give it to the application self.request_io(iocb) # do something for error/reject/abort if iocb.ioError: sys.stdout.write(str(iocb.ioError) + '\n') except Exception as error: logger.debug("exception: %r", error)
def readMultiple(self, args): """ This function build a readMultiple request wait for the answer and return the value :param args: String with <addr> ( <type> <inst> ( <prop> [ <indx> ] )... )... :returns: data read from device (str representing data like 10 or True) *Example*:: import BAC0 myIPAddr = '192.168.1.10' bacnet = BAC0.ReadWriteScript(localIPAddr = myIPAddr) bacnet.readMultiple('2:5 analogInput 1 presentValue units') will read controller with a MAC address of 5 in the network 2 Will ask for the present Value and the units of analog input 1 (AI:1) """ args = args.split() print_debug("readMultiple %r", args) try: i = 0 addr = args[i] i += 1 read_access_spec_list = [] while i < len(args): obj_type = args[i] i += 1 if obj_type.isdigit(): obj_type = int(obj_type) elif not get_object_class(obj_type): raise ValueError("unknown object type") obj_inst = int(args[i]) i += 1 prop_reference_list = [] while i < len(args): prop_id = args[i] if prop_id not in PropertyIdentifier.enumerations: break i += 1 if prop_id in ('all', 'required', 'optional'): pass else: datatype = get_datatype(obj_type, prop_id) if not datatype: raise ValueError( "invalid property for object type : %s | %s" % (obj_type, prop_id)) # build a property reference prop_reference = PropertyReference( propertyIdentifier=prop_id, ) # check for an array index if (i < len(args)) and args[i].isdigit(): prop_reference.propertyArrayIndex = int(args[i]) i += 1 # add it to the list prop_reference_list.append(prop_reference) # check for at least one property if not prop_reference_list: raise ValueError("provide at least one property") # build a read access specification read_access_spec = ReadAccessSpecification( objectIdentifier=(obj_type, obj_inst), listOfPropertyReferences=prop_reference_list, ) # add it to the list read_access_spec_list.append(read_access_spec) # check for at least one if not read_access_spec_list: raise RuntimeError( "at least one read access specification required") # build the request request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list, ) request.pduDestination = Address(addr) print_debug(" - request: %r", request) # give it to the application self.this_application.request(request) except ReadPropertyMultipleException as error: ReadProperty._exception("exception: %r", error) data = None while True: try: data, evt = self.this_application.ResponseQueue.get( timeout=self._TIMEOUT) evt.set() return data except Empty: print('No response from controller') return None
def build_rpm_request(self, args, vendor_id=0): """ Build request from args """ self._log.debug(args) i = 0 addr = args[i] i += 1 vendor_id = vendor_id read_access_spec_list = [] while i < len(args): obj_type = args[i] i += 1 if obj_type.isdigit(): obj_type = int(obj_type) elif "@obj_" in obj_type: obj_type = int(obj_type.split("_")[1]) elif not get_object_class(obj_type, vendor_id=vendor_id): raise ValueError("Unknown object type : {}".format(obj_type)) obj_inst = int(args[i]) i += 1 prop_reference_list = [] while i < len(args): prop_id = args[i] if "@obj_" in prop_id: break if prop_id not in PropertyIdentifier.enumerations: try: if "@prop_" in prop_id: prop_id = int(prop_id.split("_")[1]) self._log.debug( "Proprietary property : {} | {} -> Vendor : {}" .format(obj_type, prop_id, vendor_id)) else: break except: break elif prop_id in ( "all", "required", "optional", "objectName", "objectType", "objectIdentifier", "polarity", ): pass else: datatype = get_datatype(obj_type, prop_id, vendor_id=vendor_id) if not datatype: raise ValueError( "invalid property for object type : {} | {}". format(obj_type, prop_id)) i += 1 # build a property reference prop_reference = PropertyReference(propertyIdentifier=prop_id) # check for an array index if (i < len(args)) and args[i].isdigit(): prop_reference.propertyArrayIndex = int(args[i]) i += 1 prop_reference_list.append(prop_reference) if not prop_reference_list: raise ValueError("provide at least one property") # build a read access specification read_access_spec = ReadAccessSpecification( objectIdentifier=(obj_type, obj_inst), listOfPropertyReferences=prop_reference_list, ) read_access_spec_list.append(read_access_spec) if not read_access_spec_list: raise RuntimeError( "at least one read access specification required") # build the request request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list) request.pduDestination = Address(addr) return request
def do_rpm(self, args): """ rpm <devid> ( <objid> ( <prop> [ <indx> ] )... )... Send a Read-Property-Multiple request to a device identified by its device identifier. """ args = args.split() if _debug: DiscoverConsoleCmd._debug("do_rpm %r", args) try: i = 0 devid = int(args[i]) if _debug: DiscoverConsoleCmd._debug(" - devid: %r", devid) i += 1 # map the devid identifier to an address from the database addr = snapshot.get_value(devid, '-', 'address') if not addr: raise ValueError("unknown device") if _debug: DiscoverConsoleCmd._debug(" - addr: %r", addr) read_access_spec_list = [] while i < len(args): obj_id = ObjectIdentifier(args[i]).value if _debug: DiscoverConsoleCmd._debug(" - obj_id: %r", obj_id) i += 1 prop_reference_list = [] while i < len(args): prop_id = args[i] if _debug: DiscoverConsoleCmd._debug(" - prop_id: %r", prop_id) if prop_id not in PropertyIdentifier.enumerations: break i += 1 if prop_id in ('all', 'required', 'optional'): pass else: datatype = get_datatype(obj_id[0], prop_id) if not datatype: raise ValueError( "invalid property for object type") # build a property reference prop_reference = PropertyReference( propertyIdentifier=prop_id, ) # check for an array index if (i < len(args)) and args[i].isdigit(): prop_reference.propertyArrayIndex = int(args[i]) i += 1 # add it to the list prop_reference_list.append(prop_reference) # check for at least one property if not prop_reference_list: raise ValueError("provide at least one property") # build a read access specification read_access_spec = ReadAccessSpecification( objectIdentifier=obj_id, listOfPropertyReferences=prop_reference_list, ) # add it to the list read_access_spec_list.append(read_access_spec) # check for at least one if not read_access_spec_list: raise RuntimeError( "at least one read access specification required") # build the request request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list, ) request.pduDestination = Address(addr) if _debug: DiscoverConsoleCmd._debug(" - request: %r", request) # make an IOCB iocb = IOCB(request) if _debug: DiscoverConsoleCmd._debug(" - iocb: %r", iocb) # give it to the application deferred(this_application.request_io, iocb) # wait for it to complete iocb.wait() # do something for success if iocb.ioResponse: apdu = iocb.ioResponse if _debug: DiscoverConsoleCmd._debug(" - apdu: %r", apdu) # should be an ack if not isinstance(apdu, ReadPropertyMultipleACK): if _debug: DiscoverConsoleCmd._debug(" - not an ack") return # loop through the results for result in apdu.listOfReadAccessResults: # here is the object identifier objectIdentifier = result.objectIdentifier if _debug: DiscoverConsoleCmd._debug(" - objectIdentifier: %r", objectIdentifier) # now come the property values per object for element in result.listOfResults: # get the property and array index propertyIdentifier = element.propertyIdentifier if _debug: DiscoverConsoleCmd._debug( " - propertyIdentifier: %r", propertyIdentifier) propertyArrayIndex = element.propertyArrayIndex if _debug: DiscoverConsoleCmd._debug( " - propertyArrayIndex: %r", propertyArrayIndex) # here is the read result readResult = element.readResult property_label = str(propertyIdentifier) if propertyArrayIndex is not None: property_label += "[" + str( propertyArrayIndex) + "]" # check for an error if readResult.propertyAccessError is not None: if interactive: print("{} ! {}".format( property_label, readResult.propertyAccessError)) else: # here is the value propertyValue = readResult.propertyValue # find the datatype datatype = get_datatype(objectIdentifier[0], propertyIdentifier) if _debug: DiscoverConsoleCmd._debug( " - datatype: %r", datatype) if not datatype: str_value = '?' else: # special case for array parts, others are managed by cast_out if issubclass(datatype, Array) and (propertyArrayIndex is not None): if propertyArrayIndex == 0: datatype = Unsigned else: datatype = datatype.subtype if _debug: DiscoverConsoleCmd._debug( " - datatype: %r", datatype) value = propertyValue.cast_out(datatype) if _debug: DiscoverConsoleCmd._debug( " - value: %r", value) # convert the value to a string if hasattr(value, 'dict_contents'): dict_contents = value.dict_contents( as_class=OrderedDict) str_value = json.dumps(dict_contents) else: str_value = str(value) if interactive: print("{}: {}".format(property_label, str_value)) # save it in the snapshot snapshot.upsert(devid, '{}:{}'.format(*objectIdentifier), property_label, str_value) # do something for error/reject/abort if iocb.ioError: if interactive: print(str(iocb.ioError)) except Exception as error: DiscoverConsoleCmd._exception("exception: %r", error)
def do_read(self, args): """read <addr> ( <type> <inst> ( <prop> [ <indx> ] )... )...""" args = args.split() if _debug: ReadPropertyMultipleConsoleCmd._debug("do_read %r", args) try: i = 0 addr = args[i] i += 1 read_access_spec_list = [] while i < len(args): obj_type = args[i] i += 1 if obj_type.isdigit(): obj_type = int(obj_type) elif not get_object_class(obj_type): raise ValueError, "unknown object type" obj_inst = int(args[i]) i += 1 prop_reference_list = [] while i < len(args): prop_id = args[i] if prop_id not in PropertyIdentifier.enumerations: break i += 1 if prop_id in ('all', 'required', 'optional'): pass else: datatype = get_datatype(obj_type, prop_id) if not datatype: raise ValueError, "invalid property for object type" # build a property reference prop_reference = PropertyReference( propertyIdentifier=prop_id, ) # check for an array index if (i < len(args)) and args[i].isdigit(): prop_reference.propertyArrayIndex = int(args[i]) i += 1 # add it to the list prop_reference_list.append(prop_reference) # check for at least one property if not prop_reference_list: raise ValueError, "provide at least one property" # build a read access specification read_access_spec = ReadAccessSpecification( objectIdentifier=(obj_type, obj_inst), listOfPropertyReferences=prop_reference_list, ) # add it to the list read_access_spec_list.append(read_access_spec) # check for at least one if not read_access_spec_list: raise RuntimeError, "at least one read access specification required" # build the request request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list, ) request.pduDestination = Address(addr) if _debug: ReadPropertyMultipleConsoleCmd._debug(" - request: %r", request) # give it to the application this_application.request(request) except Exception, e: ReadPropertyMultipleConsoleCmd._exception("exception: %r", e)
def request_object_properties( self, device_address_str: str, objects: Sequence[Tuple[Union[int, str], int]], properties=None, skip_when_cached=False, chunk_size: Optional[int] = None, request_timeout: Optional[Timedelta] = None, ): if threading.current_thread() == threading.main_thread(): logger.error( "request_object_properties called from main thread! Run it from an executor!", stack_info=True, ) if properties is None: properties = ["objectName", "description", "units"] device_address = Address(device_address_str) device_info: DeviceInfo = self.deviceInfoCache.get_device_info( device_address) if skip_when_cached: object_to_request = [] for object_type, object_instance in objects: cache_key = (device_address_str, object_type, object_instance) if cache_key in self._object_info_cache: cached_object_info = self._object_info_cache[cache_key] if all(property in cached_object_info for property in properties): logger.debug( "Object info for {} already in cache. Skipping!", (object_type, object_instance), ) continue object_to_request.append((object_type, object_instance)) if not object_to_request: logger.debug("All objects already in cache") return objects = object_to_request result_values = {} if not chunk_size: chunk_size = 20 if device_info and device_info.segmentationSupported == "noSegmentation": chunk_size = 4 for objects_chunk in chunks(objects, chunk_size): prop_reference_list = [ PropertyReference(propertyIdentifier=property) for property in properties ] read_access_specs = [ ReadAccessSpecification( objectIdentifier=ObjectIdentifier(object_identifier), listOfPropertyReferences=prop_reference_list, ) for object_identifier in objects_chunk ] request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_specs) request.pduDestination = device_address iocb = IOCB(request) deferred(self.request_io, iocb) if request_timeout: iocb.set_timeout(request_timeout.s) iocb.wait() if iocb.ioResponse: chunk_result_values = self._unpack_iocb(iocb) for object_identifier in chunk_result_values: object_type, object_instance = object_identifier with self._object_info_cache_lock: cache_key = (device_address_str, object_type, object_instance) if cache_key not in self._object_info_cache: self._object_info_cache[cache_key] = {} self._object_info_cache[cache_key].update( chunk_result_values[object_identifier]) result_values.update(chunk_result_values) # do something for error/reject/abort if iocb.ioError: logger.error( "IOCB returned with error for object properties request (device {}, objects {}, props {}): {}", device_address_str, objects, properties, iocb.ioError, ) # TODO: maybe raise error here return result_values
def request_device_properties( self, device_address_str: str, properties=None, skip_when_cached=False, request_timeout: Optional[Timedelta] = None, ): if threading.current_thread() == threading.main_thread(): logger.error( "request_device_properties called from main thread! Run it from an executor!", stack_info=True, ) if properties is None: properties = ["objectName", "description"] device_address = Address(device_address_str) device_info: DeviceInfo = self.deviceInfoCache.get_device_info( device_address) if not device_info: for retry in range(self._retry_count): deferred(self.who_is, address=device_address) time.sleep(5 * (retry + 1)) device_info: DeviceInfo = self.deviceInfoCache.get_device_info( device_address) if device_info: break else: device_info: DeviceInfo = self.deviceInfoCache.get_device_info( device_address) if not device_info: logger.error( "Device with address {} is not in device cache!", device_address_str, ) return if skip_when_cached: cache_key = (device_address_str, "device", device_info.deviceIdentifier) if cache_key in self._object_info_cache: cached_object_info = self._object_info_cache[cache_key] if all(property in cached_object_info for property in properties): logger.debug("Device info already in cache. Skipping!") return prop_reference_list = [ PropertyReference(propertyIdentifier=property) for property in properties ] device_object_identifier = ("device", device_info.deviceIdentifier) read_access_spec = ReadAccessSpecification( objectIdentifier=device_object_identifier, listOfPropertyReferences=prop_reference_list, ) request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=[read_access_spec]) request.pduDestination = device_address iocb = IOCB(request) deferred(self.request_io, iocb) if request_timeout: iocb.set_timeout(request_timeout.s) iocb.wait() if iocb.ioResponse: result_values = self._unpack_iocb(iocb) if device_object_identifier in result_values: with self._object_info_cache_lock: cache_key = ( device_address_str, "device", device_info.deviceIdentifier, ) if cache_key not in self._object_info_cache: self._object_info_cache[cache_key] = {} self._object_info_cache[cache_key].update( result_values[device_object_identifier]) return result_values[device_object_identifier] # do something for error/reject/abort if iocb.ioError: logger.error( "IOCB returned with error for device properties request (device {}, objects {}, props {}) : {}", device_address_str, device_object_identifier, properties, iocb.ioError, ) return None
def simpleread(self): try: reverse_point_map = {} result_dict = [] read_access_spec_list = [] count = 0 prop_ref_list = [] propertylist = ["units"] for prop in propertylist: prop_ref = PropertyReference(propertyIdentifier=prop) print("prop_ref: {} of property: {}", prop_ref, prop) print prop_ref_list.append(prop_ref) count += 1 print("prop_ref_list:{} of property: {}", prop_ref_list, prop) print read_access_spec = ReadAccessSpecification( objectIdentifier=("analogOutput", 2), listOfPropertyReferences=prop_ref_list) read_access_spec_list.append(read_access_spec) print("read_access_spec_list is:{} of property: {}", read_access_spec_list, read_access_spec) if read_access_spec_list: _log.debug( "Requesting {count} properties from {target}".format( count=count, target="2001:127")) print "what!!" request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list) request.pduDestination = Address("2001:127") print "request addressed" iocb = IOCB(request, self.async_call) print "request made" self.simple = True self.this_application.submit_request(iocb) print "request sent" bacnet_results = tuple bacnet_results = (iocb.ioResult.get(35)) print "request received" print bacnet_results print result_dict return result_dict except Exception as e: print e try: print "g" request = WhoIsRequest() address = list() deviceidentifier = list() request.pduDestination = GlobalBroadcast() self.this_application.request(request) thread = threading.Thread(target=10) thread.start() self.this_application.request(request) self.this_application.release = True self.this_application.update = False print "run started" #run() print "done" addresslist = self.this_application.found_address addresslist = list(set(addresslist)) for a, b in addresslist: address.append(a) deviceidentifier.append(b) todelete = list() print address print deviceidentifier print "destination address list is ", address print "object instance of that address", deviceidentifier return address, deviceidentifier except Exception as e: _log.exception("an error has occurred: %s", e) return None
def create_ReadPropertyMultipleRequest(args): """ Create a request to compare with called arg """ args = args.split() i = 0 addr = args[i] i += 1 read_access_spec_list = [] while i < len(args): obj_type = args[i] i += 1 if obj_type.isdigit(): obj_type = int(obj_type) elif not get_object_class(obj_type): raise ValueError("unknown object type") obj_inst = int(args[i]) i += 1 prop_reference_list = [] while i < len(args): prop_id = args[i] if prop_id not in PropertyIdentifier.enumerations: break i += 1 if prop_id in ('all', 'required', 'optional'): pass else: datatype = get_datatype(obj_type, prop_id) if not datatype: raise ValueError( "invalid property for object type : %s | %s" % (obj_type, prop_id)) # build a property reference prop_reference = PropertyReference(propertyIdentifier=prop_id, ) # check for an array index if (i < len(args)) and args[i].isdigit(): prop_reference.propertyArrayIndex = int(args[i]) i += 1 # add it to the list prop_reference_list.append(prop_reference) # check for at least one property if not prop_reference_list: raise ValueError("provide at least one property") # build a read access specification read_access_spec = ReadAccessSpecification( objectIdentifier=(obj_type, obj_inst), listOfPropertyReferences=prop_reference_list, ) # add it to the list read_access_spec_list.append(read_access_spec) # check for at least one if not read_access_spec_list: raise RuntimeError("at least one read access specification required") # build the request request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list, ) request.pduDestination = Address(addr) return request
def do_read(self, args): """read <addr> ( <type> <inst> ( <prop> [ <indx> ] )... )...""" args = args.split() if _debug: ReadPropertyMultipleConsoleCmd._debug("do_read %r", args) try: i = 0 addr = args[i] i += 1 read_access_spec_list = [] while i < len(args): obj_type = args[i] i += 1 if obj_type.isdigit(): obj_type = int(obj_type) elif not get_object_class(obj_type): raise ValueError("unknown object type") obj_inst = int(args[i]) i += 1 prop_reference_list = [] while i < len(args): prop_id = args[i] if prop_id not in PropertyIdentifier.enumerations: break i += 1 if prop_id in ('all', 'required', 'optional'): pass else: datatype = get_datatype(obj_type, prop_id) if not datatype: raise ValueError( "invalid property for object type") # build a property reference prop_reference = PropertyReference( propertyIdentifier=prop_id, ) # check for an array index if (i < len(args)) and args[i].isdigit(): prop_reference.propertyArrayIndex = int(args[i]) i += 1 # add it to the list prop_reference_list.append(prop_reference) # check for at least one property if not prop_reference_list: raise ValueError("provide at least one property") # build a read access specification read_access_spec = ReadAccessSpecification( objectIdentifier=(obj_type, obj_inst), listOfPropertyReferences=prop_reference_list, ) # add it to the list read_access_spec_list.append(read_access_spec) # check for at least one if not read_access_spec_list: raise RuntimeError( "at least one read access specification required") # build the request request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list, ) request.pduDestination = Address(addr) if _debug: ReadPropertyMultipleConsoleCmd._debug(" - request: %r", request) # make an IOCB iocb = IOCB(request) if _debug: ReadPropertyMultipleConsoleCmd._debug(" - iocb: %r", iocb) # give it to the application this_application.request_io(iocb) # wait for it to complete iocb.wait() # do something for success if iocb.ioResponse: apdu = iocb.ioResponse # should be an ack if not isinstance(apdu, ReadPropertyMultipleACK): if _debug: ReadPropertyMultipleConsoleCmd._debug( " - not an ack") return # loop through the results for result in apdu.listOfReadAccessResults: # here is the object identifier objectIdentifier = result.objectIdentifier if _debug: ReadPropertyMultipleConsoleCmd._debug( " - objectIdentifier: %r", objectIdentifier) # now come the property values per object for element in result.listOfResults: # get the property and array index propertyIdentifier = element.propertyIdentifier if _debug: ReadPropertyMultipleConsoleCmd._debug( " - propertyIdentifier: %r", propertyIdentifier) propertyArrayIndex = element.propertyArrayIndex if _debug: ReadPropertyMultipleConsoleCmd._debug( " - propertyArrayIndex: %r", propertyArrayIndex) # here is the read result readResult = element.readResult sys.stdout.write(propertyIdentifier) if propertyArrayIndex is not None: sys.stdout.write("[" + str(propertyArrayIndex) + "]") # check for an error if readResult.propertyAccessError is not None: sys.stdout.write( " ! " + str(readResult.propertyAccessError) + '\n') else: # here is the value propertyValue = readResult.propertyValue # find the datatype datatype = get_datatype(objectIdentifier[0], propertyIdentifier) if _debug: ReadPropertyMultipleConsoleCmd._debug( " - datatype: %r", datatype) if not datatype: raise TypeError("unknown datatype") # special case for array parts, others are managed by cast_out if issubclass(datatype, Array) and (propertyArrayIndex is not None): if propertyArrayIndex == 0: value = propertyValue.cast_out(Unsigned) else: value = propertyValue.cast_out( datatype.subtype) else: value = propertyValue.cast_out(datatype) if _debug: ReadPropertyMultipleConsoleCmd._debug( " - value: %r", value) sys.stdout.write(" = " + str(value) + '\n') sys.stdout.flush() # do something for error/reject/abort if iocb.ioError: sys.stdout.write(str(iocb.ioError) + '\n') except Exception, error: ReadPropertyMultipleConsoleCmd._exception("exception: %r", error)
def read_properties(self, target_address, point_map, max_per_request=None, use_read_multiple=True): """Read a set of points and return the results""" if not use_read_multiple: return self.read_using_single_request(target_address, point_map) #Set max_per_request really high if not set. if max_per_request is None: max_per_request = self._max_per_request _log.debug("Reading {count} points on {target}, max per" " scrape: {max}".format(count=len(point_map), target=target_address, max=max_per_request)) # This will be used to get the results mapped # back on the the names reverse_point_map = {} #Used to group properties together for the request. object_property_map = defaultdict(list) for name, properties in point_map.iteritems(): if len(properties) == 3: object_type, instance_number, property_name = properties property_index = None elif len(properties) == 4: object_type, instance_number, property_name, property_index = properties else: _log.error( "skipping {} in request to {}: incorrect number of parameters" .format(name, target_address)) reverse_point_map[object_type, instance_number, property_name, property_index] = name object_property_map[object_type, instance_number].append( (property_name, property_index)) result_dict = {} finished = False while not finished: read_access_spec_list = [] count = 0 for _ in xrange(max_per_request): try: obj_data, properties = object_property_map.popitem() except KeyError: finished = True break obj_type, obj_inst = obj_data prop_ref_list = [] for prop, prop_index in properties: prop_ref = PropertyReference(propertyIdentifier=prop) if prop_index is not None: prop_ref.propertyArrayIndex = prop_index prop_ref_list.append(prop_ref) count += 1 read_access_spec = ReadAccessSpecification( objectIdentifier=(obj_type, obj_inst), listOfPropertyReferences=prop_ref_list) read_access_spec_list.append(read_access_spec) if read_access_spec_list: _log.debug( "Requesting {count} properties from {target}".format( count=count, target=target_address)) request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list) request.pduDestination = Address(target_address) iocb = self.iocb_class(request) self.this_application.submit_request(iocb) bacnet_results = iocb.ioResult.get(10) _log.debug( "Received read response from {target} count: {count}". format(count=count, target=target_address)) for prop_tuple, value in bacnet_results.iteritems(): name = reverse_point_map[prop_tuple] result_dict[name] = value return result_dict
def build_rpm_request(self, args): """ Build request from args """ i = 0 addr = args[i] i += 1 read_access_spec_list = [] while i < len(args): obj_type = args[i] i += 1 if obj_type.isdigit(): obj_type = int(obj_type) elif not get_object_class(obj_type): raise ValueError("unknown object type") obj_inst = int(args[i]) i += 1 prop_reference_list = [] while i < len(args): prop_id = args[i] if prop_id not in PropertyIdentifier.enumerations: break i += 1 if prop_id in ('all', 'required', 'optional'): pass else: datatype = get_datatype(obj_type, prop_id) if not datatype: raise ValueError( "invalid property for object type : {} | {}".format( (obj_type, prop_id))) # build a property reference prop_reference = PropertyReference(propertyIdentifier=prop_id) # check for an array index if (i < len(args)) and args[i].isdigit(): prop_reference.propertyArrayIndex = int(args[i]) i += 1 prop_reference_list.append(prop_reference) if not prop_reference_list: raise ValueError("provide at least one property") # build a read access specification read_access_spec = ReadAccessSpecification( objectIdentifier=(obj_type, obj_inst), listOfPropertyReferences=prop_reference_list) read_access_spec_list.append(read_access_spec) if not read_access_spec_list: raise RuntimeError( "at least one read access specification required") # build the request request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list) request.pduDestination = Address(addr) self._log.debug("{:<20} {!r}".format( 'REQUEST', request)) return request
def _form_ReadPropertyMultiple_request(self, args, body_json): """ Example Read http://localhost/read/adderss/analogValue:1 http://localhost/read/<address>/<object type>:<object instance number> http://localhost/read/<address>/<object type>:<object instance number>/<property> http://localhost:8081/read/192.168.1.100/analogValue:0/presentValue Example WhoIs http://localhost/whois/<address> Example ReadPropertyMultiple http://localhost:8081/readpropertymultiple/<address>/ body_json = {'address':'192.168.1.100', 'bacnet_objects': [{'object': 'analogValue:1', 'property': 'presentValue'}, {'object': 'analogValue:2', 'property': 'presentValue'}, {'object': 'analogValue:3', 'property': 'presentValue'}]} """ # Error check request if body_json['bacnet_objects'].__len__() == 0: # No objects defined in list msg = ('No BACnet object specifiers were passed. '+ 'Must include specifiers like {"object":"analogValue:1",' + '"property":"presentValue"}' ) if _debug: HTTPRequestHandler._debug(" - body_json: %r", msg) self.send_header('Content-Type','text/plain') self.end_headers() self.wfile.write(bytes(msg, 'utf-8')) raise ValueError(msg) if not 'bacnet_objects' in body_json.keys(): # Improperty structured JSON request msg = ('Bad request format. "bacnet_objects" must be a key '+ 'in the request body JSON oject. Got {}'.format(str(body_json.keys())) ) if _debug: HTTPRequestHandler._debug(" - body_json: %r", msg) self.send_header('Content-Type','text/plain') self.end_headers() self.wfile.write(bytes(msg, 'utf-8')) raise ValueError(msg) # Build Read Access Spec List read_access_spec_list = [] """Formatted like results = {'analogValue:1' : {'presentValue':'1', 'objectName':'some_name', 'arrayResult':[1,2,3]}, 'analogValue:2' : {'presentValue':'4'} }""" for bacnet_object in body_json['bacnet_objects']: # Property reference list (for EACH object being requested) prop_reference_list = [] try: # What is the object identifier? obj_id = ObjectIdentifier(bacnet_object['object']).value # Get the object type if not get_object_class(obj_id[0]): # The passed value is not a valid BACnet object type msg = ('The requested Object Identifier is not a valid BACnet '+ 'object type. Got {}'.format(str(obj_id)) ) if _debug: HTTPRequestHandler._debug(" - obj_id: %r", msg) self.send_header('Content-Type','text/plain') self.end_headers() self.wfile.write(bytes(msg, 'utf-8')) raise ValueError(msg) except ValueError: # The passed value is not a valid BACnet object type msg = ('The requested Object Identifier is not a valid BACnet '+ 'object type. Got {}'.format(str(obj_id)) ) if _debug: HTTPRequestHandler._debug(" - objectID: %r", msg) self.send_header('Content-Type','text/plain') self.end_headers() self.wfile.write(bytes(msg, 'utf-8')) raise ValueError(msg) # Property ID prop_id = bacnet_object['property'] if prop_id not in PropertyIdentifier.enumerations: # Invalid property identifier - usually 'presentValue' or 'all' msg = ('Invalid BACnet property. Valid propery must be one of '+ '{}'.format(str(PropertyIdentifier.enumerations.keys())) ) if _debug: HTTPRequestHandler._debug(" - bac property: %r", msg) self.send_header('Content-Type','text/plain') self.end_headers() self.wfile.write(bytes(msg, 'utf-8')) raise ValueError(msg) # Object datatype datatype = get_datatype(obj_id[0], prop_id) if (datatype is None) and (prop_id != 'all'): # For converting between BACnet data types and pyton types msg = ('Invalid combination of BACnet object type and property ID '+ 'Got {}, {}'.format(str(obj_id), str(prop_id)) ) if _debug: HTTPRequestHandler._debug(" - datatype: %r", msg) self.send_header('Content-Type','text/plain') self.end_headers() self.wfile.write(bytes(msg, 'utf-8')) raise ValueError(msg) # Build property reference # Not sure what this is - check ASHRAE standard lol prop_reference = PropertyReference(propertyIdentifier=prop_id) # Array index for BACnet objects with multiple values # Array index not supported for this API - just get the whole array prop_reference_list.append(prop_reference) # Build read access specification read_access_spec = ReadAccessSpecification( objectIdentifier=obj_id, listOfPropertyReferences=prop_reference_list ) read_access_spec_list.append(read_access_spec) # Build request request = ReadPropertyMultipleRequest( listOfReadAccessSpecs=read_access_spec_list, ) request.pduDestination = Address(body_json['address']) return request