diff --git a/.gitignore b/.gitignore index 30f0cd0..09cef89 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ bin/ include/ lib/ lib64/ +__pycache__/ +share/ glob random re @@ -11,4 +13,8 @@ sys time lib lib64 -pyvenv.cfg \ No newline at end of file +pyvenv.cfg +fdr1gui.2.py +gzip +os +plt diff --git a/BlockStackApp.py b/BlockStackApp.py new file mode 100644 index 0000000..5915aba --- /dev/null +++ b/BlockStackApp.py @@ -0,0 +1,228 @@ +from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, QPushButton +from PyQt5.QtCore import Qt +import glob +import requests +import serial +import re +import time +import math +from UpdateWorker import UpdateWorker + +class BlockStackApp(QWidget): + def __init__(self): + super().__init__() + + self.initUI() + self.check_usb_devices() + + self.update_count = 11 + + def initUI(self): + self.layout = QVBoxLayout() + self.layout.setSpacing(5) + self.layout.setContentsMargins(5, 5, 5, 5) + self.layout.setAlignment(Qt.AlignLeft | Qt.AlignTop) + self.setLayout(self.layout) + + self.setWindowTitle('462filament Bench GUI') + + self.setStyleSheet(""" + QWidget { + background-color: #2E2E2E; + color: #FFFFFF; + height: 100px; + } + QLabel { + background-color: #4A4A4A; + border: 1px solid #5A5A5A; + padding: 2px; + margin: 2px; + height: 30px; + width: 250px; + } + QPushButton, QComboBox { + background-color: #5A5A5A; + border: 1px solid #6A6A6A; + padding: 2px; + margin: 2px; + height: 25px; + width: 100px; + } + """) + + self.showMaximized() + + def check_usb_devices(self): + bench_list = [] + + for port in glob.glob('/dev/ttyUSB*'): + try: + with serial.Serial(port, 1000000, timeout=1) as ser: + response = ser.read_all().decode('utf-8').strip() + ser.write(b'i') + time.sleep(1) + response = ser.read_all().decode('utf-8').strip() + serial_number = self.extract_serial_number(response) + if serial_number: + print(f"Found bench on port {port}") + bench_id = self.get_bench_id(serial_number) + if bench_id: + bench_list.append((port, bench_id, serial_number)) + else: + print(f"Second check port {port}") + response = ser.read_all().decode('utf-8').strip() + ser.write(b'i') + time.sleep(1) + response = ser.read_all().decode('utf-8').strip() + serial_number = self.extract_serial_number(response) + if serial_number: + print(f"Found bench on port {port}") + bench_id = self.get_bench_id(serial_number) + if bench_id: + bench_list.append((port, bench_id, serial_number)) + else: + print(f"Ignoring port {port}") + + except serial.SerialException as e: + print(f"Could not open port {port}: {e}") + + bench_list.sort(key=lambda x: x[1]) + + self.blocks = {} + + for port, bench_id, serial_number in bench_list: + block_id = f"{bench_id}" + self.worker = UpdateWorker(serial_number, bench_id, port, block_id, self) + self.layout.addWidget(self.worker.block) + self.worker.change_color_signal.connect(self.change_button_color) + self.worker.update_signal.connect(self.update_block) + self.worker.start() + self.blocks[block_id] = self.worker.block + + def extract_serial_number(self, response): + match = re.match(r"id:([0-9A-Fa-f]+)", response) + if match: + return match.group(1) + return None + + def get_bench_id(self, serial_number): + url = f"http://462filament/api.php?data=benchid&serial={serial_number}" + try: + response = requests.get(url) + if response.status_code == 200: + data = response.json() + return data.get("id") + except requests.RequestException as e: + print(f"Error making request to API: {e}") + return None + + + + + + + + + + + + + + + + + + + + + + + + def change_button_color(self, block_id, button_name, color): + block = self.blocks.get(block_id) + if block: + button = getattr(block, button_name, None) + if button: + button.setStyleSheet(f"background-color: {color};") + + def update_mode(self, mode): + # Update button colors based on mode + if mode == 1: + self.change_button_color(self.sender().block.btn_go_left, "#0000FF") + self.change_button_color(self.sender().block.btn_go_right, "#5A5A5A") + self.change_button_color(self.sender().block.btn_reset, "#5A5A5A") + elif mode == 2: + self.change_button_color(self.sender().block.btn_go_left, "#5A5A5A") + self.change_button_color(self.sender().block.btn_go_right, "#0000FF") + self.change_button_color(self.sender().block.btn_reset, "#5A5A5A") + elif mode == 65535: + self.change_button_color(self.sender().block.btn_go_left, "#5A5A5A") + self.change_button_color(self.sender().block.btn_go_right, "#5A5A5A") + self.change_button_color(self.sender().block.btn_reset, "#5A5A5A") + else: + self.change_button_color(self.sender().block.btn_go_left, "#5A5A5A") + self.change_button_color(self.sender().block.btn_go_right, "#5A5A5A") + self.change_button_color(self.sender().block.btn_reset, "#0000FF") + + def handle_data_received(self, data): + # Handle the data received from the serial port + print(f"Data received: {data}") + + def update_block(self, is_running, diameter_value, position_value): + # Update the block with diameter_value and position_value + worker = self.sender() + diameter_avg = 2.0000 + est_wgh = 0 + worker.block.dia_label.setText(f"{diameter_value:.3f} ") + worker.block.len_label.setText(f"{position_value/1000:.3f}") + + if is_running: + if worker.reset_data: + worker.diameter_total = diameter_value + worker.diameter_count = 1 + worker.diameter_min = diameter_value + worker.diameter_max = diameter_value + worker.clear_graph() + worker.reset_data = False + else: + worker.diameter_total += diameter_value + worker.diameter_count += 1 + if diameter_value < worker.diameter_min: + worker.diameter_min = diameter_value + if diameter_value > worker.diameter_max: + worker.diameter_max = diameter_value + worker.block.min_label.setText(f"{worker.diameter_min:.3f} ") + worker.block.max_label.setText(f"{worker.diameter_max:.3f} ") + + self.update_graph(worker, diameter_value) + + # calculate and display average diameter + diameter_avg = worker.diameter_total / worker.diameter_count if worker.diameter_count > 0 else 0.0 + worker.block.avg_label.setText(f"{diameter_avg:.4f}") + + # calculate and display estimated weight + vol = math.pi * (diameter_avg / 2) ** 2 * position_value # all in mm → mm³ + est_wgh = worker.density * vol/1000 # density in g·cm³, vol in mm³ + worker.block.wht_label.setText(f"{est_wgh/1000:.3f} ") + + + def update_graph(self, worker, diameter_value): + # Update the graph with the new diameter value + x_data = worker.line.get_xdata() + y_data = worker.line.get_ydata() + x_data = list(x_data) + y_data = list(y_data) + + # Append new data point + x_data.append(len(x_data)) + y_data.append(diameter_value) + + # Update the line with the new data + worker.line.set_data(x_data, y_data) + + # Rescale the graph + worker.line.axes.relim() + worker.line.axes.autoscale_view() + + # Redraw the canvas + worker.canvas.draw() diff --git a/UpdateWorker.py b/UpdateWorker.py new file mode 100644 index 0000000..5fad03a --- /dev/null +++ b/UpdateWorker.py @@ -0,0 +1,521 @@ +from PyQt5.QtCore import QThread, pyqtSignal, QSize, QTimer +from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, QPushButton, QComboBox +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QFont + +import serial +import re +import time +import matplotlib.pyplot as plt +import os +import struct +import requests +from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas + +class UpdateWorker(QThread): + update_signal = pyqtSignal(bool, float, float, float, float) + data_received = pyqtSignal(str) + stop_signal = pyqtSignal() + mode_signal = pyqtSignal(int) + offset_signal = pyqtSignal(int) + change_color_signal = pyqtSignal(str, str, str) + + def __init__(self, serial_number, bench_id, port, block_id, main_app): + super().__init__() + print(f"id{bench_id} :\tport {port}") + print(f"id{bench_id} :\tserial {serial_number}") + self.block = self.add_block(serial_number, bench_id, port, block_id, main_app) + self.main_app = main_app # Store the reference to the BlockStackApp instance + self.serial_number = serial_number + self.bench_id = bench_id + self.port = port + self.block_id = block_id + self.running = True + self.position_value = 0.0 + self.diameter_total = 0.0 # for average calculation + self.diameter_count = 0 + self.diameter_value = 0.0 + self.diameter_min = 0.0 + self.diameter_max = 0.0 + self.density = 1.0 + self.prepare_flag = False + self.prepare_ok = False + self.reset_flag = False + self.ignore_stop = False + self.is_running = False + self.reset_data = False + self.homed = False + self.can_start = False + self.data_list = [] + self.profile_data = {} # Dictionary to store profile data + + # run at startup + self.update_profiles() + + self.timer = QTimer() + self.timer.timeout.connect(self.query_api) + self.timer.start(3000) + + def run(self): + try: + with serial.Serial(self.port, 1000000, timeout=1) as ser: + ser.write(b'a') + ser.write(b'F') + ser.write(b'i') + ser.write(b' ') + while self.running: + if ser.in_waiting > 0: + data = ser.readline().decode('utf-8').strip() + if data: + self.parse_data(data) + if self.reset_flag and self.prepare_flag: + if self.position_value > 100 and self.reset_flag: + self.ignore_stop = True + self.change_color_signal.emit(self.block_id, 'btn_prepare', "#5A5A5A") + ser.write(b'R') + self.prepare_flag = False + if ((1.65 < self.diameter_value) and (self.diameter_value < 1.85)) or ((2.70 < self.diameter_value) and (self.diameter_value < 2.95)): + self.prepare_ok = True + else: + self.prepare_ok = False + if self.prepare_ok: + self.change_color_signal.emit(self.block_id, 'btn_prepare', "#00A000") + self.change_color_signal.emit(self.block_id, 'btn_start', "#A0A000") + else: + self.change_color_signal.emit(self.block_id, 'btn_prepare', "#A00000") + else: + self.change_color_signal.emit(self.block_id, 'btn_prepare', "#0000FF") + else: + if data == '%STOP': + self.stop_running() + # if not self.ignore_stop: + # self.change_color_signal.emit(self.block_id, 'btn_start', "#A00000") + # self.is_running = False + # self.save_data_to_file() + # else: + # self.ignore_stop = False + elif data == '$NOTHOMED': + self.homed = False + self.change_color_signal.emit(self.block_id, 'btn_home', "#a0a000") + elif data == '$HOMED': + print(f"id{self.bench_id} :\tHoming ok") + self.homed = True + self.change_color_signal.emit(self.block_id, 'btn_home', "#5a5a5a") + except serial.SerialException as e: + print(f"Error with port {self.port}: {e}") + + def save_data_to_file(self): + #FIXME: set name + #FIXME: add file header + #FIXME: compress file + #FIXME: upload to API + file_path = os.path.join("data", f"{self.bench_id}_data.txt") + + # Ensure the directory exists + os.makedirs(os.path.dirname(file_path), exist_ok=True) + + # Write the data to the file + with open(file_path, "w") as file: + for data in self.data_list: + file.write(data + "\n") + + def parse_data(self, data): + self.data_list.append(data) + match = re.match(r"^[#d]:(-?[\d\.]+),p:(-?[\d\.]+)$", data) + if match: + self.diameter_value = float(match.group(1)) + self.position_value = float(match.group(2)) + self.update_signal.emit(self.is_running, self.diameter_value, self.position_value, self.diameter_min, self.diameter_max) + self.reset_flag = True + + offset_match = re.match(r"^#h:(\d+)", data) + if offset_match: + home_offset = int(offset_match.group(1)) + print(f"id{self.bench_id}:\tOffset: {home_offset:.2f}") + self.block.btn_offset.setText(f"Offset: {home_offset:.2f}") + + mode_match = re.match(r"^#o:(\d+)", data) + if mode_match: + mode = int(mode_match.group(1)) + self.mode_signal.emit(mode) + match mode: + case 1: + self.change_color_signal.emit(self.block_id, 'btn_go_left', "#0000A0") + self.change_color_signal.emit(self.block_id, 'btn_go_right', "#5a5a5a") + self.change_color_signal.emit(self.block_id, 'btn_reset', "#5a5a5a") + case 2: + self.change_color_signal.emit(self.block_id, 'btn_go_left', "#5a5a5a") + self.change_color_signal.emit(self.block_id, 'btn_go_right', "#0000A0") + self.change_color_signal.emit(self.block_id, 'btn_reset', "#5a5a5a") + case 3: + self.change_color_signal.emit(self.block_id, 'btn_go_left', "#5a5a5a") + self.change_color_signal.emit(self.block_id, 'btn_go_right', "#5a5a5a") + self.change_color_signal.emit(self.block_id, 'btn_reset', "#00A0A0") + else: + self.mode_signal.emit(65535) + self.change_color_signal.emit(self.block_id, 'btn_go_left', "#5a5a5a") + self.change_color_signal.emit(self.block_id, 'btn_go_right', "#5a5a5a") + self.change_color_signal.emit(self.block_id, 'btn_reset', "#5A5A5A") + + def send_command(self, command): + try: + with serial.Serial(self.port, 1000000, timeout=1) as ser: + ser.write(command.encode()) + except serial.SerialException as e: + print(f"Could not send command to port {self.port}: {e}") + + def int_to_two_bytes(self, value): + if not (0 <= value <= 0xFFFF): + raise ValueError("Value out of range for two bytes") + + two_bytes = struct.pack('>H', value) + return two_bytes + + def set_limits(self, left, right): + print(f"id{self.bench_id}:\tupdate limits to {left}+{right}") + try: + with serial.Serial(self.port, 1000000, timeout=1) as ser: + ser.write(b'\x04') + time.sleep(0.001) + ser.write(self.int_to_two_bytes(left)) + time.sleep(0.003) + ser.write(self.int_to_two_bytes(right)) + time.sleep(0.003) + ser.write(b'\x04') + time.sleep(0.001) + ser.write(b'\x00') + time.sleep(0.001) + except serial.SerialException as e: + print(f"Could not send command to port {self.port}: {e}") + + def set_prepare(self, prepare): + self.position_value = 0 + self.prepare_flag = True + self.reset_flag = False + + def start_running(self): + if self.prepare_ok and self.can_start: + self.reset_data = True + self.is_running = True + + self.change_color_signal.emit(self.block_id, 'btn_start', "#00a000") + self.change_color_signal.emit(self.block_id, 'btn_prepare', "#5A5A5A") + + self.send_command('S') + + def stop_running(self): + if self.is_running: + self.send_command('R') + self.timer.start() + + self.block.data_label.setText( + f"Job done, processing..." + ) + + self.change_color_signal.emit(self.block_id, 'btn_start', "#a00000") + self.change_color_signal.emit(self.block_id, 'btn_prepare', "#5A5A5A") + + self.is_running = False + self.save_data_to_file() + self.prepare_ok = False + + + def clear_graph(self): + self.line.set_data([], []) + self.canvas.draw() + + def add_block(self, serial_number, bench_id, port, block_id, main_app): + block_widget = QWidget() + block_layout = QHBoxLayout() + block_layout.setAlignment(Qt.AlignLeft | Qt.AlignTop) + + LABEL_SIZE = QSize(250, 20) + BUTTON_SIZE = QSize(100, 25) + VALUE_SIZE = QSize(80, 25) + VALUEL_SIZE = QSize(25, 25) + + monospaced_font = QFont("unexistent", 10) + monospaced_font.setStyleHint(QFont.Monospace) + + monospaced_bold_font = QFont("unexistent", 10) + monospaced_bold_font.setStyleHint(QFont.Monospace) + monospaced_bold_font.setBold(True) + + monospaced_italics_font = QFont("unexistent", 10) + monospaced_italics_font.setStyleHint(QFont.Monospace) + monospaced_italics_font.setItalic(True) + + left_layout = QVBoxLayout() + data_label = QLabel("No API data") + data_label.setTextFormat(Qt.RichText) + data_label.setAlignment(Qt.AlignLeft | Qt.AlignTop) + bench_label = QLabel(f"Bench ID: {bench_id}") + bench_label.setToolTip(f"Serial number: {serial_number}\nCPU: Microchip PIC18F4431 @ 32 MHz\nPort: {port}\nBandwidth: 1 MBps\nPosition maxspd: 638 mm/s\nDiameter freq: ≈10.5 Hz") + bench_label.setAlignment(Qt.AlignCenter) + bench_label.setFixedSize(LABEL_SIZE) + left_layout.addWidget(bench_label) + left_layout.addWidget(data_label) + + left2_layout = QHBoxLayout() + left2L_layout = QVBoxLayout() + left2V_layout = QVBoxLayout() + max_label = QLabel("2.000 ") + max_label.setFont(monospaced_bold_font) + avg_label = QLabel("2.0000") + avg_label.setFont(monospaced_font) + cur_label = QLabel("2.000 ") + cur_label.setFont(monospaced_bold_font) + len_label = QLabel("12345.00") + len_label.setFont(monospaced_font) + wht_label = QLabel("12.345 ") + wht_label.setFont(monospaced_italics_font) + min_label = QLabel("2.000 ") + min_label.setFont(monospaced_bold_font) + maxL_label = QLabel("∨") + avgL_label = QLabel("⌀̄") + curL_label = QLabel("⌀") + lenL_label = QLabel("L") + whtL_label = QLabel("M") + minL_label = QLabel("∧") + avg_label.setAlignment(Qt.AlignRight) + max_label.setAlignment(Qt.AlignRight) + cur_label.setAlignment(Qt.AlignRight) + len_label.setAlignment(Qt.AlignRight) + wht_label.setAlignment(Qt.AlignRight) + min_label.setAlignment(Qt.AlignRight) + + avg_label.setToolTip("Average diameter in mm") + max_label.setToolTip("Maximum diameter in mm") + cur_label.setToolTip("Current diameter in mm") + len_label.setToolTip("Length in m") + wht_label.setToolTip("Estimated mass in kg") + min_label.setToolTip("Minimum diameter in mm") + + maxL_label.setToolTip("Average diameter in mm") + avgL_label.setToolTip("Maximum diameter in mm") + curL_label.setToolTip("Current diameter in mm") + lenL_label.setToolTip("Length in m") + whtL_label.setToolTip("Estimated mass in kg") + minL_label.setToolTip("Minimum diameter in mm") + + max_label.setFixedSize(VALUE_SIZE) + avg_label.setFixedSize(VALUE_SIZE) + cur_label.setFixedSize(VALUE_SIZE) + len_label.setFixedSize(VALUE_SIZE) + wht_label.setFixedSize(VALUE_SIZE) + min_label.setFixedSize(VALUE_SIZE) + + maxL_label.setFixedSize(VALUEL_SIZE) + avgL_label.setFixedSize(VALUEL_SIZE) + curL_label.setFixedSize(VALUEL_SIZE) + lenL_label.setFixedSize(VALUEL_SIZE) + whtL_label.setFixedSize(VALUEL_SIZE) + minL_label.setFixedSize(VALUEL_SIZE) + + left2V_layout.addWidget(max_label) + left2V_layout.addWidget(avg_label) + left2V_layout.addWidget(cur_label) + left2V_layout.addWidget(len_label) + left2V_layout.addWidget(wht_label) + left2V_layout.addWidget(min_label) + + left2L_layout.addWidget(maxL_label) + left2L_layout.addWidget(avgL_label) + left2L_layout.addWidget(curL_label) + left2L_layout.addWidget(lenL_label) + left2L_layout.addWidget(whtL_label) + left2L_layout.addWidget(minL_label) + + left2_layout.addLayout(left2L_layout) + left2_layout.addLayout(left2V_layout) + + center_layout = QVBoxLayout() + # graph_placeholder = QLabel("Graph Placeholder") + # graph_placeholder.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Ignored) + # center_layout.addWidget(graph_placeholder) + + right_layout = QHBoxLayout() + right_layout_1 = QVBoxLayout() + right_layout_2 = QVBoxLayout() + right_layout_3 = QVBoxLayout() + + btn_prepare = QPushButton("Prepare") + btn_prepare.clicked.connect(lambda: self.send_command('P')) + btn_prepare.clicked.connect(lambda: self.set_prepare(True)) + right_layout_1.addWidget(btn_prepare) + + btn_start = QPushButton("Start") + btn_start.clicked.connect(self.start_running) + right_layout_1.addWidget(btn_start) + + btn_reset = QPushButton("Reset/Zero") + btn_reset.clicked.connect(lambda: self.send_command('r')) + btn_reset.clicked.connect(lambda: self.change_color_signal.emit(self.block_id, 'btn_start', "#5A5A5A")) + right_layout_1.addWidget(btn_reset) + + btn_stop = QPushButton("Stop") + btn_stop.clicked.connect(self.stop_running) + right_layout_1.addWidget(btn_stop) + + btn_spare1 = QPushButton() + right_layout_1.addWidget(btn_spare1) + + + + btn_sleep = QPushButton("Sleep") + btn_sleep.clicked.connect(lambda: self.send_command('a')) + right_layout_2.addWidget(btn_sleep) + + btn_home = QPushButton("Home") + btn_home.clicked.connect(lambda: self.send_command(' ')) + right_layout_2.addWidget(btn_home) + + btn_go_left = QPushButton("Go Left") + btn_go_left.clicked.connect(lambda: self.send_command('1')) + right_layout_2.addWidget(btn_go_left) + + btn_go_right = QPushButton("Go Right") + btn_go_right.clicked.connect(lambda: self.send_command('2')) + right_layout_2.addWidget(btn_go_right) + + btn_offset = QPushButton() + right_layout_2.addWidget(btn_offset) + + btn_down_left = QPushButton("Offset +") + btn_down_left.clicked.connect(lambda: self.send_command('b')) + right_layout_3.addWidget(btn_down_left) + + btn_up_left = QPushButton("Offset -") + btn_up_left.clicked.connect(lambda: self.send_command('n')) + right_layout_3.addWidget(btn_up_left) + + btn_save_offset = QPushButton("Save Offset") + btn_save_offset.clicked.connect(lambda: self.send_command('M')) + right_layout_3.addWidget(btn_save_offset) + + + + dropd_profile = QComboBox() + + dropd_profile.addItem("Select a profile...") + dropd_profile.model().item(0).setEnabled(False) + + + dropd_profile.currentIndexChanged.connect(self.on_profile_changed) + + dropd_profile.setFixedWidth(120) + + view = dropd_profile.view() + view.setMinimumWidth(350) # Set the minimum width of the dropdown list + + right_layout_3.addWidget(dropd_profile) + + btn_update_profiles = QPushButton("Reload profiles") + btn_update_profiles.clicked.connect(self.update_profiles) + right_layout_3.addWidget(btn_update_profiles) + + + right_layout.addLayout(right_layout_1) + right_layout.addLayout(right_layout_2) + right_layout.addLayout(right_layout_3) + + block_layout.addLayout(left_layout) + block_layout.addLayout(left2_layout) + block_layout.addLayout(center_layout) + block_layout.addLayout(right_layout) + + block_widget.setLayout(block_layout) + + block_widget.btn_start = btn_start + block_widget.btn_home = btn_home + block_widget.btn_go_left = btn_go_left + block_widget.btn_go_right = btn_go_right + block_widget.btn_reset = btn_reset + block_widget.btn_prepare = btn_prepare + block_widget.data_label = data_label + block_widget.bench_label = bench_label + + block_widget.max_label = max_label + block_widget.avg_label = avg_label + block_widget.dia_label = cur_label + block_widget.len_label = len_label + block_widget.wht_label = wht_label + block_widget.min_label = min_label + block_widget.btn_offset = btn_offset + block_widget.dropd_profile = dropd_profile + + # Create a Matplotlib figure and canvas for the graph + plt.style.use('dark_background') + + fig, ax = plt.subplots() + plt.subplots_adjust(left=-0.01, right=1, top=1.01, bottom=0) + ax.set_facecolor('#3a3a3a') + ax.set_xticks([]) # Hide x-axis values + ax.set_frame_on(True) + # ax.set_ylabel('Diameter (mm)') # Show y-axis label + self.line, = ax.plot([], [], '#ff5000', linewidth=0.5) + self.canvas = FigureCanvas(fig) + self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Ignored) + center_layout.addWidget(self.canvas) + + return block_widget + + def on_profile_changed(self, index): + # Get the selected ID + selected_id = self.sender().itemData(index) + + if selected_id in self.profile_data: + start_value = self.profile_data[selected_id]['start'] + width_value = self.profile_data[selected_id]['width'] + + self.set_limits(start_value, width_value) + + def update_profiles(self): + url = f"http://462filament/api.php?data=profiles" + try: + response = requests.get(url) + if response.status_code == 200: + profiles = response.json() + if profiles: + self.block.dropd_profile.clear() + self.block.dropd_profile.addItem("Select a profile...") + self.block.dropd_profile.model().item(0).setEnabled(False) + for profile in profiles: + profile_id = profile["id"] + profile_name = profile["show_name"] + start_value = int(profile["start"]) + width_value = int(profile["width"]) + self.block.dropd_profile.addItem(profile_name, profile_id) + self.profile_data[profile_id] = {'start': start_value, 'width': width_value} + except requests.RequestException as e: + print(f"Error making request to API: {e}") + return None + + def query_api(self): + try: + url = f"http://462filament/api.php?data=bench&benchid={self.bench_id}" + response = requests.get(url) + response.raise_for_status() # Raise an exception for HTTP errors + api_job = response.json() # Parse the JSON response + + if api_job is not None: + print(f"id{self.bench_id}:\tgot job {api_job['spool']} from API") + self.block.data_label.setText( + f"Job/Spool: {api_job['spool']}