This commit is contained in:
Jonathan Roth 2025-04-14 12:27:23 +02:00
parent c90ea4cf85
commit 72856ace3c
3 changed files with 91 additions and 28 deletions

View File

@ -9,15 +9,15 @@ import math
from UpdateWorker import UpdateWorker from UpdateWorker import UpdateWorker
class BlockStackApp(QWidget): class BlockStackApp(QWidget):
def __init__(self): def __init__(self, fullscreen):
super().__init__() super().__init__()
self.initUI() self.initUI(fullscreen)
self.check_usb_devices() self.check_usb_devices()
self.update_count = 11 self.update_count = 11
def initUI(self): def initUI(self, fullscreen):
self.layout = QVBoxLayout() self.layout = QVBoxLayout()
self.layout.setSpacing(5) self.layout.setSpacing(5)
self.layout.setContentsMargins(5, 5, 5, 5) self.layout.setContentsMargins(5, 5, 5, 5)
@ -50,7 +50,10 @@ class BlockStackApp(QWidget):
} }
""") """)
self.showMaximized() if fullscreen:
self.showFullScreen()
else:
self.showMaximized()
def check_usb_devices(self): def check_usb_devices(self):
bench_list = [] bench_list = []
@ -183,17 +186,24 @@ class BlockStackApp(QWidget):
worker.diameter_min = diameter_value worker.diameter_min = diameter_value
worker.diameter_max = diameter_value worker.diameter_max = diameter_value
worker.clear_graph() worker.clear_graph()
worker.data_list.clear()
worker.reset_data = False worker.reset_data = False
else: else:
worker.diameter_total += diameter_value worker.diameter_total += diameter_value # to calc average diameter
worker.diameter_count += 1 worker.diameter_count += 1
if diameter_value < worker.diameter_min:
if diameter_value < worker.diameter_min: # process min/max
worker.diameter_min = diameter_value worker.diameter_min = diameter_value
if diameter_value > worker.diameter_max: if diameter_value > worker.diameter_max:
worker.diameter_max = diameter_value worker.diameter_max = diameter_value
worker.block.min_label.setText(f"{worker.diameter_min:.3f} ") worker.block.min_label.setText(f"{worker.diameter_min:.3f} ")
worker.block.max_label.setText(f"{worker.diameter_max:.3f} ") worker.block.max_label.setText(f"{worker.diameter_max:.3f} ")
# push data to memory for report
worker.data_list.append((position_value, diameter_value))
# push data to graph and update it
self.update_graph(worker, diameter_value) self.update_graph(worker, diameter_value)
# calculate and display average diameter # calculate and display average diameter

View File

