-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.py
240 lines (165 loc) · 6.05 KB
/
app.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#!/usr/bin/env python3
import dbus
import dbus.exceptions
import dbus.mainloop.glib
import dbus.service
try:
from gi.repository import GObject # python3
except ImportError:
import gobject as GObject # python2
from ble import (
Advertisement,
Characteristic,
Service,
Application,
find_adapter,
Descriptor,
GATT_CHRC_IFACE,
)
import array
MainLoop = None
try:
from gi.repository import GLib
MainLoop = GLib.MainLoop
except ImportError:
import gobject as GObject
MainLoop = GObject.MainLoop
mainloop = None
def str_to_dbusarray(word):
"""Helper function to represent Python string as D-Dbus Byte array"""
return dbus.Array([dbus.Byte(ord(letter)) for letter in word], 'y')
BLUEZ_SERVICE_NAME = "org.bluez"
GATT_MANAGER_IFACE = "org.bluez.GattManager1"
LE_ADVERTISEMENT_IFACE = "org.bluez.LEAdvertisement1"
LE_ADVERTISING_MANAGER_IFACE = "org.bluez.LEAdvertisingManager1"
class InvalidArgsException(dbus.exceptions.DBusException):
_dbus_error_name = "org.freedesktop.DBus.Error.InvalidArgs"
class NotSupportedException(dbus.exceptions.DBusException):
_dbus_error_name = "org.bluez.Error.NotSupported"
class NotPermittedException(dbus.exceptions.DBusException):
_dbus_error_name = "org.bluez.Error.NotPermitted"
class InvalidValueLengthException(dbus.exceptions.DBusException):
_dbus_error_name = "org.bluez.Error.InvalidValueLength"
class FailedException(dbus.exceptions.DBusException):
_dbus_error_name = "org.bluez.Error.Failed"
class BLEService(Service):
"""
Dummy test service that provides characteristics and descriptors that
exercise various API functionality.
"""
service_UUID = "12634d89-d598-4874-8e86-7d042ee07ba7"
def __init__(self, bus, index):
Service.__init__(self, bus, index, self.service_UUID, True)
self.add_characteristic(DemoCharacteristic(bus, 0, self))
class DemoCharacteristic(Characteristic):
uuid = "4116f8d2-9f66-4f58-a53d-fc7440e7c14e"
description = b"this is a BLE demo characteristic with read and notify"
def __init__(self, bus, index, service):
Characteristic.__init__(
self, bus, index, self.uuid, ["read", 'notify'], service,
)
self.notifying = False
self.count = 0
self.add_descriptor(CharacteristicUserDescriptionDescriptor(bus, 1, self))
def ReadValue(self, options):
value = bytearray('Read........string read from BLE--', encoding="utf8")
return value
def NotifyTimer_cb(self):
value = str_to_dbusarray('Notify........string notify from BLE, counter: ' + str(self.count))
self.count += 1
print('Notify value: ' + str(self.count))
self.PropertiesChanged(GATT_CHRC_IFACE, {'Value': value}, [])
return self.notifying
def StartNotifyTimer(self):
if not self.notifying:
return
print('start notify timer')
GLib.timeout_add(1000, self.NotifyTimer_cb)
def StartNotify(self):
if self.notifying:
print('Already notifying, nothing to do')
return
self.notifying = True
self.StartNotifyTimer()
def StopNotify(self):
if not self.notifying:
print('Not notifying, nothing to do')
return
self.notifying = False
self.StartNotifyTimer()
class BLEAdvertisement(Advertisement):
def __init__(self, bus, index):
Advertisement.__init__(self, bus, index, "peripheral")
self.add_manufacturer_data(
0xFFFF, [0x70, 0x74],
)
self.add_service_uuid(BLEService.service_UUID)
self.add_local_name("BLE_Demo")
self.include_tx_power = True
def register_ad_cb():
print("Advertisement registered")
def register_ad_error_cb(error):
print("Failed to register advertisement: " + str(error))
mainloop.quit()
class CharacteristicUserDescriptionDescriptor(Descriptor):
"""
Writable CUD descriptor.
"""
CUD_UUID = "2901"
def __init__(
self, bus, index, characteristic,
):
self.value = array.array("B", characteristic.description)
self.value = self.value.tolist()
Descriptor.__init__(self, bus, index, self.CUD_UUID, ["read"], characteristic)
def ReadValue(self, options):
return self.value
def WriteValue(self, value, options):
if not self.writable:
raise NotPermittedException()
self.value = value
def register_app_cb():
print("GATT application registered")
def register_app_error_cb(error):
print("Failed to register application: " + str(error))
mainloop.quit()
def main():
global mainloop
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
# get the system bus
bus = dbus.SystemBus()
# get the ble controller
adapter = find_adapter(bus)
if not adapter:
print("GattManager1 interface not found")
return
adapter_obj = bus.get_object(BLUEZ_SERVICE_NAME, adapter)
adapter_props = dbus.Interface(adapter_obj, "org.freedesktop.DBus.Properties")
# powered property on the controller to on
adapter_props.Set("org.bluez.Adapter1", "Powered", dbus.Boolean(1))
# Get manager objs
service_manager = dbus.Interface(adapter_obj, GATT_MANAGER_IFACE)
ad_manager = dbus.Interface(adapter_obj, LE_ADVERTISING_MANAGER_IFACE)
advertisement = BLEAdvertisement(bus, 0)
obj = bus.get_object(BLUEZ_SERVICE_NAME, "/org/bluez")
app = Application(bus)
app.add_service(BLEService(bus, 2))
mainloop = MainLoop()
ad_manager.RegisterAdvertisement(
advertisement.get_path(),
{},
reply_handler=register_ad_cb,
error_handler=register_ad_error_cb,
)
print("Registering GATT application...")
service_manager.RegisterApplication(
app.get_path(),
{},
reply_handler=register_app_cb,
error_handler=[register_app_error_cb],
)
mainloop.run()
# ad_manager.UnregisterAdvertisement(advertisement)
# dbus.service.Object.remove_from_connection(advertisement)
if __name__ == "__main__":
main()