Skip to content

Commit c8882c4

Browse files
committed
Cleanup and documentation for first release
1 parent faeac39 commit c8882c4

File tree

13 files changed

+179
-128
lines changed

13 files changed

+179
-128
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Changelog
2+
All notable changes to this project will be documented in this file.
3+
4+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6+
7+
## [0.1.0] - 2021-07-24
8+
- First implementation with a basic example emulating a device exposing the Nordic UART Service.

README.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,28 @@
1-
# python_bluez_dbus_emulator
1+
# bluez_dbus_emulator
2+
3+
A simple set of libraries to allow emulating the behavior of a BlueZ
4+
Bluetooth device over DBus.
5+
6+
## Prerequisites
7+
8+
Before you begin, ensure you have met the following requirements:
9+
- [dbus_next](https://github.com/altdesktop/python-dbus-next)
10+
11+
## Installation
12+
13+
```
14+
pip3 install bluez_dbus_emulator
15+
```
16+
17+
## Usage
18+
19+
For usage instructions, just follow the examples provided in the `examples` folder.
20+
21+
## Contributors
22+
23+
Thanks to the following people who have contributed to this project:
24+
* [@Andrey1994](https://github.com/Andrey1994)
25+
26+
## License
27+
28+
This project is licensed under the terms of the [MIT Licence](LICENCE.md).

bluez_dbus_emulator/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from bluez_dbus_emulator.application import Application
1+
from bluez_dbus_emulator.emulator import Emulator
22
from bluez_dbus_emulator.adapter1 import Adapter1
33
from bluez_dbus_emulator.device1 import Device1
44
from bluez_dbus_emulator.gattservice1 import GattService1

bluez_dbus_emulator/adapter1.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,27 @@
1-
from dbus_next.aio import MessageBus
2-
from dbus_next.service import ServiceInterface, method, dbus_property, signal, PropertyAccess
3-
from dbus_next import Variant, DBusError
1+
from dbus_next.service import ServiceInterface, method, dbus_property, PropertyAccess
42

53
import asyncio
64
import random
75

6+
87
class Adapter1(ServiceInterface):
98
def __init__(self, bus, path):
109
self.bus = bus
1110
self.path = path
12-
super().__init__('org.bluez.Adapter1')
11+
super().__init__("org.bluez.Adapter1")
1312
self._discovering = False
1413
self._address = "00:00:00:00:00:00"
1514

1615
self._devices = []
1716

1817
def export(self):
19-
self.bus.export(f'/org/bluez/{self.path}', self)
18+
self.bus.export(f"/org/bluez/{self.path}", self)
2019

2120
def add_device(self, device):
2221
self._devices.append(device)
2322

2423
@method()
25-
def SetDiscoveryFilter(self, properties: 'a{sv}'):
24+
def SetDiscoveryFilter(self, properties: "a{sv}"):
2625
return
2726

2827
@method()
@@ -42,12 +41,11 @@ async def StopDiscovery(self):
4241
return
4342

4443
@dbus_property(access=PropertyAccess.READ)
45-
def Discovering(self) -> 'b':
44+
def Discovering(self) -> "b":
4645
return self._discovering
4746

4847
async def _update_discoverying(self, new_value: bool):
4948
await asyncio.sleep(random.uniform(0.5, 1.5))
5049
self._discovering = new_value
51-
self.emit_properties_changed({'Discovering': self._discovering})
50+
self.emit_properties_changed({"Discovering": self._discovering})
5251
print(f"Property changed: {self._discovering}")
53-

bluez_dbus_emulator/application.py

Lines changed: 0 additions & 16 deletions
This file was deleted.

bluez_dbus_emulator/device1.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
from dbus_next.aio import MessageBus
2-
from dbus_next.service import ServiceInterface, method, dbus_property, signal, PropertyAccess
3-
from dbus_next import Variant, DBusError
1+
from dbus_next.service import ServiceInterface, method, dbus_property, PropertyAccess
42

53
import asyncio
64
import random
75

6+
87
class Device1(ServiceInterface):
98
def __init__(self, bus, parent_path, mac_address="00:00:00:00:00:00"):
109
self.bus = bus
1110
self.path = f"{parent_path}/dev_{'_'.join(mac_address.split(':'))}"
12-
super().__init__('org.bluez.Device1')
11+
super().__init__("org.bluez.Device1")
1312
self._exported = False
1413
self._connected = False
1514
self._services_resolved = False
@@ -21,11 +20,10 @@ def __init__(self, bus, parent_path, mac_address="00:00:00:00:00:00"):
2120
self.__task_scanning_active = False
2221
self.__task_connected_active = False
2322

24-
2523
async def export(self):
2624
if not self._exported:
2725
await asyncio.sleep(random.uniform(0.5, 1.5))
28-
self.bus.export(f'/org/bluez/{self.path}', self)
26+
self.bus.export(f"/org/bluez/{self.path}", self)
2927
self._exported = True
3028

3129
def add_service(self, service):
@@ -37,14 +35,14 @@ def run_connected_task(self):
3735
async def task_scanning_start(self):
3836
await self.export()
3937
self.__task_scanning_active = True
40-
asyncio.ensure_future(self._task_scanning_run())
38+
asyncio.ensure_future(self._task_scanning_run())
4139

4240
def task_scanning_stop(self):
4341
self.__task_scanning_active = False
4442

4543
def task_connected_start(self):
4644
self.__task_connected_active = True
47-
asyncio.ensure_future(self._task_connected_run())
45+
asyncio.ensure_future(self._task_connected_run())
4846

4947
def task_connected_stop(self):
5048
self.__task_connected_active = False
@@ -54,14 +52,14 @@ async def _task_scanning_run(self):
5452
# Execute scanning tasks
5553
await self._update_rssi(random.uniform(-90, -60))
5654
if self.__task_scanning_active:
57-
asyncio.ensure_future(self._task_scanning_run())
55+
asyncio.ensure_future(self._task_scanning_run())
5856

5957
async def _task_connected_run(self):
6058
await asyncio.sleep(0.015)
6159
# Execute connected tasks
6260
self.run_connected_task()
6361
if self.__task_connected_active:
64-
asyncio.ensure_future(self._task_connected_run())
62+
asyncio.ensure_future(self._task_connected_run())
6563

6664
@method()
6765
async def Connect(self):
@@ -82,37 +80,36 @@ async def Disconnect(self):
8280
return
8381

8482
@dbus_property(access=PropertyAccess.READ)
85-
def Connected(self) -> 'b':
83+
def Connected(self) -> "b":
8684
return self._connected
8785

8886
@dbus_property(access=PropertyAccess.READ)
89-
def ServicesResolved(self) -> 'b':
87+
def ServicesResolved(self) -> "b":
9088
return self._services_resolved
9189

9290
@dbus_property(access=PropertyAccess.READ)
93-
def RSSI(self) -> 'n':
91+
def RSSI(self) -> "n":
9492
return self._rssi
9593

9694
@dbus_property(access=PropertyAccess.READ)
97-
def Name(self) -> 's':
95+
def Name(self) -> "s":
9896
return self._name
9997

10098
async def _update_connected(self, new_value: bool):
10199
await asyncio.sleep(random.uniform(0.5, 1.5))
102100
self._connected = new_value
103-
property_changed = {'Connected': self._connected}
101+
property_changed = {"Connected": self._connected}
104102
self.emit_properties_changed(property_changed)
105103
print(f"Property changed: {property_changed}")
106104

107105
async def _update_services_resolved(self, new_value: bool):
108106
await asyncio.sleep(random.uniform(0.0, 0.5))
109107
self._services_resolved = new_value
110-
property_changed = {'ServicesResolved': self._services_resolved}
108+
property_changed = {"ServicesResolved": self._services_resolved}
111109
self.emit_properties_changed(property_changed)
112110
print(f"Property changed: {property_changed}")
113111

114112
async def _update_rssi(self, new_value: int):
115113
self._rssi = int(new_value)
116-
property_changed = {'RSSI': self._rssi}
114+
property_changed = {"RSSI": self._rssi}
117115
self.emit_properties_changed(property_changed)
118-

bluez_dbus_emulator/emulator.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from dbus_next.service import ServiceInterface, method
2+
3+
4+
class Emulator(ServiceInterface):
5+
"""
6+
Entry point for the bluez dbus emulator. Provides programmatic
7+
control of the async application.
8+
"""
9+
10+
def __init__(self, bus):
11+
self.bus = bus
12+
super().__init__("emulator.bluez_dbus")
13+
14+
def export(self):
15+
self.bus.export("/", self)
16+
17+
@method()
18+
def Exit(self):
19+
"""
20+
Finishes the emulation session by disconnecting from dbus.
21+
"""
22+
self.bus.disconnect()
Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
1-
from dbus_next.aio import MessageBus
2-
from dbus_next.service import ServiceInterface, method, dbus_property, signal, PropertyAccess
3-
from dbus_next import Variant, DBusError
1+
from dbus_next.service import ServiceInterface, method, dbus_property, PropertyAccess
42

53
import asyncio
64
import random
75

6+
87
class GattCharacteristic1(ServiceInterface):
98
def __init__(self, bus, parent_path, id_num, uuid):
109
self.bus = bus
1110
self.path = f"{parent_path}/char{id_num:04x}"
12-
super().__init__('org.bluez.GattCharacteristic1')
11+
super().__init__("org.bluez.GattCharacteristic1")
1312
self._uuid = uuid
1413
self._value = bytes()
1514
self._notifying = False
1615
self._exported = False
1716

1817
def export(self):
1918
if not self._exported:
20-
self.bus.export(f'/org/bluez/{self.path}', self)
19+
self.bus.export(f"/org/bluez/{self.path}", self)
2120
self._exported = True
2221

2322
def update_value(self, new_value: bytes):
@@ -34,33 +33,33 @@ async def StopNotify(self):
3433
return
3534

3635
@method()
37-
def ReadValue(self, options: 'a{sv}') -> 'ay':
36+
def ReadValue(self, options: "a{sv}") -> "ay":
3837
return self._value
3938

4039
@method()
41-
def WriteValue(self, value: 'ay', options: 'a{sv}'):
40+
def WriteValue(self, value: "ay", options: "a{sv}"):
4241
self._update_value(value)
4342

4443
@dbus_property(access=PropertyAccess.READ)
45-
def Notifying(self) -> 'b':
44+
def Notifying(self) -> "b":
4645
return self._notifying
4746

4847
@dbus_property(access=PropertyAccess.READ)
49-
def UUID(self) -> 's':
48+
def UUID(self) -> "s":
5049
return self._uuid
5150

5251
@dbus_property(access=PropertyAccess.READ)
53-
def Value(self) -> 'ay':
52+
def Value(self) -> "ay":
5453
return self._value
5554

5655
def _update_value(self, new_value: bytes):
5756
self._value = new_value
5857
if self._notifying:
59-
property_changed = {'Value': self._value}
58+
property_changed = {"Value": self._value}
6059
self.emit_properties_changed(property_changed)
6160

6261
async def _update_notifying(self, new_value: bool):
6362
await asyncio.sleep(random.uniform(0.0, 0.2))
6463
self._notifying = new_value
65-
property_changed = {'Notifying': self._notifying}
66-
self.emit_properties_changed(property_changed)
64+
property_changed = {"Notifying": self._notifying}
65+
self.emit_properties_changed(property_changed)
Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,25 @@
1-
from dbus_next.aio import MessageBus
2-
from dbus_next.service import ServiceInterface, method, dbus_property, signal, PropertyAccess
3-
from dbus_next import Variant, DBusError
1+
from dbus_next.service import ServiceInterface, dbus_property, PropertyAccess
42

5-
import asyncio
6-
import random
73

84
class GattService1(ServiceInterface):
95
def __init__(self, bus, parent_path, id_num, uuid):
106
self.bus = bus
117
self.path = f"{parent_path}/service{id_num:04x}"
12-
super().__init__('org.bluez.GattService1')
8+
super().__init__("org.bluez.GattService1")
139
self._uuid = uuid
1410
self._exported = False
1511
self._characteristics = []
1612

1713
def export(self):
1814
if not self._exported:
19-
self.bus.export(f'/org/bluez/{self.path}', self)
15+
self.bus.export(f"/org/bluez/{self.path}", self)
2016
for char in self._characteristics:
2117
char.export()
2218
self._exported = True
23-
19+
2420
def add_characteristic(self, characteristic):
2521
self._characteristics.append(characteristic)
2622

2723
@dbus_property(access=PropertyAccess.READ)
28-
def UUID(self) -> 's':
29-
return self._uuid
24+
def UUID(self) -> "s":
25+
return self._uuid

0 commit comments

Comments
 (0)