From 9750c0f13c504d443d4f17871690d7df9326a3c0 Mon Sep 17 00:00:00 2001 From: Joel Bender Date: Fri, 17 Nov 2017 02:02:24 -0500 Subject: [PATCH] first crack at #148 --- py27/bacpypes/object.py | 29 --------------- py27/bacpypes/service/device.py | 33 ++++++++--------- py27/bacpypes/service/object.py | 63 +++++++++++++++++++++++++++++++-- 3 files changed, 77 insertions(+), 48 deletions(-) diff --git a/py27/bacpypes/object.py b/py27/bacpypes/object.py index 63dce6d..9bc1c9a 100755 --- a/py27/bacpypes/object.py +++ b/py27/bacpypes/object.py @@ -396,13 +396,6 @@ class Object(object): # empty list of property monitors self._property_monitors = defaultdict(list) - # start with a clean array of property identifiers - if 'propertyList' in initargs: - propertyList = None - else: - propertyList = ArrayOf(PropertyIdentifier)() - initargs['propertyList'] = propertyList - # initialize the object for propid, prop in self._properties.items(): if propid in initargs: @@ -411,20 +404,12 @@ class Object(object): # defer to the property object for error checking prop.WriteProperty(self, initargs[propid], direct=True) - # add it to the property list if we are building one - if propertyList is not None: - propertyList.append(propid) - elif prop.default is not None: if _debug: Object._debug(" - setting %s from default", propid) # default values bypass property interface self._values[propid] = prop.default - # add it to the property list if we are building one - if propertyList is not None: - propertyList.append(propid) - else: if not prop.optional: if _debug: Object._debug(" - %s value required", propid) @@ -485,13 +470,6 @@ class Object(object): self._properties[prop.identifier] = prop self._values[prop.identifier] = prop.default - # tell the object it has a new property - if 'propertyList' in self._values: - property_list = self.propertyList - if prop.identifier not in property_list: - if _debug: Object._debug(" - adding to property list") - property_list.append(prop.identifier) - def delete_property(self, prop): """Delete a property from an object. The property is an instance of a Property or one of its derived classes, but only the property @@ -507,13 +485,6 @@ class Object(object): if prop.identifier in self._values: del self._values[prop.identifier] - # remove the property identifier from its list of know properties - if 'propertyList' in self._values: - property_list = self.propertyList - if prop.identifier in property_list: - if _debug: Object._debug(" - removing from property list") - property_list.remove(prop.identifier) - def ReadProperty(self, propid, arrayIndex=None): if _debug: Object._debug("ReadProperty %r arrayIndex=%r", propid, arrayIndex) diff --git a/py27/bacpypes/service/device.py b/py27/bacpypes/service/device.py index 0382f19..873dc4f 100644 --- a/py27/bacpypes/service/device.py +++ b/py27/bacpypes/service/device.py @@ -14,6 +14,8 @@ from ..object import register_object_type, registered_object_types, \ Property, DeviceObject from ..task import FunctionTask +from .object import LocalObject + # some debugging _debug = 0 _log = ModuleLogger(globals()) @@ -67,7 +69,7 @@ class CurrentTimeProperty(Property): # @bacpypes_debugging -class LocalDeviceObject(DeviceObject): +class LocalDeviceObject(LocalObject, DeviceObject): properties = \ [ CurrentTimeProperty('localTime') @@ -102,12 +104,24 @@ class LocalDeviceObject(DeviceObject): raise RuntimeError("vendorIdentifier required to auto-register the LocalDeviceObject class") register_object_type(self.__class__, vendor_id=kwargs['vendorIdentifier']) - # check for local time + # check for properties this class implements if 'localDate' in kwargs: raise RuntimeError("localDate is provided by LocalDeviceObject and cannot be overridden") if 'localTime' in kwargs: raise RuntimeError("localTime is provided by LocalDeviceObject and cannot be overridden") + # the object identifier is required for the object list + if 'objectIdentifier' not in kwargs: + raise RuntimeError("objectIdentifier is required") + + # the object list is provided + if 'objectList' in kwargs: + raise RuntimeError("objectList is provided by LocalDeviceObject and cannot be overridden") + else: + kwargs['objectList'] = ArrayOf(ObjectIdentifier)([ + kwargs['objectIdentifier'], + ]) + # check for a minimum value if kwargs['maxApduLengthAccepted'] < 50: raise ValueError("invalid max APDU length accepted") @@ -116,20 +130,7 @@ class LocalDeviceObject(DeviceObject): if _debug: LocalDeviceObject._debug(" - updated kwargs: %r", kwargs) # proceed as usual - DeviceObject.__init__(self, **kwargs) - - # create a default implementation of an object list for local devices. - # If it is specified in the kwargs, that overrides this default. - if ('objectList' not in kwargs): - self.objectList = ArrayOf(ObjectIdentifier)([self.objectIdentifier]) - - # if the object has a property list and one wasn't provided - # in the kwargs, then it was created by default and the objectList - # property should be included - if ('propertyList' not in kwargs) and self.propertyList: - # make sure it's not already there - if 'objectList' not in self.propertyList: - self.propertyList.append('objectList') + LocalObject.__init__(self, **kwargs) # # Who-Is I-Am Services diff --git a/py27/bacpypes/service/object.py b/py27/bacpypes/service/object.py index 6cbcf13..0c33999 100644 --- a/py27/bacpypes/service/object.py +++ b/py27/bacpypes/service/object.py @@ -3,20 +3,77 @@ from ..debugging import bacpypes_debugging, ModuleLogger from ..capability import Capability -from ..basetypes import ErrorType +from ..basetypes import ErrorType, PropertyIdentifier from ..primitivedata import Atomic, Null, Unsigned -from ..constructeddata import Any, Array +from ..constructeddata import Any, Array, ArrayOf from ..apdu import Error, \ SimpleAckPDU, ReadPropertyACK, ReadPropertyMultipleACK, \ ReadAccessResult, ReadAccessResultElement, ReadAccessResultElementChoice from ..errors import ExecutionError -from ..object import PropertyError +from ..object import Object, PropertyError # some debugging _debug = 0 _log = ModuleLogger(globals()) +# +# LocalObject +# + +@bacpypes_debugging +class LocalObject(Object): + + def __init__(self, **kwargs): + if _debug: LocalObject._debug("__init__ %r", kwargs) + + # check for property list + if 'propertyList' in kwargs: + raise RuntimeError("propertyList is provided by LocalObject and cannot be overridden") + + # proceed as usual + Object.__init__(self, **kwargs) + + # make a list of the properties that were provided + property_list = [k for k, v in self._values.items() + if v is not None + and k not in ('objectName', 'objectType', 'objectIdentifier', 'propertyList') + ] + if _debug: LocalObject._debug(" - property_list: %r", property_list) + + # store the value + self._values['propertyList'] = ArrayOf(PropertyIdentifier)([property_list]) + + def add_property(self, prop): + """Add a property to an object.""" + if _debug: LocalObject._debug("add_property %r", prop) + + # let the Object class do its thing + Object.add_property(self, prop) + + # update the property list + property_list = self.propertyList + property_identifier = prop.identifier + if property_identifier in ('objectName', 'objectType', 'objectIdentifier', 'propertyList'): + pass + elif property_identifier not in property_list: + if _debug: LocalObject._debug(" - adding to property list") + property_list.append(property_identifier) + + def delete_property(self, prop): + """Delete a property from an object.""" + if _debug: LocalObject._debug("delete_property %r", prop) + + # let the Object class do its thing + Object.delete_property(self, prop) + + # remove the property identifier from its list of know properties + property_list = self.propertyList + property_identifier = prop.identifier + if property_identifier in property_list: + if _debug: LocalObject._debug(" - removing from property list") + property_list.remove(property_identifier) + # # ReadProperty and WriteProperty Services #