pyobs-core 2.0.0.dev42__tar.gz → 2.0.0.dev44__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (445) hide show
  1. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/PKG-INFO +1 -1
  2. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/application.py +9 -1
  3. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/cli/pyobsd.py +13 -3
  4. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/comm.py +11 -1
  5. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/commlogging.py +6 -0
  6. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/dummy/dummycomm.py +13 -5
  7. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/proxy.py +31 -8
  8. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/xmpp/xmppcomm.py +8 -0
  9. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IRunning.py +1 -7
  10. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/interface.py +4 -2
  11. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/mixins/follow.py +16 -4
  12. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/mixins/weatheraware.py +5 -2
  13. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/camera/dummycamera.py +6 -0
  14. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/focus/dummyautofocus.py +0 -4
  15. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/focus/focusmodel.py +8 -3
  16. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/focus/focusseries.py +0 -4
  17. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/module.py +11 -0
  18. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/_baseguiding.py +0 -8
  19. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/acquisition.py +0 -4
  20. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/dummyacquisition.py +0 -4
  21. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/dummyguiding.py +0 -3
  22. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/robotic/mastermind.py +0 -4
  23. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/robotic/pointing.py +1 -5
  24. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/robotic/scheduler.py +0 -4
  25. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/utils/kiosk.py +0 -4
  26. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/utils/trigger.py +0 -4
  27. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/weather/mockweather.py +0 -4
  28. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/weather/weather.py +4 -4
  29. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyproject.toml +1 -1
  30. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/.gitignore +0 -0
  31. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/LICENSE +0 -0
  32. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/__init__.py +0 -0
  33. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/background_task.py +0 -0
  34. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/cli/__init__.py +0 -0
  35. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/cli/_cli.py +0 -0
  36. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/cli/pyobs.py +0 -0
  37. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/cli/pyobsw.py +0 -0
  38. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/__init__.py +0 -0
  39. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/dummy/__init__.py +0 -0
  40. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/local/__init__.py +0 -0
  41. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/local/localcomm.py +0 -0
  42. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/local/localnetwork.py +0 -0
  43. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/xmpp/__init__.py +0 -0
  44. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/xmpp/rpc.py +0 -0
  45. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/xmpp/serializer.py +0 -0
  46. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
  47. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
  48. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/xmpp/xep_0009/rpc.py +0 -0
  49. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
  50. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +0 -0
  51. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
  52. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
  53. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/comm/xmpp/xmppclient.py +0 -0
  54. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/__init__.py +0 -0
  55. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/badweather.py +0 -0
  56. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/event.py +0 -0
  57. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/exposurestatuschanged.py +0 -0
  58. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/filterchanged.py +0 -0
  59. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/focusfound.py +0 -0
  60. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/goodweather.py +0 -0
  61. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/log.py +0 -0
  62. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/modechanged.py +0 -0
  63. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/moduleclosed.py +0 -0
  64. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/moduleopened.py +0 -0
  65. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/motionstatuschanged.py +0 -0
  66. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/move.py +0 -0
  67. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/newimage.py +0 -0
  68. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/newspectrum.py +0 -0
  69. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/offsets.py +0 -0
  70. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/roofclosing.py +0 -0
  71. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/roofopened.py +0 -0
  72. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/taskfailed.py +0 -0
  73. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/taskfinished.py +0 -0
  74. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/taskstarted.py +0 -0
  75. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/events/testevent.py +0 -0
  76. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/__init__.py +0 -0
  77. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/image.py +0 -0
  78. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/meta/__init__.py +0 -0
  79. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/meta/altazoffsets.py +0 -0
  80. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/meta/exptime.py +0 -0
  81. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/meta/genericoffset.py +0 -0
  82. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/meta/onskydistance.py +0 -0
  83. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/meta/pixeloffsets.py +0 -0
  84. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/meta/radecoffsets.py +0 -0
  85. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/meta/skyoffsets.py +0 -0
  86. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processor.py +0 -0
  87. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/__init__.py +0 -0
  88. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/_daobackgroundremover.py +0 -0
  89. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/annotation/__init__.py +0 -0
  90. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/annotation/_pillow.py +0 -0
  91. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/annotation/circle.py +0 -0
  92. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/annotation/crosshair.py +0 -0
  93. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/annotation/text.py +0 -0
  94. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/astrometry/__init__.py +0 -0
  95. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
  96. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
  97. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
  98. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +0 -0
  99. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/astrometry/astrometry.py +0 -0
  100. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/astrometry/dotnet.py +0 -0
  101. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/calibration/__init__.py +0 -0
  102. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
  103. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/calibration/_ccddata_calibrator.py +0 -0
  104. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/calibration/calibration.py +0 -0
  105. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/detection/__init__.py +0 -0
  106. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
  107. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/detection/_source_catalog.py +0 -0
  108. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/detection/daophot.py +0 -0
  109. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/detection/pysep.py +0 -0
  110. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/detection/simpledisk.py +0 -0
  111. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/detection/sourcedetection.py +0 -0
  112. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/exptime/__init__.py +0 -0
  113. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/exptime/exptime.py +0 -0
  114. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/exptime/star.py +0 -0
  115. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/image/__init__.py +0 -0
  116. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/image/addfitsheaders.py +0 -0
  117. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/image/download.py +0 -0
  118. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/image/flip.py +0 -0
  119. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/image/grayscale.py +0 -0
  120. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/image/httpserver.py +0 -0
  121. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/image/normalize.py +0 -0
  122. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/image/save.py +0 -0
  123. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/image/saveimage.py +0 -0
  124. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/image/smooth.py +0 -0
  125. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/image/softbin.py +0 -0
  126. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/misc/__init__.py +0 -0
  127. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/misc/addmask.py +0 -0
  128. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
  129. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/misc/circularmask.py +0 -0
  130. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/misc/createfilename.py +0 -0
  131. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
  132. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/misc/removebackground.py +0 -0
  133. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/modules/__init__.py +0 -0
  134. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/modules/getfitsheaders.py +0 -0
  135. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/offsets/__init__.py +0 -0
  136. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/offsets/astrometry.py +0 -0
  137. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/offsets/brighteststar.py +0 -0
  138. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
  139. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
  140. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
  141. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/offsets/fitsheader.py +0 -0
  142. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/offsets/offsets.py +0 -0
  143. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
  144. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/offsets/projected.py +0 -0
  145. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/offsets/spilled_light.py +0 -0
  146. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/photometry/__init__.py +0 -0
  147. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
  148. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
  149. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +0 -0
  150. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
  151. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/photometry/photometry.py +0 -0
  152. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/photometry/photutil.py +0 -0
  153. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/photometry/pysep.py +0 -0
  154. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/wcs/__init__.py +0 -0
  155. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
  156. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IAbortable.py +0 -0
  157. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IAcquisition.py +0 -0
  158. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IAutoFocus.py +0 -0
  159. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IAutoGuiding.py +0 -0
  160. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IAutonomous.py +0 -0
  161. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IBinning.py +0 -0
  162. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/ICalibrate.py +0 -0
  163. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/ICamera.py +0 -0
  164. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IConfig.py +0 -0
  165. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/ICooling.py +0 -0
  166. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IData.py +0 -0
  167. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IDataSequence.py +0 -0
  168. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IDome.py +0 -0
  169. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IExposure.py +0 -0
  170. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IExposureTime.py +0 -0
  171. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IFilters.py +0 -0
  172. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
  173. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
  174. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IFlatField.py +0 -0
  175. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IFocusModel.py +0 -0
  176. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IFocuser.py +0 -0
  177. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IGain.py +0 -0
  178. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IImageFormat.py +0 -0
  179. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IImageType.py +0 -0
  180. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IMode.py +0 -0
  181. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IModule.py +0 -0
  182. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IMotion.py +0 -0
  183. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IMultiFiber.py +0 -0
  184. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IOffsetsAltAz.py +0 -0
  185. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IOffsetsRaDec.py +0 -0
  186. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IPointingAltAz.py +0 -0
  187. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IPointingBody.py +0 -0
  188. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IPointingHeliocentricPolar.py +0 -0
  189. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IPointingHeliographicStonyhurst.py +0 -0
  190. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IPointingHelioprojective.py +0 -0
  191. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IPointingOrbitalElements.py +0 -0
  192. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IPointingRaDec.py +0 -0
  193. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IPointingSeries.py +0 -0
  194. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IReady.py +0 -0
  195. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IRoof.py +0 -0
  196. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IRotation.py +0 -0
  197. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IRunnable.py +0 -0
  198. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IScriptRunner.py +0 -0
  199. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/ISpectrograph.py +0 -0
  200. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IStartStop.py +0 -0
  201. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IStructuredConfig.py +0 -0
  202. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/ISyncTarget.py +0 -0
  203. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/ITelescope.py +0 -0
  204. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/ITemperatures.py +0 -0
  205. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/ITrackingMode.py +0 -0
  206. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/ITrackingRate.py +0 -0
  207. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IVideo.py +0 -0
  208. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IWeather.py +0 -0
  209. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/IWindow.py +0 -0
  210. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/interfaces/__init__.py +0 -0
  211. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/mixins/__init__.py +0 -0
  212. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/mixins/camerasettings.py +0 -0
  213. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/mixins/fitsheader.py +0 -0
  214. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/mixins/fitsnamespace.py +0 -0
  215. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/mixins/motionstatus.py +0 -0
  216. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/mixins/pipeline.py +0 -0
  217. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/mixins/waitformotion.py +0 -0
  218. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/__init__.py +0 -0
  219. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/camera/__init__.py +0 -0
  220. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/camera/adaptive.py +0 -0
  221. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/camera/basecamera.py +0 -0
  222. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/camera/basespectrograph.py +0 -0
  223. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/camera/basevideo.py +0 -0
  224. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/camera/dummyspectrograph.py +0 -0
  225. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/camera/dummyvideo.py +0 -0
  226. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/camera/pipelinecamera.py +0 -0
  227. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/flatfield/__init__.py +0 -0
  228. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/flatfield/flatfield.py +0 -0
  229. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/flatfield/pointing.py +0 -0
  230. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/flatfield/scheduler.py +0 -0
  231. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/focus/__init__.py +0 -0
  232. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/image/__init__.py +0 -0
  233. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/image/imagewatcher.py +0 -0
  234. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/image/imagewriter.py +0 -0
  235. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/image/pipeline.py +0 -0
  236. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/image/seeing.py +0 -0
  237. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/__init__.py +0 -0
  238. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/_base.py +0 -0
  239. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/autoguiding.py +0 -0
  240. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
  241. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
  242. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
  243. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
  244. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
  245. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/pointing/scienceframeguiding.py +0 -0
  246. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/robotic/__init__.py +0 -0
  247. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/robotic/scriptrunner.py +0 -0
  248. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/roof/__init__.py +0 -0
  249. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/roof/basedome.py +0 -0
  250. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/roof/baseroof.py +0 -0
  251. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/roof/dummyroof.py +0 -0
  252. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/telescope/__init__.py +0 -0
  253. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/telescope/_dummytelescopebase.py +0 -0
  254. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/telescope/basetelescope.py +0 -0
  255. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/telescope/dummyaltaztelescope.py +0 -0
  256. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/telescope/dummyradectelescope.py +0 -0
  257. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/telescope/dummysolartelescope.py +0 -0
  258. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/test/__init__.py +0 -0
  259. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/test/standalone.py +0 -0
  260. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/utils/__init__.py +0 -0
  261. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/utils/dummymode.py +0 -0
  262. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/utils/fluentlogger.py +0 -0
  263. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/utils/httpfilecache.py +0 -0
  264. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/utils/matrix.py +0 -0
  265. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/utils/stellarium.py +0 -0
  266. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/utils/telegram.py +0 -0
  267. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/weather/__init__.py +0 -0
  268. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/weather/weather_api.py +0 -0
  269. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/modules/weather/weather_state.py +0 -0
  270. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/object.py +0 -0
  271. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/py.typed +0 -0
  272. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/__init__.py +0 -0
  273. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/observation.py +0 -0
  274. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/__init__.py +0 -0
  275. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/astroplanscheduler.py +0 -0
  276. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
  277. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
  278. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
  279. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +0 -0
  280. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +0 -0
  281. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +0 -0
  282. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
  283. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/dataprovider.py +0 -0
  284. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
  285. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
  286. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
  287. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/merits/constant.py +0 -0
  288. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/merits/follow.py +0 -0
  289. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/merits/interval.py +0 -0
  290. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/merits/merit.py +0 -0
  291. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
  292. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/merits/random.py +0 -0
  293. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
  294. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/merits/transit.py +0 -0
  295. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
  296. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/ondemandscheduler.py +0 -0
  297. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/targets/__init__.py +0 -0
  298. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
  299. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/targets/heliocentricpolartarget.py +0 -0
  300. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/targets/helioprojectivetarget.py +0 -0
  301. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
  302. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
  303. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
  304. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
  305. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/targets/target.py +0 -0
  306. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
  307. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/__init__.py +0 -0
  308. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
  309. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/calibration/darkbias.py +0 -0
  310. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/calibration/pointing.py +0 -0
  311. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/calibration/skyflats.py +0 -0
  312. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/control/__init__.py +0 -0
  313. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/control/cases.py +0 -0
  314. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/control/conditional.py +0 -0
  315. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/control/parallel.py +0 -0
  316. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/control/selector.py +0 -0
  317. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/control/sequential.py +0 -0
  318. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/exceptions.py +0 -0
  319. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
  320. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/imaging/autofocus.py +0 -0
  321. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/imaging/imaging.py +0 -0
  322. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
  323. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/script.py +0 -0
  324. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/utils/__init__.py +0 -0
  325. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/utils/callmodule.py +0 -0
  326. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
  327. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/scripts/utils/log.py +0 -0
  328. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/__init__.py +0 -0
  329. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/backend/__init__.py +0 -0
  330. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/backend/observationarchive.py +0 -0
  331. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/backend/taskarchive.py +0 -0
  332. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
  333. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
  334. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
  335. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/__init__.py +0 -0
  336. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/_portal.py +0 -0
  337. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
  338. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
  339. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/configdb.py +0 -0
  340. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
  341. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
  342. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
  343. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/scripts/autofocus.py +0 -0
  344. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/scripts/default.py +0 -0
  345. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/scripts/script.py +0 -0
  346. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/task.py +0 -0
  347. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
  348. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/lco/taskrunner.py +0 -0
  349. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/memory/__init__.py +0 -0
  350. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
  351. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
  352. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/observationarchive.py +0 -0
  353. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/storage/taskarchive.py +0 -0
  354. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/task.py +0 -0
  355. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/taskrunner.py +0 -0
  356. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/__init__.py +0 -0
  357. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/archive/__init__.py +0 -0
  358. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/archive/archive.py +0 -0
  359. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/archive/local_archive.py +0 -0
  360. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -0
  361. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/exptime/__init__.py +0 -0
  362. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/exptime/exptime.py +0 -0
  363. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/exptime/stellarexptime.py +0 -0
  364. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
  365. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
  366. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/skyflats/flatfielder.py +0 -0
  367. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
  368. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -0
  369. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -0
  370. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
  371. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -0
  372. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -0
  373. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -0
  374. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
  375. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/__init__.py +0 -0
  376. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/average.py +0 -0
  377. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/cache.py +0 -0
  378. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/config.py +0 -0
  379. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/config_schema.py +0 -0
  380. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/coordinates.py +0 -0
  381. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/curvefit.py +0 -0
  382. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/enums.py +0 -0
  383. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/exceptions.py +0 -0
  384. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/fits.py +0 -0
  385. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/focusseries/__init__.py +0 -0
  386. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/focusseries/base.py +0 -0
  387. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/focusseries/photometry.py +0 -0
  388. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/focusseries/projection.py +0 -0
  389. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/grids/__init__.py +0 -0
  390. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/grids/filters.py +0 -0
  391. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/grids/grid.py +0 -0
  392. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/grids/gridnode.py +0 -0
  393. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/grids/pipeline.py +0 -0
  394. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/gui/__init__.py +0 -0
  395. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/gui/camera/__init__.py +0 -0
  396. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/gui/camera/binningwidget.py +0 -0
  397. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
  398. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/gui/camera/exposewidget.py +0 -0
  399. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
  400. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
  401. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
  402. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
  403. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/http.py +0 -0
  404. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/influxdb.py +0 -0
  405. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/logger.py +0 -0
  406. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/logging/__init__.py +0 -0
  407. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/logging/context.py +0 -0
  408. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/logging/resolvableerror.py +0 -0
  409. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/modulegui.py +0 -0
  410. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/offsets/__init__.py +0 -0
  411. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
  412. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/offsets/applyoffsets.py +0 -0
  413. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
  414. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/parallel.py +0 -0
  415. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/pipeline/__init__.py +0 -0
  416. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/pipeline/night.py +0 -0
  417. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/pipeline/pipeline.py +0 -0
  418. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/publisher/__init__.py +0 -0
  419. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/publisher/csv.py +0 -0
  420. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/publisher/http.py +0 -0
  421. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/publisher/log.py +0 -0
  422. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/publisher/multi.py +0 -0
  423. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/publisher/publisher.py +0 -0
  424. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/serialization.py +0 -0
  425. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/shellcommand.py +0 -0
  426. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/threads/__init__.py +0 -0
  427. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/threads/lockwithabort.py +0 -0
  428. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/time.py +0 -0
  429. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/utils/units.py +0 -0
  430. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/version.py +0 -0
  431. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/__init__.py +0 -0
  432. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/archivefile.py +0 -0
  433. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/bufferedfile.py +0 -0
  434. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/file.py +0 -0
  435. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/filelists/__init__.py +0 -0
  436. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/filelists/filelist.py +0 -0
  437. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/filelists/testing.py +0 -0
  438. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/httpfile.py +0 -0
  439. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/localfile.py +0 -0
  440. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/memfile.py +0 -0
  441. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/sftpfile.py +0 -0
  442. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/smbfile.py +0 -0
  443. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/sshfile.py +0 -0
  444. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/tempfile.py +0 -0
  445. {pyobs_core-2.0.0.dev42 → pyobs_core-2.0.0.dev44}/pyobs/vfs/vfs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyobs-core
