add serial readout. finish graph layout

This commit is contained in:
2025-04-22 22:14:43 +02:00
parent c81b2e3fbb
commit 58ebddcd48
7 changed files with 90 additions and 39 deletions

View File

@@ -5,7 +5,8 @@ Display display;
Adafruit_NAU7802 nau;
unsigned long _millis = 0;
int32_t val = 0;
bool goToSleep = False;
bool goToSleep = false;
#if BLE
BLEServer *pServer = NULL;
BLECharacteristic *millisCharacteristic = NULL;
@@ -127,6 +128,8 @@ void loop() {
}
val = nau.read();
Serial.print(millis()); Serial.print(","); Serial.println(val);
#if BLE
if (deviceConnected) {
// Send the sensor reading
@@ -148,7 +151,5 @@ void loop() {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
#else
Serial.print(millis()); Serial.print(","); Serial.println(val);
#endif
}

View File

@@ -1,6 +1,6 @@
import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import asyncio
@@ -20,19 +20,9 @@ class FilterDevApp(tk.Tk):
self.title("JannTers Filter Evaluation Tool")
# Create a frame for the plot and sliders
self.frame = tk.Frame(self)
self.frame.pack(side=tk.LEFT, fill=tk.BOTH)
# Create a figure for plotting
self.fig, self.ax = plt.subplots()
self.ax2 = self.ax.twinx()
self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame)
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH)
# Create a frame for sliders
self.toolbar = tk.Frame(self, width=200, padx=10)
self.toolbar.pack(side=tk.RIGHT, fill=tk.Y)
self.toolbar.pack(side=tk.LEFT)
# Device Settings
self.record_form = RecordForm(self.toolbar, self.record_data)
@@ -46,6 +36,16 @@ class FilterDevApp(tk.Tk):
self.data_stats = DataStats(self.toolbar, self.reset)
# Create a figure for plotting
self.frame = tk.Frame(self)
self.frame.pack(side=tk.RIGHT)
self.fig, self.ax = plt.subplots()
self.ax2 = self.ax.twinx()
self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame)
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH)
NavigationToolbar2Tk(self.canvas, self.frame)
def update_plot(self):
if self.filter is None:
return
@@ -61,19 +61,27 @@ class FilterDevApp(tk.Tk):
# Generate data
x = df['timestamps']
y1 = df['weights']
# y1_g = df['calib_weights']
# y2 = df['filtered']
y2 = df['filtered']
y2_g = df['filtered_calib']
# Plot the data
self.ax.plot(x, y1)
# self.ax.plot(x, y2)
self.ax.plot(x, y1, label="raw")
self.ax.plot(x, y2, label="filtered")
# self.ax2.plot(x, y1_g)
self.ax2.plot(x, y2_g, label="filtered", color='green')
self.ax2.set_ylabel("Weight", color="green")
self.ax.set_xlabel("Time in ms")
self.ax.set_ylabel("Raw Weight")
self.ax.grid()
self.ax.legend(loc='upper left')
self.ax2.yaxis.set_label_position("right")
self.ax2.yaxis.tick_right()
self.ax2.legend(loc='lower right')
# self.ax2.plot(x, y1_g)
self.ax2.plot(x, y2_g, color="orange")
self.fig.tight_layout()
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH)
# Draw the updated plot
self.canvas.draw()

View File

@@ -3,4 +3,4 @@ SERVICE_UUID = "9f0dfdb2-e978-494c-8f15-68dbe8d28672"
MILLIS_UUID = "abb92561-a809-453c-8c7c-71d3fff5b86e"
WEIGHT_UUID = "123e4567-e89b-12d3-a456-426614174000"
DEFAULT_CALIB = 104167.17
DEFAULT_CALIB = 307333.83

View File

@@ -32,6 +32,10 @@ class Filter:
def __call__(self) -> pd.DataFrame:
calib_factor = 100. / float(self.calib_entry.get())
df = self.device.data
df = df[df['weights'] < 10e9]
df['timestamps'] -= df['timestamps'].min()
df['filtered'], df['filtered_calib'] = self.filter(df, calib_factor)
df['calib_weights'] = df['weights'] * calib_factor
return df

