Skip to content

Commit

Permalink
Merge branch 'develop' into Acquisition_BrightCentralStar
Browse files Browse the repository at this point in the history
  • Loading branch information
LeonMee committed Apr 11, 2024
2 parents c40ba71 + 601101e commit 622bb56
Show file tree
Hide file tree
Showing 17 changed files with 464 additions and 118 deletions.
1 change: 1 addition & 0 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ python:
install:
- method: pip
path: .
- requirements: docs/requirements.txt
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sphinx-rtd-theme
16 changes: 16 additions & 0 deletions docs/source/api/interfaces.rst
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,14 @@ ILatLon
:show-inheritance:
:undoc-members:

IMode
~~~~~

.. autoclass:: pyobs.interfaces.IMode
:members:
:show-inheritance:
:undoc-members:

IModule
~~~~~~~

Expand Down Expand Up @@ -243,6 +251,14 @@ IPointingHGS
:show-inheritance:
:undoc-members:

IPointingHelioprojective
~~~~~~~~~~~~~~~~~~~~~~~~

.. autoclass:: pyobs.interfaces.IPointingHelioprojective
:members:
:show-inheritance:
:undoc-members:

IPointingRaDec
~~~~~~~~~~~~~~

Expand Down
5 changes: 5 additions & 0 deletions docs/source/api/vfs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ MemoryFile

.. autoclass:: pyobs.vfs.MemoryFile

SFTPFile
^^^^^^^^

.. autoclass:: pyobs.vfs.SFTPFile

SMBFile
^^^^^^^

Expand Down
7 changes: 7 additions & 0 deletions docs/source/modules/pyobs.modules.robotic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,10 @@ Scheduler
:members:
:show-inheritance:

ScriptRunner
~~~~~~~~~~~~

.. autoclass:: pyobs.modules.robotic.ScriptRunner
:members:
:show-inheritance:

39 changes: 39 additions & 0 deletions pyobs/background_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import asyncio
import logging
from typing import Optional, Coroutine, Any, Callable

from pyobs.utils.exceptions import SevereError

log = logging.getLogger(__name__)


class BackgroundTask:
def __init__(self, func: Callable[..., Coroutine[Any, Any, None]], restart: bool) -> None:
self._func: Callable[..., Coroutine[Any, Any, None]] = func
self._restart: bool = restart
self._task: Optional[asyncio.Future] = None

def start(self) -> None:
self._task = asyncio.create_task(self._func())
self._task.add_done_callback(self._callback_function)

def _callback_function(self, args=None) -> None:
try:
exception = self._task.exception()
except asyncio.CancelledError:
return

if isinstance(exception, SevereError):
raise exception
elif exception is not None:
log.error("Exception %s in task %s.", exception, self._func.__name__)

if self._restart:
log.error("Background task for %s has died, restarting...", self._func.__name__)
self.start()
else:
log.error("Background task for %s has died, quitting...", self._func.__name__)

def stop(self) -> None:
if self._task is not None:
self._task.cancel()
3 changes: 0 additions & 3 deletions pyobs/modules/roof/basedome.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ def __init__(self, **kwargs: Any):
"""Initialize a new base dome."""
BaseRoof.__init__(self, **kwargs)

# register exception
exc.register_exception(exc.MotionError, 3, timespan=600, callback=self._default_remote_error_callback)

