From 2733b4f392650aeeb09986c2b77a87561d4999b3 Mon Sep 17 00:00:00 2001
From: Henry Pinkard <7969470+henrypinkard@users.noreply.github.com>
Date: Fri, 29 Sep 2023 08:20:34 -0700
Subject: [PATCH 1/3] add better error message when no default devices set

---
 pycromanager/_version.py                               | 2 +-
 pycromanager/acquisition/acq_eng_py/internal/engine.py | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/pycromanager/_version.py b/pycromanager/_version.py
index e0584853..a3f9b565 100644
--- a/pycromanager/_version.py
+++ b/pycromanager/_version.py
@@ -1,2 +1,2 @@
-version_info = (0, 29, 6)
+version_info = (0, 29, 7)
 __version__ = ".".join(map(str, version_info))
diff --git a/pycromanager/acquisition/acq_eng_py/internal/engine.py b/pycromanager/acquisition/acq_eng_py/internal/engine.py
index 875c6705..0b1c7b39 100644
--- a/pycromanager/acquisition/acq_eng_py/internal/engine.py
+++ b/pycromanager/acquisition/acq_eng_py/internal/engine.py
@@ -91,9 +91,18 @@ def submit_event_iterator_inner():
         return self.event_generator_executor.submit(submit_event_iterator_inner)
     
 
+    def check_for_default_devices(self, event: AcquisitionEvent):
+        xy_stage = self.core.get_xy_stage_device()
+        z_stage = self.core.get_focus_device()
+        if event.get_z_position() is not None and (z_stage is None or z_stage == ""):
+            raise Exception("Event requires a z position, but no Core-Focus device is set")
+        if event.get_x_position() is not None and (xy_stage is None or xy_stage == ""):
+            raise Exception("Event requires an x position, but no Core-XYStage device is set")
+
     def process_acquisition_event(self, event: AcquisitionEvent) -> Future:
         def process_acquisition_event_inner():
             try:
+                self.check_for_default_devices(event)
                 if event.acquisition_.is_debug_mode():
                     self.core.logMessage("Processing event: " + event.to_string())
                 if event.acquisition_.is_debug_mode():

From f896c29a259efbadcf69475307c949991d65c7c3 Mon Sep 17 00:00:00 2001
From: Henry Pinkard <7969470+henrypinkard@users.noreply.github.com>
Date: Fri, 29 Sep 2023 10:12:18 -0700
Subject: [PATCH 2/3] update AcqEngPy

---
 pycromanager/_version.py                                      | 2 +-
 pycromanager/acquisition/acq_eng_py/main/acquisition_event.py | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/pycromanager/_version.py b/pycromanager/_version.py
index a3f9b565..005de408 100644
--- a/pycromanager/_version.py
+++ b/pycromanager/_version.py
@@ -1,2 +1,2 @@
-version_info = (0, 29, 7)
+version_info = (0, 29, 8)
 __version__ = ".".join(map(str, version_info))
diff --git a/pycromanager/acquisition/acq_eng_py/main/acquisition_event.py b/pycromanager/acquisition/acq_eng_py/main/acquisition_event.py
index 58e12a67..47c25b4b 100644
--- a/pycromanager/acquisition/acq_eng_py/main/acquisition_event.py
+++ b/pycromanager/acquisition/acq_eng_py/main/acquisition_event.py
@@ -69,6 +69,7 @@ def copy(self):
         e.stageDeviceNamesToAxisNames_ = self.stageDeviceNamesToAxisNames_.copy()
         e.xPosition_ = self.xPosition_
         e.yPosition_ = self.yPosition_
+        e.zPosition_ = self.zPosition_
         e.miniumumStartTime_ms_ = self.miniumumStartTime_ms_
         e.slmImage_ = self.slmImage_
         e.acquireImage_ = self.acquireImage_

From 337639f6d21a2c81ba3e1782606d1a4e6c21a7d1 Mon Sep 17 00:00:00 2001
From: Henry Pinkard <7969470+henrypinkard@users.noreply.github.com>
Date: Fri, 29 Sep 2023 10:18:42 -0700
Subject: [PATCH 3/3] increase default timeout to avoid errors

---
 .../acquisition/java_backend_acquisitions.py  | 24 +++++++++----------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/pycromanager/acquisition/java_backend_acquisitions.py b/pycromanager/acquisition/java_backend_acquisitions.py
