import sys import glob import serial import re import requests import random from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, QPushButton, QGridLayout) from PyQt5.QtCore import Qt, QThread, pyqtSignal import time class UpdateWorker(QThread): update_signal = pyqtSignal(int, int) def __init__(self, block, serial_number, bench_id): super().__init__() self.block = block self.serial_number = serial_number self.bench_id = bench_id self.counter = 0 def run(self): while True: random_value = random.randint(0, 100) self.counter += 1 self.update_signal.emit(random_value, self.counter) self.sleep(1) # Sleep for 1 second class BlockStackApp(QWidget): def __init__(self): super().__init__() self.initUI() self.check_usb_devices() def initUI(self): # Set up the layout self.layout = QVBoxLayout() self.layout.setSpacing(5) # Set space between widgets to 5 pixels self.layout.setContentsMargins(5, 5, 5, 5) # Set margins around the layout to 5 pixels # Align the layout to the left self.layout.setAlignment(Qt.AlignLeft | Qt.AlignTop) # Set the layout to the QWidget self.setLayout(self.layout) self.setWindowTitle('462filament Bench GUI') # Apply dark theme self.setStyleSheet(""" QWidget { background-color: #2E2E2E; color: #FFFFFF; } QLabel { background-color: #4A4A4A; border: 1px solid #5A5A5A; padding: 10px; margin: 5px; } QPushButton { background-color: #5A5A5A; border: 1px solid #6A6A6A; padding: 5px; margin: 2px; } """) # Show the window maximized self.showMaximized() def check_usb_devices(self): # Check each /dev/ttyUSB? device for port in glob.glob('/dev/ttyUSB*'): print(f"Check port {port}") try: with serial.Serial(port, 1000000, timeout=1) as ser: ser.write(b'i') # Send the character 'i' time.sleep(1) # Wait for 1 second to receive data response = ser.read_all().decode('utf-8').strip() serial_number = self.extract_serial_number(response) if serial_number: print(f"Got id on port {port}") bench_id = self.get_bench_id(serial_number) if bench_id: print(f"Adding port {port}") block = self.add_block(serial_number, bench_id) # Start a QThread for each block self.worker = UpdateWorker(block, serial_number, bench_id) self.worker.update_signal.connect(self.update_block) self.worker.start() except serial.SerialException as e: print(f"Could not open port {port}: {e}") def extract_serial_number(self, response): # Extract the hexadecimal serial number using a regular expression 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): # Make a request to the API to get the bench ID 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 add_block(self, serial_number, bench_id): # Create a new block with three zones block_widget = QWidget() block_layout = QHBoxLayout() # Left zone left_layout = QVBoxLayout() id_label = QLabel(f"id: {serial_number}") bench_label = QLabel(f"Bench ID: {bench_id}") diameter_label = QLabel("Diameter: 0") position_label = QLabel("Position: 0") left_layout.addWidget(id_label) left_layout.addWidget(bench_label) left_layout.addWidget(diameter_label) left_layout.addWidget(position_label) # Center zone (placeholder for graph) center_layout = QVBoxLayout() graph_placeholder = QLabel("Graph Placeholder") graph_placeholder.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) center_layout.addWidget(graph_placeholder) # Right zone with buttons in a grid layout right_layout = QGridLayout() buttons = [ ("Home", ""), ("Sleep", "a"), ("Down Right", "t"), ("Up Right", "y"), ("Down Left", "g"), ("Up Left", "h"), ("Start", "S"), ("Stop", "R"), ("Reset", "r"), ("Go Right", "1"), ("Go Left", "2") ] for index, (text, command) in enumerate(buttons): button = QPushButton(f"{text} ({command})") row = index // 3 # Determine the row col = index % 3 # Determine the column right_layout.addWidget(button, row, col) # Add zones to the block layout block_layout.addLayout(left_layout) block_layout.addLayout(center_layout) block_layout.addLayout(right_layout) block_widget.setLayout(block_layout) self.layout.addWidget(block_widget) # Store labels for updating block_widget.diameter_label = diameter_label block_widget.position_label = position_label return block_widget def update_block(self, random_value, counter): # Update the block with random value and incrementing counter worker = self.sender() worker.block.diameter_label.setText(f"Diameter: {random_value}") worker.block.position_label.setText(f"Position: {counter}") if __name__ == '__main__': app = QApplication(sys.argv) ex = BlockStackApp() sys.exit(app.exec_())