def read_property_multiple_g3(device, properties, timeout=3.0, no_fallback=0): # Some device's do not properly answer multiple properties to multiple # objects. This method first tries RPM, then RPM(singular) and finially RP # to retrieve a list of properties. # A readPropertyFallback attribute remembers which mode was successful and # that is used in subsequent reads. if (not (_device_table.has_key(device)) or \ (_device_table[device].readPropertyFallback < BACNET_RPM_SINGLE_OK)): results = _read_property_multiple_g3(device,properties, timeout) if (results != None): if (len(results) == len(properties)): _device_table[device].readPropertyFallback=1 # No fallback needed. return results elif no_fallback != 0: return results else: # Broken device? _device_table[device].readPropertyFallback=0 results = [] properties = copy.copy(properties) while properties: property = properties.pop(0) try: rp_result = read_property_g3(device, property) if (rp_result is not None): #remember this worked if (_device_table[device].readPropertyFallback == BACNET_RPM_UNKNOWN): msglog.log('broadway', msglog.types.WARN, 'read_property fallback for device = ' + str(device)) _device_table[device].readPropertyFallback = BACNET_RPM_NOT_SUPPORTED #convert result to RPM style result = sequence.ReadAccessResult() result.object_identifier = rp_result.object_identifier result.list_of_results = [ sequence._ReadPropertyMultipleResult( property_identifier=rp_result.property_identifier, property_array_index=rp_result.property_array_index, property_value=rp_result.property_value) ] else: # Place holder... result = ReadAccessResult() except BACnetError, e: # Simulate RPMs behaviour when a subset of reads fail. error = sequence.Error(decode=tag.decode(e.npdu.data).value) result = sequence.ReadAccessResult() result.object_identifier = data.BACnetObjectIdentifier(property[0], property[1]) if len(property) > 3 and property[3] != -1: index = property[3] else: index = -1 result.list_of_results = [ sequence._ReadPropertyMultipleResult( property_identifier=property[2], property_array_index=index, property_access_error=error) ] results.append(result)
def read_property_g3(device, prop, timeout=3.0, **keywords): object = prop[0] instance = prop[1] property = prop[2] arrayidx = None if len(prop) > 3 : arrayidx = prop[3] rp = APDU() rp.pdu_type = BACNET_CONFIRMED_SERVICE_REQUEST_PDU rp.choice = 12 objID = tag.Context(0,data.BACnetObjectIdentifier(object,instance)) propID = tag.Context(1,data.encode_enumerated(property)) rp.data = objID.encoding + propID.encoding if arrayidx is not None and arrayidx != -1: rp.data = rp.data + \ tag.Context(2,data.encode_unsigned_integer(arrayidx)).\ encoding if keywords.has_key('callback'): keywords['callback'].callback(_read_property_callback) request_id = network.send_request(device, rp, timeout, **keywords) return keywords['callback'] else: #block until answer else let tsm handle callback request_id = network.send_request(device, rp, timeout) r = recv_response(request_id, timeout) response = tag.decode(r.data) return sequence.ReadPropertyACK(decode=response.value)
def cov_subscription_request(device, prop_tuple, subscription_type, \ lifetime, subscription_pid, **keywords): object = prop_tuple[0] instance = prop_tuple[1] rp = APDU() rp.pdu_type = BACNET_CONFIRMED_SERVICE_REQUEST_PDU rp.choice = 5 # Subscribe COV Request rp.data = tag.Context(0,data.\ encode_unsigned_integer(subscription_pid)).encoding objID = tag.Context(1,data.BACnetObjectIdentifier(object,instance)) rp.data = rp.data + objID.encoding rp.data = rp.data + \ tag.Context(2,data.\ encode_boolean(subscription_type)).encoding rp.data = rp.data + \ tag.Context(3,data.\ encode_unsigned_integer(lifetime)).encoding if keywords.has_key('callback'): keywords['callback'].callback(_cov_subscription_callback) request_id = network.send_request(device, rp, **keywords) return keywords['callback'] else: #block until answer else let tsm handle callback request_id = network.send_request(device, rp) r = recv_response(request_id) return r
def read_property_multiple_real2(device, properties): results = [] rp = APDU() rp.pdu_type = BACNET_CONFIRMED_SERVICE_REQUEST_PDU rp.choice = 14 rp.data = array.array('c') for prop in properties: object = prop[0] instance = prop[1] property = prop[2] objID = tag.Context(0,data.BACnetObjectIdentifier(object,instance)) if len(prop) < 4 or prop[3] == -1: propID = tag.Construct( 1,[tag.Context(0,data.encode_enumerated(property))] ) else: arrayidx = prop[3] propID = tag.Construct( 1,[tag.Context(0, data.encode_enumerated(property)), tag.Context(1, data.encode_unsigned_integer(arrayidx))] ) rp.data.fromstring(objID.encoding) rp.data.fromstring(propID.encoding) request_id = network.send_request(device, rp) r = recv_response(request_id) responses = tag.decode(r.data) for response in responses.value: # Now if we felt like it, we could extract the BACnetIdentifierObject from # the response data, at response.number 0. But we won't because # we don't need it at the moment. if response.number == 1: # Property id/value list. for p in response.value: # Again, if we felt like it, we could extract the property # ID from tag.number 2. But we won't because we don't use # it. If we wrote code to match the request to response, # we would need it. if p.number == 4: # Property value list p_value = p.value[0].value if p_value is None: pass p_bacnet_value_type = p.value[0].number results.append((p_value, p_bacnet_value_type)) elif p.number == 3: # Property value list p_value = p.value[0].value p_bacnet_value_type = p.value[0].number results.append((p_value, p_bacnet_value_type)) elif p.number == 5: # error code results.append((None, None)) return results
def test_encode_bacnet_object_identifier(self): t = tag.BACnetObjectIdentifier(data.BACnetObjectIdentifier(0x3,0xf)) if t.name != 'BACnetObjectIdentifier': raise 'Encoded BACnetObjectIdentifier incorrectly as', t.name b = t.value if b.id != 0xc0000f: raise 'Incorrect BACnetObjectIdentifier id' if b.object_type != 0x3: raise 'Incorrect BACnetObjectIdentifier object_type' if b.instance_number != 0xf: raise 'Incorrect BACnetObjectIdentifier instance_number'
def _read_property_multiple_g3(device, properties, timeout=3.0, **keywords): rp = APDU() rp.pdu_type = BACNET_CONFIRMED_SERVICE_REQUEST_PDU rp.choice = 14 rp.data = array.array('c') for prop in properties: object = prop[0] instance = prop[1] property = prop[2] objID = tag.Context(0,data.BACnetObjectIdentifier(object,instance)) if isinstance(property, types.TupleType): tags = [] for pid in property: #loop through list of properties if isinstance(pid, types.TupleType): #may have index if len(pid) > 1: #index tags.append(tag.Context(0, data.encode_enumerated(pid[0]))) tags.append(tag.Context(1, data.encode_unsigned_integer(pid[1]))) continue pid = pid[0] #doen't need to be tuple tags.append(tag.Context(0,data.encode_enumerated(pid))) propID = tag.Construct(1,tags) #frame it in contruct tags else: if len(prop) < 4 or prop[3] == -1: propID = tag.Construct( 1,[tag.Context(0,data.encode_enumerated(property))] ) else: arrayidx = prop[3] propID = tag.Construct( 1,[tag.Context(0, data.encode_enumerated(property)), tag.Context(1, data.encode_unsigned_integer(arrayidx))] ) rp.data.fromstring(objID.encoding) rp.data.fromstring(propID.encoding) #return rp if DEBUG: for c in rp.data: print hex(ord(c)),' ', print '' if keywords.has_key('callback'): keywords['callback'].callback(_read_property_multiple_callback) network.send_request(device, rp, timeout, **keywords) return keywords['callback'] #used as flag request_id = network.send_request(device, rp, timeout) r = recv_response(request_id, timeout) responses = tag.decode(r.data) return sequence.context_read_access_result_list(responses)
def write_property_multiple_g3(device, prop_vals, no_fall_back=0): obj_ids = {} for pv in prop_vals: prop_tuple = pv[0] prop_val = pv[1] object = prop_tuple[0] instance = prop_tuple[1] k = (object, instance) # use tuple as key into object map if not obj_ids.has_key(k): # if necy, add a map entry for the given object ID was = sequence.WriteAccessSpecification() was.list_of_properties = [] # populated on this pass, and poss'ly subsequent passes was.object_identifier = data.BACnetObjectIdentifier(object, instance) obj_ids[k] = was property_id = prop_tuple[2] property_array_index = None # default priority = None # default # If valid index and/or priority is/are available, add it/them to extended tuple: if len(prop_tuple) > 3 and prop_tuple[3] != -1: property_array_index = prop_tuple[3] if len(prop_tuple) > 4: priority = prop_tuple[4] # Create and init a new BACnetPropertyValue instance (using given value), and add # that new instance to the corresponding object map entry: kw = {'property_identifier':property_id,\ 'value':prop_val,\ 'property_array_index':property_array_index} if not property_array_index is None: kw['property_array_index'] = property_array_index if not priority is None: kw['priority'] = priority obj_ids[k].list_of_properties.append(sequence.BACnetPropertyValue(*(),**kw)) rp = APDU() rp.pdu_type = BACNET_CONFIRMED_SERVICE_REQUEST_PDU rp.choice = 16 for obj_v in obj_ids.values(): obj_v_enc = obj_v.encoding t = tag.encode(obj_v_enc) rp.data.fromstring(t) request_id = network.send_request(device, rp) r = recv_response(request_id) # @fixme Decode the BACnet-SimpleACK-PDU? and/or handle error rtns by defaulting to # write_prop_mults on each "obj_v" above, and then to indiv write_props on elems of # obj_v.list_of_properties... return r
def write_property(device, object, instance, property, arrayidx, priority, value, btype): rp = APDU() rp.pdu_type = BACNET_CONFIRMED_SERVICE_REQUEST_PDU rp.choice = 15 objectIdentifier = tag.Context(0,data.BACnetObjectIdentifier(object,instance)) propertyIdentifier = tag.Context(1,data.encode_enumerated(property)) propertyArrayIndex = None # @fixme Support arrayidx propertyValue = tag.Construct(3) if (priority): priorityTag = tag.Context(4,data.encode_enumerated(priority)) if btype == 0: propertyValue.value.append(tag.Null()) elif btype == 1: propertyValue.value.append(tag.Boolean(int(value))) elif btype == 2: propertyValue.value.append(tag.UnsignedInteger(int(value))) elif btype == 3: propertyValue.value.append(tag.SignedInteger(int(value))) elif btype == 4: propertyValue.value.append(tag.Real(float(value))) elif btype == 5: propertyValue.value.append(tag.Double(float(value))) elif btype == 6: propertyValue.value.append(tag.OctetString(value)) elif btype == 7: if type(value) == types.StringValue or type(value) == array.ArrayType: propertyValue.value.append(tag.CharacterString(data.ANSI_String(value))) else: propertyValue.value.append(tag.CharacterString(value)) elif btype == 8: propertyValue.value.append(tag.BitString(value)) elif btype == 9: propertyValue.value.append(tag.Enumerated(int(value))) elif btype == 10: propertyValue.value.append(tag.Date(value)) elif btype == 11: propertyValue.value.append(tag.Time(value)) elif btype == 12: propertyValue.value.append(tag.BACnetObjectIdentifier(value)) else: raise EInvalidValue("btype", btype) if propertyArrayIndex is None: rp.data = objectIdentifier.encoding + propertyIdentifier.encoding + \ propertyValue.encoding else: rp.data = objectIdentifier.encoding + propertyIdentifier.encoding + \ propertyArrayIndex.encoding + propertyValue.encoding if (priority): #optional priority tag rp.data = rp.data + priorityTag.encoding request_id = network.send_request(device, rp) r = recv_response(request_id) return r
def write_property_g3(device, prop_tuple, value_tag_list, priority=None): object = prop_tuple[0] instance = prop_tuple[1] property = prop_tuple[2] wpr = sequence.WritePropertyRequest() wpr.object_identifier = data.BACnetObjectIdentifier(object, instance) wpr.property_identifier = property if len(prop_tuple) > 3 and prop_tuple[3] != -1: wpr.property_array_index = prop_tuple[3] wpr.property_value = value_tag_list if priority is not None: wpr.priority = priority rp = APDU() rp.pdu_type = BACNET_CONFIRMED_SERVICE_REQUEST_PDU rp.choice = 15 rp.data = tag.encode(wpr.encoding) request_id = network.send_request(device, rp) r = recv_response(request_id) return r
def read_property(device, prop): object = prop[0] instance = prop[1] property = prop[2] arrayidx = None if len(prop) > 3 : arrayidx = prop[3] rp = APDU() rp.pdu_type = BACNET_CONFIRMED_SERVICE_REQUEST_PDU rp.choice = 12 objID = tag.Context(0,data.BACnetObjectIdentifier(object,instance)) propID = tag.Context(1,data.encode_enumerated(property)) rp.data = objID.encoding + propID.encoding if arrayidx is not None and arrayidx != -1: rp.data = rp.data + \ tag.Context(2,data.encode_unsigned_integer(arrayidx)).\ encoding request_id = network.send_request(device, rp) r = recv_response(request_id) response = tag.decode(r.data) return response
def object_identifier(self): if debug: print 'return boid' return data.BACnetObjectIdentifier(self.object_type, self.instance_number)
def read_private_object_list(device, vendor, object_type, start_index=0): """## # Return a list of lists of object names and identifiers. # @param device address number, vendor number, object type number. # @return A list, each element of which is a list with the first item an object name, # the second item a BacnetObjectIndentifier object.""" results = [] identifier_list = [] answer = [] last_instance = 0 max_tags = 0 rp = APDU() rp.pdu_type = BACNET_CONFIRMED_SERVICE_REQUEST_PDU rp.choice = 18 #ConfirmedPrivateTransferRequest rp.data = array.array('c') vendorID = tag.Context(0,data.encode_unsigned_integer(vendor)) service = tag.Context(1,data.encode_unsigned_integer(0x81)) instanceTag = tag.Construct(2,[ tag.Context(0,data.encode_unsigned_integer(object_type)), tag.Context(1,data.encode_unsigned_integer(start_index)), tag.Context(2,data.encode_unsigned_integer(50))]) rp.data.fromstring(vendorID.encoding) rp.data.fromstring(service.encoding) rp.data.fromstring(instanceTag.encoding) request_id = network.send_request(device, rp) r = recv_response(request_id) responses = tag.decode(r.data) for response in responses.value: # Now if we felt like it, we could extract the BACnetIdentifierObject from # the response data, at response.number 0. But we won't because # we don't need it at the moment. if response.number == 2: #context 2 contains instance tag replay parameters # reply parameters list. for p in response.value: # we could match tag 0 with requested object type if p.number == 1: # last Instance retrieved last_instance = data.BACnetObjectIdentifier(decode=p.data).instance_number if p.number == 2: # Max tags returned. If equals 50, ask for more max_tags = ord(p.data) if p.number == 3: #yet another open context # Identifier list for i in p.value: if i.number == 4: #this is the bacnet object identifier # bnoi = data.data_decode_bacnet_object_identifier(i.data) bnoi = data.BACnetObjectIdentifier(decode=i.data) #finially we get to add one to the list identifier_list.append(bnoi) #tag 5 would be theNVMTag, whatever that is #tag 6 would be the VMTag #now create a read property multiple to request all the names of these collected id's properties = [] if len(identifier_list) > 0: for id in identifier_list: properties.append([object_type,id.instance_number,77]) try: answer = read_property_multiple(device, properties) except BACnetError, e: # @fixme Remove after we figure out the error. print e.npdu raise e if len(answer) != len(identifier_list): raise BACnetException('Identifier list and answer list are different lengths') for i in range(len(identifier_list)): results.append([device,identifier_list[i].object_type, identifier_list[i].instance_number, answer[i][0].character_string]) if max_tags == 50: results = results.append(read_private_object_list(device, vendor, object_type, last_instance))