Beispiel #1
0
    def command(self, cmd):
        """ Run gphoto2 command """

        # Test to see if there is a running command already
        if self._proc and self._proc.poll():
            raise error.InvalidCommand("Command already running")
        else:
            # Build the command.
            run_cmd = [self._gphoto2, '--port', self.port]
            run_cmd.extend(listify(cmd))

            self.logger.debug("gphoto2 command: {}".format(run_cmd))

            try:
                self._proc = subprocess.Popen(run_cmd,
                                              stdout=subprocess.PIPE,
                                              stderr=subprocess.STDOUT,
                                              universal_newlines=True,
                                              shell=False)
            except OSError as e:
                raise error.InvalidCommand(
                    "Can't send command to gphoto2. {} \t {}".format(
                        e, run_cmd))
            except ValueError as e:
                raise error.InvalidCommand(
                    "Bad parameters to gphoto2. {} \t {}".format(e, run_cmd))
            except Exception as e:
                raise error.PanError(e)
Beispiel #2
0
    def _load_transition(self, transition):
        # Add `check_safety` as the first transition for all states
        conditions = listify(transition.get('conditions', []))

        conditions.insert(0, 'check_safety')
        transition['conditions'] = conditions

        self.logger.trace(f"Returning transition: {transition}")
        return transition
Beispiel #3
0
    def make_safety_decision(self, current_values, ignore=None):
        """
        Method makes decision whether conditions are safe or unsafe.

        ignore: list of safety params to ignore. Can be 'rain', 'wind', 'gust' or 'cloud'. If None (default) nothing is ignored.
        """
        logger.debug('Making safety decision')
        logger.debug(f'Found {len(self.weather_entries)} weather entries '
                     f'in last {self.safety_delay:.0f} minutes')

        # Tuple with condition,safety
        cloud = self._get_cloud_safety(current_values)

        try:
            wind, gust = self._get_wind_safety(current_values)
        except Exception as e:
            logger.warning(f'Problem getting wind safety: {e!r}')
            wind = ['N/A', False]
            gust = ['N/A', False]

        rain = self._get_rain_safety(current_values)

        safety_params = {
            'cloud': cloud[1],
            'wind': wind[1],
            'gust': gust[1],
            'rain': rain[1]
        }

        if ignore is not None:
            for weather_to_ignore in listify(ignore):
                ignored_value = safety_params.pop(weather_to_ignore)

                # Warn if ignoring an unsafe value.
                if ignored_value is False:
                    logger.warning(
                        f'Ignored unsafe value: {weather_to_ignore}={ignored_value}'
                    )

        # Do final safety check.
        safe = all(safety_params.values())

        logger.debug(f'Weather Safe: {safe}')

        return {
            'Safe': safe,
            'Sky': cloud[0],
            'Wind': wind[0],
            'Gust': gust[0],
            'Rain': rain[0]
        }
Beispiel #4
0
def test_listfy_dicts():
    d = dict(a=42)

    d_vals = d.values()
    d_keys = d.keys()

    assert isinstance(listify(d_vals), list)
    assert listify(d_vals) == list(d_vals)

    assert isinstance(listify(d_keys), list)
    assert listify(d_keys) == list(d_keys)

    assert isinstance(listify(d), list)
    assert listify(d) == list(d_vals)
Beispiel #5
0
    def __init__(self,
                 name='Generic Filter Wheel',
                 model='simulator',
                 camera=None,
                 filter_names=None,
                 timeout=None,
                 serial_number='XXXXXX',
                 dark_position=None,
                 *args,
                 **kwargs):
        super().__init__(*args, **kwargs)

        self._model = model
        self._name = name
        self._camera = camera
        self._filter_names = [str(name) for name in listify(filter_names)]
        if not self._filter_names:
            # Empty list
            msg = "Must provide list of filter names"
            self.logger.error(msg)
            raise ValueError(msg)
        self._n_positions = len(filter_names)
        try:
            self._timeout = timeout.to_value(unit=u.second)
        except AttributeError:
            self._timeout = timeout
        self._serial_number = serial_number
        if dark_position is not None:
            # Will raise ValueError is dark_position is not a valid position for this filterwheel
            self._dark_position = self._parse_position(dark_position)
        else:
            self._dark_position = None

        self._last_light_position = None
        self._connected = False

        # Some filter wheels needs this to track whether they are moving or not.
        self._move_event = threading.Event()
        self._move_event.set()

        self.logger.debug('Filter wheel created: {}'.format(self))
