async def read_command_status(self, counter):
        """Wait for a command status message whose counter matches
        a specified value.

        Returns
        -------
        duration : `float`
            If the command succeeds.

        Raises
        ------
        salobj.ExpectedError
            If the command failed, the command status code is not recognized,
            or the command stream disconnects.
        """
        header = structs.Header()
        command_status = structs.CommandStatus()
        try:
            while True:
                if not self.command_connected:
                    raise salobj.ExpectedError(
                        "Command socket disconnected while running the command"
                    )

                await tcpip.read_into(self.command_reader, header)
                if header.frame_id != structs.CommandStatus.FRAME_ID:
                    self.log.warning(
                        f"Ignoring message with unexpected frame_id: "
                        f"{header.frame_id} != {structs.CommandStatus.FRAME_ID}"
                    )
                    continue

                if not self.command_connected:
                    raise salobj.ExpectedError(
                        "Command socket disconnected while running the command"
                    )
                await tcpip.read_into(self.command_reader, command_status)

                if header.counter != counter:
                    self.log.warning(
                        "Ignoring command status for wrong command; "
                        f"status.counter={header.counter} "
                        f"!= expected value {counter}")
                    continue
                break
        except ConnectionError:
            self.log.warning("Command stream disconnected; closing client")
            await self.basic_close()
            raise salobj.ExpectedError(
                "Command socket disconnected while running the command")

        if command_status.status == CommandStatusCode.ACK:
            return command_status.duration
        elif command_status.status == CommandStatusCode.NO_ACK:
            reason = command_status.reason.decode()
            raise salobj.ExpectedError(reason)
        else:
            raise salobj.ExpectedError(
                f"Unknown command status {command_status.status}; "
                "low-level command assumed to have failed")
Exemple #2
0
 async def do_track(self, data):
     """Specify a position, velocity, TAI time tracking update."""
     if self.summary_state != salobj.State.ENABLED:
         raise salobj.ExpectedError("Not enabled")
     if (self.server.telemetry.enabled_substate !=
             EnabledSubstate.SLEWING_OR_TRACKING):
         if self._tracking_started_telemetry_counter <= 0:
             raise salobj.ExpectedError(
                 "Low-level controller in substate "
                 f"{self.server.telemetry.enabled_substate} "
                 f"instead of {EnabledSubstate.SLEWING_OR_TRACKING}")
     dt = data.tai - salobj.current_tai()
     curr_pos = data.angle + data.velocity * dt
     if (not self.server.config.lower_pos_limit <= curr_pos <=
             self.server.config.upper_pos_limit):
         raise salobj.ExpectedError(
             f"current position {curr_pos} not in range "
             f"[{self.server.config.lower_pos_limit}, "
             f"{self.server.config.upper_pos_limit}]")
     if not abs(data.velocity) <= self.server.config.velocity_limit:
         raise salobj.ExpectedError(f"abs(velocity={data.velocity}) > "
                                    f"[{self.server.config.velocity_limit}")
     await self.run_command(
         code=enums.CommandCode.TRACK_VEL_CMD,
         param1=data.tai,
         param2=data.angle,
         param3=data.velocity,
     )
     self.evt_target.set_put(position=data.angle,
                             velocity=data.velocity,
                             tai=data.tai,
                             force_output=True)
Exemple #3
0
    async def powerLightOn(self):
        """ Signals the Horiba device to power light on.
            We always set the brightness to self.startupWattage for a
            moment (self.startupTime), then step it back down to the
            default.

            Parameters
            ----------
            None

            Returns
            -------
            None
        """
        if not self.cooldown_task.done():  # are we in the cooldown period?
            elapsed = time.time() - self.off_time
            remaining = self.cooldownPeriod - elapsed
            description = "Can't power on bulb during cool-off period. Please wait "
            raise salobj.ExpectedError(description + str(remaining) + " seconds.")
        if self.bulb_on:
            raise salobj.ExpectedError("Can't power on when we're already powered on.")
        self.component.setLightPower(self.startupWattage)
        self.on_time = time.time()
        self.warmup_task = asyncio.ensure_future(asyncio.sleep(self.warmupPeriod))
        self.bulb_on = True
        self.on_task = asyncio.ensure_future(asyncio.sleep(self.startupTime))
        await self.on_task
        self.component.setLightPower(self.defaultWattage)
