-
Notifications
You must be signed in to change notification settings - Fork 2
/
magichue.py
152 lines (119 loc) · 4.4 KB
/
magichue.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/python3
import sys
import socket
import json
from argparse import ArgumentParser
def add_checksum(values):
checksum = int(hex(sum(values) & 0xff), 16)
values.append(checksum)
return values
def get_status(ip):
try:
data = bytearray(process_raw('81:8a:8b:96'))
s = socket.socket()
s.settimeout(5)
s.connect((ip,5577))
s.send(data)
response = s.recvfrom(1024)
s.close()
response = [hex(s).replace('0x', '') for s in response[0]]
response = [ '0'+s if len(s) == 1 else s for s in response]
return response
except:
print_error("Could not get the bulb's status")
return None
def get_version(ip):
try:
data = bytearray(process_raw('48:46:2d:41:31:31:41:53:53:49:53:54:48:52:45:41:44')) #HF-A11ASSISTHREAD
s = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
s.settimeout(5)
s.sendto(data, (ip,48899))
response = s.recvfrom(1024)
s.close()
msg = response[0].decode('utf-8')
version = msg.split(',')
return version[2]
except:
print_error("Could not get the bulb's version")
return None
def send(ip, values):
try:
get_version(ip)
s = socket.socket()
s.settimeout(5)
s.connect((ip, 5577))
s.send(bytearray(add_checksum(values)))
s.close()
out = {"success":True}
print(json.dumps(out))
return
except:
print_error("Could not send the message to the bulb")
def process_raw(raw):
raw = raw.split(':')
values = ['0x' + s for s in raw]
values = [int(v,16) for v in values]
return values
def process_rgb(rgb, version):
rgb = rgb.split(',')
if len(rgb) < 3: print_error('Must have three color values (0-255) for R,G,B')
values = [int(v) for v in rgb]
values.insert(0,49) # add header
# this version has an extra zero in the body
if version == "AK001-ZJ2101":
values.extend([0])
values.extend([0,240,15]) # add tail
return values
def process_power(power):
if power == 'on':
return process_raw('71:23:0f')
if power == 'off':
return process_raw('71:24:0f')
def print_error(message):
out = {"success":False, "error":message}
print(json.dumps(out))
sys.exit()
def Main(args):
parser = ArgumentParser()
parser.add_argument("-ip", help="provide the IP for the lightbulb; i.e. -ip 192.168.2.2")
parser.add_argument("-raw", help="accept colon separated raw hex string; i.e. -raw 71:23:0f")
parser.add_argument("-rgb", help="accept comma separated rgb values; i.e. -rgb 100,155,75")
parser.add_argument("-warm", help="accept value of warm white (0-255); i.e. -warm 150")
parser.add_argument("-cool", help="accept value of cool white (0-255); i.e. -cool 150")
parser.add_argument("-power", help="accept 'on' or 'off'; i.e. -power on")
parser.add_argument("-status", help="get the bulb's status", action='store_true')
parsed_args = parser.parse_args()
if parsed_args.ip is None:
print_error('Must provide IP.')
if parsed_args.status is True:
status = get_status(parsed_args.ip)
power = status[2]
power = 'on' if power == '23' else power
power = 'off' if power == '24' else power
rgb = status[6:9]
for i,c in enumerate(rgb):
rgb[i] = int('0x'+c, 16)
warm = int('0x'+status[9], 16)
out = {"power" : power, "rgb" : rgb, "warm" : warm}
print(json.dumps(out))
return
if parsed_args.raw is not None:
values = process_raw(parsed_args.raw)
if parsed_args.rgb is not None:
version = get_version(parsed_args.ip)
if version is None: sys.exit()
values = process_rgb(parsed_args.rgb, version)
if parsed_args.warm is not None:
warm = hex(int(parsed_args.warm)).replace('0x','')
values = process_raw('31:00:00:00:'+warm+':0f:0f')
if parsed_args.cool is not None:
cool = hex(int(parsed_args.cool)).replace('0x','')
values = process_raw('31:00:00:00:00:'+cool+':0f')
if parsed_args.power is not None:
values = process_power(parsed_args.power)
if 'values' in locals():
send(parsed_args.ip, values)
else:
print_error('Must provide raw hex or rgb values.')
if __name__ == '__main__':
Main(sys.argv)