Преглед изворни кода

fix homing, improve error handling

Tuan Nguyen пре 11 месеци
родитељ
комит
4a425ccbd6

+ 30 - 7
dune_weaver_flask/app.py

@@ -114,6 +114,10 @@ def run_theta_rho():
         return jsonify({'error': 'File not found'}), 404
         return jsonify({'error': 'File not found'}), 404
 
 
     try:
     try:
+            
+        if not (state.conn.is_connected() if state.conn else False):
+            logger.warning("Attempted to run a pattern without a connection")
+            return jsonify({"success": False, "error": "Connection not established"}), 400
         files_to_run = [file_path]
         files_to_run = [file_path]
         logger.info(f'Running theta-rho file: {file_name} with pre_execution={pre_execution}')
         logger.info(f'Running theta-rho file: {file_name} with pre_execution={pre_execution}')
         pattern_manager.run_theta_rho_files(files_to_run, clear_pattern=pre_execution)
         pattern_manager.run_theta_rho_files(files_to_run, clear_pattern=pre_execution)
@@ -124,12 +128,18 @@ def run_theta_rho():
 
 
 @app.route('/stop_execution', methods=['POST'])
 @app.route('/stop_execution', methods=['POST'])
 def stop_execution():
 def stop_execution():
+    if not (state.conn.is_connected() if state.conn else False):
+        logger.warning("Attempted to stop without a connection")
+        return jsonify({"success": False, "error": "Connection not established"}), 400
     pattern_manager.stop_actions()
     pattern_manager.stop_actions()
     return jsonify({'success': True})
     return jsonify({'success': True})
 
 
 @app.route('/send_home', methods=['POST'])
 @app.route('/send_home', methods=['POST'])
 def send_home():
 def send_home():
     try:
     try:
+        if not (state.conn.is_connected() if state.conn else False):
+            logger.warning("Attempted to move to home without a connection")
+            return jsonify({"success": False, "error": "Connection not established"}), 400
         connection_manager.home()
         connection_manager.home()
         return jsonify({'success': True})
         return jsonify({'success': True})
     except Exception as e:
     except Exception as e:
@@ -141,6 +151,10 @@ def run_specific_theta_rho_file(file_name):
     file_path = os.path.join(pattern_manager.THETA_RHO_DIR, file_name)
     file_path = os.path.join(pattern_manager.THETA_RHO_DIR, file_name)
     if not os.path.exists(file_path):
     if not os.path.exists(file_path):
         return jsonify({'error': 'File not found'}), 404
         return jsonify({'error': 'File not found'}), 404
+        
+    if not (state.conn.is_connected() if state.conn else False):
+        logger.warning("Attempted to run a pattern without a connection")
+        return jsonify({"success": False, "error": "Connection not established"}), 400
 
 
     pattern_manager.run_theta_rho_file(file_path)
     pattern_manager.run_theta_rho_file(file_path)
     return jsonify({'success': True})
     return jsonify({'success': True})
@@ -169,8 +183,8 @@ def delete_theta_rho_file():
 def move_to_center():
 def move_to_center():
     global current_theta
     global current_theta
     try:
     try:
-        if not state.conn.is_connected():
-            logger.warning("Attempted to move to center without connection")
+        if not (state.conn.is_connected() if state.conn else False):
+            logger.warning("Attempted to move to center without a connection")
             return jsonify({"success": False, "error": "Connection not established"}), 400
             return jsonify({"success": False, "error": "Connection not established"}), 400
 
 
         logger.info("Moving device to center position")
         logger.info("Moving device to center position")
@@ -185,8 +199,8 @@ def move_to_center():
 def move_to_perimeter():
 def move_to_perimeter():
     global current_theta
     global current_theta
     try:
     try:
-        if not state.conn.is_connected():
-            logger.warning("Attempted to move to perimeter without connection")
+        if not (state.conn.is_connected() if state.conn else False):
+            logger.warning("Attempted to move to perimeter without a connection")
             return jsonify({"success": False, "error": "Connection not established"}), 400
             return jsonify({"success": False, "error": "Connection not established"}), 400
         pattern_manager.reset_theta()
         pattern_manager.reset_theta()
         pattern_manager.move_polar(0,1)
         pattern_manager.move_polar(0,1)
@@ -216,8 +230,8 @@ def preview_thr():
 
 
 @app.route('/send_coordinate', methods=['POST'])
 @app.route('/send_coordinate', methods=['POST'])
 def send_coordinate():
 def send_coordinate():
-    if not state.conn.is_connected():
-        logger.warning("Attempted to send coordinate without connection")
+    if not (state.conn.is_connected() if state.conn else False):
+        logger.warning("Attempted to send coordinate without a connection")
         return jsonify({"success": False, "error": "connection not established"}), 400
         return jsonify({"success": False, "error": "connection not established"}), 400
 
 
     try:
     try:
@@ -242,7 +256,7 @@ def download_file(filename):
 
 
 @app.route('/serial_status', methods=['GET'])
 @app.route('/serial_status', methods=['GET'])
 def serial_status():
 def serial_status():