3
- Version: 2.0.0.dev42
3
+ Version: 2.0.0.dev44
4
4
  Summary: robotic telescope software
5
5
  Author-email: Tim-Oliver Husser <thusser@uni-goettingen.de>
6
6
  License-Expression: MIT
@@ -10,6 +10,7 @@ from typing import Any, TypedDict
10
10
 
11
11
  import yaml
12
12
 
13
+ from pyobs.comm.dummy import DummyComm
13
14
  from pyobs.modules import Module, MultiModule
14
15
  from pyobs.object import get_class_from_string, get_object
15
16
  from pyobs.utils.config import pre_process_yaml
@@ -181,6 +182,14 @@ class Application:
181
182
  asyncio.set_event_loop(self._loop)
182
183
 
183
184
  # create module and open it
185
+ config_stem = Path(self._config).stem.lstrip("_")
186
+ if "comm" not in cfg and not issubclass(klass, MultiModule):
187
+ # no comm configured -- module would otherwise fall back to a DummyComm named
188
+ # with the fixed placeholder "module", indistinguishable from every other
189
+ # comm-less module in PYOBS_MODULE log tagging (see
190
+ # specs/steering/finding-module-logs-under-pyobsd.md) and guaranteed to trip the
191
+ # stem-mismatch check below. Give it the config file's own stem instead.
192
+ cfg = {**cfg, "comm": {"class": f"{DummyComm.__module__}.{DummyComm.__name__}", "name": config_stem}}
184
193
  log.info("Creating module from class %s...", klass.__name__)