Exemple #4
0
 def do_setInstrumentPort(self, data):
     self.assert_enabled("setInstrumentPort")
     if self._tracking_enabled:
         raise salobj.ExpectedError(
             "Cannot setInstrumentPort while tracking is enabled"
         )
     port = data.port
     try:
         m3_port_positions_ind = self._port_info_dict[port][0]
     except IndexError:
         raise salobj.ExpectedError(f"Invalid port={port}")
     try:
         m3_port_positions = self.m3_port_positions[m3_port_positions_ind]
     except IndexError:
         raise RuntimeError(
             f"Bug! invalid m3_port_positions_ind={m3_port_positions_ind} for port={port}"
         )
     self.evt_m3PortSelected.set_put(selected=port)
     m3actuator = self.actuators[Axis.M3]
     if (
         m3actuator.target.position == m3_port_positions
         and self.evt_m3InPosition.data.inPosition
     ):
         # already there; don't do anything
         return
     self.actuators[Axis.M3].set_target(
         tai=utils.current_tai(), position=m3_port_positions, velocity=0
     )
     self._axis_enabled[Axis.NA1] = False
     self._axis_enabled[Axis.NA2] = False
     self.update_events()
Exemple #5
0
    async def enable_controller(self):
        """Enable the low-level controller.

        Returns
        -------
        states : `list` [`ControllerState`]
            A list of the initial controller state, and all controller states
            this function transitioned the low-level controller through,
            ending with the ControllerState.ENABLED.
        """
        self.assert_commandable()

        # Desired controller state
        controller_state = ControllerState.ENABLED

        states = []
        if self.client.telemetry.state == ControllerState.FAULT:
            states.append(self.client.telemetry.state)
            # Start by issuing the clearError command.
            # This must be done twice, with a delay between.
            self.log.info("Clearing low-level controller fault state")
            await self.run_command(code=self.CommandCode.SET_STATE,
                                   param1=SetStateParam.CLEAR_ERROR)
            await asyncio.sleep(0.9)
            await self.run_command(code=self.CommandCode.SET_STATE,
                                   param1=SetStateParam.CLEAR_ERROR)
            # Give the controller time to reset
            # then check the resulting state
            await asyncio.sleep(1)
            if self.client.telemetry.state == ControllerState.FAULT:
                raise salobj.ExpectedError(
                    "Cannot clear low-level controller fault state")

        current_state = self.client.telemetry.state
        states.append(current_state)
        if current_state == controller_state:
            # we are already in the desired controller_state
            return states

        command_state_list = _STATE_TRANSITION_DICT[(current_state,
                                                     controller_state)]

        for command_param, resulting_state in command_state_list:
            self.assert_commandable()
            try:
                self.log.debug(
                    f"Issue SET_STATE command with param1={command_param!r}")
                await self.run_command(code=self.CommandCode.SET_STATE,
                                       param1=command_param)
                await self.wait_controller_state(resulting_state)
                current_state = resulting_state
            except Exception as e:
                raise salobj.ExpectedError(
                    f"SET_STATE command with param1={command_param!r} failed: {e!r}"
                ) from e
            states.append(resulting_state)
        return states
