Skip to content

Commit

Permalink
Options and monitoring (#10)
Browse files Browse the repository at this point in the history
* Checkbox for using unique address

* Monitoring animation
  • Loading branch information
pauloesteban committed Aug 29, 2022
1 parent 582a00c commit ff872b6
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 15 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@ Cross-platform application to pair STEVAL-STLCX01V1 BLE devices to send sensor d

Download the compressed file accordingly from the [Releases](https://github.com/pauloesteban/sensor-tile-osc/releases) page.

### Windows

- Uncompress the `tar.gz` file on a folder of your preference.
- Add a Windows security [exclusion](https://support.microsoft.com/en-us/windows/add-an-exclusion-to-windows-security-811816c0-4dfd-af4a-47e4-c301afe13b26) to the `bridge` folder.
- Execute `bridge.exe`
### macOS

- Uncompress the `tar.xz` file on a folder of your preference.
- Uncompress the `tar.xz` file into a folder of your preference.
- Using a terminal application, remove quarantine from the `bridge.app`

```
sudo xattr -r -d com.apple.quarantine bridge.app
```

### Windows

- Uncompress the `tar.gz` file into a folder of your preference.
- Add a Windows security [exclusion](https://support.microsoft.com/en-us/windows/add-an-exclusion-to-windows-security-811816c0-4dfd-af4a-47e4-c301afe13b26) to the `bridge` folder.
- Execute `bridge.exe`

## References

- [MP730026 DMM BLE Tutorial using Python](https://www.element14.com/community/community/element14-presents/workbenchwednesdays/blog/2020/03/09/connecting-to-mp730026-ble-dmm-with-python-and-bleak)
Expand Down
58 changes: 49 additions & 9 deletions metabow_bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,16 @@ def __init__(self, loop): # Delete type hint when building on Windows
self.ports_frame.grid(column=0, row=0, padx=10, pady=10, sticky=tk.NW)
self.devices_frame = self.create_scanner_frame(self.root)
self.devices_frame.grid(column=1, row=0, padx=10, pady=10)
self.option_address = tk.StringVar()
self.option_address.set(0)
self.options_frame = self.create_options_frame(self.root)
self.options_frame.grid(column=0, row=1, padx=10, pady=10, sticky=tk.NW)
self.animation = "░▒▒▒▒▒▒▒▒▒"
self.monitoring_frame = self.create_monitoring_frame(self.root)
self.monitoring_frame.grid(column=1, row=1, padx=10, pady=10, sticky=tk.NW)
self.refresh_listbox = False
self.selected_devices_keys = []
self.is_notify_loop = True
self.is_notify_loop = False
self.is_destroyed = False
self.characteristic_uuid = "00E00000-0001-11E1-AC36-0002A5D5C51B"
self.device_name = "AM1V330"
Expand Down Expand Up @@ -76,8 +83,8 @@ def _instantiate_scanner(self):


def _instantiate_udp_client(self):
self.LOCAL_ADDRESS = "127.0.0.1"
self.udp_client = udp_client.SimpleUDPClient(self.LOCAL_ADDRESS, int(self.port0.get()))
localhost = "127.0.0.1"
self.udp_client = udp_client.SimpleUDPClient(localhost, int(self.port0.get()))


def on_exit(self):
Expand All @@ -99,6 +106,25 @@ def create_ports_frame(self, container):
return label_frame


def create_options_frame(self, container):
label_frame = ttk.Labelframe(container, text='Options', relief=tk.RIDGE)
label_frame.grid(row=0, column=0, sticky=tk.W)
self.address_checkbox = ttk.Checkbutton(label_frame, text="Use Device Identifier for OSC", variable=self.option_address)
self.address_checkbox.grid(row=0, column=0, sticky=tk.W)

return label_frame


def create_monitoring_frame(self, container):
label_frame = ttk.Labelframe(container, text='Monitoring', relief=tk.RIDGE)
label_frame.grid(row=0, column=0, sticky=tk.W)
self.monitoring_label = ttk.Label(label_frame, text="")
self.monitoring_label.grid(row=0, column=0, sticky=tk.W)
self.monitoring_label.state(['disabled'])

return label_frame


def items_selected(self, event):
selected_ix = self.devices_listbox.curselection()
selected_devices_keys = [self.devices_listbox.get(i) for i in selected_ix]
Expand Down Expand Up @@ -182,18 +208,23 @@ async def connect(self):
return
self.is_notify_loop = True
self.port0_spinbox.state(['disabled'])
self.address_checkbox.state(['disabled'])
self._instantiate_udp_client()
self.start_scan_button.state(['disabled'])
self.connect_button.state(['disabled'])
self.disconnect_button.state(['!disabled'])
self.devices_listbox.config(state=tk.DISABLED)
self.monitoring_label.state(['!disabled'])
self._create_csv_file()
await asyncio.gather(*(self.notify(i, device) for i, device in enumerate(self.selected_devices)))


async def notify(self, i, device):
async with BleakClient(device) as client:
await client.start_notify(self.characteristic_uuid, partial(self.notification_handler, i))
if self.option_address.get() == "0":
await client.start_notify(self.characteristic_uuid, partial(self.notification_handler, i))
elif self.option_address.get() == "1":
await client.start_notify(self.characteristic_uuid, partial(self.notification_handler, str(device.address)))
while self.is_notify_loop:
await asyncio.sleep(1.0)
await client.stop_notify(self.characteristic_uuid)
Expand All @@ -204,24 +235,30 @@ async def disconnect(self):
self.port0_spinbox.state(['!disabled'])
self.disconnect_button.state(['disabled'])
self.start_scan_button.state(['!disabled'])
self.address_checkbox.state(['!disabled'])
self.monitoring_label.state(['disabled'])
await asyncio.sleep(1.0)


def notification_handler(self, device_number:int, sender: int, data: bytearray):
def notification_handler(self, device_number: int | str, sender: int, data: bytearray):
"""Simple notification handler
"""
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S.%f")
address_raw = f"/{device_number}/raw"
address_quaternion = f"/{device_number}/quaternion"
address_sensor_frame = f"/{device_number}/motion_acceleration/sensor_frame"
join_array = bytearray_to_fusion_data(data)
self.model.tick(join_array[1:4], join_array[4:7], join_array[7:10])
self.udp_client.send_message(f"/{device_number}/raw", join_array)
quaternion = self.model.quaternion.elements.tolist()
self.udp_client.send_message(f"/{device_number}/quaternion", quaternion)
movement_accl = self.model.movement_acceleration.tolist()
self.udp_client.send_message(f"/{device_number}/motion_acceleration/sensor_frame", movement_accl)
self.udp_client.send_message(address_raw, join_array)
self.udp_client.send_message(address_quaternion, quaternion)
self.udp_client.send_message(address_sensor_frame, movement_accl)
row = [device_number, timestamp, *join_array[1:], *quaternion, *movement_accl]

with open(self.log_name, 'a', encoding='UTF8') as f:
writer = csv.writer(f)
writer.writerow([device_number, timestamp, *join_array[1:], *quaternion, *movement_accl])
writer.writerow(row)


def populate_devices(self):
Expand All @@ -243,6 +280,9 @@ async def show(self):
while not self.is_destroyed:
if self.refresh_listbox:
self.populate_devices()
if self.is_notify_loop:
self.monitoring_label["text"] = self.animation
self.animation = self.animation[-1] + self.animation[:-1]
self.root.update()
await asyncio.sleep(0.1)

Expand Down

0 comments on commit ff872b6

Please sign in to comment.