#!/usr/bin/env python """ Recurring Read Property This application has a static list of points that it would like to read. It reads the values of each of them in turn and then quits. """ from collections import deque from bacpypes.debugging import bacpypes_debugging, ModuleLogger from bacpypes.consolelogging import ConfigArgumentParser from bacpypes.core import run, deferred from bacpypes.iocb import IOCB from bacpypes.task import RecurringTask from bacpypes.pdu import Address from bacpypes.object import get_datatype from bacpypes.apdu import ReadPropertyRequest from bacpypes.primitivedata import Unsigned, ObjectIdentifier from bacpypes.constructeddata import Array from bacpypes.app import BIPSimpleApplication from bacpypes.local.device import LocalDeviceObject # some debugging _debug = 0 _log = ModuleLogger(globals()) # point list point_list = [ ('1.2.3.4', 'analogValue:1', 'presentValue'), ('1.2.3.4', 'analogValue:2', 'presentValue'), ] # # PrairieDog # @bacpypes_debugging class PrairieDog(BIPSimpleApplication, RecurringTask): def __init__(self, interval, *args): if _debug: PrairieDog._debug("__init__ %r %r", interval, args) BIPSimpleApplication.__init__(self, *args) RecurringTask.__init__(self, interval * 1000) # no longer busy self.is_busy = False # install the task self.install_task() def process_task(self): if _debug: PrairieDog._debug("process_task") global point_list # check to see if we're idle if self.is_busy: if _debug: PrairieDog._debug(" - busy") return # now we are busy self.is_busy = True # turn the point list into a queue self.point_queue = deque(point_list) # clean out the list of the response values self.response_values = [] # fire off the next request self.next_request() def next_request(self): if _debug: PrairieDog._debug("next_request") # check to see if we're done if not self.point_queue: if _debug: PrairieDog._debug(" - done") # dump out the results for request, response in zip(point_list, self.response_values): print(request, response) # no longer busy self.is_busy = False return # get the next request addr, obj_id, prop_id = self.point_queue.popleft() obj_id = ObjectIdentifier(obj_id).value # build a request request = ReadPropertyRequest( objectIdentifier=obj_id, propertyIdentifier=prop_id, ) request.pduDestination = Address(addr) if _debug: PrairieDog._debug(" - request: %r", request) # make an IOCB iocb = IOCB(request) if _debug: PrairieDog._debug(" - iocb: %r", iocb) # set a callback for the response iocb.add_callback(self.complete_request) # give it to the application self.request_io(iocb) def complete_request(self, iocb): if _debug: PrairieDog._debug("complete_request %r", iocb) if iocb.ioResponse: apdu = iocb.ioResponse # find the datatype datatype = get_datatype(apdu.objectIdentifier[0], apdu.propertyIdentifier) if _debug: PrairieDog._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 (apdu.propertyArrayIndex is not None): if apdu.propertyArrayIndex == 0: value = apdu.propertyValue.cast_out(Unsigned) else: value = apdu.propertyValue.cast_out(datatype.subtype) else: value = apdu.propertyValue.cast_out(datatype) if _debug: PrairieDog._debug(" - value: %r", value) # save the value self.response_values.append(value) if iocb.ioError: if _debug: PrairieDog._debug(" - error: %r", iocb.ioError) self.response_values.append(iocb.ioError) # fire off another request deferred(self.next_request) # # __main__ # def main(): # parse the command line arguments parser = ConfigArgumentParser(description=__doc__) # add an argument for interval parser.add_argument('interval', type=int, help='repeat rate in seconds', ) # now parse the arguments args = parser.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 dog this_application = PrairieDog(args.interval, this_device, args.ini.address) if _debug: _log.debug(" - this_application: %r", this_application) _log.debug("running") run() _log.debug("fini") if __name__ == "__main__": main()