Exemple #6
0
    async def do_expose(self, data):
        """Take an exposure with the connected spectrograph.

        Parameters
        ----------
        data : `DataType`
            Command data

        Raises
        ------
        asyncio.CancelledError
            Raised if the exposure is cancelled before it completes.
        lsst.ts.salobj.ExpectedError
            Raised if an error occurs while taking the exposure.
        """
        self.assert_enabled()
        msg = self.device.check_expose_ok(data.duration)
        if msg is not None:
            raise salobj.ExpectedError(msg)
        try:
            date_begin = utils.astropy_time_from_tai_unix(utils.current_tai())
            task = asyncio.create_task(self.device.expose(data.duration))
            await self.evt_exposureState.set_write(status=ExposureState.INTEGRATING)
            wavelength, spectrum = await task
            date_end = utils.astropy_time_from_tai_unix(utils.current_tai())
            await self.evt_exposureState.set_write(status=ExposureState.DONE)
            temperature = self.tel_temperature.data.temperature * u.deg_C
            setpoint = self.tel_temperature.data.setpoint * u.deg_C
            n_pixels = self.evt_deviceInfo.data.npixels
            spec_data = dataManager.SpectrographData(
                wavelength=wavelength,
                spectrum=spectrum,
                duration=data.duration,
                date_begin=date_begin,
                date_end=date_end,
                type=data.type,
                source=data.source,
                temperature=temperature,
                temperature_setpoint=setpoint,
                n_pixels=n_pixels,
            )
        except asyncio.TimeoutError as e:
            await self.evt_exposureState.set_write(status=ExposureState.TIMEDOUT)
            msg = f"Timeout waiting for exposure: {repr(e)}"
            await self.fault(code=20, report=msg)
            raise salobj.ExpectedError(msg)
        except asyncio.CancelledError:
            await self.evt_exposureState.set_write(status=ExposureState.CANCELLED)
            raise
        except Exception as e:
            await self.evt_exposureState.set_write(status=ExposureState.FAILED)
            msg = f"Failed to take exposure with fiber spectrograph: {repr(e)}"
            await self.fault(code=20, report=msg)
            raise salobj.ExpectedError(msg)

        await self.save_data(spec_data)
Exemple #7
0
    async def run_command(self, cmd):
        """Send a command to the TCP/IP controller and process its replies.

        Parameters
        ----------
        cmd : `str`
            The command to send, e.g. "5.0 MV", "SO" or "+".

        Raises
        ------
        salobj.ExpectedError
            If communication fails. Also an exception is logged,
            the CSC disconnects from the low level controller,
            and goes into FAULT state.
            If the wrong number of lines is read. Also a warning is logged.
        """
        if not self.connected:
            if self.disabled_or_enabled and not self.connect_task.done():
                await self.connect_task
            else:
                raise RuntimeError("Not connected and not trying to connect")

        async with self.cmd_lock:
            self.writer.write(f"{cmd}\r\n".encode())
            await self.writer.drain()
            if cmd == "?":
                # Turn short status into long status
                cmd = "+"
            expected_lines = {"+": 25}.get(cmd, 0)  # excluding final ">" line

            try:
                read_bytes = await asyncio.wait_for(
                    self.reader.readuntil(b">"), timeout=self.config.read_timeout
                )
            except Exception as e:
                if isinstance(e, asyncio.streams.IncompleteReadError):
                    err_msg = "TCP/IP controller exited"
                else:
                    err_msg = "TCP/IP read failed"
                self.log.exception(err_msg)
                await self.disconnect()
                self.fault(code=2, report=f"{err_msg}: {e}")
                raise salobj.ExpectedError(err_msg)

            data = read_bytes.decode()
            lines = data.split("\n")[:-1]  # strip final > line
            lines = [elt.strip() for elt in lines]
            if len(lines) != expected_lines:
                err_msg = (
                    f"Command {cmd} returned {data!r}; expected {expected_lines} lines"
                )
                self.log.error(err_msg)
                raise salobj.ExpectedError(err_msg)
            elif cmd == "+":
                self.handle_status(lines)
