Sensors and Raspberry Pi to control a Mi Light bulb

Easily control the Mi Light using a Raspberry Pi and some sensors to send the commands found previously (link)

Using a PIR

Before going on, a quick check to be sure the PIR is working: just hook it up to a breadboard with a LED and power it up using the Raspberry GPIO pins.

PIR check

Raspberry to PIR
Pin 2 (5V) connected to Vcc (on the + column of the breadboard)
Pin 6 (Ground) connected to GND (on the – column)

Then, Pin 1 (3.3V) connected to the LED anode (on row 14, the anode is the longer leg of the LED)
PIR signal (the middle pin) connected to the LED cathode (on row 18, the cathode is the shorter leg of the LED)

The led will stay ON when the PIR signal is low (no motion detected), and will turn OFF when motion is detected. The duration of the OFF state in this case can be modified using the notch on the right (in the picture is set to the minimum, which is around 5 seconds). The PIR can be calibrated to our needs it by using the two notches on the board to set delay and sensitivity.

PIR Notches
Once this step is complete, it is time to send the PIR output signal to the Raspberry. To do this, remove the LED and connect the PIR output to the GPIO pin 18 (BCM 24). In the picture, the pins are connected on row 18 of the breadboard.

PIR Wiring

Now, using the following code I can send an UDP message that will turn on the Mi Light whenever the PIR will be triggered.

import RPi.GPIO as io
import socket
import time

UDP_IP = "192.168.1.72"
UDP_PORT = 8899
MESSAGE_ON = "4200".decode('hex')
MESSAGE_OFF = "4100".decode('hex')

io.setmode(io.BCM)
pin_pir = 24
io.setup(pin_pir, io.IN)

while True:
      if io.input(pin_pir):
           sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
           sock.sendto(MESSAGE_ON, (UDP_IP, UDP_PORT))
           sock.close()
      else: 
           sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
           sock.sendto(MESSAGE_OFF, (UDP_IP, UDP_PORT))
           sock.close()
     time.sleep(0.5)

(check that UDP_IP and UDP_PORT correspond to the address and port of the Mi Light controller.)

Then, once this is saved to pir.py, run
sudo python pi_light.py &

This code will constantly send UDP packets to the Mi Light controller. Since the controller doesn’t send information on the state (ON/OFF) of the lightbulb, and I’d prefer not to spam the controller with packets, it is possible to define a variable (light_state) and check against it in the while loop before sending a packet

while True:
       if io.input(pin_pir):
            if light_state == 0 : 
                sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
                sock.sendto(MESSAGE_ON, (UDP_IP, UDP_PORT))
                sock.close()
                light_state = 1
        else:
            if light_state == 1 :
                sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
                sock.sendto(MESSAGE_OFF, (UDP_IP, UDP_PORT))
                sock.close()
                light_state = 0
        time.sleep(0.5)

The resulting script doesn’t weigh too much on the Raspberry

ps aux | grep python

Using a Button to turn OFF the light

A different setup that uses a button to trigger an interrupt that turns off the light.
(a prerequisite for this script to work properly is that the PIR timer must be the lowest possible, usually it is 5 seconds, further improvements may be added easily to avoid this limitation)

Pi Light Button

And here’s the code

import RPi.GPIO as io
import socket
import time

UDP_IP = "192.168.1.72"
UDP_PORT = 8899
MESSAGE_ON = "4200".decode('hex')
MESSAGE_OFF = "4100".decode('hex')

io.setmode(io.BCM)
pin_pir = 24
button_pin = 22
light_state = 0

io.setup(pin_pir, io.IN)
io.setup(button_pin, io.IN, pull_up_down=io.PUD_UP)

def BUTTON_Handler (pin):
       global light_state
       if io.input(pin) == False :
          if light_state == 1:
              sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
              sock.sendto(MESSAGE_OFF, (UDP_IP, UDP_PORT))
              sock.close()
              time_sleep(1)
              light_state = 0

io.add_event_detect(button_pin, io.BOTH, callback = BUTTON_Handler, bouncetime=100)

try:
       while True:
          if io.input(pin_pir):
             if light_state == 0 : 
                sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
                sock.sendto(MESSAGE_ON, (UDP_IP, UDP_PORT))
                sock.close()
                light_state = 1
                time.sleep(0.5)

except KeyboardInterrupt:
       io.cleanup()

io.cleanup()

Using a light sensor to control the light

By slightly modifying the previous script, it is possible to add a check to keep the Mi light OFF when there is already enough light (or daylight), or make it so that it turns ON at dusk.
Pi Light Sensor