A YeeLight bulb.

YeeLight library

https://gitlab.com/stavros/python-yeelight/badges/master/pipeline.svg https://gitlab.com/stavros/python-yeelight/badges/master/coverage.svg https://img.shields.io/pypi/v/yeelight.svg Documentation Status

The YeeLight Python library is a small library that lets you control your YeeLight RGB LED bulbs over WiFi. The latest version can be found at:


To see a real-world usage example, have a look at yeecli, a command-line YeeLight utility that uses this library.

yeelight currently does not support some features of the YeeLight API, such as discovery, but is mostly otherwise complete.


To install yeelight, you can use pip:

pip install yeelight

That’s all that’s required to install the library.


First of all, you need to discover your bulb’s IP. If you already know it, you can skip to the next section.

Discovering all the devices on your network and their capabilities is easy with discover_bulbs:

>>> from yeelight import discover_bulbs
>>> discover_bulbs()
[{'capabilities': {'bright': '50',
                   'color_mode': '1',
                   'ct': '2700',
                   'fw_ver': '45',
                   'hue': '359',
                   'id': '0x0000000002dfb19a',
                   'model': 'color',
                   'name': 'bedroom',
                   'power': 'off',
                   'rgb': '16711935',
                   'sat': '100',
                   'support': 'get_prop set_default set_power toggle '
                              'set_bright start_cf stop_cf set_scene cron_add '
                              'cron_get cron_del set_ct_abx set_rgb set_hsv '
                              'set_adjust set_music set_name'},
  'ip': '',
  'port': 55443},
  {'capabilities': {'bright': '50',
                   'color_mode': '1',
                   'ct': '2700',
                   'fw_ver': '45',
                   'hue': '359',
                   'id': '0x0000000002dfb2f1',
                   'model': 'color',
                   'name': 'livingroom',
                   'power': 'off',
                   'rgb': '16711935',
                   'sat': '100',
                   'support': 'get_prop set_default set_power toggle '
                              'set_bright start_cf stop_cf set_scene cron_add '
                              'cron_get cron_del set_ct_abx set_rgb set_hsv '
                              'set_adjust set_music set_name'},
  'ip': '',
  'port': 55443}]

That’s it, now you know the addresses of all the bulbs on your local network.

Now that you’ve discovered your bulb’s IP, it’s time to instantiate a new Bulb:

>>> from yeelight import Bulb
>>> bulb = Bulb("")

# Turn the bulb on.
>>> bulb.turn_on()

# Turn the bulb off.
>>> bulb.turn_off()

# Toggle power.
>>> bulb.toggle()

# Set brightness to 50%.
>>> bulb.set_brightness(50)

# Set brightness of the background light to 50%, if your
# light supports it.
>>> from yeelight import LightType
>>> bulb.set_brightness(50, light_type=LightType.Ambient)

# Set RGB value.
>>> bulb.set_rgb(255, 0, 0)

# Set HSV value.
>>> bulb.set_hsv(320, 100, 50)

# Set hue and saturation, but keep value (brightness) the same.
>>> bulb.set_hsv(320, 100)

# Set color temperature.
>>> bulb.set_color_temp(4700)

# Save this setting as default.
>>> bulb.set_default()

For efficiency, yeelight will use a single TCP connection for all the above commands. However, this means that, if there’s an error, a command could raise a socket.error exception and need to be retried. Note that YeeLight connections are rate-limited to 60 per minute. If you need your connection to not have a limit, you need to use Music mode.

For a complete list of the commands you can issue, see the API reference.

By default, yeelight will refuse to make any changes to the bulb if it’s off:

>>> bulb.set_brightness(10)
AssertionError: Commands have no effect when the bulb is off.

You can check the bulb’s state by reading its properties:

>>> bulb.get_properties()
{'bright': u'10',
 'color_mode': u'2',
 'ct': u'2700',
 'delayoff': u'0',
 'flowing': u'0',
 'hue': u'300',
 'music_on': u'0',
 'name': u'My light',
 'power': u'off',
 'rgb': u'16737280',
 'sat': u'100'}

Notice that the properties don’t include flow_params by default, as that causes problems. If you want that, specify it as an argument to get_properties().

If you want to always turn the bulb on before running a command, set auto_on to True. This will refresh the bulb’s properties before most calls, and will cost you an extra message per command, so watch out for rate-limiting:

>>> bulb.auto_on = True

# Or, when instantiating:
>>> bulb = Bulb("", auto_on=True)

# This will work even if the bulb is off.
>>> bulb.set_brightness(10)

For documentation of the Flow feature, see Working with Flow.


yeelight provides full support for effects. Effects control whether the bulb changes from one state to the other immediately or gradually, and how long the gradual change takes.

You can either specify effects to run by default when instantiating, or with each call:

>>> bulb = Bulb("", effect="smooth", duration=1000)

# This will turn the bulb on gradually within one second:
>>> bulb.turn_on()

# This will turn the bulb on immediately:
>>> bulb.turn_on(effect="sudden")

# You can easily change the default effect, too:
>>> bulb.effect = "sudden"

# This will turn the bulb off immediately:
>>> bulb.turn_off()

There are two effect types, "sudden" and "smooth". The "sudden" type ignores the duration parameter.

Keep in mind that the effect and duration parameters must be passed by keyword.


To get read-time state update notifications, run listen in a Thread:

>>> import threading
>>> thread = threading.Thread(target=bulb.listen, args=(callback,))
>>> thread.start()

# To stop listening:
>>> bulb.stop_listening()

Note that the callback function should take one parameter, which will be a dict containing the new/updated parameters. It will be called when last_properties is updated.

You can also use asyncio event loop:

>>> import asyncio
>>> async def main():
>>>     loop = asyncio.get_running_loop()
>>>     await loop.run_in_executor(None, bulb.listen, callback)
>>> asyncio.run(main())

# To stop listening in an event loop:
>>> await loop.run_in_executor(None, bulb.stop_listening)