Created
February 17, 2018 17:54
-
-
Save cava/5628289fa2bd804aa5db8185729d9741 to your computer and use it in GitHub Desktop.
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
# 'Lunvon Smart LED Bulb' bluetooth reverse engineering | |
import bluetooth | |
from string import hexdigits | |
from time import sleep | |
LAMP_ADDR = "f4:4e:fd:00:00:00" | |
LAMP_UUID = "00001101-0000-1000-8000-00805f9b34fb" | |
LAMP_LOGIN = "3031323334353637" # '01234567' | |
CMD_BASE = "01fe000053831000" | |
CMD_TURNON = "0000000050ff0000" | |
CMD_TURNOFF = "0000000050000000" | |
# RGB: BASE + "GGBBRR0050000000" where GG is green hex, etc. | |
# Bluetooth connection socket | |
btsock = None | |
def bt_send(data, debug=False): | |
cleanPayload = data.replace(":", "") | |
if debug: | |
print("> ", cleanPayload) | |
try: | |
btsock.send(bluetooth.binascii.unhexlify(cleanPayload)) | |
except bluetooth.btcommon.BluetoothError as e: | |
print("! lamp disconnected") | |
lamp_connect() | |
def bt_read(n, debug=False): | |
d = bluetooth.binascii.hexlify(btsock.recv(n)) | |
if debug: | |
print("< ", str(d)) | |
return d | |
def lamp_turnon(): | |
bt_send(CMD_BASE + CMD_TURNON) | |
def lamp_turnoff(): | |
bt_send(CMD_BASE + CMD_TURNOFF) | |
def lamp_setrgb(rgb): | |
assert len(rgb) == 6 | |
assert all(c in hexdigits for c in rgb) | |
hexR, hexG, hexB = rgb[0:2], rgb[2:4], rgb[4:6] | |
gbr = hexG + hexB + hexR + "0050000000" | |
bt_send(CMD_BASE + gbr) | |
def hsv2rgb(h,s,v): | |
assert 0 <= h < 360 | |
assert 0 <= s <= 1 | |
assert 0 <= v <= 1 | |
c = s*v | |
x = c * (1 - abs((h/60) % 2 - 1)) | |
m = v - c | |
r = g = b = 0 | |
if 0 <= h < 60: | |
r, g = c, x | |
elif 60 <= h < 120: | |
r, g = x, c | |
elif 120 <= h < 180: | |
g, b = c, x | |
elif 180 <= h < 240: | |
g, b = x, c | |
elif 240 <= h < 300: | |
r, b = x, c | |
else: | |
r, b = c, x | |
return [ (r+m)*255, (g+m)*255, (b+m)*255 ] | |
def lamp_sethsv(h,s,v): | |
r, g, b = hsv2rgb(h,s,v) | |
rgbStr = "%.2X" % r + "%.2X" % g + "%.2X" % b | |
lamp_setrgb(rgbStr) | |
def lamp_connect(rgbTest=False): | |
global btsock | |
services = [] | |
print("? searching for compatible devices ...") | |
# wait for the lamp to be avaible | |
while True: | |
services = bluetooth.find_service( | |
uuid=LAMP_UUID, address=LAMP_ADDR) | |
if len(services) > 0: break | |
print("? device not found, retrying in 5 seconds ...") | |
sleep(2) | |
lamp = services[0] | |
print("> lamp found [{}], connecting ...".format(LAMP_ADDR)) | |
btsock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) | |
btsock.connect((lamp['host'], lamp['port'])) | |
# Login | |
print("> lamp 'login' ...") | |
bt_send(LAMP_LOGIN) | |
sleep(0.5) | |
if rgbTest: | |
print("> RGB test") | |
lamp_setrgb("220000") | |
sleep(0.4) | |
lamp_setrgb("002200") | |
sleep(0.4) | |
lamp_setrgb("000022") | |
sleep(0.4) | |
def lamp_color_loop(): | |
print("> color loop ...") | |
while True: | |
for i in range(1, 360): | |
lamp_sethsv(i, 1, 1) | |
sleep(0.25) | |
if __name__ == "__main__": | |
lamp_connect(rgbTest=True) | |
lamp_color_loop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment