XKNX/xknx

Cover update callback stops in some special case

mralessio opened this issue ยท 8 comments

Hello!

My intention is to use device_updated_cb callback for Cover to process some logic during its movement etc..
I faced the problem when callback stops working in some special case, for example:

Pretend the blind initial position is 0% and we need to move it to 90%

  1. start moving the blind to some position await cover.set_position(90)
  2. send Stop during movement cover.stop()
  3. then continue to move it to the previously given position await cover.set_position(90)
    Here the device_updated_cb stops
  4. if then or instead to send the blind to any other position but except 90%, the callback gets back to work, for example, sending to any of 0-89 or 91-100% .

Not sure if I'm doing something not correctly.
Here is the reduced example:

async def cover_update_cb(cover: Cover):
    print('Something inside cover update callback')
    
cover: Cover = None

async def test():
    global cover
    await asyncio.sleep(1)
    await cover.set_position(90)
    await asyncio.sleep(4)
    print('STOP command')
    await cover.stop()
    await asyncio.sleep(2)
    print(f'Continue to move to 90')
    await cover.set_position(90) 
    """here cover_update_cb stops. If instead set any different position from a position 
         that the blind started moving from at the beginning (in our case 90) then callback will work. """
     
async def main():
    global cover
    xknx = XKNX(daemon_mode=True)     

    cover = Cover(
        xknx,
        'Cover',
        group_address_stop = "1/1/2",
        group_address_position = "1/1/3",
        group_address_position_state = "1/1/4",
        device_updated_cb=cover_update_cb
    )
    
    loop = asyncio.get_running_loop()
    loop.create_task(test())
        
    await xknx.start()
    await xknx.stop()    
    
asyncio.run(main())

Hi ๐Ÿ‘‹!
Thanks for reporting this issue!

Can you try to add always_callback=True to this call and try again?

await self.position_target.process(telegram)

Hi @farmio ! Great! It fixes! Many thanks!

๐Ÿ‘ If you want to provide a fix (and tests) feel free to submit a PR.

May I ask you for a help/advice in parallel?

I have the feedback position (DPT 5.001) of the blind.
Instead of sending a blind position cyclicly, I want to use the cover callback to update the current position each 1 sec by reading value from the group address, only when the blind moving.

Now I tried it like this:

async def cover_update_cb(self, cover: Cover):
        await cover.sync()
        self.position_fb = cover.position_current.value

or via read_group_value()
Is it a good practice/method to achieve it?

Sending a GroupValueRead to a state address of a xknx Device won't yield a response.
Calling device.sync() will send multiple reads.

Why don't you just write the calculated position out with write_group_value() when moving?

I have RS485 digital motor connected over the KNX RS485 motor-controller which returns the precise blind position. I want to get advantage of it showing always precise position instead of calculated.

Then calling sync() or even read_group_value() in the callback will yield a loop over the bus - as a response will yield another callback.
You start an asyncio.Task in the callback when it is moving and cancel it again when it isn't anymore. In the Task call read_group_value() (or sync() if you only have that one state address) every 1 second or so.

Thank you for help, @farmio