diff --git a/.idea/cs-fancy-clock.iml b/.idea/cs-fancy-clock.iml
index 2c80e1269497d12e018fd6afa29982e56b0fb70d..53e113651728f0424d584ea209a227a3957db8e4 100644
--- a/.idea/cs-fancy-clock.iml
+++ b/.idea/cs-fancy-clock.iml
@@ -4,7 +4,7 @@
     <content url="file://$MODULE_DIR$">
       <excludeFolder url="file://$MODULE_DIR$/.venv" />
     </content>
-    <orderEntry type="inheritedJdk" />
+    <orderEntry type="jdk" jdkName="Python 3.10 (cs-fancy-clock)" jdkType="Python SDK" />
     <orderEntry type="sourceFolder" forTests="false" />
   </component>
 </module>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index aa1a89dc11e565177fd80429d6bae9a90894896b..49a77e5b0d7f3bb03aea4f068954a0350ccff68e 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,5 +3,5 @@
   <component name="Black">
     <option name="sdkName" value="Python 3.10 (cs-fancy-clock)" />
   </component>
-  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (cs-fancy-clock)" project-jdk-type="Python SDK" />
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (cs-fancy-clock)" project-jdk-type="Python SDK" />
 </project>
\ No newline at end of file
diff --git a/main.py b/main.py
index 0e605cbfc7155b0f0221f8e183cf0693e4b68ad1..4f34567a5ea9302416fb895a8f1cc3bc13211c8a 100644
--- a/main.py
+++ b/main.py
@@ -95,30 +95,68 @@ def wr_index():
 
 @app.route("/api/available_fonts")
 def wr_available_fonts():
+    """
+    Returns a list of available fonts on the system.
+    :return: A JSON response with a list of available fonts.
+    """
+
     return json_response(pygame.font.get_fonts())
 
 @app.route("/api/available_widgets")
 def wr_available_widgets():
+    """
+    Returns a list of available widgets.
+    :return: A JSON response with a list of available widgets.
+    """
+
     return json_response(PROP_AVAILABLE_WIDGETS)
 
 
 @app.route("/api/get_state")
 def wr_get_state():
-    return json_response({}) # TODO
+    return json_response({
+
+    }) # TODO
 
 @app.route("/api/toggle_screen_state", methods=["POST"])
 def wr_toggle_state():
-    mainthread_queue.put("TOGGLE_SCREEN_STATE")
-    return json_response({
-        "status": "OK"
-    })
+    """
+    Toggles the screen state between widget cycle and single widget.
+    :return: A JSON response with the status of the request.
+    """
+
+    global screen_state, screen_state_lock
+
+    with screen_state_lock:
+        if screen_state == ScreenState.WIDGET_CYCLE:
+            screen_state = ScreenState.WIDGET_SINGLE
+        elif screen_state == ScreenState.WIDGET_SINGLE:
+            screen_state = ScreenState.WIDGET_CYCLE
+
+        return json_response({
+            "status": "OK",
+            "state": screen_state.name
+        })
 
 @app.route("/api/available_patterns")
 def wr_available_patterns():
+    """
+    Queries available patterns from the server.
+    :return: A JSON response with a list of available patterns.
+    """
+
     return json_response(PROP_AVAILABLE_PATTERNS)
 
 @app.route("/api/set_widget", methods=["POST"])
 def wr_set_widget():
+    """
+    Sets the widget configuration for the screen temporarily (does not write to the config).
+
+    Will only really work if the screen mode is set to single rather than cycle,
+    but it doesn't prevent you from setting it.
+
+    :return: A JSON response with the status of the request.
+    """
     # Make sure the request is valid
     valid, validation_response = verify_json_request(request, ["widget"])
     if not valid:
@@ -152,6 +190,15 @@ def wr_set_widget():
 
 @app.route("/api/set_pattern", methods=["POST"])
 def wr_set_pattern():
+    """
+    Sets the pattern configuration for the LEDs temporarily (does not write to the config).
+
+    Will only really work if the screen mode is set to single rather than cycle,
+    but it doesn't prevent you from setting it.
+
+    :return: A JSON response with the status of the request.
+    """
+
     # Make sure the request is valid
     valid, validation_response = verify_json_request(request, ["pattern"])
     if not valid:
@@ -185,6 +232,12 @@ def wr_set_pattern():
 
 @app.route("/api/set_sequence", methods=["POST"])
 def wr_set_sequence():