185
194
  self._module = get_object(cfg, Module)
186
195
 
@@ -193,7 +202,6 @@ class Application:
193
202
  # (module.py), never meant to match a filename -- each child module is already
194
203
  # correctly distinguished via execute()/BackgroundTask.
195
204
  if not isinstance(self._module, MultiModule):
196
- config_stem = Path(self._config).stem.lstrip("_")
197
205
  if self._module.name != config_stem:
198
206
  log.warning(
199
207
  "Config file stem (%s) does not match module's own name "
@@ -33,6 +33,7 @@ class PyobsDaemonCLI(CLI):
33
33
  "log_path",
34
34
  "log_level",
35
35
  "syslog",
36
+ "file_log",
36
37
  "chuid",
37
38
  ]
38
39
 
@@ -54,6 +55,12 @@ class PyobsDaemonCLI(CLI):
54
55
  help="send module logs to systemd journal (use --no-syslog to disable)",
55
56
  default=self._config.get("syslog", True),
56
57
  )
58
+ self._parser.add_argument(
59
+ "--file-log",
60
+ action=argparse.BooleanOptionalAction,
61
+ help="also write each module's log to <log-path>/<module>.log (off by default; use --file-log to enable)",
62
+ default=self._config.get("file_log", False),
63
+ )
57
64
  self._parser.add_argument("--chuid", type=str, default=self._config.get("chuid", "pyobs:pyobs"))