Exemple #8
0
 def do_startTracking(self, data):
     self.assert_enabled("startTracking")
     if not self.evt_m3InPosition.data.inPosition:
         raise salobj.ExpectedError(
             "Cannot startTracking until M3 is at a known position"
         )
     if not self._stop_tracking_task.done():
         raise salobj.ExpectedError("stopTracking not finished yet")
     self._tracking_enabled = True
     self.update_events()
     self._set_tracking_timer(restart=True)
Exemple #9
0
    async def setLightPower(self, watts):
        """ Sets the brightness (in watts) on the white light source.
            There are lots of constraints.
            1 When we turn the bulb on (>800w) we aren't allowed to turn
              it off for 15m because the Hg inside needs to fully evaporate
              But we can overrride.
            2 When we turn the bulb off, we need to wait 15m for the Hg to
              recondense before we can turn it on again.
            3 When we turn on, we go to maximum brightness for 2 seconds and
              then drop back down.
            4 1200w is the maximum brightness, and requesting higher will
              produce an error.
            5 800w is the minimum, and requesting lower is the same as
              requesting to power off.

            Parameters
            ----------
            watts : int or float
                Should be <= 1200. Values under 800 power the light off entirely.

            Returns
            -------
            None
        """
        # TODO: report watts as telemetry (or events?)
        if watts > 1200:
            raise salobj.ExpectedError(f"Wattage {watts} too high (over 1200)")
        if watts < 800:
            # turn bulb off
            if not self.warmup_task.done():
                description = "Can't power off bulb during warm-up period. Please wait "
                elapsed = time.time() - self.on_time
                remaining = self.warmupPeriod - elapsed
                raise salobj.ExpectedError(description + str(remaining) + " seconds.")
                
            if self.bulb_on:
                self.cooldown_task = asyncio.ensure_future(asyncio.sleep(self.cooldownPeriod))
                self.component.setLightPower(0)
                self.bulb_on = False
                self.off_time = time.time()
            else:
                raise salobj.ExpectedError("Bulb is already off")
        else:
            # this executes when watts are inside the 800-1200 range
            if not self.bulb_on:
                raise salobj.ExpectedError("You must turn the light on before setting light power.")
            if not self.on_task.done():
                await self.on_task
                self.component.setLightPower(watts)
            else:
                self.component.setLightPower(watts)
                self.bulb_on = True
Exemple #10
0
    async def do_homeAzimuth(self, data):
        """Implement the ``homeAzimuth`` command."""
        self.assert_enabled()
        put_final_azimuth_commanded_state = False
        if self.evt_azimuthState.data.homing or self.homing:
            raise salobj.ExpectedError("Already homing")
        try:
            self.homing = True

            await self.wait_n_status(n=2)
            if bool(self.evt_moveCode.data.code & MoveCode.AZIMUTH_HOMING):
                raise salobj.ExpectedError("Already homing")
            if not self.evt_azimuthState.data.state == AzimuthState.NOTINMOTION:
                raise salobj.ExpectedError("Azimuth is moving")

            # Homing is allowed; do it!
            self.cmd_homeAzimuth.ack_in_progress(data=data,
                                                 timeout=HOME_AZIMUTH_TIMEOUT)
            self.evt_azimuthCommandedState.set_put(
                commandedState=AzimuthCommandedState.HOME,
                azimuth=math.nan,
                force_output=True,
            )
            put_final_azimuth_commanded_state = True
            await self.run_command("HM")
            self.status_sleep_task.cancel()
            # Check status until move code is no longer homing.
            # Skip one status to start with.
            n_to_await = 2
            while self.homing:
                await self.wait_n_status(n=n_to_await)
                n_to_await = 1
                # Do not use self.evt_azimuthState.data.homing because
                # it includes self.homing, which we have set true.
                self.homing = bool(self.evt_moveCode.data.code
                                   & MoveCode.AZIMUTH_HOMING)
            self.evt_azimuthState.set_put(homed=True,
                                          homing=False,
                                          force_output=True)
        except Exception:
            self.log.exception("homing failed")
        finally:
            self.homing = False
            if put_final_azimuth_commanded_state:
                self.evt_azimuthCommandedState.set_put(
                    commandedState=AzimuthCommandedState.STOP,
                    force_output=True,
                )
