JoelBender / bacpypes

BACpypes provides a BACnet application layer and network layer written in Python for daemons, scripting, and graphical interfaces.
MIT License
302 stars 129 forks source link

Configuration error in Schedule #420

Closed henrisokka closed 3 years ago

henrisokka commented 3 years ago

Hey, and thanks for an awesome library!

We are building a bacnet integration for a legacy automation system and we are modelling whole site's BMS with it.

I'm having issues when creating schedules. I've been trying following the sample. I have two issues, first is that the reliability of the schedule is 10 Configuration error other is that there are only 6 items on the weekly schdedule -property although I'm creating it with 7.

I've been trying to disable all the properties one by one but that doesn't help. I get the configuration error until there is only presentValue left and if I remove that the object is empty.

def create_schedule(point_id, present_value, weekly_schedule, property_references):
    global schedule_index

    print(f"point_id: {point_id}, type: {type(point_id)}")
    print(f"present_value: {present_value}, type: {type(present_value)}")
    print(f"weekly_schedule: {weekly_schedule}, type: {type(weekly_schedule)}")
    print(f"property_references: {property_references}, type: {type(property_references)}")

    obj = create_object(Schedule, "schedule", point_id,
                        objectIdentifier=('schedule', schedule_index),
                        presentValue=present_value,
                        effectivePeriod=DateRange(startDate=(0, 1, 1, 1), endDate=(254, 12, 31, 2),),
                        weeklySchedule=weekly_schedule,
                        scheduleDefault=present_value,
                        listOfObjectPropertyReferences=property_references
                        )

    schedule_index += 1

    return obj

def create_object(bacnet_class, point_id, property_name, **kwargs):
    global application

    for key in kwargs:
        print(f"{key} type: {type(kwargs[key])} value: {kwargs[key]}")

    obj = bacnet_class(
        objectName=point_id + get_separator() + property_name,
        _device_interface=application.device_interface,
        **kwargs
    )

    register_property(point_id, property_name, kwargs['presentValue'], bacnet_object=obj)
    application.add_object(obj)
    return obj

class Schedule(LocalScheduleObject): #Just exnteding the LocalScheduleObject to be able to see what properties are read
    def __init__(self, _device_interface=None, **kwargs):
        LocalScheduleObject.__init__(self, **kwargs)

    def ReadProperty(self, propid, arrayIndex=None):
        print(f"ReadProperty: {propid}")

        return LocalScheduleObject.ReadProperty(self, propid, arrayIndex)

Console output when creating an object:

point_id: T.VILLIPV/TK02OHJ, type: <class 'str'>
present_value: Enumerated(0), type: <class 'bacpypes.primitivedata.Enumerated'>
weekly_schedule: [<bacpypes.basetypes.DailySchedule object at 0x7fa3c5542910>, <bacpypes.basetypes.DailySchedule object at 0x7fa3c5542af0>, <bacpypes.basetypes.DailySchedule object at 0x7fa3c5542cd0>, <bacpypes.basetypes.DailySchedule object at 0x7fa3c5542eb0>, <bacpypes.basetypes.DailySchedule object at 0x7fa3c55460d0>, <bacpypes.basetypes.DailySchedule object at 0x7fa3c55461f0>, <bacpypes.basetypes.DailySchedule object at 0x7fa3c5546310>], type: <class 'list'>
property_references: [<bacpypes.basetypes.DeviceObjectPropertyReference object at 0x7fa3c5542760>], type: <class 'list'>
objectIdentifier type: <class 'tuple'> value: ('schedule', 1)
presentValue type: <class 'bacpypes.primitivedata.Enumerated'> value: Enumerated(0)
effectivePeriod type: <class 'bacpypes.basetypes.DateRange'> value: <bacpypes.basetypes.DateRange object at 0x7fa3c55463d0>
weeklySchedule type: <class 'list'> value: [<bacpypes.basetypes.DailySchedule object at 0x7fa3c5542910>, <bacpypes.basetypes.DailySchedule object at 0x7fa3c5542af0>, <bacpypes.basetypes.DailySchedule object at 0x7fa3c5542cd0>, <bacpypes.basetypes.DailySchedule object at 0x7fa3c5542eb0>, <bacpypes.basetypes.DailySchedule object at 0x7fa3c55460d0>, <bacpypes.basetypes.DailySchedule object at 0x7fa3c55461f0>, <bacpypes.basetypes.DailySchedule object at 0x7fa3c5546310>]
scheduleDefault type: <class 'bacpypes.primitivedata.Enumerated'> value: Enumerated(0)
listOfObjectPropertyReferences type: <class 'list'> value: [<bacpypes.basetypes.DeviceObjectPropertyReference object at 0x7fa3c5542760>]

Screenshot from Yabe: Screenshot 2021-08-25 at 9 49 15

Thanks!

JoelBender commented 3 years ago

tl;dr : This is a problem with the sample code.

The "configuration error" for reliability is set in the _check_reliability() function of the LocalScheduleObject when an exception is raised during the process of crawling through the weekly and exception schedules. If you turn on debugging for the class then you should be able to see it, python3 app.py --debug bacpypes.local.schedule.LocalScheduleObject.

The weeklySchedule property value you are providing is a list and it needs to be converted to the appropriate array datatype. From this:

weeklySchedule=weekly_schedule,

to this:

weeklySchedule = ArrayOf(DailySchedule, 7)(weekly_schedule),

In an older version of BACpypes, initialization of property values went through a "convert the value if it needs to be converted" process. In later versions the design attitude changed to "if the developer is setting something to a value, assume they know what they're doing."

Note that if you set an exception schedule there is no fixed length, so the code would look something like this:

exceptionSchedule = ArrayOf(SpecialEvent)(exception_schedule),

I'll fix the sample code.

henrisokka commented 3 years ago

Thanks for the quick reply! It turned out the we were supposed to use Unisgned instead of Enumerated type. That made the configuration error go away.

There is still only 6 items in the weekly schedule although I'm creating the object like this weeklySchedule=ArrayOf(DailySchedule, 7)(weekly_schedule) and len(weekly_schedule) is 7.

henrisokka commented 3 years ago

Update, the length of obj.weeklySchedule is 7 in the bacpypes. For some reason the Yabe only shows only 6 items in the list. As all seems to be working correctly on the Bacpypes side I'll close this issue.