58
65
  self._parser.add_argument("-v", "--verbose", action="store_true")
59
66
 
@@ -76,6 +83,7 @@ class PyobsDaemonCLI(CLI):
76
83
  str(os.path.join(self._config["path"], self._config["log_path"])),
77
84
  log_level=self._config["log_level"],
78
85
  syslog=self._config["syslog"],
86
+ file_log=self._config["file_log"],
79
87
  chuid=self._config["chuid"],
80
88
  verbose=self._config["verbose"],
81
89
  )
@@ -104,6 +112,7 @@ class PyobsDaemon:
104
112
  log_path: str,
105
113
  log_level: str = "info",
106
114
  syslog: bool = False,
115
+ file_log: bool = False,
107
116
  chuid: str | None = None,
108
117
  verbose: bool = False,
109
118
  **kwargs: Any,
@@ -113,6 +122,7 @@ class PyobsDaemon:
113
122
  self._log_path = log_path
114
123
  self._log_level = log_level
115
124
  self._syslog = syslog
125
+ self._file_log = file_log
116
126
  self._verbose = verbose
117
127
 
118
128
  # parse optional user/group from chuid (format: "user:group" or "user")
@@ -317,18 +327,18 @@ class PyobsDaemon:
317
327
 
318
328
  def _start_service(self, module: str) -> None:
319
329
  os.makedirs(self._run_path, exist_ok=True)
320
- os.makedirs(self._log_path, exist_ok=True)
321
330
 
322
331
  cmd = [
323
332
  self._pyobs_exec,
324
333
  "--pid-file",
325
334
  self._pid_file(module),
326
- "--log-file",
327
- self._log_file(module),
328
335
  "--log-level",
329
336
  self._log_level,
330
337
  self._config_file(module),
331
338
  ]
339
+ if self._file_log:
340
+ os.makedirs(self._log_path, exist_ok=True)
341
+ cmd += ["--log-file", self._log_file(module)]
332
342
  if self._syslog:
333
343
  cmd.append("--syslog")
334
344
 
@@ -41,6 +41,7 @@ class Comm:
41
41
  self._event_handlers: dict[type[Event], list[Callable[[Event, str], Coroutine[Any, Any, bool]]]] = {}
42
42
  self._registered_events: set[type[Event]] = set()
43
43
  self._closing = asyncio.Event()
44
+ self._published_state: set[type[Interface]] = set()
44
45
 
45
46
  @property
46
47
  def has_module(self) -> bool:
@@ -381,7 +382,10 @@ class Comm:
381
382
  return
382
383
 
383
384
  except Exception:
384
- log.exception("Something went wrong")
385
+ # don't forward this back through CommLoggingHandler -- it would re-queue
386
+ # itself onto _log_queue, and if the send failure is due to a sustained
387
+ # outage, every retry generates another one of these, forever
388
+ log.exception("Something went wrong", extra={"pyobs_no_forward": True})
385
389
  pass
386
390
 
387
391
  def log_message(self, entry: LogEvent) -> None:
@@ -479,11 +483,17 @@ class Comm:
479
483
  interface: Interface type for the state.
480
484
  state: State object to publish.