Exemple #11
0
    def assert_summary_state(self, state, isbefore=None):
        """Assert that the current summary state is as specified.

        First check that CSC can command the low-level controller.

        Used in do_xxx methods to check that a command is allowed.

        Parameters
        ----------
        state : `lsst.ts.salobj.State`
            Expected summary state.
        isbefore : `bool`, optional
            Deprecated. The only allowed values are False
            (which raises a deprecation warning) and None.
        """
        if isbefore:
            raise ValueError(
                f"isbefore={isbefore}; this deprecated argument must be None or False"
            )
        elif isbefore is False:
            warnings.warn(f"isbefore={isbefore} is deprecated",
                          DeprecationWarning)
        state = salobj.State(state)
        self.assert_connected()
        if self.summary_state != state:
            raise salobj.ExpectedError(
                f"Rejected: initial state is {self.summary_state!r} instead of {state!r}"
            )
Exemple #12
0
 def convert_values(name, values, nval):
     out = np.array(values, dtype=float)
     if out.shape != (nval,):
         raise salobj.ExpectedError(
             f"Could not format {name}={values!r} as {nval} floats"
         )
     return out
Exemple #13
0
    async def do_moveShutterMainDoor(self, data):
        """Implement the ``moveShutterMainDoor`` command."""
        self.assert_enabled()
        if data.open:
            self.evt_mainDoorCommandedState.set_put(
                commandedState=ShutterDoorCommandedState.OPENED,
                force_output=True)
            await self.run_command("OP")
        else:
            if self.evt_dropoutDoorState.data.state not in (
                    ShutterDoorState.CLOSED,
                    ShutterDoorState.OPENED,
            ):
                raise salobj.ExpectedError(
                    "Cannot close the main door "
                    "until the dropout door is fully closed or fully open.")
            self.evt_mainDoorCommandedState.set_put(
                commandedState=ShutterDoorCommandedState.CLOSED,
                force_output=True)
            await self.run_command("CL")

        await self.wait_for_shutter(
            dropout_state=None,
            main_state=ShutterDoorState.OPENED
            if data.open else ShutterDoorState.CLOSED,
        )
Exemple #14
0
    async def do_abort_job(self, data):
        """Implement the ``abort_job`` command.

        Parameters
        ----------
        data: types.SimpleNamespace
            Must contain job_id attribute.
        """
        self.assert_enabled("abort_job")
        self.log.info(f"abort_job command with {data}")
        if self.simulation_mode == 0:
            self.log.info(f"DELETE: {data.job_id}")
            result = self.connection.delete(
                f"{self.config.url}/job/{data.job_id}")
            result.raise_for_status()
            self.log.info(f"Abort result: {result.text}")
            self.evt_job_result.set_put(job_id=data.job_id,
                                        exit_code=255,
                                        result=result.text)
        else:
            if data.job_id in self.simulated_jobs:
                self.simulated_jobs.remove(data.job_id)
                payload = json.dumps(dict(abort_time=salobj.current_tai()))
                self.evt_job_result.set_put(job_id=data.job_id,
                                            exit_code=255,
                                            result=payload)
                self.log.info(f"Abort result: {payload}")
            else:
                raise salobj.ExpectedError("No such job id: {data.job_id}")
