unable to stop my addon when xbmc shuts down
#1
Hi,

I'm busy creating my very first XBMC/Kodi addon in Python. It's a service that sets up a pyinotify notifier loop and watch for filesystem changes. In particular if my camera is connected via USB, so it'll copy over the images to an attached harddisk. This works well (enough), but I'm unable to stop the pyinotify notifier loop upon XBMC shutdown. It now looks like this:

Code:
def main():
    # watch manager
    wm = pyinotify.WatchManager()
    mask = pyinotify.IN_CREATE | pyinotify.IN_DELETE
    wm.add_watch(mediadir, mask, rec=True)

    # event handler
    eh = MyEventHandler()

    # notifier
    notifier = pyinotify.Notifier(wm, eh)
    notifier.loop()

if __name__ == '__main__':
    main()

I read in the wiki that for the XBMC version I'm running (13.2), I should start the script like this:

Code:
if __name__ == '__main__':
    while not xbmc.abortRequested:
        some code
        xbmc.sleep(500)

Now I can replace the 'some code' with my notifier.loop, but since the script will happily keep looping, it'll never go to the sleep(500) part.

I'm kind of stuck here ... Every time I want to close XBMC, it gives me an error in the logfile:

Quote:10:47:59 T:140134299994560 ERROR: CPythonInvoker(5, /home/leon/.xbmc/addons/plugin.program.camerasync/service.py): script didn't stop in 5 seconds - let's kill it

which is probably caused by the notifier.loop() ...

Any ideas?
Reply
#2
If notifier.loop() truly blocks, then start it in another thread and then stop the notifier when abort is called.

Code:
import threading
notifier = None  # global so you can pick it up in main

def watcher():
    global notifier
    # watch manager
    wm = pyinotify.WatchManager()
    mask = pyinotify.IN_CREATE | pyinotify.IN_DELETE
    wm.add_watch(mediadir, mask, rec=True)

    # event handler
    eh = MyEventHandler()

    # notifier
    notifier = pyinotify.Notifier(wm, eh)
    notifier.loop()

def main():
    global notifier
    thread = threading.Thread(target=watcher)
    thread.start()
    while not xbmc.abortRequested:
        xbmc.sleep(500)
    notifier.stop()

if __name__ == '__main__':
    main()

Looking at the docs for pyinotify, you could also set a callback function to return True when xbmc.abortRequested is true when you call loop.

Or just play ostrich with the log notice. You wouldn't be the only one who does not exit gracefully. Wink
Reply
#3
(2014-12-09, 14:30)KenV99 Wrote: Looking at the docs for pyinotify, you could also set a callback function to return True when xbmc.abortRequested is true when you call loop.

Or just play ostrich with the log notice. You wouldn't be the only one who does not exit gracefully. Wink

Hi, thanks for replying! I tried your code but xbmc still 'hangs' upon shutdown, waiting for my addon to stop. Apparently it's unable to kill it either. I played with pyinotify's callback function and that works, but only if I make a change to the watched (by pyinotify) directory, after which the callback function is called. This of course is not likely to happen, so I'm back to the drawing board Smile

Edit: added some debugging rules and the notifier is killed .... but xbmc still doesn't want to exit.
Reply
#4
Check that notifier.loop() actually returns as experted after calling stop. Also, you should do thread.join() after stop to make sure main thread tries to exit last.
Reply
#5
Using the example here: https://github.com/seb-m/pyinotify/wiki/Tutorial, perhaps try:

Code:
def watcher():
    # watch manager
    wm = pyinotify.WatchManager()
    mask = pyinotify.IN_CREATE | pyinotify.IN_DELETE
    wm.add_watch(mediadir, mask, rec=True)

    # event handler
    eh = MyEventHandler()

    # notifier
    notifier = pyinotify.Notifier(wm, eh, timeout=10)
    return notifier

def quick_check(notifier):
    assert notifier._timeout is not None, 'Notifier must be constructed with a short timeout'
    notifier.process_events()
    while notifier.check_events():  #loop in case more events appear while we are processing
        notifier.read_events()
        notifier.process_events()

def main():
    mynotifier = watcher()
    while not xbmc.abortRequested:
        quick_check(mynotifier)
        xbmc.sleep(500)
    mynotifier.stop()

if __name__ == '__main__':
    main()
Reply
#6
Thanks a lot, KenV99! Worked like a charm Smile

Next step: make everything configurable, and then see if I can publish it ..


Edit: spent the entire evening working on the addon, and now looking at the piece of code again, I finally understand _how_ it works Smile Also managed to make things configurable and adding a language. Just in time for Christmas, since I'm buying my daughter a 'my-first-camera' that she can simply hook up to the raspberry (I'll probably use a long extension cord) and her pictures will be copied to the hd, from which she can easily browse them. I think I'll let the script delete the source file (configurable) so she won't have to do that herself and she can simply go on making more pictures that she can then watch on tv Big Grin
Reply
#7
(2014-12-09, 18:22)sebvieira Wrote: Thanks a lot, KenV99! Worked like a charm Smile

Next step: make everything configurable, and then see if I can publish it ..


Edit: spent the entire evening working on the addon, and now looking at the piece of code again, I finally understand _how_ it works Smile Also managed to make things configurable and adding a language. Just in time for Christmas, since I'm buying my daughter a 'my-first-camera' that she can simply hook up to the raspberry (I'll probably use a long extension cord) and her pictures will be copied to the hd, from which she can easily browse them. I think I'll let the script delete the source file (configurable) so she won't have to do that herself and she can simply go on making more pictures that she can then watch on tv Big Grin

Nice! When you're ready, put the code up on github and open a thread with a link to it...
Reply

Logout Mark Read Team Forum Stats Members Help
unable to stop my addon when xbmc shuts down0