dev gui, mostly working
This commit is contained in:
parent
3245233401
commit
c82835cdb0
392
fdr1gui.py
392
fdr1gui.py
@ -3,28 +3,234 @@ import glob
|
||||
import serial
|
||||
import re
|
||||
import requests
|
||||
import random
|
||||
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout,
|
||||
QLabel, QSizePolicy, QPushButton)
|
||||
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QSize
|
||||
import time
|
||||
|
||||
class UpdateWorker(QThread):
|
||||
update_signal = pyqtSignal(int, int)
|
||||
update_signal = pyqtSignal(float, float, float, float)
|
||||
data_received = pyqtSignal(str)
|
||||
stop_signal = pyqtSignal()
|
||||
not_homed_signal = pyqtSignal()
|
||||
mode_signal = pyqtSignal(int)
|
||||
change_color_signal = pyqtSignal(str, str, str) # Signal to change button color with identifier
|
||||
|
||||
def __init__(self, block, serial_number, bench_id):
|
||||
def __init__(self, serial_number, bench_id, port, block_id):
|
||||
super().__init__()
|
||||
self.block = block
|
||||
self.block = self.add_block(serial_number, bench_id, port, block_id)
|
||||
|
||||
self.serial_number = serial_number
|
||||
self.bench_id = bench_id
|
||||
self.position_value = 0
|
||||
self.port = port
|
||||
self.block_id = block_id # Unique identifier for the block
|
||||
self.running = True
|
||||
self.position_value = 0.0
|
||||
self.diameter_value = 0.0
|
||||
self.diameter_min = 0.0
|
||||
self.diameter_max = 0.0
|
||||
self.prepare_flag = False
|
||||
self.prepare_ok = False
|
||||
self.reset_flag = False
|
||||
self.ignore_stop = False
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
diameter_value = random.randint(0, 100)
|
||||
self.position_value += 1
|
||||
self.update_signal.emit(diameter_value, self.position_value)
|
||||
self.sleep(1) # Sleep for 1 second
|
||||
try:
|
||||
with serial.Serial(self.port, 1000000, timeout=1) as ser:
|
||||
ser.write(b'a') # Send the character 'F'
|
||||
ser.write(b'F') # Send the character 'F
|
||||
self.change_color_signal.emit(self.block_id, 'btn_home', "#A0A000")
|
||||
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 < 2.99:
|
||||
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':
|
||||
if not self.ignore_stop :
|
||||
self.change_color_signal.emit(self.block_id, 'btn_start', "#A00000")
|
||||
else:
|
||||
self.ignore_stop = False
|
||||
elif data == '$NOTHOMED':
|
||||
self.not_homed_signal.emit()
|
||||
except serial.SerialException as e:
|
||||
print(f"Error with port {self.port}: {e}")
|
||||
|
||||
def parse_data(self, data):
|
||||
# Parse the data and update diameter_value and position_value
|
||||
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))
|
||||
if self.diameter_value < self.diameter_min:
|
||||
self.diameter_min = self.diameter_value
|
||||
if self.diameter_value > self.diameter_max:
|
||||
self.diameter_max = self.diameter_value
|
||||
self.update_signal.emit(self.diameter_value, self.position_value, self.diameter_min, self.diameter_max)
|
||||
self.reset_flag = True
|
||||
|
||||
# Parse mode and position data
|
||||
mode_match = re.match(r"#o:(\d+),l:(\d+),r:(\d+),c:(\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 set_prepare(self, prepare):
|
||||
self.position_value = 0
|
||||
self.prepare_flag = True
|
||||
self.reset_flag = False
|
||||
|
||||
def reset_diameter_limits(self):
|
||||
self.diameter_min = self.diameter_value
|
||||
self.diameter_max = self.diameter_value
|
||||
|
||||
def add_block(self, serial_number, bench_id, port, block_id):
|
||||
block_widget = QWidget()
|
||||
block_layout = QHBoxLayout()
|
||||
block_layout.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
||||
|
||||
LABEL_SIZE = QSize(250, 20)
|
||||
BUTTON_SIZE = QSize(100, 25)
|
||||
|
||||
left_layout = QVBoxLayout()
|
||||
data_label = QLabel("---")
|
||||
bench_label = QLabel(f"Bench ID: {bench_id}")
|
||||
bench_label.setFixedSize(LABEL_SIZE)
|
||||
left_layout.addWidget(bench_label)
|
||||
left_layout.addWidget(data_label)
|
||||
|
||||
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(lambda: self.change_color_signal.emit(self.block_id, 'btn_start', "#00a000"))
|
||||
btn_start.clicked.connect(lambda: self.change_color_signal.emit(self.block_id, 'btn_prepare', "#5A5A5A"))
|
||||
btn_start.clicked.connect(self.reset_diameter_limits)
|
||||
btn_start.clicked.connect(lambda: self.send_command('S'))
|
||||
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(lambda: self.send_command('R'))
|
||||
btn_stop.clicked.connect(lambda: self.change_color_signal.emit(self.block_id, 'btn_start', "#a00000"))
|
||||
btn_stop.clicked.connect(lambda: self.change_color_signal.emit(self.block_id, 'btn_prepare', "#5A5A5A"))
|
||||
right_layout_1.addWidget(btn_stop)
|
||||
|
||||
btn_sleep = QPushButton("Sleep")
|
||||
btn_sleep.clicked.connect(lambda: self.send_command('a'))
|
||||
btn_sleep.clicked.connect(lambda: self.change_color_signal.emit(self.block_id, 'btn_home', "#a0a000"))
|
||||
right_layout_2.addWidget(btn_sleep)
|
||||
|
||||
btn_home = QPushButton("Home")
|
||||
btn_home.clicked.connect(lambda: self.send_command(' '))
|
||||
btn_home.clicked.connect(lambda: self.change_color_signal.emit(self.block_id, 'btn_home', "#5A5A5A"))
|
||||
btn_home.clicked.connect(lambda: self.change_color_signal.emit(self.block_id, 'btn_start', "#5A5A5A"))
|
||||
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_down_left = QPushButton("Down Left")
|
||||
btn_down_left.clicked.connect(lambda: self.send_command('g'))
|
||||
right_layout_3.addWidget(btn_down_left)
|
||||
|
||||
btn_up_left = QPushButton("Up Left")
|
||||
btn_up_left.clicked.connect(lambda: self.send_command('h'))
|
||||
right_layout_3.addWidget(btn_up_left)
|
||||
|
||||
btn_down_right = QPushButton("Down Right")
|
||||
btn_down_right.clicked.connect(lambda: self.send_command('t'))
|
||||
right_layout_3.addWidget(btn_down_right)
|
||||
|
||||
btn_up_right = QPushButton("Up Right")
|
||||
btn_up_right.clicked.connect(lambda: self.send_command('y'))
|
||||
right_layout_3.addWidget(btn_up_right)
|
||||
|
||||
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(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
|
||||
|
||||
return block_widget
|
||||
|
||||
|
||||
|
||||
class BlockStackApp(QWidget):
|
||||
def __init__(self):
|
||||
@ -34,20 +240,14 @@ class BlockStackApp(QWidget):
|
||||
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.setSpacing(5)
|
||||
self.layout.setContentsMargins(5, 5, 5, 5)
|
||||
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;
|
||||
@ -72,38 +272,62 @@ class BlockStackApp(QWidget):
|
||||
}
|
||||
""")
|
||||
|
||||
# Show the window maximized
|
||||
self.showMaximized()
|
||||
|
||||
def check_usb_devices(self):
|
||||
# Check each /dev/ttyUSB? device
|
||||
bench_list = []
|
||||
|
||||
for port in glob.glob('/dev/ttyUSB*'):
|
||||
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()
|
||||
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:
|
||||
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()
|
||||
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 = {} # Dictionary to store blocks by block_id
|
||||
|
||||
for port, bench_id, serial_number in bench_list:
|
||||
block_id = f"{bench_id}_{port}" # Unique identifier for the block
|
||||
self.worker = UpdateWorker(serial_number, bench_id, port, block_id)
|
||||
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 # Store the block with its identifier
|
||||
|
||||
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)
|
||||
@ -114,86 +338,44 @@ class BlockStackApp(QWidget):
|
||||
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()
|
||||
block_layout.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
||||
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};")
|
||||
|
||||
LABEL_SIZE = QSize(250, 20)
|
||||
BUTTON_SIZE = QSize(100, 25)
|
||||
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")
|
||||
|
||||
# Left zone
|
||||
left_layout = QVBoxLayout()
|
||||
data_label = QLabel(f"Est. weight: 0 g\nStop: at end")
|
||||
bench_label = QLabel(f"Bench ID: {bench_id}")
|
||||
bench_label.setFixedSize(LABEL_SIZE)
|
||||
diameter_label = QLabel("Diameter: 0")
|
||||
diameter_label.setFixedSize(LABEL_SIZE)
|
||||
position_label = QLabel("Position: 0")
|
||||
position_label.setFixedSize(LABEL_SIZE)
|
||||
left_layout.addWidget(bench_label)
|
||||
left_layout.addWidget(diameter_label)
|
||||
left_layout.addWidget(position_label)
|
||||
left_layout.addWidget(data_label)
|
||||
def handle_data_received(self, data):
|
||||
# Handle the data received from the serial port
|
||||
print(f"Data received: {data}")
|
||||
|
||||
# Center zone (placeholder for graph)
|
||||
center_layout = QVBoxLayout()
|
||||
graph_placeholder = QLabel("Graph Placeholder")
|
||||
graph_placeholder.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Ignored)
|
||||
center_layout.addWidget(graph_placeholder)
|
||||
|
||||
# Right zone with buttons
|
||||
right_layout = QHBoxLayout()
|
||||
right_layout_1 = QVBoxLayout()
|
||||
right_layout_2 = QVBoxLayout()
|
||||
right_layout_3 = QVBoxLayout()
|
||||
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")
|
||||
]
|
||||
|
||||
btn_start = QPushButton(f"Start")
|
||||
right_layout_1.addWidget(btn_start)
|
||||
|
||||
|
||||
right_layout_1.addWidget(QPushButton(f"Reset"))
|
||||
right_layout_1.addWidget(QPushButton(f"Stop"))
|
||||
right_layout_1.addWidget(QPushButton(f"Home"))
|
||||
right_layout_2.addWidget(QPushButton(f"Go Left"))
|
||||
right_layout_2.addWidget(QPushButton(f""))
|
||||
right_layout_2.addWidget(QPushButton(f"Go Right"))
|
||||
right_layout_2.addWidget(QPushButton(f"Sleep"))
|
||||
right_layout_3.addWidget(QPushButton(f"Down Left"))
|
||||
right_layout_3.addWidget(QPushButton(f"Up Left"))
|
||||
right_layout_3.addWidget(QPushButton(f"Down Right"))
|
||||
right_layout_3.addWidget(QPushButton(f"Up Right"))
|
||||
|
||||
right_layout.addLayout(right_layout_1)
|
||||
right_layout.addLayout(right_layout_2)
|
||||
right_layout.addLayout(right_layout_3)
|
||||
|
||||
# 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, diameter_value, position_value):
|
||||
# Update the block with random value and incrementing position_value
|
||||
def update_block(self, diameter_value, position_value, diameter_min, diameter_max):
|
||||
# Update the block with diameter_value and position_value
|
||||
worker = self.sender()
|
||||
worker.block.diameter_label.setText(f"Diameter: {diameter_value}")
|
||||
worker.block.position_label.setText(f"Position: {position_value}")
|
||||
worker.block.data_label.setText(f"⌀: {diameter_min:.3f} < ⌀̄ {diameter_value:.3f} mm < {diameter_max:.3f}\n"
|
||||
f"L: {position_value/1000:.4f} m\n"
|
||||
f"ρ: {1} g·cm¯³\n"
|
||||
"\n- - -\n\n"
|
||||
f"M: 0 g\nStop: at end")
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user