Mi Light commands and tricks

Controlling a Wi-Fi lightbulb

I recently purchased a Mi Light wireless controlled lightbulb and a Mi Light Wi-Fi controller.
The bulb is radio controlled, can change colours, brightness, and can also be put in breath or disco mode.

While the idea behind it is nice, it lacks some flexibility, the light in itself isn’t very “smart”, it isn’t programmable. You set it up with the smartphone, and that’s it.

I wanted to see if I could control it via PC, and send commands to it without having to leave the keyboard, or make the light respond to specific events.

The protocol

Capturing

Using the Aircrack suite and Wireshark for the sniffing and analyzing, and sendip to send the commands to the light. (If you don’t have them yet, in a terminal window run sudo apt-get install aircrack-ng wireshark sendip )

When I did this, the Mi-Light was already installed and configured with my router, as per manufacturer instructions, and I had already installed the remote control app on my phone.
Keep handy your router wi-fi MAC address (if you are lazy like me, you can just run sudo airodump-ng wlan0 and look for it on your screen). On a terminal window run:

sudo airudump-ng wlan0 -d <router_bssid> -w pacchetti

Capture

Since my Wi-Fi is encrypted, as you can see from the screenshot I also captured the handshakes between router and Mi Light Wi-Fi box, and between router and smartphone. The easiest way to do it is to turn off and on the router while the packet capture is running.
Now that the capture is running, perform as many actions as possible on the phone app to issue all the possible commands to the light, and then stop the capture process.

Opening the capture file (in my case “pacchetti-01.cap“) with Wireshark, I can see the traffic between the controller and the  smartphone. (if the Wi-Fi traffic is encrypted, remember to enable and configure decryption in Wireshark, Protocols –> IEEE 802.11 or the capture will yeld no useful results.)

The Wireshark cap shows several UDP packets between the smartphone and the Mi Light Controller.
The useful data is in the packets going from the smartphone (192.168.1.67) to the Controller (192.168.1.72).

They are UDP packets with 2 bytes of data sent to port 8899

Wireshark Capture

Control Codes

Trying with sendip the codes, I can finally turn on and off my light from the PC
sudo sendip -p ipv4 -p udp -ud 8899 -d 0x4100 -v 192.168.1.72

Turn_lights_on

By changing the data payload (option -d, with 0x since the data is hexadecimal) I can give different instructions to the Mi Light. Here’s the list of control codes:

4100 : OFF
4200 : ON
4d00 : Switch Mode
4b00 : ON Group 4
4c00 : OFF Group 4
4900 : ON Group 3
4a00 : OFF Group 3
4700 : ON Group 2
4800 : OFF Group 2
4500 : ON Group 1
4600 : OFF Group 1
4400 : Faster breathe/change
4300 : Slower breathe/change
4eXX : Intensity (XX seems to range from 02 to 1b)
c200 : Reset – Full light
c500 : Reset – Full light Group 1
c700 : Reset – Full light Group 2
c900 : Reset – Full light Group 3
cb00 : Reset – Full light Group 4
40XX : Set colour (XX is the colour value)

Setting the colour is a bit tricky. The code has to be entered in the form of “hue”, from HSL.

After a bit of tweaking, I found out how to change the colour to green.
sudo sendip -p ipv4 -p udp -ud 8899 -d 0x4078 -v 192.168.1.72

Discovery

From the capture file it is also possible to find out the discovery protocol used by the app.
To find the local IP address of the Mi Ligth Wi-Fi controller, it is needed to send a UDP packet to the broadcast address of the network (in my case 192.168.1.255), with the string “Link_Wi-Fi“, or the hex code 4c696e6b5f57692d4669

At this point, the Wi-Fi controller will reply to the broadcast by sending another UDP packet containing its IP address and MAC address.

The scripts – PC or Raspberry

With the codes gathered now, it is possible to control the Mi Light and turn it into a smarter lamp.

The light can be used as a visual reminder. Save the following script in a text file named luce.sh

#!/bin/bash
[ $# -eq 0 ] || [ $# -eq 1 ] && { echo "Uso: $0 tempo colore[red|green|blue]"; exit 1; }
sleep $1;
sendip -p ipv4 -p udp -ud 8899 -d 0x4200 192.168.1.72
if [ $2 = "red" ]; then
    sendip -p ipv4 -p udp -ud 8899 -d 0x40b0 192.168.1.72
else
    if [ $2 = "green" ]; then
    sendip -p ipv4 -p udp -ud 8899 -d 0x4078 192.168.1.72
    else
       if [ $2 = "blue" ]; then
       sendip -p ipv4 -p udp -ud 8899 -d 0x4020 192.168.1.72
       fi
    fi
fi

This simple shell script allows me to set up a reminder making the light turn on after a specific time. If I want my light to turn red after 5 minutes, I just need to run sudo ./luce.sh 5m red &

lights

I could also add a similar script as a cron job and have the light turn on or turn off at a specific hours of the day.

Or, if I keep my PC or my Raspberry connected to the internet, I could control the light via SSH from work.

Many more possible use cases open up now.