Beispiel #6
0
def load_config(config_files=None, parse=True, load_local=True):
    """Load configuration information.

    .. note::

        This function is used by the config server and normal config usage should
        be via a running config server.

    This function supports loading of a number of different files. If no options
    are passed to ``config_files`` then the default ``$PANOPTES_CONFIG_FILE``
    will be loaded.

    ``config_files`` is a list and loaded in order, so the second entry will overwrite
    any values specified by similarly named keys in the first entry.

    ``config_files`` should be specified by an absolute path, which can exist anywhere
    on the filesystem.

    Local versions of files can override built-in versions and are automatically loaded if
    they exist alongside the specified config path. Local files have a ``<>_local.yaml`` name, where
    ``<>`` is the built-in file.

    Given the following path:

    ::

        /path/to/dir
        |- my_conf.yaml
        |- my_conf_local.yaml

    You can do a ``load_config('/path/to/dir/my_conf.yaml')`` and both versions of the file will
    be loaded, with the values in the local file overriding the non-local. Typically the local
    file would also be ignored by ``git``, etc.

    For example, the ``panoptes.utils.config.server.config_server`` will always save values to
    a local version of the file so the default settings can always be recovered if necessary.

    Local files can be ignored (mostly for testing purposes or for recovering default values)
    with the ``load_local=False`` parameter.

    Args:
        config_files (list, optional): A list of files to load as config,
            see Notes for details of how to specify files.
        parse (bool, optional): If the config file should attempt to create
            objects such as dates, astropy units, etc.
        load_local (bool, optional): If local files should be used, see
            Notes for details.

    Returns:
        dict: A dictionary of config items.
    """
    config = dict()

    config_files = listify(config_files)
    logger.debug(f'Loading config files:  config_files={config_files!r}')
    for config_file in config_files:
        try:
            logger.debug(f'Adding  config_file={config_file!r} to config dict')
            _add_to_conf(config, config_file, parse=parse)
        except Exception as e:  # pragma: no cover
            logger.warning(f"Problem with  config_file={config_file!r}, skipping. {e!r}")

        # Load local version of config
        if load_local:
            local_version = config_file.replace('.', '_local.')
            if os.path.exists(local_version):
                try:
                    _add_to_conf(config, local_version, parse=parse)
                except Exception as e:  # pragma: no cover
                    logger.warning(
                        f"Problem with  local_version={local_version!r}, skipping: {e!r}")

    # parse_config_directories currently only corrects directory names.
    if parse:
        logger.trace(f'Parsing  config={config!r}')
        with suppress(KeyError):
            config['directories'] = parse_config_directories(config['directories'])
            logger.trace(f'Config directories parsed:  config={config!r}')

    return config
Beispiel #7
0
    def get_observation(self,
                        time=None,
                        show_all=False,
                        reread_fields_file=False):
        """Get a valid observation

        Args:
            time (astropy.time.Time, optional): Time at which scheduler applies,
                defaults to time called
            show_all (bool, optional): Return all valid observations along with
                merit value, defaults to False to only get top value
            reread_fields_file (bool, optional): If the fields file should be reread
                before scheduling occurs, defaults to False.

        Returns:
            tuple or list: A tuple (or list of tuples) with name and score of ranked observations
        """
        if reread_fields_file:
            self.logger.debug("Rereading fields file")
            self.read_field_list()

        if time is None:
            time = current_time()

        valid_obs = {obs: 0.0 for obs in self.observations}
        best_obs = []

        self.set_common_properties(time)

        for constraint in listify(self.constraints):
            self.logger.info("Checking Constraint: {}".format(constraint))
            for obs_name, observation in self.observations.items():
                if obs_name in valid_obs:
                    current_score = valid_obs[obs_name]
                    self.logger.debug(
                        f"\t{obs_name}\tCurrent score: {current_score:.03f}")

                    veto, score = constraint.get_score(
                        time, self.observer, observation,
                        **self.common_properties)

                    self.logger.debug(
                        f"\t\tConstraint Score: {score:.03f}\tVeto: {veto}")

                    if veto:
                        self.logger.debug(f"\t\tVetoed by {constraint}")
                        del valid_obs[obs_name]
                        continue

                    valid_obs[obs_name] += score
                    self.logger.debug(
                        f"\t\tTotal score: {valid_obs[obs_name]:.03f}")

        self.logger.debug(f'Multiplying final scores by priority')
        for obs_name, score in valid_obs.items():
            priority = self.observations[obs_name].priority
            new_score = score * priority
            self.logger.debug(
                f'{obs_name}: {priority:7.2f} *{score:7.2f} = {new_score:7.2f}'
            )
            valid_obs[obs_name] = new_score

        if len(valid_obs) > 0:
            # Sort the list by highest score (reverse puts in correct order)
            best_obs = sorted(valid_obs.items(), key=lambda x: x[1])[::-1]

            top_obs_name, top_obs_score = best_obs[0]
            self.logger.info(
                f'Best observation: {top_obs_name}\tScore: {top_obs_score:.02f}'
            )

            # Check new best against current_observation
            if self.current_observation is not None \
                    and top_obs_name != self.current_observation.name:

                # Favor the current observation if still available
                end_of_next_set = time + self.current_observation.set_duration
                if self.observation_available(self.current_observation,
                                              end_of_next_set):

                    # If current is better or equal to top, use it
                    if self.current_observation.merit >= top_obs_score:
                        best_obs.insert(0, (self.current_observation,
                                            self.current_observation.merit))

            # Set the current
            self.current_observation = self.observations[top_obs_name]
            self.current_observation.merit = top_obs_score
        else:
            if self.current_observation is not None:
                # Favor the current observation if still available
                end_of_next_set = time + self.current_observation.set_duration
                if end_of_next_set < self.common_properties['end_of_night'] and \
                        self.observation_available(self.current_observation, end_of_next_set):

                    self.logger.debug("Reusing {}".format(
                        self.current_observation))
                    best_obs = [(self.current_observation.name,
                                 self.current_observation.merit)]
                else:
                    self.logger.warning("No valid observations found")
                    self.current_observation = None

        if not show_all and len(best_obs) > 0:
            best_obs = best_obs[0]

        return best_obs
Beispiel #8
0
def test_empty_listify():
    assert listify(None) == []
Beispiel #9
0
def test_listify():
    assert listify(12) == [12]
    assert listify([1, 2, 3]) == [1, 2, 3]