View File

@@ -2,8 +2,8 @@ from bleak import BleakClient, BleakScanner
import pandas as pd
from tkinter.ttk import Entry
from tkinter.messagebox import showerror, showinfo
import asyncio
from time import time
from serial import Serial
from ..config import MILLIS_UUID, WEIGHT_UUID
@@ -27,7 +27,12 @@ class Device:
self.weights = []
async def connect(self):
self.device = await BleakScanner.find_device_by_name(self.device_name.get())
device_name = self.device_name.get()
if device_name.startswith('/dev'):
self.device = device_name
else:
self.device = await BleakScanner.find_device_by_name(self.device_name.get())
return self.device is not None
@@ -35,26 +40,51 @@ class Device:
self.device = None
async def read_values(self, duration):
duration = int(duration)
if not await self.connect():
showerror("Record Data", f"Device {self.device_name.get()} not found!")
return
self.clear_data()
async with BleakClient(self.device.address) as client:
showinfo("Recording Data", f"Recording data for {duration} seconds.")
if isinstance(self.device, str):
self._read_values_serial(duration)
else:
await self._read_values_ble(duration)
def _read_values_serial(self, duration):
with Serial(self.device, baudrate=115200) as ser:
showinfo("Record Data", f"Recording data for {duration} seconds.")
time_start = time()
time_passed = 0
while time_passed < duration:
millis = await client.read_gatt_char(MILLIS_UUID)
millis = int.from_bytes(millis, byteorder='little') # Adjust based on your data format
weight = await client.read_gatt_char(WEIGHT_UUID)
weight = int.from_bytes(weight, byteorder='little') # Adjust based on your data format
line = ser.readline()
_timestamp, _raw_weight = line.decode('utf-8').split(',')
self.timestamps.append(millis)
self.weights.append(weight)
self.timestamps.append(int(_timestamp))
self.weights.append(int(_raw_weight))
time_passed = time() - time_start
async def _read_values_ble(self, duration):
self.clear_data()
try:
async with BleakClient(self.device.address) as client:
showinfo("Record Data", f"Recording data for {duration} seconds.")
time_start = time()
time_passed = 0
while time_passed < duration:
millis = await client.read_gatt_char(MILLIS_UUID)
millis = int.from_bytes(millis, byteorder='little') # Adjust based on your data format
weight = await client.read_gatt_char(WEIGHT_UUID)
weight = int.from_bytes(weight, byteorder='little') # Adjust based on your data format
self.timestamps.append(millis)
self.weights.append(weight)
time_passed = time() - time_start
except:
showerror("Record Data", f"Client could not be started for {self.device_name.get()}: {self.device.address}.")
def clear_data(self):
self.timestamps = []

View File

@@ -3,17 +3,24 @@ from tkinter import ttk
from ..slider import Slider
from serial.tools import list_ports
class RecordForm(tk.Frame):
def __init__(self, master, record_command, **kwargs):
super().__init__(master, **kwargs)
self.device_label = ttk.Label(self, text="Device Name:")
# get serial ports
serials = [d.device for d in list_ports.grep('usbmodem')]
devices = serials + ["Smaage"]
default_record_len = 10 if len(serials) > 0 else 30
self.device_label = ttk.Label(self, text="Device:")
self.device_label.pack(pady=10)
self.device_name = ttk.Entry(self)
self.device_name.insert(0, "Smaage") # Set default value
self.device_name = ttk.Combobox(self, values=devices)
self.device_name.set(devices[0])
self.device_name.pack()
self.record_time = Slider(self, "Record Time:", 10, 30, 10, lambda: None)
self.record_time = Slider(self, "Record Time:", 10, 60, default_record_len, lambda: None)
self.record_time.pack(pady=10)
self.record_button = ttk.Button(self, text="Record Data", command=record_command)
self.record_button.pack(pady=10)

View File

@@ -3,3 +3,4 @@ bleak
pandas
tqdm
numpy
pyserial