@ -10,6 +10,9 @@ import matplotlib.pyplot as plt
import os import os
import struct import struct
import requests import requests
import subprocess
from datetime import datetime
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
class UpdateWorker(QThread): class UpdateWorker(QThread):
@ -18,12 +21,13 @@ class UpdateWorker(QThread):
stop_signal = pyqtSignal() stop_signal = pyqtSignal()
mode_signal = pyqtSignal(int) mode_signal = pyqtSignal(int)
offset_signal = pyqtSignal(int) offset_signal = pyqtSignal(int)
apitimer_signal = pyqtSignal()
change_color_signal = pyqtSignal(str, str, str) change_color_signal = pyqtSignal(str, str, str)
def __init__(self, serial_number, bench_id, port, block_id, main_app): def __init__(self, serial_number, bench_id, port, block_id, main_app):
super().__init__() super().__init__()
print(f"id{bench_id} :\tport {port}") print(f"id{bench_id}:\tport {port}")
print(f"id{bench_id} :\tserial {serial_number}") print(f"id{bench_id}:\tserial {serial_number}")
self.block = self.add_block(serial_number, bench_id, port, block_id, main_app) 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.main_app = main_app # Store the reference to the BlockStackApp instance
self.serial_number = serial_number self.serial_number = serial_number
@ -46,6 +50,8 @@ class UpdateWorker(QThread):
self.reset_data = False self.reset_data = False
self.homed = False self.homed = False
self.can_start = False self.can_start = False
self.current_job = None
self.current_job = None
self.data_list = [] self.data_list = []
self.profile_data = {} # Dictionary to store profile data self.profile_data = {} # Dictionary to store profile data
@ -98,29 +104,61 @@ class UpdateWorker(QThread):
self.homed = False self.homed = False
self.change_color_signal.emit(self.block_id, 'btn_home', "#a0a000") self.change_color_signal.emit(self.block_id, 'btn_home', "#a0a000")
elif data == '$HOMED': elif data == '$HOMED':
print(f"id{self.bench_id} :\tHoming ok") # print(f"id{self.bench_id} :\tHoming ok")
self.homed = True self.homed = True
self.change_color_signal.emit(self.block_id, 'btn_home', "#5a5a5a") self.change_color_signal.emit(self.block_id, 'btn_home', "#5a5a5a")
except serial.SerialException as e: except serial.SerialException as e:
print(f"Error with port {self.port}: {e}") print(f"Error with port {self.port}: {e}")
def save_data_to_file(self): def save_data_to_file(self):
#FIXME: set name
#FIXME: add file header
#FIXME: compress file
#FIXME: upload to API #FIXME: upload to API
file_path = os.path.join("data", f"{self.bench_id}_data.txt")
# Ensure the directory exists # format:
os.makedirs(os.path.dirname(file_path), exist_ok=True) #
# #bench: FDR1-proto0
# #date: 20250224_232750
# #spool: R587
# #material: Enky PP Ortho V1-2106 20251007-00 N°7
# d:1.730,dm:1.730,dM:1.730,p:0.000,s:0.0,m:1500.0000,q:3,ap:0/3598
# d:1.730,dm:1.730,dM:1.730,p:2.291,s:0.0,m:1504.5000,q:3,ap:0/3598
# d:1.750,dm:1.730,dM:1.750,p:6.021,s:0.0,m:1504.5000,q:3,ap:0/3598
# d:1.730,dm:1.730,dM:1.750,p:11.192,s:0.0,m:1504.5000,q:3,ap:0/3598
# d:1.730,dm:1.730,dM:1.750,p:17.999,s:0.0,m:1504.5000,q:3,ap:0/3598
# d:1.730,dm:1.730,dM:1.750,p:26.049,s:0.0,m:1504.5000,q:3,ap:0/3598
#
# [...]
#
# d:1.750,dm:1.690,dM:1.820,p:1614324.750,s:49.6,m:969.1023,q:2,ap:1180/3598
# d:1.820,dm:1.690,dM:1.820,p:1614324.250,s:1.1,m:972.0096,q:2,ap:1180/3598
# MOTOR DISABLED: FILAMENT OUT OF RANGE
# #end: 20250224_232750
# Write the data to the file
with open(file_path, "w") as file:
for data in self.data_list:
file.write(data + "\n")
print(f"id{self.bench_id}:\tsaving job: {self.current_job}")
spool, vendor, material, batch, description, startstamp = self.current_job
endstamp = datetime.now().strftime("%Y%m%d_%H%M%S")
outfilename = os.path.join("data", f"{spool}_{startstamp}.fsl")
with open(outfilename, "w") as outfile:
outfile.write(F"#bench: {self.serial_number} (#{self.bench_id})\n")
outfile.write(F"#date: {startstamp}\n")
outfile.write(F"#spool: {spool}\n")
outfile.write(F"#material: {vendor} {material} {batch} {description}\n")
for position, diameter in self.data_list:
outfile.write(f"d:{diameter},p:{position}\n")
outfile.write(F"#end: {endstamp}\n")
subprocess.run(["gzip", "-9", outfilename])
def parse_data(self, data): def parse_data(self, data):
self.data_list.append(data)
match = re.match(r"^[#d]:(-?[\d\.]+),p:(-?[\d\.]+)$", data) match = re.match(r"^[#d]:(-?[\d\.]+),p:(-?[\d\.]+)$", data)
if match: if match:
self.diameter_value = float(match.group(1)) self.diameter_value = float(match.group(1))
@ -131,7 +169,7 @@ class UpdateWorker(QThread):
offset_match = re.match(r"^#h:(\d+)", data) offset_match = re.match(r"^#h:(\d+)", data)
if offset_match: if offset_match:
home_offset = int(offset_match.group(1)) home_offset = int(offset_match.group(1))
print(f"id{self.bench_id}:\tOffset: {home_offset:.2f}") # print(f"id{self.bench_id}:\tOffset: {home_offset:.2f}")
self.block.btn_offset.setText(f"Offset: {home_offset:.2f}") self.block.btn_offset.setText(f"Offset: {home_offset:.2f}")
mode_match = re.match(r"^#o:(\d+)", data) mode_match = re.match(r"^#o:(\d+)", data)
@ -198,6 +236,15 @@ class UpdateWorker(QThread):
self.reset_data = True self.reset_data = True
self.is_running = True self.is_running = True
self.current_job = (
self.api_job['spool'],
self.api_job['vendor'],
self.api_job['material'],
self.api_job['batch'],
self.api_job['description'],
datetime.now().strftime("%Y%m%d_%H%M%S")
)
self.change_color_signal.emit(self.block_id, 'btn_start', "#00a000") self.change_color_signal.emit(self.block_id, 'btn_start', "#00a000")
self.change_color_signal.emit(self.block_id, 'btn_prepare', "#5A5A5A") self.change_color_signal.emit(self.block_id, 'btn_prepare', "#5A5A5A")
@ -206,12 +253,14 @@ class UpdateWorker(QThread):
def stop_running(self): def stop_running(self):
if self.is_running: if self.is_running:
self.send_command('R') self.send_command('R')
self.timer.start()
self.block.data_label.setText( self.block.data_label.setText(
f"Job done, processing..." f"Job done, processing..."
) )
# for position, diameter in self.data_list:
# print(f"{position} -> {diameter}")
self.change_color_signal.emit(self.block_id, 'btn_start', "#a00000") self.change_color_signal.emit(self.block_id, 'btn_start', "#a00000")
self.change_color_signal.emit(self.block_id, 'btn_prepare', "#5A5A5A") self.change_color_signal.emit(self.block_id, 'btn_prepare', "#5A5A5A")
@ -341,6 +390,7 @@ class UpdateWorker(QThread):
btn_prepare = QPushButton("Prepare") btn_prepare = QPushButton("Prepare")
btn_prepare.clicked.connect(lambda: self.send_command('P')) btn_prepare.clicked.connect(lambda: self.send_command('P'))
time.sleep(0.1)
btn_prepare.clicked.connect(lambda: self.set_prepare(True)) btn_prepare.clicked.connect(lambda: self.set_prepare(True))
right_layout_1.addWidget(btn_prepare) right_layout_1.addWidget(btn_prepare)
@ -498,8 +548,10 @@ class UpdateWorker(QThread):
response.raise_for_status() # Raise an exception for HTTP errors response.raise_for_status() # Raise an exception for HTTP errors
api_job = response.json() # Parse the JSON response api_job = response.json() # Parse the JSON response
if api_job is not None: self.api_job = api_job
print(f"id{self.bench_id}:\tgot job {api_job['spool']} from API")
if self.api_job is not None:
# print(f"id{self.bench_id}:\tgot job {api_job['spool']} from API")
self.block.data_label.setText( self.block.data_label.setText(
f"Job/Spool: {api_job['spool']}<hr>" f"Job/Spool: {api_job['spool']}<hr>"
f"Fabricant: {api_job['vendor']}<br>" f"Fabricant: {api_job['vendor']}<br>"
@ -510,12 +562,11 @@ class UpdateWorker(QThread):
) )
self.density = float(api_job['density']) self.density = float(api_job['density'])
self.can_start = True self.can_start = True
self.timer.stop()
else: else:
print(f"id{self.bench_id}:\tno job from API") # print(f"id{self.bench_id}:\tno job from API")
self.block.data_label.setText( self.block.data_label.setText(
f"API responded with no job" f"API responded with no job"
) )
self.can_start = False self.can_start = False
except requests.RequestException as e: except requests.RequestException as e:
print(f"Error querying API: {e}") print(f"Error querying API: {e}")

View File

@ -1,8 +1,10 @@
#!./bin/python
import sys import sys
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
from BlockStackApp import BlockStackApp from BlockStackApp import BlockStackApp
if __name__ == '__main__': if __name__ == '__main__':
app = QApplication(sys.argv) app = QApplication(sys.argv)
ex = BlockStackApp() ex = BlockStackApp(True) # True for bordeless fullscreen, False for maximisedgit pl
sys.exit(app.exec_()) sys.exit(app.exec_())