async def get_fits_header_before(
Expand All @@ -34,10 +33,8 @@ async def get_fits_header_before(
Dictionary containing FITS headers.
"""

# get from parent
hdr = await BaseRoof.get_fits_header_before(self, namespaces, **kwargs)

# add azimuth and return it
_, az = await self.get_altaz()
hdr["ROOF-AZ"] = (az, "Azimuth of roof slit, deg E of N")
return hdr
Expand Down
3 changes: 1 addition & 2 deletions pyobs/modules/roof/baseroof.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ def __init__(self, **kwargs: Any):
"""Initialize a new base roof."""
Module.__init__(self, **kwargs)

# init mixins
WeatherAwareMixin.__init__(self, **kwargs)
MotionStatusMixin.__init__(self, **kwargs)

Expand Down Expand Up @@ -50,7 +49,7 @@ async def get_fits_header_before(
}

async def is_ready(self, **kwargs: Any) -> bool:
"""Returns the device is "ready", whatever that means for the specific device.
"""The roof is ready, if it is open.
Returns:
True, if roof is open.
Expand Down
87 changes: 34 additions & 53 deletions pyobs/modules/roof/dummyroof.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,23 @@ class DummyRoof(BaseRoof, IRoof):

__module__ = "pyobs.modules.roof"

_ROOF_CLOSED_PERCENTAGE = 0
_ROOF_OPEN_PERCENTAGE = 100

def __init__(self, **kwargs: Any):
"""Creates a new dummy root."""
BaseRoof.__init__(self, **kwargs)

# dummy state
self.open_percentage = 0
self._open_percentage: int = self._ROOF_CLOSED_PERCENTAGE

# allow to abort motion
self._lock_motion = asyncio.Lock()
self._abort_motion = asyncio.Event()

async def open(self) -> None:
"""Open module."""
await BaseRoof.open(self)

# register event
await self.comm.register_event(RoofOpenedEvent)
await self.comm.register_event(RoofClosingEvent)

Expand All @@ -44,34 +45,19 @@ async def init(self, **kwargs: Any) -> None:
AcquireLockFailed: If current motion could not be aborted.
"""

# already open?
if self.open_percentage != 100:
# acquire lock
with LockWithAbort(self._lock_motion, self._abort_motion):
# change status
await self._change_motion_status(MotionStatus.INITIALIZING)

# open roof
while self.open_percentage < 100:
# open more
self.open_percentage += 1
if self._is_open():
return

# abort?
if self._abort_motion.is_set():
await self._change_motion_status(MotionStatus.IDLE)
return
async with LockWithAbort(self._lock_motion, self._abort_motion):
await self._change_motion_status(MotionStatus.INITIALIZING)

# wait a little
await asyncio.sleep(0.1)
await self._move_roof(self._ROOF_OPEN_PERCENTAGE)

# open fully
self.open_percentage = 100

# change status
await self._change_motion_status(MotionStatus.IDLE)
await self._change_motion_status(MotionStatus.IDLE)
self.comm.send_event(RoofOpenedEvent())

# send event
self.comm.send_event(RoofOpenedEvent())
def _is_open(self):
return self._open_percentage == self._ROOF_OPEN_PERCENTAGE

@timeout(15)
async def park(self, **kwargs: Any) -> None:
Expand All @@ -81,35 +67,34 @@ async def park(self, **kwargs: Any) -> None:
AcquireLockFailed: If current motion could not be aborted.
"""

# already closed?
if self.open_percentage != 0:
# acquire lock
with LockWithAbort(self._lock_motion, self._abort_motion):
# change status
await self._change_motion_status(MotionStatus.PARKING)
if self._is_closed():
return

async with LockWithAbort(self._lock_motion, self._abort_motion):
await self._change_motion_status(MotionStatus.PARKING)
self.comm.send_event(RoofClosingEvent())

# send event
self.comm.send_event(RoofClosingEvent())
await self._move_roof(self._ROOF_CLOSED_PERCENTAGE)

# close roof
while self.open_percentage > 0:
# close more
self.open_percentage -= 1
await self._change_motion_status(MotionStatus.PARKED)

# abort?
if self._abort_motion.is_set():
await self._change_motion_status(MotionStatus.IDLE)
return
def _is_closed(self):
return self._open_percentage == self._ROOF_CLOSED_PERCENTAGE

# wait a little
await asyncio.sleep(0.1)
async def _move_roof(self, target_pos: int) -> None:
step = 1 if target_pos > self._open_percentage else -1

while self._open_percentage != target_pos:
if self._abort_motion.is_set():
await self._change_motion_status(MotionStatus.IDLE)
return

# change status
await self._change_motion_status(MotionStatus.PARKED)
self._open_percentage += step
await asyncio.sleep(0.1)

def get_percent_open(self) -> float:
"""Get the percentage the roof is open."""
return self.open_percentage
return self._open_percentage

async def stop_motion(self, device: Optional[str] = None, **kwargs: Any) -> None:
"""Stop the motion.
Expand All @@ -121,13 +106,9 @@ async def stop_motion(self, device: Optional[str] = None, **kwargs: Any) -> None
AcquireLockFailed: If current motion could not be aborted.
"""

# change status
await self._change_motion_status(MotionStatus.ABORTING)

# abort
# acquire lock
with LockWithAbort(self._lock_motion, self._abort_motion):
# change status
async with LockWithAbort(self._lock_motion, self._abort_motion):
await self._change_motion_status(MotionStatus.IDLE)


Expand Down
Loading

0 comments on commit 622bb56

Please sign in to comment.