Exemple #15
0
    async def handle_summary_state(self):
        # disabled: connect and send telemetry, but no commands allowed.
        if self.summary_state in (salobj.State.ENABLED, salobj.State.DISABLED):
            if self.s3bucket is None:
                domock = self.simulation_mode & constants.SimulationMode.S3Server != 0
                self.s3bucket = salobj.AsyncS3Bucket(
                    name=self.s3bucket_name, domock=domock, create=domock
                )
            if self.device is None:
                try:
                    self.device = AvsFiberSpectrograph(
                        serial_number=self.serial_number, log=self.log
                    )
                except Exception as e:
                    msg = "Failed to connect to fiber spectrograph."
                    await self.fault(code=1, report=f"{msg}: {repr(e)}")
                    raise salobj.ExpectedError(msg)

            if self.telemetry_loop_task.done():
                self.telemetry_loop_task = asyncio.create_task(self.telemetry_loop())
            status = self.device.get_status()
            await self.evt_deviceInfo.set_write(
                npixels=status.n_pixels,
                fpgaVersion=status.fpga_version,
                firmwareVersion=status.firmware_version,
                libraryVersion=status.library_version,
            )
        else:
            self.telemetry_loop_task.cancel()
            if self.device is not None:
                self.device.disconnect()
            self.device = None
            if self.s3bucket is not None:
                self.s3bucket.stop_mock()
            self.s3bucket = None
Exemple #16
0
 async def do_stop(self, data):
     """Halt tracking or any other motion."""
     if self.summary_state != salobj.State.ENABLED:
         raise salobj.ExpectedError("Not enabled")
     await self.run_command(
         code=enums.CommandCode.SET_ENABLED_SUBSTATE,
         param1=enums.SetEnabledSubstateParam.STOP,
     )
Exemple #17
0
 def assert_commandable(self):
     """Assert that CSC is connected to the low-level controller
     and can command it.
     """
     self.assert_connected()
     if not self.evt_commandableByDDS.data.state:
         raise salobj.ExpectedError("Controller has CSC commands disabled; "
                                    "use the EUI to enable CSC commands")
Exemple #18
0
 async def do_moveAzimuth(self, data):
     """Implement the ``moveAzimuth`` command."""
     self.assert_enabled("moveAzimuth")
     if self.evt_azimuthState.data.homing:
         raise salobj.ExpectedError("Cannot move azimuth while homing")
     azimuth = data.azimuth
     if azimuth < 0 or azimuth >= 360:
         raise salobj.ExpectedError(
             f"azimuth={azimuth} deg; must be in range [0, 360)"
         )
     await self.run_command(f"{azimuth:0.3f} MV")
     self.evt_azimuthCommandedState.set_put(
         commandedState=AzimuthCommandedState.GOTOPOSITION,
         azimuth=azimuth,
         force_output=True,
     )
     self.status_sleep_task.cancel()
Exemple #19
0
 async def run(self) -> None:
     self.log.info("Run started")
     await self.checkpoint("start")
     if self.config.fail_run:
         raise salobj.ExpectedError(
             f"Failed in run after wait: fail_run={self.config.fail_run}")
     await asyncio.sleep(self.config.wait_time)
     await self.checkpoint("end")
     self.log.info("Run succeeded")
Exemple #20
0
 async def do_configureVelocity(self, data):
     """Specify the velocity limit."""
     self.assert_enabled_substate(EnabledSubstate.STATIONARY)
     if not 0 < data.vlimit <= constants.MAX_VEL_LIMIT:
         raise salobj.ExpectedError(
             f"vlimit={data.vlimit} must be > 0 and <= {constants.MAX_VEL_LIMIT}"
         )
     await self.run_command(code=enums.CommandCode.CONFIG_VEL,
                            param1=data.vlimit)
Exemple #21
0
 async def begin_start(self, data):
     if data.configurationOverride == "logLevel":
         self.is_log_level = True
     elif data.configurationOverride == "arrays":
         self.is_log_level = False
     else:
         raise salobj.ExpectedError(
             f"data.configurationOverride={data.configurationOverride} must be logLevel or arrays"
         )
     print(f"TopicWriter: writing {data.configurationOverride}")