index 98235619..5521710d 100644
--- a/pycromanager/acquisition/java_backend_acquisitions.py
+++ b/pycromanager/acquisition/java_backend_acquisitions.py
@@ -234,7 +234,7 @@ def __init__(
         show_display: bool=True,
         napari_viewer=None,
         saving_queue_size: int=20,
-        timeout: int=2000,
+        timeout: int=2500,
         port: int=DEFAULT_PORT,
         debug: int=False
     ):
@@ -286,7 +286,8 @@ def __init__(
 
         try:
             self._remote_notification_handler = JavaObject('org.micromanager.remote.RemoteNotificationHandler',
-                                                           args=[self._acq], port=self._port, new_socket=False)
+                                                           args=[self._acq], port=self._port, new_socket=False,
+                                                           timeout=self._timeout)
             self._acq_notification_recieving_thread = self._start_receiving_notifications()
             self._acq_notification_dispatcher_thread = self._start_notification_dispatcher(notification_callback_fn)
         # TODO: can remove this after this feature has been present for a while
@@ -476,7 +477,7 @@ def _initialize_image_processor(self, **kwargs):
 
         if kwargs['image_process_fn'] is not None:
             java_processor = JavaObject(
-                "org.micromanager.remote.RemoteImageProcessor", port=self._port
+                "org.micromanager.remote.RemoteImageProcessor", port=self._port, timeout=self._timeout
             )
             self._acq.add_image_processor(java_processor)
             self._processor_thread = self._start_processor(
@@ -489,14 +490,14 @@ def _initialize_hooks(self, **kwargs):
         self._hook_threads = []
         if kwargs['event_generation_hook_fn'] is not None:
             hook = JavaObject(
-                "org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq]
+                "org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq], timeout=self._timeout
             )
             self._hook_threads.append(self._start_hook(hook, kwargs['event_generation_hook_fn'],
                                                        self._event_queue, process=False))
             self._acq.add_hook(hook, self._acq.EVENT_GENERATION_HOOK)
         if kwargs['pre_hardware_hook_fn'] is not None:
             hook = JavaObject(
-                "org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq]
+                "org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq], timeout=self._timeout
             )
             self._hook_threads.append(self._start_hook(hook,
                                             kwargs['pre_hardware_hook_fn'], self._event_queue,
@@ -504,14 +505,14 @@ def _initialize_hooks(self, **kwargs):
             self._acq.add_hook(hook, self._acq.BEFORE_HARDWARE_HOOK)
         if kwargs['post_hardware_hook_fn'] is not None:
             hook = JavaObject(
-                "org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq]
+                "org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq], timeout=self._timeout
             )
             self._hook_threads.append(self._start_hook(hook, kwargs['post_hardware_hook_fn'],
                                                        self._event_queue, process=False))
             self._acq.add_hook(hook, self._acq.AFTER_HARDWARE_HOOK)
         if kwargs['post_camera_hook_fn'] is not None:
             hook = JavaObject(
-                "org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq],
+                "org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq], timeout=self._timeout
             )
             self._hook_threads.append(self._start_hook(hook, kwargs['post_camera_hook_fn'],
                                                        self._event_queue, process=False))
@@ -523,7 +524,7 @@ def _create_remote_acquisition(self, **kwargs):
             # create a new socket for it to run on so that it can have blocking calls without interfering with
             # the main socket or other internal sockets
             new_socket=True,
-            port=self._port, args=[core], debug=self._debug)
+            port=self._port, args=[core], debug=self._debug, timeout=self._timeout)
         show_viewer = kwargs['show_display'] is True and kwargs['napari_viewer'] is None
         self._acq = acq_factory.create_acquisition(kwargs['directory'], kwargs['name'], show_viewer,
                                                    kwargs['saving_queue_size'], self._debug,)
@@ -665,9 +666,8 @@ def __init__(
 
     def _create_remote_acquisition(self, port, **kwargs):
         core = ZMQRemoteMMCoreJ(port=self._port, timeout=self._timeout)
-        acq_factory = JavaObject(
-            "org.micromanager.remote.RemoteAcquisitionFactory", port=self._port, args=[core]
-        )
+        acq_factory = JavaObject("org.micromanager.remote.RemoteAcquisitionFactory",
+                                 port=self._port, args=[core], timeout=self._timeout)
 
         show_viewer = kwargs['show_display'] is True and\
                       kwargs['napari_viewer'] is None and\
@@ -711,7 +711,7 @@ def __init__(
             show_display: bool=True,
             image_saved_fn: callable=None,
             saving_queue_size: int=20,
-            timeout: int=1000,
+            timeout: int=2500,
             port: int=DEFAULT_PORT,
             debug: bool=False,
     ):