JoelBender / BACpypes3

BACnet communications library
33 stars 7 forks source link

Low values not send via send_cov_notifications #24

Open chrissli opened 5 months ago

chrissli commented 5 months ago

Hello there,

I just migrated my code from the old BACpypes to BACpypes3 and had some minor issues, which are foremost my own fault / lack of knowledge. Maybe this one is one of those, too, but maybe not.

What I do to see if my code works is, I open YABE and see what values are sent. So I noticed the values ( AnalogueValueObject ) I add to an app are registered in YABE and I can subscribe to them, but they don't update regularly. Most do only once a minute ( which I assume is just YABE doing a roll call ). So I tried the example from cov-server.py and it updates every second.

I then did some fiddling around and noticed the following: When I add some bigger numbers to my values, so the difference to their previous value is bigger, then they update every second as intended. But when the difference is small, then they don't. I tried it with the code from cov-server.py and adjusted the ramp-function to barely change the values, with the same result, the notification is not triggered ( I added a print() into event.py to see if send_cov_notifications() is triggered, but it isn't ).

Is this supposed to work like that or is this an error? If it is supposed to work like this, is there a way to trigger the notifications manually? The thing is, I need notifications for all the values, even if the do not change.

This is the adjusted code I used to test ( based on cov-server.py, everything else besides the ramp() is the same ), I changed the ramp so the value is only changed by 0.1, as I noticed this behaviour with my temperature sensor.

Thank you in advance!


async def ramp(
    avo: AnalogValueObject, starting_value: float, step_count: int, step_size: float
) -> None:
    """
    Ramp the present value from the starting value up step_size increments
    step_count number of times, then back down again.
    """
    if _debug:
        _log.debug("ramp %r %r %r %r", avo, starting_value, step_count, step_size)

    try:
        while True:
            if _debug:
                _log.debug("- ramp up")
            for i in range(step_count):
                #only go up 0.1 each step
                avo.presentValue = avo.presentValue +0.1
                await asyncio.sleep(1.0)

            if _debug:
                _log.debug("- ramp down")
            for i in range(step_count):
                #only go down 0.1 each step
                avo.presentValue = avo.presentValue -0.1
                await asyncio.sleep(0.5)

    except KeyboardInterrupt:
        pass
chrissli commented 5 months ago

Ok, now I have seen there is the possibility to overwrite COVIncrementCriteria

class COVAlwaysNotify(COVIncrementCriteria):
    def present_value_filter(self, old_value, new_value) -> bool:
        return True # No checking required. We want everything. Always.

and even using GenericCriteria seems to work

class AnalogValueObject(_Object, _AnalogValueObject):
    #_cov_criteria = COVAlwaysNotify
    _cov_criteria = GenericCriteria

But still, is there a way to send notifications even when a value didn't change, like just update all subscriptions?

JoelBender commented 5 months ago

Inside the COVDetection class is a send_cov_notifications() method you can call, and if it is not given a specific subscription it will send a notification to all of the subscribers. Local Analog Value Objects have a class attribute _cov_criteria = COVIncrementCriteria that is instantiated and associated with the object (see bacpypes3.service.cov line 601) by a dictionary _cov_detections in the application (assuming it has inherited ChangeOfValueServices).

So you should be able to call something like app._cov_detections[objid].send_cov_notifications() any time you would like. Untested!

chrissli commented 5 months ago

I see. Thank you, really!! I'll give it a try.