481
485
  """
486
+ self._published_state.add(interface)
482
487
  await self._set_state(interface, state)
483
488
 
484
489
  async def _set_state(self, interface: type[Interface], state: Any) -> None:
485
490
  pass
486
491
 
492
+ def missing_published_state(self, interfaces: list[type[Interface]]) -> list[type[Interface]]:
493
+ """Return interfaces (from the given list) that declare state via has_own_state() but
494
+ haven't had set_state() called for them yet."""
495
+ return [i for i in interfaces if i.has_own_state() and i not in self._published_state]
496
+
487
497
  async def set_capabilities(self, interface: type[Interface], capabilities: Any) -> None:
488
498
  """Publish capabilities for this module.
489
499
 
@@ -31,6 +31,12 @@ class CommLoggingHandler(logging.Handler):
31
31
  rec: Log record to send.
32
32
  """
33
33
 
34
+ # a record about the forwarding pipeline itself failing (e.g. Comm._logging's own
35
+ # send failure) must not be forwarded again, or a sustained outage turns into an
36
+ # unbounded loop of "failed to send" records about failing to send that record
37
+ if getattr(rec, "pyobs_no_forward", False):
38
+ return
39
+
34
40
  # format message
35
41
  msg = self._formatter.format(rec) # noqa: UP031
36
42
 
@@ -14,9 +14,17 @@ log = logging.getLogger(__name__)
14
14
  class DummyComm(Comm):
15
15
  """A dummy implementation of the Comm interface."""
16
16
 
17
- def __init__(self, *args: Any, **kwargs: Any):
18
- """Creates a new dummy comm."""
17
+ def __init__(self, name: str = "module", *args: Any, **kwargs: Any):
18
+ """Creates a new dummy comm.
19
+
20
+ Args:
21
+ name: Name to report for this comm. Defaults to the generic placeholder "module"
22
+ for callers (e.g. tests) that construct a DummyComm directly without a real
23
+ identity; Application fills in the config file's stem when a module has no
24
+ comm of its own configured.
25
+ """
19
26
  Comm.__init__(self, *args, **kwargs)
27
+ self._name = name
20
28
 
21
29
  @property
22
30
  def clients(self) -> list[str]:
@@ -47,8 +55,8 @@ class DummyComm(Comm):
47
55
 
48
56
  @property
49
57
  def name(self) -> str:
50
- """Name of this client, which is unknown."""
51
- return "module"
58
+ """Name of this client."""
59
+ return self._name
52
60
 
53
61
  async def send_event(self, event: Event) -> None:
54
62
  """Send an event to other clients.
@@ -56,7 +64,7 @@ class DummyComm(Comm):
56
64
  Args:
57
65
  event (Event): Event to send
58
66
  """
59
- self._send_event_to_module(event, "module")
67
+ self._send_event_to_module(event, self._name)
60
68
 
61
69
 
62
70
  __all__ = ["DummyComm"]
@@ -7,6 +7,7 @@ from collections.abc import Coroutine
7
7
  from typing import TYPE_CHECKING, Any, Generic, TypeVar, get_type_hints
8
8
 
9
9
  from pyobs.interfaces import Interface
10
+ from pyobs.utils.time import Time
10
11
 
11
12
  if TYPE_CHECKING:
12
13
  from pyobs.comm import Comm
@@ -172,9 +173,22 @@ class Proxy:
172
173
  """Clear all cached state. Called by Comm when the remote module disconnects."""
173
174
  self._state.clear()
174
175
 
175
- def get_state(self, interface: type[Interface]) -> Any | None:
176
- """Latest known state for the given interface, or None if nothing has arrived yet."""
177
- return self._state.get(interface)
176
+ def get_state(self, interface: type[Interface], *, max_age: float | None = None) -> Any | None:
177
+ """Latest known state for the given interface, or None if nothing has arrived yet
178
+ (or, with max_age given, if the latest known state is older than max_age seconds)."""
179
+ state = self._state.get(interface)
180
+ if state is None or max_age is None:
181
+ return state
182
+ return state if self._state_age(state) <= max_age else None
183
+
184
+ def _state_age(self, state: Any) -> float:
185
+ """Seconds since `state` (a State dataclass instance) was constructed by its publisher."""
186
+ t = getattr(state, "time", None)
187
+ if t is None:
188
+ raise ValueError(
189
+ f"{type(state).__name__} has no 'time' field -- max_age is not supported for this interface."
190
+ )
191
+ return (Time.now() - t).sec
178
192
 
179
193
  def update_capabilities(self, interface: type[Interface], capabilities: Any) -> None:
180
194
  """Called by Comm once capabilities for an interface arrive.
@@ -194,16 +208,22 @@ class Proxy:
194
208
  self,
195
209
  interface: type[Interface],
196
210
  timeout: float = 10.0,
211
+ *,
212
+ max_age: float | None = None,
197
213
  ) -> Any:
198
- """Return state immediately if available, otherwise wait for the first update.
214
+ """Return state immediately if available (and fresh enough per max_age), otherwise wait
215
+ for the next update.
199
216
 
200
217
  Returns None on timeout rather than raising -- every caller across the codebase already
201
218
  does `if state is not None else ...` right after calling this, so that's the contract
202
219
  actually being relied on; letting asyncio.wait_for's TimeoutError propagate would just
203
- turn "peer hasn't published yet" into an unhandled exception for all of them.
220
+ turn "peer hasn't published yet" into an unhandled exception for all of them. The same
221
+ None-on-"not usable yet" contract now also covers "published, but too stale" when max_age
222
+ is given.
204
223
  """
205
- if self._state.get(interface) is not None:
206
- return self._state[interface]
224
+ cached = self._state.get(interface)
225
+ if cached is not None and (max_age is None or self._state_age(cached) <= max_age):
226
+ return cached
207
227
 
208
228
  event = asyncio.Event()
209
229
 
@@ -220,7 +240,10 @@ class Proxy:
220
240
  finally:
221
241
  await self._comm.unsubscribe_state(self._client, interface, _notify)
222
242
 
223
- return self._state.get(interface)
243
+ result = self._state.get(interface)
244
+ if max_age is not None and result is not None and self._state_age(result) > max_age:
245
+ return None
246
+ return result
224
247
 
