Control Xiaomi Yeelight Bulbs with Python
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():
passif __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.
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.
Assemble our script
The first step is create a menu to allow us select the option we want. For example:
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.