8000 Trying to poll device every 5 seconds but getting asyncio errors · Issue #316 · python-kasa/python-kasa · GitHub
[go: up one dir, main page]

Skip to content

Trying to poll device every 5 seconds but getting asyncio errors #316

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
pushshift opened this issue Feb 23, 2022 · 5 comments · Fixed by #333
Closed

Trying to poll device every 5 seconds but getting asyncio errors #316

pushshift opened this issue Feb 23, 2022 · 5 comments · Fixed by #333
Labels
documentation Improvements or additions to documentation

Comments

@pushshift
Copy link
pushshift commented Feb 23, 2022

Here is a copy of my current code:

#!/usr/bin/env python3

from kasa import SmartPlug
import asyncio
import time

plug = SmartPlug("192.168.1.96")

while True:
    asyncio.run(plug.update())
    power = plug.emeter_realtime.power
    print(power)
    time.sleep(5)

This almost works, but I encounter "Detected protocol reuse between different event loop" and then it eventually errors out.

What is the proper way to update the emeter information every X seconds?

Polling devices and storing them in a database is probably one of the top reasons for using this library. It would be wonderful if more examples were added to the documentation to show how to poll every X seconds / minutes.

@rytilahti
Copy link
Member
rytilahti commented Feb 24, 2022

You need to run all updates in the same event loop (or close the connection to let it reinitialize for the next update) as the connection is being shared (and asyncio.run() creates a new loop for each individual invocation). Take a look at #225 (comment) for more in-depth answer.

I will leave this issue open as I agree that this could be explained better in the documentation. #238 is also related to this.

@rytilahti rytilahti added the documentation Improvements or additions to documentation label Feb 24, 2022
@pushshift
Copy link
Author

Thank you rytilahti! I took a look at that comment and I think this helps cover my use-case. One thing I've noticed (at least for K115 plugs) is that after 5 queries, it throws a socket error (#104). My guess is that if you query too often, there is code to prevent DDOSing the plug :)

This can be handled by a try statement but I'm wondering if it wouldn't hurt to throw in a try within the module itself to catch socket errors and try exponential fall backs. If you think it might be worth looking into, I can create a new issue and provide a code example along with the error encountered to see if it is worth adding to the module itself or if it should be left to the user to handle themselves when importing.

@rytilahti
Copy link
Member

How fast are you performing the queries to hit that? And what's the exception?

Anyway, I think it's better not to add more "magic" to the lib to cover such cases, as the limits differ from device to device. If the exception is something else than SmartDeviceException, what we could do is to wrap it to make it easier to catch. What do you think?

@jdimpson
Copy link
jdimpson commented Aug 10, 2022

You need to run all updates in the same event loop (or close the connection to let it reinitialize for the next update) as the connection is being shared (and asyncio.run() creates a new loop for each individual invocation). Take a look at #225 (comment) for more in-depth answer.

How would I go about closing the connection and reinitializing it? I am trying to get some old code working that was based on pyHS100. It's very synchronous, thread-based stuff, and i desperately wish to avoid re-writing it.

@rytilahti
Copy link
Member
rytilahti commented Aug 10, 2022

So, the best approach depends on how your code is structured. But one way to disconnect is to execute the close() that is exposed through protocol variable of the device object. Executing the update() (or any other query on the device) will automatically form a connection if none exists. So something like this:

import asyncio
from time import sleep

from kasa import SmartBulb

x = SmartBulb("bulb")

def update_loop():
    loop = asyncio.get_event_loop()
    while True:
        loop.run_until_complete(x.update())
        loop.run_until_complete(x.protocol.close())
        print(x)

        sleep(2)


update_loop()

Btw, please don't post for support requests on long-time ago closed issues, but use the discussions feature of github, thanks :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants
0