-    connected = state.conn.is_connected()
+    connected = state.conn.is_connected() if state.conn else False
     port = state.port
     port = state.port
     logger.debug(f"Serial status check - connected: {connected}, port: {port}")
     logger.debug(f"Serial status check - connected: {connected}, port: {port}")
     return jsonify({
     return jsonify({
@@ -336,6 +350,11 @@ def run_playlist():
         logger.warning("Run playlist request received without playlist name")
         logger.warning("Run playlist request received without playlist name")
         return jsonify({"success": False, "error": "Missing 'playlist_name' field"}), 400
         return jsonify({"success": False, "error": "Missing 'playlist_name' field"}), 400
 
 
+        
+    if not (state.conn.is_connected() if state.conn else False):
+        logger.warning("Attempted to run a playlist without a connection")
+        return jsonify({"success": False, "error": "Connection not established"}), 400
+
     playlist_name = data["playlist_name"]
     playlist_name = data["playlist_name"]
     pause_time = data.get("pause_time", 0)
     pause_time = data.get("pause_time", 0)
     clear_pattern = data.get("clear_pattern", None)
     clear_pattern = data.get("clear_pattern", None)
@@ -379,6 +398,10 @@ def run_playlist():
 @app.route('/set_speed', methods=['POST'])
 @app.route('/set_speed', methods=['POST'])
 def set_speed():
 def set_speed():
     try:
     try:
+        if not (state.conn.is_connected() if state.conn else False):
+            logger.warning("Attempted to change speed without a connection")
+            return jsonify({"success": False, "error": "Connection not established"}), 400
+        
         data = request.json
         data = request.json
         new_speed = data.get('speed')
         new_speed = data.get('speed')
 
 

+ 7 - 6
dune_weaver_flask/modules/connection/connection_manager.py

@@ -6,6 +6,7 @@ import serial.tools.list_ports
 import websocket
 import websocket
 
 
 from dune_weaver_flask.modules.core.state import state
 from dune_weaver_flask.modules.core.state import state
+from dune_weaver_flask.modules.core.pattern_manager import move_polar, reset_theta
 
 
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
 
 
@@ -163,7 +164,7 @@ def connect_device(homing=True):
         state.conn = WebSocketConnection('ws://fluidnc.local:81')
         state.conn = WebSocketConnection('ws://fluidnc.local:81')
     else:
     else:
         state.conn = SerialConnection(ports[0])
         state.conn = SerialConnection(ports[0])
-    if state.conn.is_connected():
+    if (state.conn.is_connected() if state.conn else False):
         device_init(homing)
         device_init(homing)
 
 
 def get_status_response() -> str:
 def get_status_response() -> str:
@@ -230,7 +231,7 @@ def get_machine_steps(timeout=10):
     Send "$$" to retrieve machine settings and update state.
     Send "$$" to retrieve machine settings and update state.
     Returns True if the expected configuration is received, or False if it times out.
     Returns True if the expected configuration is received, or False if it times out.
     """
     """
-    if not state.conn.is_connected():
+    if not (state.conn.is_connected() if state.conn else False):
         logger.error("Connection is not established.")
         logger.error("Connection is not established.")
         return False
         return False
 
 
@@ -290,9 +291,9 @@ def home():
         logger.info("Sensorless homing not supported. Using crash homing")
         logger.info("Sensorless homing not supported. Using crash homing")
         logger.info(f"Homing with speed {state.speed}")
         logger.info(f"Homing with speed {state.speed}")
         send_grbl_coordinates(0, -22, state.speed, home=True)
         send_grbl_coordinates(0, -22, state.speed, home=True)
+        state.machine_y -= 22
+
     state.current_theta = state.current_rho = 0
     state.current_theta = state.current_rho = 0
-    update_machine_position()
-    state.save()
 
 
 def check_idle():
 def check_idle():
     """
     """
@@ -345,7 +346,7 @@ def restart_connection(homing=False):
         True if the connection was restarted successfully, False otherwise.
         True if the connection was restarted successfully, False otherwise.
     """
     """
     try:
     try:
-        if state.conn and state.conn.is_connected():
+        if (state.conn.is_connected() if state.conn else False):
             logger.info("Closing current connection...")
             logger.info("Closing current connection...")
             state.conn.close()
             state.conn.close()
     except Exception as e:
     except Exception as e:
@@ -357,7 +358,7 @@ def restart_connection(homing=False):
     logger.info("Attempting to restart connection...")
     logger.info("Attempting to restart connection...")
     try:
     try:
         connect_device(homing)  # This will set state.conn appropriately.
         connect_device(homing)  # This will set state.conn appropriately.
-        if state.conn and state.conn.is_connected():
+        if (state.conn.is_connected() if state.conn else False):
             logger.info("Connection restarted successfully.")
             logger.info("Connection restarted successfully.")
             return True
             return True
         else:
         else:

+ 1 - 2
dune_weaver_flask/modules/core/pattern_manager.py

@@ -149,7 +149,6 @@ def move_polar(theta, rho):
     x_total_steps = state.x_steps_per_mm * (100/x_scaling_factor)
     x_total_steps = state.x_steps_per_mm * (100/x_scaling_factor)
     y_total_steps = state.y_steps_per_mm * (100/y_scaling_factor)
     y_total_steps = state.y_steps_per_mm * (100/y_scaling_factor)
         
         
-    x_increment / 50 * (x_total_steps)
     offset = x_increment * (x_total_steps * x_scaling_factor / (state.gear_ratio * y_total_steps * y_scaling_factor))
     offset = x_increment * (x_total_steps * x_scaling_factor / (state.gear_ratio * y_total_steps * y_scaling_factor))
     y_increment += offset
     y_increment += offset
     
     
@@ -193,7 +192,7 @@ def run_theta_rho_file(file_path, schedule_hours=None):
     # if not connection_manager.get_status_response() and isinstance(state.conn, connection_manager.WebSocketConnection):
     # if not connection_manager.get_status_response() and isinstance(state.conn, connection_manager.WebSocketConnection):
     #     logger.info('Cannot get status response, restarting connection')
     #     logger.info('Cannot get status response, restarting connection')
     #     connection_manager.restart_connection(home=False)
     #     connection_manager.restart_connection(home=False)
-    # if not state.conn and not state.conn.is_connected():
+    # if (state.conn.is_connected() if state.conn else False):
     #     logger.error('Connection not established')
     #     logger.error('Connection not established')
     #     return
     #     return
     # if not file_path:
     # if not file_path:

+ 1 - 1
dune_weaver_flask/modules/mqtt/handler.py

@@ -239,7 +239,7 @@ class MQTTHandler(BaseMQTTHandler):
             
             
     def _publish_serial_state(self):
     def _publish_serial_state(self):
         """Helper to publish serial state."""
         """Helper to publish serial state."""
-        serial_connected = state.conn.is_connected()
+        serial_connected = (state.conn.is_connected() if state.conn else False)
         serial_port = state.port if serial_connected else None
         serial_port = state.port if serial_connected else None
         serial_status = f"connected to {serial_port}" if serial_connected else "disconnected"
         serial_status = f"connected to {serial_port}" if serial_connected else "disconnected"
         self.client.publish(self.serial_state_topic, serial_status, retain=True)
         self.client.publish(self.serial_state_topic, serial_status, retain=True)

+ 1 - 1
dune_weaver_flask/modules/mqtt/utils.py

@@ -39,7 +39,7 @@ def get_mqtt_state():
     is_running = bool(state.current_playing_file) and not state.stop_requested
     is_running = bool(state.current_playing_file) and not state.stop_requested
     
     
     # Get serial status
     # Get serial status
-    serial_connected = state.conn.is_connected
+    serial_connected = (state.conn.is_connected() if state.conn else False)
     serial_port = state.port if serial_connected else None
     serial_port = state.port if serial_connected else None
     serial_status = f"connected to {serial_port}" if serial_connected else "disconnected"
     serial_status = f"connected to {serial_port}" if serial_connected else "disconnected"
     
     

+ 4 - 5
dune_weaver_flask/static/js/main.js

@@ -261,6 +261,7 @@ async function runThetaRho() {
     } else {
     } else {
         logMessage(`Failed to run file: ${selectedFile}`,LOG_TYPE.ERROR);
         logMessage(`Failed to run file: ${selectedFile}`,LOG_TYPE.ERROR);
     }
     }
+    updateCurrentlyPlaying();
 }
 }
 
 
 async function stopExecution() {
 async function stopExecution() {
@@ -1529,13 +1530,11 @@ function formatSecondsToHMS(seconds) {
 // Function to start or stop updates based on visibility
 // Function to start or stop updates based on visibility
 function handleVisibilityChange() {
 function handleVisibilityChange() {
     if (document.hasFocus()) {
     if (document.hasFocus()) {
-        // User is active, start updating
+        updateCurrentlyPlaying(); // Run immediately
         if (!updateInterval) {
         if (!updateInterval) {
-            updateCurrentlyPlaying(); // Run immediately
-            updateInterval = setInterval(updateCurrentlyPlaying, 5000); // Update every 5s
+            updateInterval = setInterval(updateCurrentlyPlaying, 3000);
         }
         }
     } else {
     } else {
-        // User is inactive, stop updating
         clearInterval(updateInterval);
         clearInterval(updateInterval);
         updateInterval = null;
         updateInterval = null;
     }
     }
@@ -1708,7 +1707,7 @@ document.addEventListener('DOMContentLoaded', () => {
 
 
     // Periodically check for currently playing status
     // Periodically check for currently playing status
     if (document.hasFocus()) {
     if (document.hasFocus()) {
-        updateInterval = setInterval(updateCurrentlyPlaying, 5000);
+        updateInterval = setInterval(updateCurrentlyPlaying, 3000);
     }
     }
     checkForUpdates();
     checkForUpdates();
 });
 });