-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update README.md and Add yeelight control program
- Loading branch information
Showing
2 changed files
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
<a id="Zengge BLE Protocol"></a> | ||
<table> | ||
<tr> | ||
<th scope="col">기능</th><th scope="col">명령</th><th scope="col">특성 (핸들)</th><th scope="col">데이터</th> | ||
</tr> | ||
<tr> | ||
<td>전원</td><td>쓰기</td><td>0xffe9 (0x43)</td> | ||
<td>STX(cc) : 0x24 : ETX(33)</br>예) 켜기 : 0xcc2333, 끄기: 0xcc2433</td> | ||
</tr> | ||
<tr> | ||
<td>RGB 등</td><td>쓰기</td><td>0xffe9 (0x43)</td> | ||
<td>STX(56) : R : G : B : 00 : f0 : ETX(aa)</br>예) 빨강 : 0x56ff000000f0aa</br>노랑 : 0x56ffff0000f0aa, 파랑: 0x560000ff00f0aa</td> | ||
</tr> | ||
<tr> | ||
<td>Warm 등</td><td>쓰기</td><td>0xffe9 (0x43)</td> | ||
<td>STX(56) : 00 00 00 : 밝기 : 0f : ETX(aa)</br>예) 0x56000000ff0faa</td> | ||
</tr> | ||
<tr> | ||
<td>모드</td><td>쓰기</td><td>0xffe9 (0x43)</td> | ||
<td>STX(bb) : 모드(25-38) : 속도(01-FF) : ETX(44)</br>예) 7가지 색으로 변화(모드=0x25) : 0xbb250344</td> | ||
</tr> | ||
<tr> | ||
<td>상태 획득</td><td>쓰기 및 읽기</td><td>0xffe9 (0x43)</br>0xffe4 (0x50)</td> | ||
<td>STX(ef) : 01 : ETX(77) = 0xef0177</br>반환: STX(66) 15 전원 모드 20 속도 R G B 밝기 06 ETX(99)</br>66 15 23 41 20 00 ff ff ff 00 06 99</br>66 15 23 25 20 05 ff ff ff 00 06 99 모드 (0x25)</br>66 15 23 41 20 00 00 00 00 ff 06 99 Warm </td> | ||
</tr> | ||
</table> | ||
|
||
##[Yeelight Bedside Lamp](http://item.mi.com/1152300006.html) | ||
<a id="Yeelight BLE Protocol"></a> | ||
<table> | ||
<tr> | ||
<th scope="col">기능</th><th scope="col">명령</th><th scope="col">특성 (핸들)</th><th scope="col">데이터</th> | ||
</tr> | ||
<tr> | ||
<td>인증</td><td>쓰기 및 읽기</td><td>0xaa7d3f34 (0x12)</td> | ||
<td>STX(43) : CMD(0x67) : ON(0x02) : ETX(00)\*15 - 총 18B</br>반환: STX(43) : CMD(0x63) : ON(0x02) : ETX(00)</td> | ||
</tr> | ||
<tr> | ||
<td>전원</td><td>쓰기</td><td>0xaa7d3f34 (0x12)</td> | ||
<td>STX(43) : CMD(0x40) : ON(0x01)|OFF(0x02) : ETX(00)\*15 - 총 18B</br>예) 켜기 : 0x434001000000000000000000000000000000</br>끄기: 0x434002000000000000000000000000000000</td> | ||
</tr> | ||
<tr> | ||
<td>RGB 등</td><td>쓰기</td><td>0xaa7d3f34 (0x12)</td> | ||
<td>STX(43) : CMD(0x41) : R : G : B : 00 : 65 : ETX(00)\*11</br>예) 빨강 : 0x4341ff000000650000000000000000000000</td> | ||
</tr> | ||
<tr> | ||
<td>Warm 등</td><td>쓰기</td><td>0xaa7d3f34 (0x12)</td> | ||
<td>STX(43) : CMD(0x43) ; 색(2B, 1700~6500) : 65 : ETX(00)\*13</br>예) 0x43430400650000000000000000000000</td> | ||
</tr> | ||
<tr> | ||
<td>밝기</td><td>쓰기</td><td>0xaa7d3f34 (0x12)</td> | ||
<td>STX(43) : CMD(0x42) : 밝기 : ETX(00)*15</br>밝기 범위는 1 ~ 100</br>예) 0x434263000000000000000000000000000000</td> | ||
</tr> | ||
</table> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() |