225
248
  async def wait_for_capabilities(
226
249
  self,
@@ -315,6 +315,14 @@ class XmppComm(Comm):
315
315
  self._xmpp.enable_direct_tls = self._use_tls
316
316
  self._xmpp.enable_plaintext = not self._use_tls
317
317
  self._xmpp.plugin["feature_mechanisms"].unencrypted_scram = not self._use_tls # type: ignore[typeddict-item]
318
+ # Without this, slixmpp still refuses PLAIN over a non-TLS connection even
319
+ # with enable_plaintext set above -- it only affects the stream feature
320
+ # advertisement, not SASL mechanism selection. Matters in practice: this
321
+ # server's SCRAM implementation fails unencrypted SCRAM auth with "Invalid
322
+ # channel binding" (confirmed against ejabberd 26.4.0), so without this
323
+ # flag every non-TLS connection falls through all mechanisms and fails
324
+ # with "No appropriate login method" rather than falling back to PLAIN.
325
+ self._xmpp.plugin["feature_mechanisms"].unencrypted_plain = not self._use_tls # type: ignore[typeddict-item]
318
326
  if self._ignore_cert_errors:
319
327
  self._xmpp.ssl_context.check_hostname = False
320
328
  self._xmpp.ssl_context.verify_mode = ssl.CERT_NONE
@@ -1,8 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- from abc import ABCMeta, abstractmethod
3
+ from abc import ABCMeta
4
4
  from dataclasses import dataclass, field
5
- from typing import Any
6
5
 
7
6
  from ..utils.time import Time
8
7
  from .interface import Interface
@@ -21,10 +20,5 @@ class IRunning(Interface, metaclass=ABCMeta):
21
20
 
22
21
  state = RunningState
23
22
 
24
- @abstractmethod
25
- async def is_running(self, **kwargs: Any) -> bool:
26
- """Whether a service is running."""
27
- ...
28
-
29
23
 
30
24
  __all__ = ["IRunning", "RunningState"]
@@ -42,7 +42,7 @@ class Interface(metaclass=ABCMeta):
42
42
  )
43
43
  _REGISTRY[cls.__name__] = cls
44
44
 
45
- def get_state(self, interface: "type[Interface]") -> Any | None:
45
+ def get_state(self, interface: "type[Interface]", *, max_age: float | None = None) -> Any | None:
46
46
  """Return the last received state for the given interface, or None."""
47
47
  return None
48
48
 
@@ -50,7 +50,9 @@ class Interface(metaclass=ABCMeta):
50
50
  """Return the capabilities for the given interface, or None."""
51
51
  return None
52
52
 
53
- async def wait_for_state(self, interface: "type[Interface]", timeout: float = 10.0) -> Any | None:
53
+ async def wait_for_state(
54
+ self, interface: "type[Interface]", timeout: float = 10.0, *, max_age: float | None = None
55
+ ) -> Any | None:
54
56
  """Return state immediately if available, otherwise wait for the first update."""
55
57
  return None
56
58
 
@@ -15,13 +15,18 @@ log = logging.getLogger(__name__)
15
15
 
16
16
 
17
17
  async def get_coords(
18
- obj: IPointingAltAz | IPointingRaDec, mode: type[IPointingAltAz | IPointingRaDec]
18
+ obj: IPointingAltAz | IPointingRaDec,
19
+ mode: type[IPointingAltAz | IPointingRaDec],
20
+ max_age: float | None = None,
19
21
  ) -> tuple[float, float]:
20
22
  """Gets coordinates from object
21
23
 
22
24
  Args:
23
25
  obj: Object to fetch coordinates from.
24
26
  mode: IAltAz or IRaDec.
27
+ max_age: If obj is a remote Proxy, treat cached state older than this many seconds the
28
+ same as "not available" (raises ValueError below). Ignored for a Module, whose own
29
+ state is always current from its own perspective.
25
30
 
26
31
  Returns:
27
32
  Return from method call.
@@ -29,7 +34,7 @@ async def get_coords(
29
34
 
30
35
  if mode == IPointingAltAz:
31
36
  if isinstance(obj, Proxy):
32
- state: AltAzState | None = obj.get_state(IPointingAltAz)
37
+ state: AltAzState | None = obj.get_state(IPointingAltAz, max_age=max_age)
33
38
  elif isinstance(obj, Module):
34
39
  state = obj.comm.get_own_state(IPointingAltAz)
35
40
  else:
@@ -39,7 +44,7 @@ async def get_coords(
39
44
  return state.alt, state.az
40
45
  elif mode == IPointingRaDec:
41
46
  if isinstance(obj, Proxy):
42
- state2: RaDecState | None = obj.get_state(IPointingRaDec)
47
+ state2: RaDecState | None = obj.get_state(IPointingRaDec, max_age=max_age)
43
48
  elif isinstance(obj, Module):
44
49
  state2 = obj.comm.get_own_state(IPointingRaDec)
45
50
  else:
@@ -80,6 +85,7 @@ class FollowMixin:
80
85
  interval: float = 10,
81
86
  tolerance: float = 1,
82
87
  only_follow_when_ready: bool = True,
88
+ follow_max_age: float | None = None,
83
89
  *args: Any,
84
90
  **kwargs: Any,
85
91
  ):
@@ -91,6 +97,11 @@ class FollowMixin:
91
97
  tolerance: Tolerance in degrees between both devices to trigger new movement.
92
98
  mode: Set to "altaz" to follow Alt/Az coordinates or "radec" to follow RA/Dec.
93
99
  only_follow_when_ready: Only follow if is_ready() is True.
100
+ follow_max_age: Treat the followed device's cached position as unavailable once
101
+ it's older than this many seconds -- guards against silently following a frozen
102
+ position if the followed device's own position-publish loop dies while its
103
+ connection stays up. Defaults to 3x interval (loose enough to tolerate a slow
104
+ tick, tight enough to notice a dead feed within a few position checks).
94
105
  """
95
106
 
96
107
  # store
@@ -99,6 +110,7 @@ class FollowMixin:
99
110
  self.__follow_tolerance = tolerance
100
111
  self.__follow_mode = mode
101
112
  self.__follow_only_when_ready = only_follow_when_ready