+    """
+    Sets the sequence configuration for the widgets and patterns.
+    Uses the request json "widget" and "pattern" to set the sequence.
+    :return: A JSON response with the status of the request.
+    """
+
     # Make sure the request is valid
     valid, validation_response = verify_json_request(request, ["widget", "pattern"])
     if not valid:
@@ -395,6 +448,8 @@ if __name__ == "__main__":
         raise ValueError("No patterns in sequence")
 
     screen_state = ScreenState.WIDGET_CYCLE
+    screen_state_lock = threading.Lock()
+    screen_state_event = threading.Event()
 
     initial_widget = widget_sequence[0]
     initial_pattern = pattern_sequence[0]
@@ -457,48 +512,42 @@ if __name__ == "__main__":
                     force_change_widget = True
                 elif message == "CYCLE_PATTERN":
                     force_change_pattern = True
-                elif message == "TOGGLE_SCREEN_STATE":
-                    if screen_state == ScreenState.WIDGET_CYCLE:
-                        screen_state = ScreenState.WIDGET_SINGLE
-                    elif screen_state == ScreenState.WIDGET_SINGLE:
-                        screen_state = ScreenState.WIDGET_CYCLE
-                    else:
-                        pass
-
             except queue.Empty:
                 pass
-            # Check if time delta has passed
-            if screen_state == ScreenState.WIDGET_CYCLE:
-                # For Widgets
-                curr_widget = widget_sequence[current_widget_index]
-                if curr_widget.get("duration", -1) != -1 or force_change_widget:
-                    # Check if the widget has existed for too long
-                    if curr_widget.get("duration") * 1000 <= current_widget_delta or force_change_widget:
-                        # Set the widget to the next widget
-                        current_widget_index += 1
-                        if current_widget_index >= len(widget_sequence):
-                            current_widget_index = 0
-                        display_queue.put("SET_WIDGET:" +
-                                          widget_sequence[current_widget_index].get("type") + ":" +
-                                          encode_dict(widget_sequence[current_widget_index].get("config_override", {}))
+
+            # Widget cycle after time delta
+            with screen_state_lock:
+                if screen_state == ScreenState.WIDGET_CYCLE:
+                    # For Widgets
+                    curr_widget = widget_sequence[current_widget_index]
+                    if curr_widget.get("duration", -1) != -1 or force_change_widget:
+                        # Check if the widget has existed for too long
+                        if curr_widget.get("duration") * 1000 <= current_widget_delta or force_change_widget:
+                            # Set the widget to the next widget
+                            current_widget_index += 1
+                            if current_widget_index >= len(widget_sequence):
+                                current_widget_index = 0
+                            display_queue.put("SET_WIDGET:" +
+                                              widget_sequence[current_widget_index].get("type") + ":" +
+                                              encode_dict(widget_sequence[current_widget_index].get("config_override", {}))
+                                              )
+                            current_widget_delta = 0
+                            force_change_widget = False
+                    # For patterns
+                    curr_pattern = pattern_sequence[current_pattern_index]
+                    if curr_pattern.get("duration", -1) != -1 or force_change_pattern:
+                        # Check if the pattern has existed for too long
+                        if curr_pattern.get("duration") * 1000 <= current_pattern_delta or force_change_pattern:
+                            # Set the pattern to the next pattern
+                            current_pattern_index += 1
+                            if current_pattern_index >= len(pattern_sequence):
+                                current_pattern_index = 0
+                            led_queue.put("SET_PATTERN:" +
+                                          pattern_sequence[current_pattern_index].get("type") + ":" +
+                                          encode_dict(pattern_sequence[current_pattern_index].get("config_override", {}))
                                           )
-                        current_widget_delta = 0
-                        force_change_widget = False
-                # For patterns
-                curr_pattern = pattern_sequence[current_pattern_index]
-                if curr_pattern.get("duration", -1) != -1 or force_change_pattern:
-                    # Check if the pattern has existed for too long
-                    if curr_pattern.get("duration") * 1000 <= current_pattern_delta or force_change_pattern:
-                        # Set the pattern to the next pattern
-                        current_pattern_index += 1
-                        if current_pattern_index >= len(pattern_sequence):
-                            current_pattern_index = 0
-                        led_queue.put("SET_PATTERN:" +
-                                      pattern_sequence[current_pattern_index].get("type") + ":" +
-                                      encode_dict(pattern_sequence[current_pattern_index].get("config_override", {}))
-                                      )
-                        current_pattern_delta = 0
-                        force_change_pattern = False
+                            current_pattern_delta = 0
+                            force_change_pattern = False
 
             # Keep main thread alive
             current_widget_delta += hw_config["main_update_frequency"]