def __init__( self, show_shell: bool = True, show_events: bool = True, show_status: bool = True, show_modules: Optional[List[str]] = None, widgets: Optional[List[Dict[str, Any]]] = None, sidebar: Optional[List[Dict[str, Any]]] = None, *args: Any, **kwargs: Any, ): """Inits a new GUI. Args: show_shell: Whether to show the shell page. show_events: Whether to show the events page. show_modules: If not empty, show only listed modules. widgets: List of custom widgets. sidebar: List of custom sidebar widgets. """ # init Qt with asyncio self._app = QtWidgets.QApplication(sys.argv) loop = QEventLoop(self._app) asyncio.set_event_loop(loop) # init module Module.__init__(self, *args, **kwargs) self._window: Optional[MainWindow] = None self._show_shell = show_shell self._show_events = show_events self._show_status = show_status self._show_modules = show_modules self._custom_widgets = widgets self._custom_sidebar_widgets = sidebar
def __init__( self, fits_headers: Optional[Dict[str, Any]] = None, filenames: str = "/cache/pyobs-{DAY-OBS|date:}-{FRAMENUM|string:04d}.fits.gz", fits_namespaces: Optional[List[str]] = None, **kwargs: Any, ): """Creates a new BaseCamera. Args: fits_headers: Additional FITS headers. flip: Whether or not to flip the image along its first axis. filenames: Template for file naming. fits_namespaces: List of namespaces for FITS headers that this camera should request """ Module.__init__(self, **kwargs) SpectrumFitsHeaderMixin.__init__( self, fits_namespaces=fits_namespaces, fits_headers=fits_headers, filenames=filenames ) # init camera self._exposure: Optional[ExposureInfo] = None self._spectrograph_status = ExposureStatus.IDLE # multi-threading self._expose_lock = asyncio.Lock() self.expose_abort = asyncio.Event() # check if self.comm is None: log.warning("No comm module given, will not be able to signal new images!")
def __init__(self, tasks: Union[TaskArchive, dict], allowed_late_start: int = 300, allowed_overrun: int = 300, **kwargs: Any): """Initialize a new auto focus system. Args: tasks: Task archive to use allowed_late_start: Allowed seconds to start late. allowed_overrun: Allowed time for a task to exceed it's window in seconds """ Module.__init__(self, **kwargs) # store self._allowed_late_start = allowed_late_start self._allowed_overrun = allowed_overrun self._running = False # add thread func self.add_background_task(self._run_thread, True) # get task archive self._task_archive = self.add_child_object(tasks, TaskArchive) # observation name and exposure number self._task = None self._obs = None self._exp = None
def __init__(self, watchpath: Optional[str] = None, destinations: Optional[List[str]] = None, **kwargs: Any): """Create a new image watcher. Args: watchpath: Path to watch. destinations: Filename patterns for destinations. """ Module.__init__(self, **kwargs) # test import import pyinotify # add thread func self.add_background_task(self._worker) # variables self._watchpath = watchpath self._notifier = None self._queue = asyncio.Queue[str]() # filename patterns if not destinations: raise ValueError( "No filename patterns given for the destinations.") self._destinations = destinations
def __init__(self, token: str, password: str, allow_new_users: bool = True, **kwargs: Any): """Initialize a new bot. Args: token: The telegram API token. password: Password for users to log in. allow_new_users: Whether new users are allowed to connect. """ Module.__init__(self, **kwargs) from telegram.ext import Updater # store self._token = token self._password = password self._allow_new_users = allow_new_users self._updater: Optional[Updater] = None self._message_queue = asyncio.Queue() self._loop = None # get log levels self._log_levels = { logging.getLevelName(x): x for x in range(1, 101) if not logging.getLevelName(x).startswith("Level") } # thread self.add_background_task(self._log_sender_thread)
def __init__(self, port: int = 37075, cache_size: int = 25, max_file_size: int = 100, **kwargs: Any): """Initializes file cache. Args: port: Port for HTTP server. cache_size: Size of file cache, i.e. number of files to cache. max_file_size: Maximum file size in MB. """ Module.__init__(self, **kwargs) # store stuff self._cache = DataCache(cache_size) self._is_listening = False self._port = port self._cache_size = cache_size self._max_file_size = max_file_size * 1024 * 1024 # define web server self._app = web.Application() self._app.add_routes([ web.get("/{filename}", self.download_handler), web.post("/", self.upload_handler) ]) self._runner = web.AppRunner(self._app) self._site: Optional[web.TCPSite] = None
def __init__(self, **kwargs: Any): """Initialize a new base roof.""" Module.__init__(self, **kwargs) # init mixins WeatherAwareMixin.__init__(self, **kwargs) MotionStatusMixin.__init__(self, **kwargs)
def __init__( self, focuser: Union[str, IFocuser], camera: Union[str, IImageGrabber], series: FocusSeries, offset: bool = False, filters: Optional[Union[str, IFilters]] = None, filter_name: Optional[str] = None, binning: Optional[int] = None, **kwargs: Any, ): """Initialize a new auto focus system. Args: focuser: Name of IFocuser. camera: Name of ICamera. filters: Name of IFilters, if any. filter_name: Name of filter to set. offset: If True, offsets are used instead of absolute focus values. """ Module.__init__(self, **kwargs) # store focuser and camera self._focuser = focuser self._camera = camera self._filters = filters self._offset = offset self._abort = threading.Event() # create focus series self._series: FocusSeries = get_object(series, FocusSeries) # init camera settings mixin CameraSettingsMixin.__init__(self, filters=filters, filter_name=filter_name, binning=binning, **kwargs) # register exceptions if isinstance(camera, str): exc.register_exception( exc.RemoteError, 3, timespan=600, module=camera, callback=self._default_remote_error_callback) if isinstance(focuser, str): exc.register_exception( exc.RemoteError, 3, timespan=600, module=focuser, callback=self._default_remote_error_callback)
def __init__( self, fits_headers: Optional[Dict[str, Any]] = None, centre: Optional[Tuple[float, float]] = None, rotation: float = 0.0, flip: bool = False, filenames: str = "/cache/pyobs-{DAY-OBS|date:}-{FRAMENUM|string:04d}-{IMAGETYP|type}00.fits.gz", fits_namespaces: Optional[List[str]] = None, **kwargs: Any, ): """Creates a new BaseCamera. Args: fits_headers: Additional FITS headers. centre: (x, y) tuple of camera centre. rotation: Rotation east of north. flip: Whether or not to flip the image along its first axis. filenames: Template for file naming. fits_namespaces: List of namespaces for FITS headers that this camera should request """ Module.__init__(self, **kwargs) ImageFitsHeaderMixin.__init__( self, fits_namespaces=fits_namespaces, fits_headers=fits_headers, centre=centre, rotation=rotation, filenames=filenames, ) # check if self.comm is None: log.warning( "No comm module given, will not be able to signal new images!") # store self._flip = flip self._exposure_time: float = 0.0 self._image_type = ImageType.OBJECT # init camera self._exposure: Optional[ExposureInfo] = None self._camera_status = ExposureStatus.IDLE # multi-threading self.expose_abort = asyncio.Event() # register exception exc.register_exception(exc.GrabImageError, 3, timespan=600, callback=self._default_remote_error_callback)
def __init__( self, telescope: Union[str, ITelescope], pointing: Union[Dict[str, Any], SkyFlatsBasePointing], **kwargs: Any ): """Initialize a new flat field pointing. Args: telescope: Telescope to point pointing: Pointing for calculating coordinates. """ Module.__init__(self, **kwargs) # store telescope and pointing self._telescope = telescope self._pointing = pointing
def __init__( self, tasks: Union[dict, TaskArchive], schedule_range: int = 24, safety_time: int = 60, twilight: str = "astronomical", trigger_on_task_started: bool = False, trigger_on_task_finished: bool = False, **kwargs: Any, ): """Initialize a new scheduler. Args: scheduler: Scheduler to use schedule_range: Number of hours to schedule into the future safety_time: If no ETA for next task to start exists (from current task, weather became good, etc), use this time in seconds to make sure that we don't schedule for a time when the scheduler is still running twilight: astronomical or nautical trigger_on_task_started: Whether to trigger a re-calculation of schedule, when task has started. trigger_on_task_finishes: Whether to trigger a re-calculation of schedule, when task has finished. """ Module.__init__(self, **kwargs) # get scheduler self._task_archive = self.add_child_object(tasks, TaskArchive) # store self._schedule_range = schedule_range self._safety_time = safety_time self._twilight = twilight self._running = True self._initial_update_done = False self._need_update = False self._trigger_on_task_started = trigger_on_task_started self._trigger_on_task_finished = trigger_on_task_finished # time to start next schedule from self._schedule_start = None # ID of currently running task, and current (or last if finished) block self._current_task_id = None self._last_task_id = None # blocks self._blocks: List[ObservingBlock] = [] # update thread self.add_background_task(self._schedule_thread) self.add_background_task(self._update_thread)
def __init__( self, alt_range: Tuple[float, float] = (30.0, 85.0), num_alt: int = 8, az_range: Tuple[float, float] = (0.0, 360.0), num_az: int = 24, dec_range: Tuple[float, float] = (-80.0, 80.0), min_moon_dist: float = 15.0, finish: int = 90, exp_time: float = 1.0, acquisition: str = "acquisition", telescope: str = "telescope", **kwargs: Any, ): """Initialize a new auto focus system. Args: alt_range: Range in degrees to use in altitude. num_alt: Number of altitude points to create on grid. az_range: Range in degrees to use in azimuth. num_az: Number of azimuth points to create on grid. dec_range: Range in declination in degrees to use. min_moon_dist: Minimum moon distance in degrees. finish: When this number in percent of points have been finished, terminate mastermind. exp_time: Exposure time in secs. acquisition: IAcquisition unit to use. telescope: ITelescope unit to use. """ Module.__init__(self, **kwargs) # store self._alt_range = tuple(alt_range) self._num_alt = num_alt self._az_range = tuple(az_range) self._num_az = num_az self._dec_range = dec_range self._min_moon_dist = min_moon_dist self._finish = 1.0 - finish / 100.0 self._exp_time = exp_time self._acquisition = acquisition self._telescope = telescope # if Az range is [0, 360], we got north double, so remove one step if self._az_range == (0.0, 360.0): self._az_range = (0.0, 360.0 - 360.0 / self._num_az) # add thread func self.add_background_task(self._run_thread, False)
def __init__(self, hostname: str, port: int, *args: Any, **kwargs: Any): """Initialize a new logger. Args: hostname: Hostname of server. port: Port of server. """ from fluent import sender Module.__init__(self, **kwargs) # store self._hostname = hostname self._port = port self._fluent: Optional[sender.FluentSender] = None
def __init__(self, message: str = "Hello world", interval: int = 10, **kwargs: Any): """Creates a new StandAlone object. Args: message: Message to log in the given interval. interval: Interval between messages. """ Module.__init__(self, **kwargs) # add thread func self.add_background_task(self._message_func) # store self._message = message self._interval = interval
def __init__(self, filename: str = "/archive/{FNAME}", sources: Optional[Union[str, List[str]]] = None, **kwargs: Any): """Creates a new image writer. Args: filename: Pattern for filename to store images at. sources: List of sources (e.g. cameras) to process images from or None for all. """ Module.__init__(self, **kwargs) # add thread func self.add_background_task(self._worker, True) # variables self._filename = filename self._sources = [sources] if isinstance(sources, str) else sources self._queue = asyncio.Queue()
def __init__(self, triggers: List[Dict[str, Any]], **kwargs: Any): """Initialize a new trigger module. Args: triggers: List of dictionaries defining the trigger. Must contain fields for event, module and method, may contain a sender. """ Module.__init__(self, **kwargs) # store self._running = False # store triggers and convert event strings to actual classes self._triggers = triggers for trigger in self._triggers: # get class and store it kls = get_class_from_string(trigger["event"]) trigger["event"] = kls
def __init__( self, fits_headers: Optional[Dict[str, Any]] = None, min_altitude: float = 10, wait_for_dome: Optional[str] = None, **kwargs: Any, ): """Initialize a new base telescope. Args: fits_headers: Additional FITS headers to send. min_altitude: Minimal altitude for telescope. wait_for_dome: Name of dome module to wait for. """ Module.__init__(self, **kwargs) # store self._fits_headers = fits_headers if fits_headers is not None else {} self._min_altitude = min_altitude # some multi-threading stuff self._lock_moving = asyncio.Lock() self._abort_move = asyncio.Event() # celestial status self._celestial_headers: Dict[str, Any] = {} # add thread func self.add_background_task(self._celestial, True) # init mixins WeatherAwareMixin.__init__(self, **kwargs) MotionStatusMixin.__init__(self, **kwargs) WaitForMotionMixin.__init__( self, wait_for_modules=None if wait_for_dome is None else [wait_for_dome], wait_for_timeout=60000, wait_for_states=[MotionStatus.POSITIONED, MotionStatus.TRACKING], ) # register exception exc.register_exception(exc.MotionError, 3, timespan=600, callback=self._default_remote_error_callback)
def __init__( self, warn_sound: str, warn_interval: float = 1, start_sound: Optional[str] = None, started_sound: Optional[str] = None, stop_sound: Optional[str] = None, stopped_sound: Optional[str] = None, player: str = "mpg123", trigger_file: Optional[str] = None, **kwargs: Any, ): """Initialize a new warning. Args: warn_sound: Name of file to play. warn_interval: Interval in seconds between sounds. start_sound: Sound to play when starting systems. started_sound: Sound to play when systems started. stop_sound: Sound to play when stopping systems. stopped_sound: Sound to play when systems stopped. trigger_file: File, which triggers to switch on-off and vice versa, when created. Will be deleted afterwards. """ Module.__init__(self, **kwargs) # store self._warn_sound = warn_sound self._warn_interval = warn_interval self._start_sound = start_sound self._started_sound = started_sound self._stop_sound = stop_sound self._stopped_sound = stopped_sound self._trigger_file = trigger_file self._player = player self._autonomous = False # threads self.add_background_task(self._heartbeat) self.add_background_task(self._check_autonomous) self.add_background_task(self._check_trigger)
def __init__(self, camera: Union[ICamera, str], port: int = 37077, **kwargs: Any): """Initializes file cache. Args: camera: Camera to use for kiosk mode. port: Port for HTTP server. """ Module.__init__(self, **kwargs) # add thread funcs self.add_background_task(self._camera_thread) # store stuff self._is_listening = False self._camera = camera self._port = port self._exp_time = 2 self._running = False self._image: Optional[bytes] = None # create empty image from PIL import Image, ImageDraw img = Image.new("RGB", (300, 300), color=(0, 0, 0)) d = ImageDraw.Draw(img) d.text((110, 150), "No image taken yet", fill=(255, 255, 255)) # create image from data array with io.BytesIO() as bio: img.save(bio, format="jpeg") self._empty = bio.getvalue() # define web server self._app = web.Application() self._app.add_routes([web.get("/image.jpg", self.image_handler)]) self._runner = web.AppRunner(self._app) self._site: Optional[web.TCPSite] = None
def __init__(self, **kwargs: Any): Module.__init__(self, **kwargs) self._running = False
def __init__( self, telescope: Union[str, ITelescope], camera: Union[str, ICamera], flat_fielder: Optional[Union[Dict[str, Any], FlatFielder]], filters: Optional[Union[str, IFilters]] = None, log_file: Optional[str] = None, **kwargs: Any, ): """Initialize a new flat fielder. Args: telescope: Name of ITelescope. camera: Name of ICamera. flat_fielder: Flat field object to use. filters: Name of IFilters, if any. log_file: Name of file to store flat field log in. """ Module.__init__(self, **kwargs) # store telescope, camera, and filters self._telescope = telescope self._camera = camera self._filter_wheel = filters self._abort = asyncio.Event() self._running = False # flat fielder self._flat_fielder = self.get_object(flat_fielder, FlatFielder, callback=self.callback) # init log file self._publisher = None if log_file is None else CsvPublisher(log_file) # init binning and filter self._binning = (1, 1) self._filter: Optional[str] = None # need to add IFilters interface? if self._filter_wheel is not None: # check filters if not self._flat_fielder.has_filters: raise ValueError( "Filter wheel module given in config, but no filters in functions." ) # add it # self.__class__ = type('FlatFieldFilter', (FlatField, IFilters), {}) # register exceptions if isinstance(camera, str): exc.register_exception( exc.RemoteError, 3, timespan=600, module=camera, callback=self._default_remote_error_callback) if isinstance(telescope, str): exc.register_exception( exc.RemoteError, 3, timespan=600, module=telescope, callback=self._default_remote_error_callback) if isinstance(filters, str): exc.register_exception( exc.RemoteError, 3, timespan=600, module=filters, callback=self._default_remote_error_callback)
def __init__( self, focuser: Optional[str] = None, weather: Optional[str] = None, interval: int = 300, temperatures: Optional[Dict[str, Dict[str, float]]] = None, model: Optional[str] = None, coefficients: Optional[Dict[str, float]] = None, update: bool = False, log_file: Optional[str] = None, min_measurements: int = 10, enabled: bool = True, temp_sensor: str = "average.temp", default_filter: Optional[str] = None, filter_offsets: Optional[Dict[str, float]] = None, filter_wheel: Optional[str] = None, **kwargs: Any, ): """Initialize a focus model. Args: focuser: Name of focuser. weather: Name of weather station. interval: Interval for setting focus or None, if no regular setting of focus is required. model: Focus model to use. coefficients: Coefficients in model, mainly used when updating it. update: Whether to update the model on new focus values. log_file: Path to file containing all focus measurements. min_measurements: Minimum number of measurements to update model. enabled: If False, no focus is set. temp_sensor: Name of sensor at weather station to provide ambient temperature. default_filter: Name of default filter. If None, filters are ignored. filter_offsets: Offsets for different filters. If None, they are not modeled. filter_wheel: Name of filter wheel module to use for fetching filter before setting focus. """ Module.__init__(self, **kwargs) # check import import lmfit log.info(f"Found lmfit {lmfit.__version__}.") # add thread func if interval is not None and interval > 0: self.add_background_task(self._update) # store self._focuser = focuser self._weather = weather self._interval = interval self._temperatures: Dict[str, Dict[ str, float]] = {} if temperatures is None else temperatures self._focuser_ready = True self._coefficients = {} if coefficients is None else coefficients self._update_model = update self._min_measurements = min_measurements self._enabled = enabled self._temp_station, sensor = temp_sensor.split(".") self._temp_sensor = WeatherSensors(sensor) self._default_filter = default_filter self._filter_offsets = filter_offsets self._filter_wheel = filter_wheel log.info("Going to fetch temperature from sensor %s at station %s.", self._temp_sensor, self._temp_station) # model parser = Parser() log.info("Parsing model: %s", model) self._model = parser.parse(model) # coefficients if self._coefficients is not None and len(self._coefficients) > 0: log.info( "Found coefficients: %s", ", ".join([ "%s=%.3f" % (k, v) for k, v in self._coefficients.items() ])) # variables variables = self._model.variables() for c in self._coefficients.keys(): variables.remove(c) log.info("Found variables: %s", ", ".join(variables)) # init log file self._publisher = None if log_file is None else CsvPublisher(log_file) # update model now? if update: self._calc_focus_model()
def __init__( self, http_port: int = 37077, interval: float = 0.5, video_path: str = "/webcam/video.mjpg", filenames: str = "/webcam/pyobs-{DAY-OBS|date:}-{FRAMENUM|string:04d}.fits", fits_namespaces: Optional[List[str]] = None, fits_headers: Optional[Dict[str, Any]] = None, centre: Optional[Tuple[float, float]] = None, rotation: float = 0.0, cache_size: int = 5, live_view: bool = True, flip: bool = False, sleep_time: int = 600, **kwargs: Any, ): """Creates a new BaseWebcam. On the receiving end, a VFS root with a HTTPFile must exist with the same name as in image_path and video_path, i.e. "webcam" in the default settings. Args: http_port: HTTP port for webserver. exposure_time: Initial exposure time. interval: Min interval for grabbing images. video_path: VFS path to video. filename: Filename pattern for FITS images. fits_namespaces: List of namespaces for FITS headers that this camera should request. fits_headers: Additional FITS headers. centre: (x, y) tuple of camera centre. rotation: Rotation east of north. cache_size: Size of cache for previous images. live_view: If True, live view is served via web server. flip: Whether to flip around Y axis. sleep_time: Time in s with inactivity after which the camera should go to sleep. """ Module.__init__(self, **kwargs) ImageFitsHeaderMixin.__init__( self, fits_namespaces=fits_namespaces, fits_headers=fits_headers, centre=centre, rotation=rotation, filenames=filenames, ) # store self._is_listening = False self._port = http_port self._interval = interval self._new_image_event = asyncio.Event() self._video_path = video_path self._frame_num = 0 self._live_view = live_view self._image_type = ImageType.OBJECT self._image_request_lock = asyncio.Lock() self._image_requests: List[ImageRequest] = [] self._next_image: Optional[NextImage] = None self._last_image: Optional[LastImage] = None self._last_time = 0.0 self._flip = flip self._sleep_time = sleep_time # active self._active = False self._active_time = 0.0 self.add_background_task(self._active_update) # image cache self._cache = DataCache(cache_size) # define web server self._app = web.Application() self._app.add_routes([ web.get("/", self.web_handler), web.get("/video.mjpg", self.video_handler), web.get("/{filename}", self.image_handler), ]) self._runner = web.AppRunner(self._app) self._site: Optional[web.TCPSite] = None
def __init__(self, **kwargs: Any): """Create a new dummy acquisition.""" Module.__init__(self, **kwargs) # store self._is_running = False