113
+ self.__follow_max_age = follow_max_age if follow_max_age is not None else interval * 3
102
114
 
103
115
  # store self for later
104
116
  this = self
@@ -154,7 +166,7 @@ class FollowMixin:
154
166
  else:
155
167
  continue
156
168
  async with module.proxy(this.__follow_device, this.__follow_mode) as proxy:
157
- xy_coords = await get_coords(proxy, this.__follow_mode)
169
+ xy_coords = await get_coords(proxy, this.__follow_mode, max_age=this.__follow_max_age)
158
170
  if xy_coords is None:
159
171
  continue
160
172
  other_coords = build_skycoord(xy_coords, this.__follow_mode)
@@ -18,8 +18,9 @@ class WeatherAwareMixin:
18
18
 
19
19
  __module__ = "pyobs.mixins"
20
20
 
21
- def __init__(self, weather: str | IWeather | None = None, **kwargs: Any):
21
+ def __init__(self, weather: str | IWeather | None = None, weather_max_age: float = 120.0, **kwargs: Any):
22
22
  self.__weather = weather
23
+ self.__weather_max_age = weather_max_age
23
24
  self.__is_weather_good: bool | None = None
24
25
  self.__last_park_attempt: float | None = None
25
26
  self.__weatheraware_is_error_state = False
@@ -121,7 +122,9 @@ class WeatherAwareMixin:
121
122
  try:
122
123
  # get good status
123
124
  async with module.proxy(this.__weather, IWeather) as proxy:
124
- weather_state = await proxy.wait_for_state(IWeather, timeout=5.0)
125
+ weather_state = await proxy.wait_for_state(
126
+ IWeather, timeout=5.0, max_age=this.__weather_max_age
127
+ )
125
128
  this.__is_weather_good = weather_state.good if weather_state is not None else False
126
129
  this.__weather_check_failures = 0
127
130
 
@@ -153,6 +153,12 @@ class DummyCamera(BaseCamera, IWindow, IBinning, ICooling, IGain, IImageFormat):
153
153
  ICooling,
154
154
  CoolingState(setpoint=self._cooling.set_point, power=self._cooling.power, enabled=self._cooling.enabled),
155
155
  )
156
+ await self.comm.set_state(
157
+ ITemperatures,
158
+ TemperaturesState(
159
+ readings=[SensorReading(name=name, value=value) for name, value in self._cooling.temperatures.items()]
160
+ ),
161
+ )
156
162
  await self.comm.set_state(IGain, GainState(gain=self._gain, offset=self._gain_offset))
157
163
  await self.comm.set_state(IWindow, WindowState(*self._full_frame))
158
164
  await self.comm.set_state(IBinning, BinningState(*self._binning))
@@ -99,10 +99,6 @@ class DummyAutoFocus(Module, IAutoFocus):
99
99
  await self.comm.send_event(FocusFoundEvent(self._best_focus, error))
100
100
  return AutoFocusResult(focus=self._best_focus, focus_err=error)
101
101
 
102
- async def is_running(self, **kwargs: Any) -> bool:
103
- """Whether a service is running."""
104
- return self._running
105
-
106
102
  async def abort(self, **kwargs: Any) -> None:
107
103
  """Abort current actions."""
108
104
  self._abort.set()
@@ -84,7 +84,7 @@ class FocusModel(Module, IFocusModel):
84
84
  focuser: str | None = None,
85
85
  weather: str | None = None,
86
86
  interval: int = 300,
87
- temperatures: dict[str, dict[str, float]] | None = None,
87
+ temperatures: dict[str, dict[str, str]] | None = None,
88
88
  model: str | None = None,
89
89
  coefficients: dict[str, float] | None = None,
90
90
  update: bool = False,
@@ -96,6 +96,7 @@ class FocusModel(Module, IFocusModel):
96
96
  filter_offsets: dict[str, float] | None = None,
97
97
  filter_wheel: str | None = None,
98
98
  auto_focus: str | list[str] | None = None,
99
+ temp_max_age: float | None = None,
99
100
  **kwargs: Any,
100
101
  ):
101
102
  """Initialize a focus model.
@@ -115,6 +116,9 @@ class FocusModel(Module, IFocusModel):
115
116
  filter_offsets: Offsets for different filters. If None, they are not modeled.
116
117
  filter_wheel: Name of filter wheel module to use for fetching filter before setting focus.
117
118
  auto_focus: Name or list of names of auto-focus modules to accept focus values from.
119
+ temp_max_age: Treat a temperature module's cached ITemperatures reading as unavailable
120
+ once it's older than this many seconds -- guards against silently feeding a frozen
121
+ reading (from a dead sensor module) into the focus model. Defaults to 2x interval.
118
122
  """
119
123
  Module.__init__(self, **kwargs)
120
124
 
@@ -130,7 +134,8 @@ class FocusModel(Module, IFocusModel):
130
134
  self._focuser = focuser
131
135
  self._weather = weather
132
136
  self._interval = interval
133
- self._temperatures: dict[str, dict[str, float]] = {} if temperatures is None else temperatures
137
+ self._temperatures: dict[str, dict[str, str]] = {} if temperatures is None else temperatures
138
+ self._temp_max_age = temp_max_age if temp_max_age is not None else float(interval) * 2
134
139
  self._focuser_ready = True
135
140
  self._coefficients = {} if coefficients is None else coefficients
136
141
  self._update_model = update
@@ -318,7 +323,7 @@ class FocusModel(Module, IFocusModel):
318
323
  # get temperatures
319
324
  async with self.proxy(cfg["module"], ITemperatures) as proxy:
320
325
  try:
321
- temp_state = await proxy.wait_for_state(ITemperatures)
326
+ temp_state = await proxy.wait_for_state(ITemperatures, max_age=self._temp_max_age)
322
327
  except TimeoutError:
323
328
  raise FocusTimeoutError(f"Timeout waiting for temperatures from module {cfg['module']}.")
