init
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
__pycache__
|
||||||
6
README.md
Normal file
6
README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Filter Dev App
|
||||||
|
|
||||||
|
App and small arduino code to develop an optimal filter algorithm.
|
||||||
|
|
||||||
|
## Algorithm
|
||||||
|
|
||||||
37
esp32_readout/display.cpp
Normal file
37
esp32_readout/display.cpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#include "display.h"
|
||||||
|
|
||||||
|
#include <Adafruit_SharpMem.h>
|
||||||
|
|
||||||
|
Display::Display() {
|
||||||
|
this->_display = new Adafruit_SharpMem(SHARP_SCK, SHARP_MOSI, SHARP_SS, DISPLAY_HEIGHT, DISPLAY_WIDTH);
|
||||||
|
|
||||||
|
this->mid_x = DISPLAY_WIDTH / 2;
|
||||||
|
this->mid_y = DISPLAY_HEIGHT / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::setup() {
|
||||||
|
// start & clear the display
|
||||||
|
this->_display->begin();
|
||||||
|
this->_display->clearDisplay();
|
||||||
|
this->_display->setRotation(2);
|
||||||
|
|
||||||
|
this->_display->setTextColor(BLACK, WHITE);
|
||||||
|
this->_display->setTextSize(FONT_SIZE);
|
||||||
|
this->_display->setFont(FONT);
|
||||||
|
|
||||||
|
this->print("Smaage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::print(const char* text) {
|
||||||
|
this->_display->clearDisplay();
|
||||||
|
this->_display->setCursor(12, this->mid_x);
|
||||||
|
this->_display->println(text);
|
||||||
|
this->_display->refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::print_weight(double val) {
|
||||||
|
this->_display->clearDisplay();
|
||||||
|
this->_display->setCursor(12, this->mid_x);
|
||||||
|
this->_display->printf("%.2f g", val);
|
||||||
|
this->_display->refresh();
|
||||||
|
}
|
||||||
25
esp32_readout/display.h
Normal file
25
esp32_readout/display.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
#ifndef DISPLAY_DEF
|
||||||
|
#define DISPLAY_DEF
|
||||||
|
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Adafruit_SharpMem.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "env.h"
|
||||||
|
|
||||||
|
class Display {
|
||||||
|
private:
|
||||||
|
Adafruit_SharpMem* _display;
|
||||||
|
|
||||||
|
int mid_x;
|
||||||
|
int mid_y;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Display();
|
||||||
|
void setup();
|
||||||
|
void print(const char* text);
|
||||||
|
void print_weight(double weight);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
67
esp32_readout/env.h
Normal file
67
esp32_readout/env.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#ifndef ENV
|
||||||
|
#define ENV
|
||||||
|
#include <BLEDevice.h>
|
||||||
|
#include <BLEUtils.h>
|
||||||
|
#include <BLEScan.h>
|
||||||
|
#include <BLEAdvertisedDevice.h>
|
||||||
|
|
||||||
|
#include <Adafruit_NAU7802.h>
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Fonts/FreeSans9pt7b.h>
|
||||||
|
|
||||||
|
/********************* NAU7802 ****************************/
|
||||||
|
|
||||||
|
#define LDO NAU7802_3V3
|
||||||
|
#define GAIN NAU7802_GAIN_128
|
||||||
|
#define SPS NAU7802_RATE_20SPS
|
||||||
|
|
||||||
|
/****************************** DISPLAY *******************/
|
||||||
|
|
||||||
|
// any pins can be used
|
||||||
|
#define SHARP_SCK 7
|
||||||
|
#define SHARP_MOSI 9
|
||||||
|
#define SHARP_SS 44
|
||||||
|
#define DISPLAY_HEIGHT 144
|
||||||
|
#define DISPLAY_WIDTH 168
|
||||||
|
|
||||||
|
#define BLACK 0
|
||||||
|
#define WHITE 1
|
||||||
|
|
||||||
|
#define FONT_SIZE 2
|
||||||
|
#define FONT &FreeSans9pt7b
|
||||||
|
|
||||||
|
/********************* BLE ********************************/
|
||||||
|
|
||||||
|
#define BLE true
|
||||||
|
#if BLE
|
||||||
|
#define SERVICE_UUID "9f0dfdb2-e978-494c-8f15-68dbe8d28672"
|
||||||
|
#define MILLIS_UUID "abb92561-a809-453c-8c7c-71d3fff5b86e"
|
||||||
|
#define WEIGHT_UUID "123e4567-e89b-12d3-a456-426614174000"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if GAIN == NAU7802_GAIN_1
|
||||||
|
#define CALIBRATION_FACTOR 100.0 / 424.47
|
||||||
|
|
||||||
|
#elif GAIN == NAU7802_GAIN_2
|
||||||
|
#define CALIBRATION_FACTOR 100.0 / 2457.96
|
||||||
|
|
||||||
|
#elif GAIN == NAU7802_GAIN_4
|
||||||
|
#define CALIBRATION_FACTOR 100.0 / 3622.82
|
||||||
|
|
||||||
|
#elif GAIN == NAU7802_GAIN_8
|
||||||
|
#define CALIBRATION_FACTOR 100.0 / 6630.74
|
||||||
|
|
||||||
|
#elif GAIN == NAU7802_GAIN_16
|
||||||
|
#define CALIBRATION_FACTOR 100.0 / 13179.24
|
||||||
|
|
||||||
|
#elif GAIN == NAU7802_GAIN_32
|
||||||
|
#define CALIBRATION_FACTOR 100.0 / 25955.84
|
||||||
|
|
||||||
|
#elif GAIN == NAU7802_GAIN_64
|
||||||
|
#define CALIBRATION_FACTOR 100.0 / 52865.63
|
||||||
|
|
||||||
|
#elif GAIN == NAU7802_GAIN_128
|
||||||
|
#define CALIBRATION_FACTOR 100.0 / 104167.17
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
121
esp32_readout/readout_test.ino
Normal file
121
esp32_readout/readout_test.ino
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
#include "env.h"
|
||||||
|
#include "display.h"
|
||||||
|
|
||||||
|
Display display;
|
||||||
|
Adafruit_NAU7802 nau;
|
||||||
|
unsigned long _millis = 0;
|
||||||
|
int32_t val = 0;
|
||||||
|
#if BLE
|
||||||
|
BLEServer *pServer = NULL;
|
||||||
|
BLECharacteristic *millisCharacteristic = NULL;
|
||||||
|
BLECharacteristic *weightCharacteristic = NULL;
|
||||||
|
BLEAdvertising *pAdvertising = NULL;
|
||||||
|
bool deviceConnected = false;
|
||||||
|
bool oldDeviceConnected = false;
|
||||||
|
|
||||||
|
// Callback class to handle connection events
|
||||||
|
class MyServerCallbacks : public BLEServerCallbacks {
|
||||||
|
void onConnect(BLEServer* pServer) {
|
||||||
|
deviceConnected = true;
|
||||||
|
BLEDevice::startAdvertising();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDisconnect(BLEServer* pServer) {
|
||||||
|
deviceConnected = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
display.setup();
|
||||||
|
|
||||||
|
if (! nau.begin()) {
|
||||||
|
Serial.println("Failed to find NAU7802");
|
||||||
|
while (1) delay(10); // Don't proceed.
|
||||||
|
}
|
||||||
|
|
||||||
|
nau.setLDO(LDO);
|
||||||
|
nau.setGain(GAIN);
|
||||||
|
nau.setRate(SPS);
|
||||||
|
|
||||||
|
// Take 10 readings to flush out readings
|
||||||
|
for (uint8_t i=0; i<10; i++) {
|
||||||
|
while (! nau.available()) delay(1);
|
||||||
|
nau.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (! nau.calibrate(NAU7802_CALMOD_INTERNAL)) {
|
||||||
|
Serial.println("Failed to calibrate internal offset, retrying!");
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (! nau.calibrate(NAU7802_CALMOD_OFFSET)) {
|
||||||
|
Serial.println("Failed to calibrate system offset, retrying!");
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BLE
|
||||||
|
// initialize the Bluetooth® Low Energy hardware
|
||||||
|
BLEDevice::init("Smaage");
|
||||||
|
pServer = BLEDevice::createServer();
|
||||||
|
pServer->setCallbacks(new MyServerCallbacks());
|
||||||
|
|
||||||
|
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||||
|
|
||||||
|
millisCharacteristic = pService->createCharacteristic(
|
||||||
|
MILLIS_UUID,
|
||||||
|
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
|
||||||
|
);
|
||||||
|
weightCharacteristic = pService->createCharacteristic(
|
||||||
|
WEIGHT_UUID,
|
||||||
|
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
|
||||||
|
);
|
||||||
|
millisCharacteristic->setValue((uint8_t *)&_millis, sizeof _millis);
|
||||||
|
weightCharacteristic->setValue((uint8_t *)&val, sizeof val);
|
||||||
|
pService->start();
|
||||||
|
|
||||||
|
pAdvertising = BLEDevice::getAdvertising();
|
||||||
|
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||||
|
pAdvertising->setScanResponse(true);
|
||||||
|
BLEDevice::startAdvertising();
|
||||||
|
|
||||||
|
Serial.println("BLE device is now advertising...");
|
||||||
|
Serial.print("BLE Address: ");
|
||||||
|
Serial.println(BLEDevice::getAddress().toString().c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
display.print("Smaage is ready!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
while (!nau.available()) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
val = nau.read();
|
||||||
|
|
||||||
|
#if BLE
|
||||||
|
if (deviceConnected) {
|
||||||
|
// Send the sensor reading
|
||||||
|
_millis = millis();
|
||||||
|
millisCharacteristic->setValue((uint8_t *)&_millis, sizeof _millis);
|
||||||
|
millisCharacteristic->notify();
|
||||||
|
weightCharacteristic->setValue((uint8_t *)&val, sizeof val);
|
||||||
|
weightCharacteristic->notify();
|
||||||
|
}
|
||||||
|
// disconnecting
|
||||||
|
if (!deviceConnected && oldDeviceConnected) {
|
||||||
|
delay(500); // give the bluetooth stack the chance to get things ready
|
||||||
|
pServer->startAdvertising(); // restart advertising
|
||||||
|
Serial.println("start advertising");
|
||||||
|
oldDeviceConnected = deviceConnected;
|
||||||
|
}
|
||||||
|
// connecting
|
||||||
|
if (deviceConnected && !oldDeviceConnected) {
|
||||||
|
// do stuff here on connecting
|
||||||
|
oldDeviceConnected = deviceConnected;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Serial.print(millis()); Serial.print(","); Serial.println(val);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
91
filter_dev/app.py
Normal file
91
filter_dev/app.py
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
||||||
|
|
||||||
|
from .filter import *
|
||||||
|
from .gui.device import Device
|
||||||
|
|
||||||
|
class FilterDevApp:
|
||||||
|
def __init__(self, root):
|
||||||
|
self.filter = None
|
||||||
|
|
||||||
|
self.root = root
|
||||||
|
self.root.title("JannTers Filter Evaluation Tool")
|
||||||
|
|
||||||
|
# Create a frame for the plot and sliders
|
||||||
|
self.frame = tk.Frame(self.root)
|
||||||
|
self.frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# Create a figure for plotting
|
||||||
|
self.fig, self.ax = plt.subplots()
|
||||||
|
self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame)
|
||||||
|
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# Create a frame for sliders
|
||||||
|
self.toolbar = tk.Frame(self.root)
|
||||||
|
self.toolbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||||
|
|
||||||
|
# Device Settings
|
||||||
|
self.device_label = ttk.Label(self.toolbar, text="Device Name:")
|
||||||
|
self.device_label.pack(pady=10)
|
||||||
|
self.device_name = ttk.Entry(self.toolbar)
|
||||||
|
self.device_name.insert(0, "Smaage") # Set default value
|
||||||
|
self.device_name.pack(pady=10)
|
||||||
|
|
||||||
|
self.device = Device(self.device_name)
|
||||||
|
|
||||||
|
self.connect_button = ttk.Button(self.toolbar, text="Connect Device", command=self.device.connect)
|
||||||
|
self.connect_button.pack(pady=10)
|
||||||
|
|
||||||
|
# Filter Settings
|
||||||
|
self.filter_type_label = ttk.Label(self.toolbar, text="Filter:")
|
||||||
|
self.filter_type_label.pack(pady=10)
|
||||||
|
self.filter_type_combobox = ttk.Combobox(self.toolbar, values=["MovAvg"])
|
||||||
|
self.filter_type_combobox.set("MovAvg") # Set default value
|
||||||
|
self.filter_type_combobox.pack(pady=10)
|
||||||
|
self.change_filter = ttk.Button(self.toolbar, text="Change Filter", command=self.update_filter)
|
||||||
|
self.change_filter.pack(pady=10)
|
||||||
|
|
||||||
|
# Objects
|
||||||
|
self.filter = MovAvg(self.device, self.toolbar, self.update_plot)
|
||||||
|
|
||||||
|
# Initial plot
|
||||||
|
self.update_plot()
|
||||||
|
|
||||||
|
def update_plot(self, *args):
|
||||||
|
if self.filter is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Clear the current plot
|
||||||
|
self.ax.clear()
|
||||||
|
|
||||||
|
# Get current values from sliders
|
||||||
|
df = self.filter()
|
||||||
|
|
||||||
|
# Generate data
|
||||||
|
x = df['timestamps']
|
||||||
|
y1 = df['weights']
|
||||||
|
y2 = df['filtered']
|
||||||
|
|
||||||
|
# Plot the data
|
||||||
|
self.ax.plot(x, y1)
|
||||||
|
self.ax.plot(x, y2)
|
||||||
|
self.ax.set_xlabel("Time in ms")
|
||||||
|
self.ax.set_ylabel("Weight")
|
||||||
|
self.ax.grid()
|
||||||
|
|
||||||
|
# Draw the updated plot
|
||||||
|
self.canvas.draw()
|
||||||
|
|
||||||
|
def update_filter(self):
|
||||||
|
option = self.filter_type_combobox.get()
|
||||||
|
if option == 'MovAvg' and not isinstance(self.filter, MovAvg):
|
||||||
|
self.filter = MovAvg(self.device, self.toolbar, self.update_plot)
|
||||||
|
|
||||||
|
self.update_plot()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
root = tk.Tk()
|
||||||
|
app = FilterDevApp(root)
|
||||||
|
root.mainloop()
|
||||||
47
filter_dev/ble.py
Normal file
47
filter_dev/ble.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from time import time
|
||||||
|
import asyncio
|
||||||
|
from bleak import BleakClient, BleakScanner
|
||||||
|
import pandas as pd
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from tqdm.auto import tqdm
|
||||||
|
|
||||||
|
async def read_ble(reading_time=READING_TIME):
|
||||||
|
device = await BleakScanner.find_device_by_name("Smaage")
|
||||||
|
timestamps = []
|
||||||
|
raw_weights = []
|
||||||
|
|
||||||
|
async with BleakClient(device.address) as client:
|
||||||
|
print(f"Connected to {device}")
|
||||||
|
|
||||||
|
# Read the characteristic value
|
||||||
|
pbar = tqdm(desc="reading data", total=reading_time)
|
||||||
|
time_start = time()
|
||||||
|
time_passed = 0
|
||||||
|
last_time_passed = 0
|
||||||
|
while time_passed < reading_time:
|
||||||
|
try:
|
||||||
|
# Read the sensor data
|
||||||
|
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
|
||||||
|
|
||||||
|
timestamps.append(millis)
|
||||||
|
raw_weights.append(weight)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error reading data: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
time_passed = time() - time_start
|
||||||
|
time_delta = (time_passed - last_time_passed)
|
||||||
|
last_time_passed = time_passed
|
||||||
|
pbar.update(time_delta)
|
||||||
|
|
||||||
|
pbar.close()
|
||||||
|
|
||||||
|
df = pd.DataFrame({"timestamps": timestamps, "weights": raw_weights})
|
||||||
|
print(df['weights'].describe())
|
||||||
|
plt.plot(timestamps, raw_weights)
|
||||||
|
plt.show()
|
||||||
4
filter_dev/config.py
Normal file
4
filter_dev/config.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Replace with your Arduino's service and characteristic UUIDs
|
||||||
|
SERVICE_UUID = "9f0dfdb2-e978-494c-8f15-68dbe8d28672"
|
||||||
|
MILLIS_UUID = "abb92561-a809-453c-8c7c-71d3fff5b86e"
|
||||||
|
WEIGHT_UUID = "123e4567-e89b-12d3-a456-426614174000"
|
||||||
1
filter_dev/filter/__init__.py
Normal file
1
filter_dev/filter/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .mov_avg import MovAvg
|
||||||
36
filter_dev/filter/base.py
Normal file
36
filter_dev/filter/base.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
from tkinter.ttk import Frame
|
||||||
|
|
||||||
|
from ..gui.device import Device
|
||||||
|
from ..gui.slider import Slider
|
||||||
|
|
||||||
|
class Filter:
|
||||||
|
|
||||||
|
param_map: Dict[str, Slider] = {}
|
||||||
|
|
||||||
|
def __init__(self, device: Device, toolbar: Frame, callback: callable):
|
||||||
|
self.device = device
|
||||||
|
self.toolbar = toolbar
|
||||||
|
self.callback = callback
|
||||||
|
|
||||||
|
self.init_params(toolbar)
|
||||||
|
|
||||||
|
def init_params(self, toolbar):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
def _get_params(self):
|
||||||
|
params = {}
|
||||||
|
for k, v in self.param_map.items():
|
||||||
|
params[k] = v.get_value()
|
||||||
|
return params
|
||||||
|
|
||||||
|
def __call__(self) -> pd.DataFrame:
|
||||||
|
df = self.device.data
|
||||||
|
df['filtered'] = self.filter(df)
|
||||||
|
return df
|
||||||
|
|
||||||
|
def filter(self, df: pd.DataFrame) -> pd.Series:
|
||||||
|
raise NotImplementedError()
|
||||||
18
filter_dev/filter/mov_avg.py
Normal file
18
filter_dev/filter/mov_avg.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
from .base import Filter
|
||||||
|
from ..gui.slider import Slider
|
||||||
|
|
||||||
|
class MovAvg(Filter):
|
||||||
|
|
||||||
|
def init_params(self, toolbar):
|
||||||
|
self.param_map = {
|
||||||
|
"window_size": Slider(toolbar, "Window Size", 1, 500, 10, self.callback),
|
||||||
|
"decimals": Slider(toolbar, "Decimals", 1, 5, 1, self.callback),
|
||||||
|
# "reset_threshold": Slider(self.toolbar, "Reset Threshold", 0.001, 0.1, 0.1, self.update),
|
||||||
|
}
|
||||||
|
|
||||||
|
def filter(self, df: pd.DataFrame) -> pd.Series:
|
||||||
|
params = self._get_params()
|
||||||
|
return df['weights'].rolling(window=int(params['window_size'])).mean()\
|
||||||
|
.round(int(params['decimals']))
|
||||||
0
filter_dev/gui/__init__.py
Normal file
0
filter_dev/gui/__init__.py
Normal file
40
filter_dev/gui/device.py
Normal file
40
filter_dev/gui/device.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
from bleak import BleakClient, BleakScanner
|
||||||
|
import pandas as pd
|
||||||
|
from tkinter.ttk import Entry
|
||||||
|
|
||||||
|
from ..config import MILLIS_UUID, WEIGHT_UUID
|
||||||
|
|
||||||
|
class Device:
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_connected(self):
|
||||||
|
return self.device is not None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data(self):
|
||||||
|
return pd.DataFrame({
|
||||||
|
"timestamps": self.timestamps,
|
||||||
|
"weights": self.weights
|
||||||
|
})
|
||||||
|
|
||||||
|
def __init__(self, device_name: Entry):
|
||||||
|
self.device = None
|
||||||
|
self.device_name = device_name
|
||||||
|
self.timestamps = []
|
||||||
|
self.weights = []
|
||||||
|
|
||||||
|
async def connect(self):
|
||||||
|
self.device = await BleakScanner.find_device_by_name(self.device_name.get())
|
||||||
|
|
||||||
|
assert self.device is not None, "No Device found!"
|
||||||
|
|
||||||
|
async def read_values(self):
|
||||||
|
assert self.is_connected, "Not connected"
|
||||||
|
async with BleakClient(self.device.address) as client:
|
||||||
|
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)
|
||||||
28
filter_dev/gui/slider.py
Normal file
28
filter_dev/gui/slider.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from tkinter import ttk
|
||||||
|
|
||||||
|
class Slider:
|
||||||
|
def __init__(self,
|
||||||
|
parent,
|
||||||
|
label_text,
|
||||||
|
from_, to,
|
||||||
|
initial_value,
|
||||||
|
command):
|
||||||
|
self.command = command
|
||||||
|
|
||||||
|
self.frame = ttk.Frame(parent)
|
||||||
|
self.frame.pack(pady=10)
|
||||||
|
|
||||||
|
self.label = ttk.Label(self.frame, text=f"{label_text}: {int(initial_value)}")
|
||||||
|
self.label.pack()
|
||||||
|
|
||||||
|
self.slider = ttk.Scale(self.frame, from_=from_, to=to, orient='horizontal', command=self.update)
|
||||||
|
self.slider.set(initial_value)
|
||||||
|
self.slider.pack()
|
||||||
|
|
||||||
|
def update(self, event=None):
|
||||||
|
value = self.slider.get()
|
||||||
|
self.label.config(text=f"{self.label.cget('text').split(':')[0]}: {int(value)}")
|
||||||
|
self.command()
|
||||||
|
|
||||||
|
def get_value(self):
|
||||||
|
return self.slider.get()
|
||||||
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
matplotlib
|
||||||
|
bleak
|
||||||
|
pandas
|
||||||
|
tqdm
|
||||||
|
numpy
|
||||||
Reference in New Issue
Block a user