-
Notifications
You must be signed in to change notification settings - Fork 5
/
tools.py
executable file
·145 lines (104 loc) · 3.86 KB
/
tools.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
from struct import pack, unpack
import logging
logger = logging.getLogger("lifx_packet_tools")
"""
LiFX packet generator
Author: Petr Klus
"""
MESSAGE_SET_COLOR = 102
MESSAGE_SET_POWER = 117
MESSAGE_SET_COLOR_ZONES = 501
DURATION = 100
NO_APPLY = 0
APPLY = 1
APPLY_ONLY = 2
def gen_packet_universal(seq_num, message_type, payload):
# size
#packet = b"\x31\x00"
# binary field
packet = b"\x00\x34"
# source
packet += b"\x00\x00\x00\x00"
# frame address
packet += b"\x00\x00\x00\x00\x00\x00\x00\x00"
# reserved section
packet += b"\x00\x00\x00\x00\x00\x00" # NOQA
# we actually want 6 bits of padding and 2 bits of 1s,
# res_required and ack_required
packet += pack(">B", 3)
packet += pack("<B", seq_num) # sequence number
# protocol header
packet += b"\x00\x00\x00\x00\x00\x00\x00\x00" # padding
packet += pack("<H", message_type) # type
packet += b"\x00\x00" # padding
# payload
packet += payload
# finally, calculate size adjusting for the size information itself
packet = pack("<H", len(packet)+2) + packet + b"\x00"
return packet
def gen_packet(hue, sat, bri, kel, seq_num):
if hue < 0 or hue > 360:
raise Exception("Invalid hue: 0-360")
if sat < 0 or sat > 100:
raise Exception("Invalid sat: 0-100")
if bri < 0 or bri > 100:
raise Exception("Invalid bri: 0-100")
if kel < 2500 or kel > 9000:
raise Exception("Invalid kel: 2500-9000")
def calc_hue(hue):
return int(hue / 360.0 * 65535) # degrees
def calc_sat(sat):
return int(sat / 100.0 * 65535) # percentage
def calc_bri(bri):
return int(bri / 100.0 * 65535) # percentage
payload = b"\x00"
payload += pack("<H", calc_hue(hue))
payload += pack("<H", calc_sat(sat))
payload += pack("<H", calc_bri(bri))
payload += pack("<H", int(kel))
transition_time = pack("<L", DURATION)
payload += transition_time
return gen_packet_universal(seq_num, MESSAGE_SET_COLOR, payload)
def get_power_packet(seq_num, power_state):
if type(power_state) != type(True):
raise Exception("Invalid power state")
if power_state:
payload = pack(">H", 65535) # 1 - switched on
else:
payload = pack(">H", 0) # 0 - switched off
payload += pack("<L", DURATION) # duration
return gen_packet_universal(seq_num, MESSAGE_SET_POWER, payload)
def get_colour_zones_packet(start_index, end_index,
hue, sat, bri, kel, apply_changes, seq_num):
if start_index < 0 or start_index > 255:
raise Exception("Invalid start_index: 0-255")
if end_index < 0 or end_index > 255:
raise Exception("Invalid end_index: 0-255")
if start_index > end_index:
raise Exception("Invalid end_index: needs to be < start_index")
if hue < 0 or hue > 360:
raise Exception("Invalid hue: 0-360")
if sat < 0 or sat > 100:
raise Exception("Invalid sat: 0-100")
if bri < 0 or bri > 100:
raise Exception("Invalid bri: 0-100")
if kel < 2500 or kel > 9000:
raise Exception("Invalid kel: 2500-9000")
if apply_changes not in [0, 1, 2]:
raise Exception("Invalid apply_changes, allowed: 0, 1 or 2")
def calc_hue(hue):
return int(hue / 360.0 * 65535) # degrees
def calc_sat(sat):
return int(sat / 100.0 * 65535) # percentage
def calc_bri(bri):
return int(bri / 100.0 * 65535) # percentage
payload = pack("<B", start_index)
payload += pack("<B", end_index)
payload += pack("<H", calc_hue(hue))
payload += pack("<H", calc_sat(sat))
payload += pack("<H", calc_bri(bri))
payload += pack("<H", int(kel))
payload += pack("<L", DURATION) # duration
payload += pack("<B", apply_changes) # apply_changes
logger.debug("test")
return gen_packet_universal(seq_num, MESSAGE_SET_COLOR_ZONES, payload)