324
329
  module_temps[cfg["module"]] = (
@@ -291,10 +291,6 @@ class AutoFocusSeries(Module, CameraSettingsMixin, IAutoFocus):
291
291
  """Abort current actions."""
292
292
  self._abort.set()
293
293
 
294
- async def is_running(self, **kwargs: Any) -> bool:
295
- """Whether a service is running."""
296
- return self._running
297
-
298
294
  async def _on_bad_weather(self, event: Event, sender: str) -> bool:
299
295
  """Abort series if a bad weather event occurs.
300
296
 
@@ -344,6 +344,17 @@ class Module(Object, IModule, IConfig):
344
344
  which would then never leave STARTING under Application/MultiModule.
345
345
  """
346
346
  await self.open()
347
+
348
+ # warn if any stateful interface hasn't published state yet
349
+ if self._comm is not None:
350
+ missing = self._comm.missing_published_state(self._interfaces)
351
+ for iface in missing:
352
+ log.warning(
353
+ "Module %s implements %s which declares state, but no state has been published for it yet.",
354
+ self.name,
355
+ iface.__name__,
356
+ )
357
+
347
358
  await self.set_state(ModuleState.READY)
348
359
 
349
360
  async def close(self) -> None:
@@ -95,14 +95,6 @@ class BaseGuiding(BasePointing, IAutoGuiding, IFitsHeaderBefore, IFitsHeaderAfte
95
95
  await self._reset_guiding(enabled=False)
96
96
  await self.comm.set_state(IRunning, RunningState(running=False))
97
97
 
98
- async def is_running(self, **kwargs: Any) -> bool:
99
- """Whether auto-guiding is running.
100
-
101
- Returns:
102
- Auto-guiding is running.
103
- """
104
- return self._enabled
105
-
106
98
  async def get_fits_header_before(
107
99
  self, namespaces: list[str] | None = None, **kwargs: Any
108
100
  ) -> dict[str, FitsHeaderEntry]:
@@ -103,10 +103,6 @@ class Acquisition(BasePointing, CameraSettingsMixin, IAcquisition):
103
103
  await self.comm.set_state(IAcquisition, AcquisitionState())
104
104
  await self.comm.set_state(IRunning, RunningState(running=False))
105
105
 
106
- async def is_running(self, **kwargs: Any) -> bool:
107
- """Whether a service is running."""
108
- return self._is_running
109
-
110
106
  @raises(exc.AbortedError, exc.AcquisitionError)
111
107
  @timeout(120)
112
108
  async def acquire_target(self, **kwargs: Any) -> AcquisitionResult:
@@ -59,10 +59,6 @@ class DummyAcquisition(Module, IAcquisition):
59
59
  await self.comm.set_state(IAcquisition, AcquisitionState())
60
60
  await self.comm.set_state(IRunning, RunningState(running=False))
61
61
 
62
- async def is_running(self, **kwargs: Any) -> bool:
63
- """Whether a service is running."""
64
- return self._is_running
65
-
66
62
  @timeout(120)
67
63
  async def acquire_target(self, **kwargs: Any) -> AcquisitionResult:
68
64
  """Acquire target at given coordinates.
@@ -56,9 +56,6 @@ class DummyAutoGuiding(Module, IAutoGuiding):
56
56
  await self.comm.set_state(IRunning, RunningState(running=False))
57
57
  await self._publish_guiding_state(loop_closed=False)
58
58
 
59
- async def is_running(self, **kwargs: Any) -> bool:
60
- return self._running
61
-
62
59
  async def _publish_guiding_state(self, loop_closed: bool) -> None:
63
60
  await self.comm.set_state(
64
61
  IAutoGuiding,
@@ -90,10 +90,6 @@ class Mastermind(Module, IAutonomous, IFitsHeaderBefore):
90
90
  self._running = False
91
91
  await self.comm.set_state(IRunning, RunningState(running=self._running))
92
92
 
93
- async def is_running(self, **kwargs: Any) -> bool:
94
- """Whether a service is running."""
95
- return self._running
96
-
97
93
  async def _run_thread(self) -> None:
98
94
  # wait a little
99
95
  await asyncio.sleep(5)
@@ -50,7 +50,7 @@ class PointingSeries(Module, IAutonomous):
50
50
  async def open(self) -> None:
51
51
  """Open module."""
52
52
  await Module.open(self)
53
- await self.comm.set_state(IRunning, RunningState(running=await self.is_running()))
53
+ await self.comm.set_state(IRunning, RunningState(running=True))
54
54
 
55
55
  async def start(self, **kwargs: Any) -> None:
56
56
  """Starts a service."""
@@ -60,10 +60,6 @@ class PointingSeries(Module, IAutonomous):
60
60
  """Stops a service."""
61
61
  pass
62
62
 
63
- async def is_running(self, **kwargs: Any) -> bool:
64
- """Whether a service is running."""
65
- return True
66
-
67
63
  async def _run_thread(self) -> None:
68
64
  """Run a pointing series."""
69
65
 
@@ -119,10 +119,6 @@ class Scheduler(Module, IStartStop, IRunnable):
119
119
  self._running = False
120
120
  await self.comm.set_state(IRunning, RunningState(running=self._running))
121
121
 
122
- async def is_running(self, **kwargs: Any) -> bool:
123
- """Whether scheduler is running."""
124
- return self._running
125
-
126
122
  async def _update_schedule(self) -> None:
127
123
  # get schedulable tasks and sort them
128
124
  log.info("Found update in schedulable block, downloading them...")
@@ -109,10 +109,6 @@ class Kiosk(Module, IStartStop):
109
109
  self._running = False
110
110
  await self.comm.set_state(IRunning, RunningState(running=self._running))
111
111
 
112
- async def is_running(self, **kwargs: Any) -> bool:
113
- """Whether kiosk mode is running."""
114
- return self._running
115
-
116
112
  async def _camera_thread(self) -> None:
117
113
  """Thread for taking images."""
118
114
 
@@ -63,10 +63,6 @@ class Trigger(Module, IAutonomous):
63
63
  self._running = False
64
64
  await self.comm.set_state(IRunning, RunningState(running=self._running))
65
65
 
66
- async def is_running(self, **kwargs: Any) -> bool:
67
- """Whether a service is running."""
68
- return self._running
69
-
70
66
  async def _handle_event(self, event: Event, sender: str) -> bool:
71
67
  """Handle an incoming event.
72
68