From c802802edcd6ff77be6367518487ed121ae3e196 Mon Sep 17 00:00:00 2001 From: "swkim01@gmail.com" Date: Tue, 26 Jan 2016 19:04:49 +0900 Subject: [PATCH] Update README.md and Add yeelight control program --- README.md | 75 +++++++++++++++++++++++++ yeelight.py | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 yeelight.py diff --git a/README.md b/README.md index 4cbf3e8..24f6a12 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,77 @@ # ble Bluetooth LE related programs + +- bledevice.py : basic class module for BLE devices +- blecomm.py : test program for communicating with an HM-10 BLE module +- blebulb.py : control program for Zengge BLE bulb +- yeelight.py : control program for Yeelight bedside lamp +- beacon : iBeacon and Google Eddystone related programs + +To use these programs, you have to install bluez and python pexpect module. + +The [bluez](http://www.elinux.org/RPi_Bluetooth_LE) (Bluetooth stack for linux) package can be installed by executing the following command: +```` +sudo apt-get install bluetooth blueman bluez python-gobject python-gobject-2 +```` + +The [pexpect](http://pexpect.readthedocs.org/en/stable/) module can be installed as follows: +```` +sudo pip install pexpect +```` + +# BLE bulb Protocols +##[Zengge Bluetooth LED](http://www.enledcontroller.com/picture/show/164.aspx) + + + + + + + + + + + + + + + + + + + + + + + + + +
기능명령특성 (핸들)데이터
전원쓰기0xffe9 (0x43)STX(cc) : 0x24 : ETX(33)
예) 켜기 : 0xcc2333, 끄기: 0xcc2433
RGB 등쓰기0xffe9 (0x43)STX(56) : R : G : B : 00 : f0 : ETX(aa)
예) 빨강 : 0x56ff000000f0aa
노랑 : 0x56ffff0000f0aa, 파랑: 0x560000ff00f0aa
Warm 등쓰기0xffe9 (0x43)STX(56) : 00 00 00 : 밝기 : 0f : ETX(aa)
예) 0x56000000ff0faa
모드쓰기0xffe9 (0x43)STX(bb) : 모드(25-38) : 속도(01-FF) : ETX(44)
예) 7가지 색으로 변화(모드=0x25) : 0xbb250344
상태 획득쓰기 및 읽기0xffe9 (0x43)
0xffe4 (0x50)
STX(ef) : 01 : ETX(77) = 0xef0177
반환: STX(66) 15 전원 모드 20 속도 R G B 밝기 06 ETX(99)
66 15 23 41 20 00 ff ff ff 00 06 99
66 15 23 25 20 05 ff ff ff 00 06 99 모드 (0x25)
66 15 23 41 20 00 00 00 00 ff 06 99 Warm
+ +##[Yeelight Bedside Lamp](http://item.mi.com/1152300006.html) + + + + + + + + + + + + + + + + + + + + + + + + + +
기능명령특성 (핸들)데이터
인증쓰기 및 읽기0xaa7d3f34 (0x12)STX(43) : CMD(0x67) : ON(0x02) : ETX(00)\*15 - 총 18B
반환: STX(43) : CMD(0x63) : ON(0x02) : ETX(00)
전원쓰기0xaa7d3f34 (0x12)STX(43) : CMD(0x40) : ON(0x01)|OFF(0x02) : ETX(00)\*15 - 총 18B
예) 켜기 : 0x434001000000000000000000000000000000
끄기: 0x434002000000000000000000000000000000
RGB 등쓰기0xaa7d3f34 (0x12)STX(43) : CMD(0x41) : R : G : B : 00 : 65 : ETX(00)\*11
예) 빨강 : 0x4341ff000000650000000000000000000000
Warm 등쓰기0xaa7d3f34 (0x12)STX(43) : CMD(0x43) ; 색(2B, 1700~6500) : 65 : ETX(00)\*13
예) 0x43430400650000000000000000000000
밝기쓰기0xaa7d3f34 (0x12)STX(43) : CMD(0x42) : 밝기 : ETX(00)*15
밝기 범위는 1 ~ 100
예) 0x434263000000000000000000000000000000
diff --git a/yeelight.py b/yeelight.py new file mode 100644 index 0000000..4c52a6b --- /dev/null +++ b/yeelight.py @@ -0,0 +1,158 @@ +from Tkinter import * +from tkColorChooser import askcolor +import colorsys +import math, sys, time +from bledevice import scanble, BLEDevice + +bulb = None +WRITE_CHAR_UUID = "aa7d3f34" #-2d4f-41e0-807f-52fbf8cf7443" + +COMMAND_STX = "43" +COMMAND_ETX = "00" + +AUTH_CMD = "67" +AUTH_ON = "02" + +POWER_CMD = "40" +POWER_ON = "01" +POWER_OFF = "02" + +COLOR_CMD = "41" +RGB_MODE = "65" + +BRIGHT_CMD = "42" + +COLORTEMP_CMD = "43" +TEMP_MODE = "65" + +COLORFLOW_CMD = "4a" + +class ConnectPanel(Frame): + def __init__(self, app): + Frame.__init__(self, app) + self.scanb = Button(self, text="Scan", command=self.scan) + self.bl = StringVar() + self.bles = OptionMenu(self, self.bl, ()) + self.connb = Button(self, text="Connect", command=self.connect) + + self.scanb.pack(side=LEFT) + self.bles.pack(side=LEFT) + self.connb.pack(side=RIGHT) + + def scan(self): + bllist = scanble(timeout=2) + print bllist + if len(bllist) != 0: + self.bl.set(bllist[0]['addr']) + menu = self.bles['menu'] + menu.delete(0, 'end') + for bl in bllist: + menu.add_command(label=bl, command=lambda v=bl: self.bl.set(v['addr'])) + + def connect(self): + global bulb + bulb = BLEDevice(self.bl.get()) + time.sleep(0.1) + bulb.writereq(bulb.getvaluehandle(WRITE_CHAR_UUID), COMMAND_STX+AUTH_CMD+AUTH_ON+COMMAND_ETX*15) + +class PowerPanel(Frame): + def __init__(self, app): + Frame.__init__(self, app) + self.powerl = Label(self, text="Power") + self.onb = Button(self, text="On", command=self.poweron) + self.offb = Button(self, text="Off", command=self.poweroff) + + self.powerl.pack(side=LEFT) + self.offb.pack(side=RIGHT) + self.onb.pack(side=RIGHT) + + def poweron(self): + global bulb + bulb.writecmd(bulb.getvaluehandle(WRITE_CHAR_UUID), COMMAND_STX+POWER_CMD+POWER_ON+COMMAND_ETX*15) + + def poweroff(self): + global bulb + bulb.writecmd(bulb.getvaluehandle(WRITE_CHAR_UUID), COMMAND_STX+POWER_CMD+POWER_OFF+COMMAND_ETX*15) + +class RgbPanel(Frame): + def __init__(self, app): + Frame.__init__(self, app) + self.rgbl = Label(self, text="RGB") + self.color = ((255, 255, 255), '#ffffff') + self.selectb = Button(self, text="Select", command=self.getcolor) + self.coll = Label(self, text=" ", bg="#FFFFFF") + self.setb = Button(self, text="Set", command=self.setrgb) + + self.rgbl.pack(side=LEFT) + self.setb.pack(side=RIGHT) + self.coll.pack(side=RIGHT) + self.selectb.pack(side=RIGHT) + + def getcolor(self): + self.color = askcolor() + print "color is ", self.color + self.coll.configure(bg=self.color[1]) + + def setrgb(self): + global bulb + bulb.writecmd(bulb.getvaluehandle(WRITE_CHAR_UUID), COMMAND_STX+COLOR_CMD+self.color[1][1:]+"00"+RGB_MODE+COMMAND_ETX*11) + +class BrightnessPanel(Frame): + def __init__(self, app): + Frame.__init__(self, app) + self.brightl = Label(self, text="Brightness") + self.value = DoubleVar() + self.value.set(1.0) + self.scale = Scale(self, variable=self.value, from_=0.0, to=1.0, resolution=0.01, orient=HORIZONTAL) + self.setb = Button(self, text="Set", command=self.setvalue) + + self.brightl.pack(side=LEFT) + self.setb.pack(side=RIGHT) + self.scale.pack(side=RIGHT) + + def setvalue(self): + global bulb + bulb.writecmd(bulb.getvaluehandle(WRITE_CHAR_UUID), COMMAND_STX+BRIGHT_CMD+("%02x"%(self.value.get()*100))+COMMAND_ETX*15) + +class WarmPanel(Frame): + def __init__(self, app): + Frame.__init__(self, app) + self.warml = Label(self, text="Warm") + self.color = DoubleVar() + self.color.set(1.0) + self.scale = Scale(self, variable=self.color, from_=0.0, to=1.0, resolution=0.01, command=self.changecolor, orient=HORIZONTAL) + self.setb = Button(self, text="Set", command=self.setwarm) + + self.warml.pack(side=LEFT) + self.setb.pack(side=RIGHT) + self.scale.pack(side=RIGHT) + + def changecolor(self, v): + value = self.color.get()*255 + color = "#FFFF%02x" % (value) + self.scale.configure(bg=color) + + def setwarm(self): + global bulb + bulb.writecmd(bulb.getvaluehandle(WRITE_CHAR_UUID), COMMAND_STX+COLORTEMP_CMD+("%04x"%(1700+self.color.get()*4800))+TEMP_MODE+COMMAND_ETX*13) + +if __name__ == "__main__": + tk = Tk() + tk.title("Yeelight Bedside Lamp") + + connectp = ConnectPanel(tk) + connectp.pack() + powerp = PowerPanel(tk) + powerp.pack(fill="both") + rgbp = RgbPanel(tk) + rgbp.pack(fill="both") + brightp = BrightnessPanel(tk) + brightp.pack(fill="both") + warmp = WarmPanel(tk) + warmp.pack(fill="both") + + def shutdown(): + tk.destroy() + + tk.protocol("WM_DELETE_WINDOW", shutdown) + tk.mainloop()