# -*- coding: utf-8 -*- import argparse import asyncio import logging import struct import time from bleak import BleakClient, BleakScanner from bleak.backends.characteristic import BleakGATTCharacteristic from bleak.uuids import normalize_uuid_str from ble_interface import ble_interface import dearpygui.dearpygui as dpg import myUUIDs from ble_interface import ble_interface logger = logging.getLogger(__name__) loop: asyncio.AbstractEventLoop device: ble_interface current_meas = {} max_current = 0 start_time = None def clear_plot(sender, app_data): logger.info("clear") global current_meas global start_time global max_current for d in current_meas: current_meas[d] = [] start_time = None max_current = 0 def on_connect_handler(device: ble_interface): device.subscribe_to(device.CURRENT) device.subscribe_to(device.RANGE, normalize_uuid_str(myUUIDs.ELECTRIC_CURRENT_RANGE_CHAR)) loop.create_task(update_conf_values()) async def update_conf_values(): refresh_rate = await device.get_refresh_delay() dpg.set_value("refresh delay", refresh_rate) zero_cali_nsamp = await device.get_zero_cali_nsamp() dpg.set_value("zero_nsamp", zero_cali_nsamp) auto_range = await device.get_auto_range() dpg.set_value("auto_range", auto_range) range = await device.get_range() dpg.set_value("range", range) def current_meas_handler(device: ble_interface, input_handle: int, newval: int): value = newval handle = input_handle logger.info("%s: %f", handle, value * 1.0e-6) global start_time global current_meas if(start_time is None): start_time = time.monotonic_ns() start_time += 1 if(not handle in current_meas): logger.info("%d %s", handle, current_meas) current_meas[handle] = [] dpg.add_line_series([], [], label=f"{handle}", parent="y_axis", tag=f"serie{handle}") current_meas[handle].append(((time.monotonic_ns() - start_time) * 1e-9, value)) dpg.set_value(f"serie{handle}", [ [v[0] for v in current_meas[handle]], [v[1] for v in current_meas[handle]] ]) dpg.fit_axis_data("x_axis") # dpg.fit_axis_data("y_axis") global max_current max_current = max(max_current, newval) dpg.set_axis_limits("y_axis", 0., 1.1 * max_current) txt = "" for h in current_meas: if(len(current_meas[h]) == 0): continue txt += f"{h} : {current_meas[h][-1][1]} | " dpg.set_value("last_current_values", txt) def range_changed_handler(device: ble_interface, val: int): dpg.set_value("range", val) def update_refresh_rate(sender, app_data): logger.info("refresh rate %d", app_data) device.update_refresh_delay(app_data) def update_zero_nsamp(sender, app_data): logger.info("nsamp %d", app_data) device.update_zero_cali_nsamp(app_data) def set_auto_range(sender, app_data): logger.info("auto range %d", app_data) device.update_auto_range(app_data) def set_range(sender, app_data): logger.info("set range %d", app_data) device.update_range(app_data) async def init_gui(): dpg.create_context() dpg.create_viewport() dpg.setup_dearpygui() with dpg.window(label="Controls", pos = [0, 0], width = 200, height = dpg.get_viewport_height()): dpg.add_button(label="Connect", callback=device.connect) dpg.add_input_int(label="Refresh Delay", callback=update_refresh_rate, on_enter=True, tag="refresh delay") dpg.add_button(label="Zero", callback=device.zero_cali) dpg.add_input_int(label="Zero nb sample", callback=update_zero_nsamp, on_enter=True, tag="zero_nsamp") dpg.add_button(label="Reset offsets", callback=device.reset_offsets) dpg.add_checkbox(label="Auto-range", callback=set_auto_range, tag="auto_range") dpg.add_input_int(label="Range", callback=set_range, on_enter=True, tag="range") with dpg.window(label="Graphs", pos = [200, 0], width = dpg.get_viewport_width()-200, height = dpg.get_viewport_height()): dpg.add_button(label="Clear", callback=clear_plot) dpg.add_text(label="Current", tag="last_current_values") with dpg.plot(label="Current", width = -1, height = -1): dpg.add_plot_legend() dpg.add_plot_axis(dpg.mvXAxis, label="x", tag="x_axis") dpg.add_plot_axis(dpg.mvYAxis, label="y", tag="y_axis") dpg.set_axis_limits_auto("x_axis") # dpg.set_axis_limits_auto("y_axis") dpg.show_viewport() while dpg.is_dearpygui_running(): dpg.render_dearpygui_frame() await asyncio.sleep(0) dpg.destroy_context() if __name__ == "__main__": logging.basicConfig( level="INFO", format="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s", ) loop = asyncio.get_event_loop() device = ble_interface("84:F7:03:1B:C6:A2", loop, logger) device.add_callback(device.ON_CONNECT, on_connect_handler) device.add_callback(device.CURRENT, current_meas_handler) device.add_callback(device.RANGE, range_changed_handler) loop.create_task(init_gui()) loop.run_forever()