Control Xiaomi Yeelight Bulbs with Python

Rui Coelho
5 min readMar 23, 2021

I’m an enthusiast user of Smart Home stuff, a year ago I bought a Xiaomi Yeelight Bulb and recently I decide to use a bit more of his capabilities.

Let’s get started

To be able to use the Yeelight library for python we must enable developer mode on our lamp. Go to Yeelight App available on Play Store install it and log into your account.

Enable Developer Mode

Open your bulb on your app and at the bottom right press the “eject” icon, this action will open an new menu where you can see “Lan Control”, press that button.

After that turn on Lan Control and you are ready to go.

Note: One of the recent versions of Yeelight App dropped support to developer mode. I’m currently using 3.2.59 and I’m able to execute the steps mentioned above.

Let’s code

For this particular case we need to create a new python project and create a new virtual environment:

python3 -m venv .venv
source .venv/bin/activate
pip install tabulate
pip install yeelight

After this we can create our main.py file with a basic main:

def menu():
pass
if __name__ == '__main__':
menu()

I will add new futures on a near future but now let’s start with six basic functions: adjust brightness, turn on lights, turn off lights, list bulb properties, list bulbs and exit function (not Yeelight related, only to quit our program).

Basics of Yeelight Library

First let’s understand a bit more of yeelight library. There is a pre-build function to find your bulbs:

from yeelight import discover_bulbsbulbs = discover_bulbs()
print(bulbs)

This will return a list with a dict with all information about our bulb.

List with all bulb information

If we take into consideration the first bulb we can access the first element (element 0) of our list and connect to that specific bulb:

from yeelight import discover_bulbs, Bulb# Discover Bulbs
bulbs = discover_bulbs()
print(bulbs)
# Connect to bulb
bulb = Bulb(bulbs[0]['ip'])
print(bulb)
# Turn on bulb
bulb.turn_on()
# Turn off bulb
bulb.turn_off()

If everything worked as planed your should be able to turn on and turn off the lights.

Example of turning on and off the Yeelight bulb

Assemble our script

The first step is create a menu to allow us select the option we want. For example:

Options menu

We can create a simple menu on our main.py . Let’s use a simple structure that allow us to easily handle the different events:

import readlinedef menu():
print("""
[5] - Adjust brightness
[4] - Turn on lights
[3] - Turn off lights
[2] - List Bulb Properties
[1] - List bulbs
[0] - Exit
[F] - Force Bulb Reload
""")

# Get user option
ans = input("Option => ")
if ans == "0" or ans.lower() == "exit":
pass
elif ans == "1":
# execute action
menu()
elif ans == "2":
# execute action
menu()
else:
print("Select a valid option")
menu()

I imported readline to allow navigation on entered values, using arrow keys the user will be able to navigate across the history.

Define Yeelight operations

Let’s create a folder with our operations:

mkdir -p operations
touch operations/operations.py

On our operations.py let’s define a couple headers and import some libraries:

from yeelight import Bulb, discover_bulbs
from tabulate import tabulate

This will import Bulb and discover_bulbs as mentioned before and tabulate. Tabulate will help us print the content we want on tables. The headers will define table headers and content, the content that will be filled with bulb information:

headers = ['ID', 'IP', 'Name', 'Type']
content = []
properties_headers = ["ID", "Name", "Power", "Brightness", "Saturation", "Music On"]
properties_content = []

List bulb info

We need to create a method that allow us to print the bulb information to present on a nice table:

def list_info(bulbs, force=False):
if len(content) > 0:
content.clear()
for i in range(0, len(bulbs)):
content.append([i, bulbs[0]['ip'], bulbs[0]['capabilities']['name'], bulbs[0]['capabilities']['model']])
return bulbs

This method will fill the previously defined variable content if not filled, when it’s filled the variable need to be reseted and after that filled with new information.

Turn on and off lights

We can define a single method to turn off and on our bulbs:

def turn_lights(bulbs, event):
print(tabulate(content, headers, "pretty"))
try:
ans = input("\nBulb IDs (separated by space) => ")
for a in ans.split(" "):
bulb = Bulb(bulbs[int(a)]['ip'])
if event == "off":
bulb.turn_off()
else:
bulb.turn_on()
except Exception as e:
print(e)

First we print our table with bulb information and ask the user the bulb id to turn on or off. The user will input a single id or multiple ids using space to define the separation between ids. The event variable will determinate if it’s a turn on event or a turn off event, this parameter is changed on our menu.

Adjust brightness

We can adjust brightness levels using the following method:

def adjust_brightness(bulbs):
print(tabulate(content, headers, "pretty"))
try:
ans = input("\nBulb IDs (separated by space) => ")
bright = input("Brightness level => ")
for a in ans.split(" "):
bulb = Bulb(bulbs[int(a)]['ip'])
bulb.set_brightness(int(bright))
except Exception as e:
print(e)

First we print our table with bulb information and ask the user the bulb id to change brightness. After that we ask the id or multiple ids to change brightness and after that the brightness level we want (this level is mesured in %).

Get bulb properties

We can access more information about our bulb using the following method:

def list_bulb_properties(bulbs):
if len(properties_content) > 0:
properties_content.clear()
for i in range(0, len(bulbs)):
bulb = Bulb(bulbs[0]['ip'])
props = bulb.get_properties()
properties_content.append([i, props['name'], props['power'], props['bright'], props['sat'], props['music_on']])

This method only lists a few properties although there is more properties available. You can check the library documentation for more information.

Now you just need to call this methods from our menu.

Conclusions

The integration between our code and Yeelight Bulbs it’s pretty simple and can be used for multiple proposes. I will continue to develop more features to this script and add it to my GitHub, stay tuned.

Source Code

The code for the entire project is available on my github.

--

--