Skip to content

Commit

Permalink
release 0.16.5 good to go
Browse files Browse the repository at this point in the history
  • Loading branch information
JoelBender committed Dec 7, 2017
1 parent ab8a8b8 commit 89a9ac4
Show file tree
Hide file tree
Showing 38 changed files with 1,524 additions and 173 deletions.
2 changes: 1 addition & 1 deletion py25/bacpypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# Project Metadata
#

__version__ = '0.16.4'
__version__ = '0.16.5'
__author__ = 'Joel Bender'
__email__ = '[email protected]'

Expand Down
22 changes: 21 additions & 1 deletion py25/bacpypes/basetypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,7 @@ class EventType(Enumerated):
, 'unsignedOutOfRange':16
, 'changeOfCharacterstring':17
, 'changeOfStatusFlags':18
, 'changeOfReliability':19
}

class FaultType(Enumerated):
Expand Down Expand Up @@ -1471,7 +1472,18 @@ class Reliability(Enumerated):
, 'multiStateFault':9
, 'configurationError':10
, 'communicationFailure':12
, 'numberFault':13
, 'memberFault': 13
, 'monitoredObjectFault': 14
, 'tripped': 15
, 'lampFailure': 16
, 'activationFailure': 17
, 'renewDHCPFailure': 18
, 'renewFDRegistration-failure': 19
, 'restartAutoNegotiationFailure': 20
, 'restartFailure': 21
, 'proprietaryCommandFailure': 22
, 'faultsListed': 23
, 'referencedObjectFault': 24
}

class RestartReason(Enumerated):
Expand Down Expand Up @@ -2261,6 +2273,13 @@ class NotificationParametersChangeOfStatusFlagsType(Sequence):
, Element('referencedFlags', StatusFlags, 1)
]

class NotificationParametersChangeOfReliabilityType(Sequence):
sequenceElements = \
[ Element('reliability', Reliability, 0)
, Element('statusFlags', StatusFlags, 1)
, Element('propertyValues', SequenceOf(PropertyValue), 2)
]

class NotificationParameters(Choice):
choiceElements = \
[ Element('changeOfBitstring', NotificationParametersChangeOfBitstring, 0)
Expand All @@ -2280,6 +2299,7 @@ class NotificationParameters(Choice):
, Element('unsignedOutOfRange', NotificationParametersUnsignedOutOfRangeType, 16)
, Element('changeOfCharacterString', NotificationParametersChangeOfCharacterStringType, 17)
, Element('changeOfStatusFlags', NotificationParametersChangeOfStatusFlagsType, 18)
, Element('changeOfReliability', NotificationParametersChangeOfReliabilityType, 19)
]

class ObjectPropertyValue(Sequence):
Expand Down
1 change: 1 addition & 0 deletions py25/bacpypes/bvllservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def __init__(self, addr=None, noBroadcast=False):
bind(self.direct, self.broadcastPort)
else:
self.broadcast = None
self.broadcastPort = None

# create and bind the Annex H and J servers
self.annexH = _MultiplexServer(self)
Expand Down
8 changes: 6 additions & 2 deletions py25/bacpypes/constructeddata.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ def __getitem__(self, item):

def __setitem__(self, item, value):
# no wrapping index
if (item < 1) or (item > self.value[0]):
if (item < 0) or (item > self.value[0]):
raise IndexError("index out of range")

# special length handling for index 0
Expand All @@ -575,7 +575,11 @@ def __setitem__(self, item, value):
self.value = self.value[0:value + 1]
elif value > self.value[0]:
# extend
self.value.extend( [None] * (value - self.value[0]) )
if issubclass(self.subtype, Atomic):
self.value.extend( [self.subtype().value] * (value - self.value[0]) )
else:
for i in range(value - self.value[0]):
self.value.append(self.subtype())
else:
return
self.value[0] = value
Expand Down
3 changes: 2 additions & 1 deletion py25/bacpypes/iocb.py
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,7 @@ def request_io(self, iocb):

# if there was an error, abort the request
if err:
if _debug: IOQController._debug(" - aborting")
self.abort_io(iocb, err)

def process_io(self, iocb):
Expand Down Expand Up @@ -767,7 +768,7 @@ def complete_io(self, iocb, msg):

# schedule a call in the future
task = FunctionTask(IOQController._wait_trigger, self)
task.install_task(delay=self.wait_time)
task.install_task(delta=self.wait_time)

else:
# change our state
Expand Down
81 changes: 50 additions & 31 deletions py25/bacpypes/object.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ def ReadProperty(self, obj, arrayIndex=None):

# get the value
value = obj._values[self.identifier]
if _debug: Property._debug(" - value: %r", value)