Exemple #22
0
    def assert_connected(self):
        """Assert that the CSC is connected to the low-level controller.

        Raises
        ------
        lsst.ts.salobj.ExpectedError
            If one or both streams is disconnected.
        """
        if not self.connected:
            raise salobj.ExpectedError(
                "Not connected to the low-level controller.")
Exemple #23
0
 async def do_move(self, data):
     """Move a script within the queue."""
     self.assert_enabled("move")
     try:
         await self.model.move(
             sal_index=data.salIndex,
             location=data.location,
             location_sal_index=data.locationSalIndex,
         )
     except ValueError as e:
         raise salobj.ExpectedError(str(e))
Exemple #24
0
 async def do_stopTracking(self, data):
     self.assert_enabled("stopTracking")
     if not self._stop_tracking_task.done():
         raise salobj.ExpectedError("Already stopping")
     self._set_tracking_timer(restart=False)
     self._tracking_enabled = False
     for axis in MainAxes:
         self.actuators[axis].stop()
     self._stop_tracking_task.cancel()
     self._stop_tracking_task = asyncio.ensure_future(self._finish_stop_tracking())
     self.update_events()
Exemple #25
0
 async def emergencyPowerLightOff(self):
     """Signals the device to power off immediately, ignoring the 15m
        warmup period. The manufacturer warns that this can significantly
        reduce the life of the bulb.
     """
     if self.bulb_on:
         self.cooldown_task = asyncio.ensure_future(asyncio.sleep(self.cooldownPeriod))
         self.component.setLightPower(0)
         self.bulb_on = False
         self.off_time = time.time()
     else:
         raise salobj.ExpectedError("Bulb is already off")
Exemple #26
0
 async def do_move(self, data):
     """Specify a position."""
     self.assert_enabled_substate(EnabledSubstate.STATIONARY)
     if (not self.client.config.min_position <= data.position <=
             self.client.config.max_position):
         raise salobj.ExpectedError(
             f"position {data.position} not in range "
             f"[{self.client.config.min_position}, "
             f"{self.client.config.max_position}]")
     await self.run_command(
         code=simple_mock_controller.SimpleCommandCode.MOVE,
         param1=data.position)
Exemple #27
0
 async def do_homeAzimuth(self, data):
     """Implement the ``homeAzimuth`` command."""
     self.assert_enabled("homeAzimuth")
     if self.evt_azimuthState.data.homing:
         raise salobj.ExpectedError("Already homing")
     self.evt_azimuthCommandedState.set_put(
         commandedState=AzimuthCommandedState.HOME,
         azimuth=math.nan,
         force_output=True,
     )
     await self.run_command("HM")
     self.status_sleep_task.cancel()
Exemple #28
0
 async def do_requeue(self, data):
     """Put a script back on the queue with the same configuration."""
     self.assert_enabled("requeue")
     try:
         await self.model.requeue(
             sal_index=data.salIndex,
             seq_num=data.private_seqNum,
             location=data.location,
             location_sal_index=data.locationSalIndex,
         )
     except ValueError as e:
         raise salobj.ExpectedError(str(e))
    def assert_ready(self) -> None:
        """Assert summary state is enabled and detailed state is READY.

        Raises
        ------
        ExpectedError
            If summary_state is not ENABLED or detailed state is not READY.
        """
        self.assert_enabled()
        if self.detailed_state != DetailedState.READY:
            raise salobj.ExpectedError(
                f"Detailed state={self.detailed_state!r} not READY")
    def configure(self, *, max_delta_azimuth=5):
        """Configure the algorithm.

        Parameters
        ----------
        max_delta_azimuth : `float`
            Maximum allowed difference between dome commanded azimuth
            and telescope_target target azimuth.
        """
        if max_delta_azimuth < 0:
            raise salobj.ExpectedError(
                f"max_delta_azimuth={max_delta_azimuth} must not be negative")
        self.max_delta_azimuth = max_delta_azimuth