def test_date_time_tag(self): if _debug: TestNameValue._debug("test_date_time_tag") # BACnet Birthday (close) date_time = DateTime(date=(95, 1, 25, 3), time=(9, 0, 0, 0)) if _debug: TestNameValue._debug(" - date_time: %r", date_time) # try the primitive types name_value_endec("start", date_time)
def create_DateTimeValue(oid=1, date=None, time=None, name="DateTime", pv_writable=False): datetime = DateTimeValueObject(objectIdentifier=("datetimeValue", oid), objectName=name) datetime = _make_mutable(datetime, mutable=pv_writable) datetime.presentValue = DateTime(date=Date(date), time=Time(time)) return datetime
def build_rrange_request( self, args, range_params=None, arr_index=None, vendor_id=0, bacoid=None ): addr, obj_type, obj_inst, prop_id = args[:4] vendor_id = vendor_id bacoid = bacoid if obj_type.isdigit(): obj_type = int(obj_type) elif not get_object_class(obj_type, vendor_id=vendor_id): raise ValueError("Unknown object type {}".format(obj_type)) obj_inst = int(obj_inst) if prop_id.isdigit(): prop_id = int(prop_id) datatype = get_datatype(obj_type, prop_id, vendor_id=vendor_id) if not datatype: raise ValueError("invalid property for object type") # build a request request = ReadRangeRequest( objectIdentifier=(obj_type, obj_inst), propertyIdentifier=prop_id ) request.pduDestination = Address(addr) if range_params is not None: range_type, first, date, time, count = range_params if range_type == "p": rbp = RangeByPosition(referenceIndex=int(first), count=int(count)) request.range = Range(byPosition=rbp) elif range_type == "s": rbs = RangeBySequenceNumber( referenceSequenceNumber=int(first), count=int(count) ) request.range = Range(bySequenceNumber=rbs) elif range_type == "t": rbt = RangeByTime( referenceTime=DateTime( date=Date(date).value, time=Time(time).value ), count=int(count), ) request.range = Range(byTime=rbt) elif range_type == "x": # should be missing required parameter request.range = Range() else: raise ValueError("unknown range type: %r" % (range_type,)) if len(args) == 5: request.propertyArrayIndex = int(args[4]) self._log.debug("{:<20} {!r}".format("REQUEST", request)) return request
def datetime_value(**kwargs): definition = { "name": "DATETIME_VALUE", "objectType": DateTimeValueObject, "instance": 0, "description": "No description", "presentValue": DateTime(), "properties": {}, "is_commandable": False, "relinquish_default": "inactive", } return _create(definition, **kwargs)
def test_8_10_1(self): """Confirmed Notifications Subscription""" if _debug: TestPulseConverter._debug("test_8_10_1") # create a network anet = ApplicationNetwork("test_8_10_1") # add the ability to accept COV notifications to the TD anet.td.add_capability(COVTestClientServices) # tell the TD how to respond to confirmed notifications anet.td.test_ack = True anet.td.test_reject = None anet.td.test_abort = None # add the service capability to the IUT anet.iut.add_capability(ChangeOfValueServices) # make a pulse converter object test_pc = PulseConverterObject( objectIdentifier=('pulseConverter', 1), objectName='pc', presentValue=0.0, statusFlags=[0, 0, 0, 0], updateTime=DateTime(date=Date().now().value, time=Time().now().value), covIncrement=10.0, covPeriod=10, ) # add it to the implementation anet.iut.add_object(test_pc) # wait for the subscription anet.iut.start_state.doc("8.10.1-1-0") \ .receive(SubscribeCOVRequest).doc("8.10.1-1-1") \ .success() # send the subscription, wait for the ack anet.td.start_state.doc("8.10.1-2-0") \ .send(SubscribeCOVRequest( destination=anet.iut.address, subscriberProcessIdentifier=1, monitoredObjectIdentifier=('pulseConverter', 1), issueConfirmedNotifications=True, lifetime=30, )).doc("8.10.1-2-1") \ .receive(SimpleAckPDU).doc("8.10.1-2-2") \ .success() # run the group anet.run()
def process_task(self): if _debug: PulseTask._debug("process_task") # increment the present value self.accumulator.presentValue += self.increment # update the value change time current_date = Date().now().value current_time = Time().now().value value_change_time = DateTime(date=current_date, time=current_time) if _debug: PulseTask._debug(" - value_change_time: %r", value_change_time) self.accumulator.valueChangeTime = value_change_time
def ReadProperty(self, obj, arrayIndex=None): if _debug: CurrentDateTimeProperty._debug("ReadProperty %r arrayIndex=%r", obj, arrayIndex) # access an array if arrayIndex is not None: raise ExecutionError(errorClass='property', errorCode='propertyIsNotAnArray') # get the value current_date = Date().now().value current_time = Time().now().value value = DateTime(date=current_date, time=current_time) if _debug: CurrentDateTimeProperty._debug(" - value: %r", value) return value
def _set_value(self, utc_time): # convert to a time tuple based on timezone offset time_tuple = time.gmtime(utc_time + timezone_offset) # extra the pieces date_quad = ( time_tuple[0] - 1900, time_tuple[1], time_tuple[2], time_tuple[6] + 1, ) time_quad = (time_tuple[3], time_tuple[4], time_tuple[5], 0) date_time = DateTime(date=date_quad, time=time_quad) self.presentValue = date_time
def _build_datetime(UTC=False): if UTC: _d = dt.datetime.utcnow().date() _t = dt.datetime.utcnow().time() _date = Date(year=_d.year - 1900, month=_d.month, day=_d.day, day_of_week=_d.isoweekday()).value _time = Time( hour=_t.hour, minute=_t.minute, second=_t.second, hundredth=int(_t.microsecond / 10000), ).value else: _date = Date().now().value _time = Time().now().value return DateTime(date=_date, time=_time)
def test_no_traffic(self): """Test basic configuration of a network.""" if _debug: TestPulseConverter._debug("test_no_traffic") # create a network anet = ApplicationNetwork("test_no_traffic") # add the service capability to the IUT anet.iut.add_capability(ChangeOfValueServices) # make a pulse converter object test_pc = PulseConverterObject( objectIdentifier=('pulseConverter', 1), objectName='pc', presentValue=0.0, statusFlags=[0, 0, 0, 0], updateTime=DateTime(date=Date().now().value, time=Time().now().value), covIncrement=10.0, covPeriod=10, ) # an easy way to change the present value write_test_pc = lambda v: setattr(test_pc, 'presentValue', v) # add it to the implementation anet.iut.add_object(test_pc) # make some transitions anet.iut.start_state.doc("1-1-0") \ .call(write_test_pc, 100.0).doc("1-1-1") \ .timeout(1).doc("1-1-2") \ .call(write_test_pc, 0.0).doc("1-1-3") \ .timeout(1).doc("1-1-4") \ .success() # test device is quiet anet.td.start_state.timeout(5).success() # run the group anet.run()
def main(): global this_application # parse the command line arguments args = ConfigArgumentParser(description=__doc__).parse_args() if _debug: _log.debug("initialization") if _debug: _log.debug(" - args: %r", args) # make a device object this_device = LocalDeviceObject(ini=args.ini) if _debug: _log.debug(" - this_device: %r", this_device) # make a simple application this_application = ReadRangeApplication(this_device, args.ini.address) timestamp = DateTime(date=Date().now().value, time=Time().now().value) # log_status = LogStatus([0,0,0]) log_record_datum = LogRecordLogDatum(booleanValue=False) status_flags = StatusFlags([0, 0, 0, 0]) log_record = LogRecord(timestamp=timestamp, logDatum=log_record_datum, statusFlags=status_flags) trend_log_object = TrendLogObject( objectIdentifier=("trendLog", 1), objectName="Trend-Log-1", logBuffer=[log_record], ) _log.debug(" - trend_log_object: %r", trend_log_object) this_application.add_object(trend_log_object) _log.debug("running") run() _log.debug("fini")
def sometime(self, klass, now, args): if _debug: TestConsoleCmd._debug("sometime %r %r %r", klass, now, args) try: addr = args[0] # look for a time to send if (len(args) > 1): when = time.strptime(' '.join(args[1:]), TIME_FORMAT) else: when = now if _debug: TestConsoleCmd._debug(" - when: %r", when) # build the date and time primitives when_date = Date( year=when.tm_year - 1900, month=when.tm_mon, day=when.tm_mday, dayOfWeek=when.tm_wday + 1, ) if _debug: TestConsoleCmd._debug(" - when_date: %s", when_date) when_time = Time(hour=when.tm_hour, minute=when.tm_min, second=when.tm_sec, hundredth=0) if _debug: TestConsoleCmd._debug(" - when_time: %s", when_time) # build a request request = klass() request.pduDestination = Address(addr) # only one simple parameter, happens to be the same for both types request.time = DateTime(date=when_date, time=when_time) # give it to the application this_application.request(request) except Exception, e: TestConsoleCmd._exception("exception: %r", e)
def _set_value(self, utc_time): if _debug: LocalDateTimeValueObject._debug("_set_value %r", utc_time) # convert to a time tuple based on timezone offset time_tuple = time.gmtime(utc_time + timezone_offset) if _debug: LocalDateTimeValueObject._debug(" - time_tuple: %r", time_tuple) # extra the pieces date_quad = ( time_tuple[0] - 1900, time_tuple[1], time_tuple[2], time_tuple[6] + 1, ) time_quad = (time_tuple[3], time_tuple[4], time_tuple[5], 0) date_time = DateTime(date=date_quad, time=time_quad) if _debug: LocalDateTimeValueObject._debug(" - date_time: %r", date_time) self.presentValue = date_time
def test_8_2_1(self): """To verify that the IUT can initiate ConfirmedCOVNotification service requests conveying a change of the Present_Value property of Analog Input, Analog Output, and Analog Value objects.""" if _debug: TestPulseConverter._debug("test_8_2_1") # create a network anet = ApplicationNetwork("test_8_2_1") # add the ability to accept COV notifications to the TD anet.td.add_capability(COVTestClientServices) # tell the TD how to respond to confirmed notifications anet.td.test_ack = True anet.td.test_reject = None anet.td.test_abort = None # add the service capability to the IUT anet.iut.add_capability(ChangeOfValueServices) # make a pulse converter object test_pc = PulseConverterObject( objectIdentifier=('pulseConverter', 1), objectName='pc', presentValue=0.0, statusFlags=[0, 0, 0, 0], updateTime=DateTime(date=Date().now().value, time=Time().now().value), covIncrement=10.0, covPeriod=10, ) # an easy way to change the present value def write_test_pc(v): if _debug: TestPulseConverter._debug("=== marco %r", v) setattr(test_pc, 'presentValue', v) if _debug: TestPulseConverter._debug("=== polo") # add it to the implementation anet.iut.add_object(test_pc) # receive the subscription request, wait until the client has # received the ack and the 'instant' notification. Then change the # value a little bit and nothing should be sent. Change it some more # and wait for the notification ack. anet.iut.start_state.doc("2-1-0") \ .receive(SubscribeCOVRequest).doc("2-1-1") \ .receive(SimpleAckPDU).doc("2-1-2") \ .wait_event("e1").doc("2-1-3") \ .call(write_test_pc, 5.0).doc("2-1-4") \ .timeout(5).doc("2-1-5") \ .call(write_test_pc, 10.0).doc("2-1-6") \ .receive(SimpleAckPDU).doc("2-1-7") \ .receive(SimpleAckPDU).doc("2-1-8") \ .timeout(10).doc("2-1-9") \ .success() # send the subscription request, wait for the ack and the 'instant' # notification, set the event so the IUT can continue, then wait # for the next notification anet.td.start_state.doc("2-2-0") \ .send(SubscribeCOVRequest( destination=anet.iut.address, subscriberProcessIdentifier=1, monitoredObjectIdentifier=('pulseConverter', 1), issueConfirmedNotifications=True, lifetime=30, )).doc("2-2-1") \ .receive(SimpleAckPDU).doc("2-2-2") \ .receive(ConfirmedCOVNotificationRequest).doc("2-2-3") \ .set_event("e1").doc("2-2-4") \ .receive(ConfirmedCOVNotificationRequest).doc("2-2-5") \ .receive(ConfirmedCOVNotificationRequest).doc("2-2-6") \ .timeout(10).doc("2-2-7") \ .success() # run the group anet.run()
def do_readrange(self, args): """readrange <addr> <objid> <prop> [ <indx> ] [ p <indx> <count> ] [ s <seq> <count> ] [ t <date> <time> <count> ] """ args = args.split() if _debug: ReadRangeConsoleCmd._debug("do_readrange %r", args) try: addr = Address(args.pop(0)) obj_id = ObjectIdentifier(args.pop(0)).value prop_id = args.pop(0) datatype = get_datatype(obj_id[0], prop_id) if not datatype: raise ValueError("invalid property for object type") # build a request request = ReadRangeRequest(destination=addr, objectIdentifier=obj_id, propertyIdentifier=prop_id) # index is optional if args: if args[0].isdigit(): if not issubclass(datatype, Array): raise ValueError("property is not an array") request.propertyArrayIndex = int(args.pop(0)) datatype = datatype.subtype if not issubclass(datatype, List): raise ValueError("property is not a list") # range is optional if args: range_type = args.pop(0) if range_type == "p": rbp = RangeByPosition(referenceIndex=int(args[0]), count=int(args[1])) request.range = Range(byPosition=rbp) elif range_type == "s": rbs = RangeBySequenceNumber(referenceSequenceNumber=int( args[0]), count=int(args[1])) request.range = Range(bySequenceNumber=rbs) elif range_type == "t": rbt = RangeByTime( referenceTime=DateTime(date=Date(args[0]), time=Time(args[1])), count=int(args[2]), ) request.range = Range(byTime=rbt) else: raise ValueError("unknown range type: %r" % (range_type, )) if _debug: ReadRangeConsoleCmd._debug(" - request: %r", request) # make an IOCB iocb = IOCB(request) if _debug: ReadRangeConsoleCmd._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: ReadRangeConsoleCmd._debug(" - apdu: %r", apdu) # should be an ack if not isinstance(apdu, ReadRangeACK): if _debug: ReadRangeConsoleCmd._debug(" - not an ack") return # find the datatype datatype = get_datatype(apdu.objectIdentifier[0], apdu.propertyIdentifier) if _debug: ReadRangeConsoleCmd._debug(" - datatype: %r", datatype) if not datatype: raise TypeError("unknown datatype") sys.stdout.write("firstSequenceNumber: %s\n" % (apdu.firstSequenceNumber, )) sys.stdout.write("resultFlags: %s\n" % (apdu.resultFlags, )) # cast out the data into a list value = apdu.itemData.cast_out(datatype) # dump it out for i, item in enumerate(value): sys.stdout.write("[%d]\n" % (i, )) item.debug_contents(file=sys.stdout, indent=2) sys.stdout.flush() # do something for error/reject/abort if iocb.ioError: sys.stdout.write(str(iocb.ioError) + "\n") except Exception as error: ReadRangeConsoleCmd._exception("exception: %r", error)
def time_sync(self, *args, datetime=None): """ Take local time and send it to devices. User can also provide a datetime value (constructed following bacpypes.basetypes.Datetime format). To create a DateTime :: from bacpypes.basetypes import DateTime from bacpypes.primitivedata import Date, Time # Create date and time _date = Date('2019-08-05') _time = Time('16:45') # Create Datetime _datetime = DateTime(date=_date.value, time=_time.value) # Pass this to the function bacnet.time_sync(datetime=_datetime) """ if not self._started: raise ApplicationNotStarted( "BACnet stack not running - use startApp()") if args: args = args[0].split() msg = args if args else "everyone" self._log.debug("time sync {!r}".format(msg)) if not datetime: _date = Date().now().value _time = Time().now().value _datetime = DateTime(date=_date, time=_time) elif isinstance(datetime, DateTime): _datetime = datetime else: raise ValueError( "Please provide valid DateTime in bacpypes.basetypes.DateTime format" ) # build a request request = TimeSynchronizationRequest(time=_datetime) if len(args) == 1: request.pduDestination = Address(args[0]) del args[0] else: request.pduDestination = GlobalBroadcast() self._log.debug("{:>12} {}".format("- request:", request)) iocb = IOCB(request) # make an IOCB # pass to the BACnet stack deferred(self.this_application.request_io, iocb) # Unconfirmed request...so wait until complete iocb.wait() # Wait for BACnet response year, month, day, dow = _datetime.date year = year + 1900 hour, minutes, sec, msec = _datetime.time d = dt.datetime(year, month, day, hour, minutes, sec, msec) self._log.info("Time Sync Request sent to network : {}".format( d.isoformat()))
def test_changing_properties(self): """This test changes the value of multiple properties to verify that only one COV notification is sent.""" if _debug: TestPulseConverter._debug("test_changing_properties") # create a network anet = ApplicationNetwork("test_changing_properties") # add the ability to accept COV notifications to the TD anet.td.add_capability(COVTestClientServices) # tell the TD how to respond to confirmed notifications anet.td.test_ack = True anet.td.test_reject = None anet.td.test_abort = None # add the service capability to the IUT anet.iut.add_capability(ChangeOfValueServices) # make a pulse converter object test_pc = PulseConverterObject( objectIdentifier=('pulseConverter', 1), objectName='pc', presentValue=0.0, statusFlags=[0, 0, 0, 0], updateTime=DateTime(date=Date().now().value, time=Time().now().value), covIncrement=10.0, covPeriod=10, ) # an easy way to change the present value def test_pc_fault(): if _debug: TestPulseConverter._debug("test_pc_fault") test_pc.presentValue = 100.0 test_pc.statusFlags = [0, 0, 1, 0] # add it to the implementation anet.iut.add_object(test_pc) # receive the subscription request, wait until the client has # received the ack and the 'instant' notification. Then change the # value, no ack coming back anet.iut.start_state.doc("5-1-0") \ .receive(SubscribeCOVRequest).doc("5-1-1") \ .wait_event("e1").doc("5-1-2") \ .call(test_pc_fault).doc("5-1-3") \ .timeout(10).doc("5-2-4") \ .success() # test device is quiet anet.td.start_state.doc("5-2-0") \ .send(SubscribeCOVRequest( destination=anet.iut.address, subscriberProcessIdentifier=1, monitoredObjectIdentifier=('pulseConverter', 1), issueConfirmedNotifications=False, lifetime=30, )).doc("5-2-1") \ .receive(SimpleAckPDU).doc("5-2-2") \ .receive(UnconfirmedCOVNotificationRequest).doc("5-2-3") \ .set_event("e1").doc("5-2-4") \ .receive(UnconfirmedCOVNotificationRequest).doc("5-2-5") \ .timeout(10).doc("5-2-6") \ .success() # run the group anet.run()
def test_8_10_2(self): """Unconfirmed Notifications Subscription""" if _debug: TestPulseConverter._debug("test_8_10_2") # create a network anet = ApplicationNetwork("test_8_10_2") # add the ability to accept COV notifications to the TD anet.td.add_capability(COVTestClientServices) # tell the TD how to respond to confirmed notifications anet.td.test_ack = True anet.td.test_reject = None anet.td.test_abort = None # add the service capability to the IUT anet.iut.add_capability(ChangeOfValueServices) # make a pulse converter object test_pc = PulseConverterObject( objectIdentifier=('pulseConverter', 1), objectName='pc', presentValue=0.0, statusFlags=[0, 0, 0, 0], updateTime=DateTime(date=Date().now().value, time=Time().now().value), covIncrement=10.0, covPeriod=10, ) # add it to the implementation anet.iut.add_object(test_pc) # wait for the subscription anet.iut.start_state.doc("8.10.2-1-0") \ .receive(SubscribeCOVRequest).doc("8.10.2-1-1") \ .success() # send the subscription, wait for the ack anet.td.start_state.doc("8.10.2-2-0") \ .send(SubscribeCOVRequest( destination=anet.iut.address, subscriberProcessIdentifier=1, monitoredObjectIdentifier=('pulseConverter', 1), issueConfirmedNotifications=False, lifetime=30, )).doc("8.10.2-2-1") \ .receive(SimpleAckPDU).doc("8.10.2-2-2") \ .success() # run the group, cut the time limit short anet.run(time_limit=5.0) # check that the IUT still has the detection if _debug: TestPulseConverter._debug(" - detections: %r", anet.iut.cov_detections) assert len(anet.iut.cov_detections) == 1 # pop out the subscription list and criteria obj_ref, criteria = anet.iut.cov_detections.popitem() if _debug: TestPulseConverter._debug(" - criteria: %r", criteria) # get the list of subscriptions from the criteria subscriptions = criteria.cov_subscriptions.cov_subscriptions if _debug: TestPulseConverter._debug(" - subscriptions: %r", subscriptions) assert len(subscriptions) == 1
def test_multiple_subscribers(self): """This has more than one subscriber for the object.""" if _debug: TestPulseConverter._debug("test_multiple_subscribers") # create a network anet = ApplicationNetwork("test_multiple_subscribers") # add the ability to accept COV notifications to the TD anet.td.add_capability(COVTestClientServices) # tell the TD how to respond to confirmed notifications anet.td.test_ack = True anet.td.test_reject = None anet.td.test_abort = None # add the service capability to the IUT anet.iut.add_capability(ChangeOfValueServices) # make a pulse converter object test_pc = PulseConverterObject( objectIdentifier=('pulseConverter', 1), objectName='pc', presentValue=0.0, statusFlags=[0, 0, 0, 0], updateTime=DateTime(date=Date().now().value, time=Time().now().value), covIncrement=10.0, covPeriod=10, ) # an easy way to change both the present value and status flags # which should trigger only one notification def test_pc_fault(): if _debug: TestPulseConverter._debug("test_pc_fault") test_pc.presentValue = 100.0 test_pc.statusFlags = [0, 0, 1, 0] # add it to the implementation anet.iut.add_object(test_pc) # add another test device object anet.td2_device_object = LocalDeviceObject( objectName="td2", objectIdentifier=('device', 30), maxApduLengthAccepted=1024, segmentationSupported='noSegmentation', vendorIdentifier=999, ) # another test device anet.td2 = ApplicationStateMachine(anet.td2_device_object, anet.vlan) anet.td2.add_capability(COVTestClientServices) anet.append(anet.td2) # receive the subscription requests, wait until both clients have # received the ack and the 'instant' notification. Then change the # value, no ack coming back anet.iut.start_state.doc("6-1-0") \ .receive(SubscribeCOVRequest, pduSource=anet.td.address).doc("6-1-1") \ .receive(SubscribeCOVRequest, pduSource=anet.td2.address).doc("6-1-2") \ .wait_event("e2").doc("6-1-3") \ .call(test_pc_fault).doc("6-1-4") \ .timeout(10).doc("6-2-5") \ .success() # first test device; send the subscription request, get an ack # followed by the 'instant' notification anet.td.start_state.doc("6-2-0") \ .send(SubscribeCOVRequest( destination=anet.iut.address, subscriberProcessIdentifier=1, monitoredObjectIdentifier=('pulseConverter', 1), issueConfirmedNotifications=False, lifetime=30, )).doc("6-2-1") \ .receive(SimpleAckPDU).doc("6-2-2") \ .receive(UnconfirmedCOVNotificationRequest).doc("6-2-3") \ .set_event("e1").doc("6-2-4") \ .receive(UnconfirmedCOVNotificationRequest).doc("6-2-5") \ .timeout(10).doc("6-2-6") \ .success() # same pattern for the other test device anet.td2.start_state.doc("6-3-0") \ .wait_event("e1").doc("6-3-1") \ .send(SubscribeCOVRequest( destination=anet.iut.address, subscriberProcessIdentifier=1, monitoredObjectIdentifier=('pulseConverter', 1), issueConfirmedNotifications=False, lifetime=30, )).doc("6-3-2") \ .receive(SimpleAckPDU).doc("6-3-3") \ .receive(UnconfirmedCOVNotificationRequest).doc("6-3-4") \ .set_event("e2").doc("6-3-5") \ .receive(UnconfirmedCOVNotificationRequest).doc("6-3-6") \ .timeout(10).doc("6-3-7") \ .success() # run the group anet.run()