# access an array
if arrayIndex is not None:
Expand Down Expand Up @@ -200,14 +201,61 @@ def WriteProperty(self, obj, value, arrayIndex=None, priority=None, direct=False
if not self.mutable:
raise ExecutionError(errorClass='property', errorCode='writeAccessDenied')

# if changing the length of the array, the value is unsigned
if arrayIndex == 0:
if not Unsigned.is_valid(value):
raise InvalidParameterDatatype("length of %s must be unsigned" % (
self.identifier,
))

# if it's atomic, make sure it's valid
if issubclass(self.datatype, Atomic):
elif issubclass(self.datatype, Atomic):
if _debug: Property._debug(" - property is atomic, checking value")
if not self.datatype.is_valid(value):
raise InvalidParameterDatatype("%s must be of type %s" % (
self.identifier, self.datatype.__name__,
))

# if it's an array, make sure it's valid regarding arrayIndex provided
elif issubclass(self.datatype, Array):
if _debug: Property._debug(" - property is array, checking subtype and index")

# changing a single element
if arrayIndex is not None:
# if it's atomic, make sure it's valid
if issubclass(self.datatype.subtype, Atomic):
if _debug: Property._debug(" - subtype is atomic, checking value")
if not self.datatype.subtype.is_valid(value):
raise InvalidParameterDatatype("%s must be of type %s" % (
self.identifier, self.datatype.__name__,
))
# constructed type
elif not isinstance(value, self.datatype.subtype):
raise InvalidParameterDatatype("%s must be of type %s" % (
self.identifier, self.datatype.subtype.__name__
))

# replacing the array
elif isinstance(value, list):
# check validity regarding subtype
for item in value:
# if it's atomic, make sure it's valid
if issubclass(self.datatype.subtype, Atomic):
if _debug: Property._debug(" - subtype is atomic, checking value")
if not self.datatype.subtype.is_valid(item):
raise InvalidParameterDatatype("elements of %s must be of type %s" % (
self.identifier, self.datatype.subtype.__name__,
))
# constructed type
elif not isinstance(item, self.datatype.subtype):
raise InvalidParameterDatatype("elements of %s must be of type %s" % (
self.identifier, self.datatype.subtype.__name__
))

# value is mutated into a new array
value = self.datatype(value)

# some kind of constructed data
elif not isinstance(value, self.datatype):
if _debug: Property._debug(" - property is not atomic and wrong type")
raise InvalidParameterDatatype("%s must be of type %s" % (
Expand Down Expand Up @@ -389,13 +437,6 @@ def __init__(self, **kwargs):
# 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:
Expand All @@ -404,20 +445,12 @@ def __init__(self, **kwargs):
# 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)
Expand Down Expand Up @@ -478,19 +511,12 @@ def add_property(self, prop):
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
is relavent. Deleting a property disconnects it from the collection of
properties common to all of the objects of its class."""
if _debug: Object._debug("delete_property %r", value)
if _debug: Object._debug("delete_property %r", prop)

# make a copy of the properties dictionary
self._properties = _copy(self._properties)
Expand All @@ -500,13 +526,6 @@ def delete_property(self, prop):
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)

Expand Down
35 changes: 18 additions & 17 deletions py25/bacpypes/service/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
Property, DeviceObject
from ..task import FunctionTask

from .object import CurrentPropertyListMixIn

# some debugging
_debug = 0
_log = ModuleLogger(globals())
Expand All @@ -25,7 +27,7 @@
class CurrentDateProperty(Property):

def __init__(self, identifier):
Property.__init__(self, identifier, Date, default=None, optional=True, mutable=False)
Property.__init__(self, identifier, Date, default=(), optional=True, mutable=False)

def ReadProperty(self, obj, arrayIndex=None):
# access an array
Expand All @@ -47,7 +49,7 @@ def WriteProperty(self, obj, value, arrayIndex=None, priority=None, direct=False
class CurrentTimeProperty(Property):

def __init__(self, identifier):
Property.__init__(self, identifier, Time, default=None, optional=True, mutable=False)
Property.__init__(self, identifier, Time, default=(), optional=True, mutable=False)

def ReadProperty(self, obj, arrayIndex=None):
# access an array
Expand All @@ -66,7 +68,7 @@ def WriteProperty(self, obj, value, arrayIndex=None, priority=None, direct=False
# LocalDeviceObject
#

class LocalDeviceObject(DeviceObject):
class LocalDeviceObject(CurrentPropertyListMixIn, DeviceObject):

properties = \
[ CurrentTimeProperty('localTime')
Expand Down Expand Up @@ -107,6 +109,18 @@ def __init__(self, **kwargs):
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")
Expand All @@ -115,20 +129,7 @@ def __init__(self, **kwargs):
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')
super(LocalDeviceObject, self).__init__(**kwargs)

bacpypes_debugging(LocalDeviceObject)

Expand Down
Loading

0 comments on commit 89a9ac4

Please sign in to comment.