FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Misleading usage of asyncio.run() in code examples · Issue #348 · python-kasa/python-kasa · GitHub

Repository navigation

Misleading usage of asyncio.run() in code examples #348

Closed

Description

I'm relatively new to asyncio sooo maybe I use it in a wrong way.
Therefore maybe I call the methods wrongly.

My first goal was to just turn off an on the light and waiting 1 seconds in between those actions.
It works for the first bulb.set_brightness(0) call.
When I call bulb.set_brightness(100) it will set the brightness of my LB130 light bulb indeed to 100.
However the responds of the device raises a SmartDeviceException.

This is my current code:

from kasa import SmartBulb
import asyncio
import time

IP = "192.168.179.54"
bulb = SmartBulb(IP)
asyncio.run(bulb.update())

for i in range(10):
    asyncio.run(bulb.set_brightness(0))
    time.sleep(1)
    asyncio.run(bulb.set_brightness(100))
    time.sleep(1)

The entire console output:

Traceback (most recent call last):
  File "/home/lightbulb/.local/lib/python3.9/site-packages/kasa/protocol.py", line 156, in _query
    return await asyncio.wait_for(
  File "/usr/lib/python3.9/asyncio/tasks.py", line 481, in wait_for
    return fut.result()
  File "/home/lightbulb/.local/lib/python3.9/site-packages/kasa/protocol.py", line 94, in _execute_query
    packed_block_size = await self.reader.readexactly(self.BLOCK_SIZE)
  File "/usr/lib/python3.9/asyncio/streams.py", line 723, in readexactly
    await self._wait_for_data('readexactly')
  File "/usr/lib/python3.9/asyncio/streams.py", line 517, in _wait_for_data
    await self._waiter
RuntimeError: Task <Task pending name='Task-13' coro=<TPLinkSmartHomeProtocol._execute_query() running at /home/lightbulb/.local/lib/python3.9/site-packages/kasa/protocol.py:94> cb=[_release_waiter(<Future pendi...x74cebe50>()]>)() at /usr/lib/python3.9/asyncio/tasks.py:416]> got Future <Future pending> attached to a different loop

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/lightbulb/.local/lib/python3.9/site-packages/kasa/smartdevice.py", line 254, in _query_helper
    response = await self.protocol.query(request=request)
  File "/home/lightbulb/.local/lib/python3.9/site-packages/kasa/protocol.py", line 73, in query
    return await self._query(request, retry_count, timeout)
  File "/home/lightbulb/.local/lib/python3.9/site-packages/kasa/protocol.py", line 160, in _query
    await self.close()
  File "/home/lightbulb/.local/lib/python3.9/site-packages/kasa/protocol.py", line 110, in close
    writer.close()
  File "/usr/lib/python3.9/asyncio/streams.py", line 353, in close
    return self._transport.close()
  File "/usr/lib/python3.9/asyncio/selector_events.py", line 700, in close
    self._loop.call_soon(self._call_connection_lost, None)
  File "/usr/lib/python3.9/asyncio/base_events.py", line 746, in call_soon
    self._check_closed()
  File "/usr/lib/python3.9/asyncio/base_events.py", line 510, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/lightbulb/Desktop/scripts/kasa/kasa_light_control.py", line 15, in <module>
    asyncio.run(bulb.set_brightness(i))
  File "/usr/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/home/lightbulb/.local/lib/python3.9/site-packages/kasa/smartdevice.py", line 77, in wrapped
    return await f(*args, **kwargs)
  File "/home/lightbulb/.local/lib/python3.9/site-packages/kasa/smartbulb.py", line 357, in set_brightness
    return await self.set_light_state(light_state, transition=transition)
  File "/home/lightbulb/.local/lib/python3.9/site-packages/kasa/smartbulb.py", line 233, in set_light_state
    light_state = await self._query_helper(
  File "/home/lightbulb/.local/lib/python3.9/site-packages/kasa/smartdevice.py", line 257, in _query_helper
    raise SmartDeviceException(f"Communication error on {target}:{cmd}") from ex
kasa.exceptions.SmartDeviceException: Communication error on smartlife.iot.smartbulb.lightingservice:transition_light_state

Therefore the error gets thrown in the _query_helper function from the smartdevice.py module:
As mentioned above during the call of the brightness method I receive a responds that is perfectly fine.
However the second responds does not come through and raises the exception.

    async def _query_helper(
        self, target: str, cmd: str, arg: Optional[Dict] = None, child_ids=None
    ) -> Any:
        """Query device, return results or raise an exception.

        :param target: Target system {system, time, emeter, ..}
        :param cmd: Command to execute
        :param arg: payload dict to be send to the device
        :param child_ids: ids of child devices
        :return: Unwrapped result for the call.
        """
        request = self._create_request(target, cmd, arg, child_ids)
        
        try:
            response = await self.protocol.query(request=request)
        except Exception as ex:
            #print("oh no")
            raise SmartDeviceException(f"Communication error on {target}:{cmd}") from ex

Activity

  1. changed the title [-]SmartDeviceException Raspberry Pi LB130 light bulb[/-] [+]Misleading usage of asyncio.run() in code examples[/+] on Jun 19, 2022
  2. rytilahti commented on Jun 19, 2022

    Member

    So this is happening as every asyncio.run() call creates a new event loop which then tries to re-use an already opened socket of another event loop causing it to crash. The first note on documentation (https://python-kasa.readthedocs.io/en/latest/smartdevice.html) and the examples that follow it instruct how to use it properly, while examples in the API documentation (e.g., https://python-kasa.readthedocs.io/en/latest/smartbulb.html#kasa.SmartBulb) are misleading. I will leave this issue open until the documentation gets updated to fix that.

    For your specific use case, the simplest way to fix your issue is to move all device handling to happen inside a coroutine that gets executed using asyncio.run(), something like this:

    from kasa import SmartBulb
    import asyncio
    
    IP = "192.168.179.54"
    bulb = SmartBulb(IP)
    
    async def loop_brightness(bulb):
        for i in range(10):
            await bulb.set_brightness(0)
            await asyncio.sleep(1)
            await bulb.set_brightness(100)
            await asyncio.sleep(1)
    
    asyncio.run(loop_brightness(bulb))
    

    Note the usage of await instead of asyncio.run(), and asyncio.sleep() instead of time.sleep().

  3. timovr-dev commented on Jun 20, 2022

    Author

    Thank you and you were right I was actually just looking at the light bulb documentation.
    The code did not work entirely but it gave me the right idea therefore thank you so much!

    This is the code that worked flawlessly:

    async def loop_brightness():
       
       IP = "192.168.179.54"
       bulb = SmartBulb(IP)
       await bulb.update()
       for i in range(10):
           await bulb.set_brightness(0)
           await asyncio.sleep(1)
           await bulb.set_brightness(100)
           await asyncio.sleep(1)
    
    asyncio.run(loop_brightness())
  4. rytilahti commented on Jun 20, 2022

    Member

    Glad it is working for you now, I'll reopen this issue so that updating the docs doesn't get forgotten :-)

  5. rytilahti commented on Jul 2, 2024

    Member

    This should now be fixed by #968 and other recent PRs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL