-
Notifications
You must be signed in to change notification settings - Fork 2
/
remote.py
104 lines (84 loc) · 3.19 KB
/
remote.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
import time
from bluepy.btle import BTLEDisconnectError
from . import bt
class RemoteListener:
def event_battery(self, percent: int):
pass
def event_power(self, charging: bool):
pass
def event_button(self, button: int):
pass
def event_touchpad(self, data, pressed: bool):
pass
class SiriRemote:
__HANDLE_INPUT = 35
__HANDLE_BATTERY = 40
__HANDLE_POWER = 43
__TOUCH_EVENT = 50
__POWER_CHARGING = 171
__POWER_DISCHARGING = 175
__POWER_PLUGGED_IN = 187
BUTTON_RELEASED = 0
BUTTON_AIRPLAY = 1
BUTTON_VOLUME_UP = 2
BUTTON_VOLUME_DOWN = 4
BUTTON_PLAY_PAUSE = 8
BUTTON_SIRI = 16
BUTTON_MENU = 32
BUTTON_TOUCHPAD_2 = 64 # custom: 2 finger click
BUTTON_TOUCHPAD = 128
__lastButton = 0
def __init__(self, mac, listener: RemoteListener):
self.__device = bt.Device(mac)
self.__listener = listener
self.__setup()
def __setup(self):
try:
self.__device.connect()
self.__device.set_mtu(104)
self.__device.set_listener(self.__handle_notification)
self.__device.enable_notifications(0x0029) # battery service
self.__device.enable_notifications(0x002c) # power service
self.__device.enable_notifications(0x0024) # hid service
self.__device.write_characteristic(0x001d, b'\xAF') # "magic" byte
self.__device.loop()
except BTLEDisconnectError:
self.__listener.event_button(0) # release all keys
time.sleep(0.5)
self.__setup()
def __handle_notification(self, handle, data):
if handle == self.__HANDLE_BATTERY:
self.__handle_battery(data)
elif handle == self.__HANDLE_POWER:
self.__handle_power(data)
elif handle == self.__HANDLE_INPUT:
self.__handle_input(data)
def __handle_battery(self, data):
self.__listener.event_battery(data[0])
def __handle_power(self, data):
if data[0] == self.__POWER_CHARGING:
self.__listener.event_power(True)
elif data[0] == self.__POWER_DISCHARGING:
self.__listener.event_power(False)
def __handle_input(self, data):
button = data[1]
if data[0] == 2 and button & self.BUTTON_TOUCHPAD:
button += self.BUTTON_TOUCHPAD_2 - self.BUTTON_TOUCHPAD
if button != self.__lastButton:
self.__lastButton = button
self.__listener.event_button(button)
if len(data) >= 3 and data[2] == self.__TOUCH_EVENT:
self.__handle_touchpad(data)
def __handle_touchpad(self, data):
pressed = data[1] & self.BUTTON_TOUCHPAD
if len(data) == 13:
self.__listener.event_touchpad([self.__decode_finger(data[6:13])], pressed)
elif len(data) == 20:
self.__listener.event_touchpad([self.__decode_finger(data[6:13]),
self.__decode_finger(data[13:20])], pressed)
@staticmethod
def __decode_finger(data):
x = int((data[0] + 255 * (data[1] & 7) - 230) / 15)
y = (data[2] if data[2] & 128 else data[2] + 255) - 188
p = data[5]
return x, y, p