コード例 #1
0
    def MoveToPosition_Result(self, request, context: grpc.ServicerContext) \
            -> AxisPositionController_pb2.MoveToPosition_Responses:
        """
        Returns the final result of the command call :meth:`~.MoveToPosition`.

        :param request: A request object with the following properties
            CommandExecutionUUID: The UUID of the command executed.
        :param context: gRPC :class:`~grpc.ServicerContext` object providing gRPC-specific information

        :returns: The return object defined for the command with the following fields:
            EmptyResponse (Empty Response): An empty response data type used if no response is required.
        """

        # Get the UUID of the command
        command_uuid = request.value

        # catch invalid CommandExecutionUUID:
        if not command_uuid or command_uuid not in self.uuid_to_axis:
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.INVALID_COMMAND_EXECUTION_UUID)

        axis = self.uuid_to_axis[command_uuid]

        # catch premature command call
        if not axis.is_target_position_reached():
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.COMMAND_EXECUTION_NOT_FINISHED)

        logging.info("Finished moving! (UUID: %s)", command_uuid)
        del self.uuid_to_axis[command_uuid]
        time.sleep(0.6)

        return AxisPositionController_pb2.MoveToPosition_Responses()
コード例 #2
0
    def GenerateFlow_Result(self, request, context: grpc.ServicerContext) \
            -> ContinuousFlowDosingService_pb2.GenerateFlow_Responses:
        """
        Returns the final result of the command call :meth:`~.GenerateFlow`.

        :param request: A request object with the following properties
            CommandExecutionUUID: The UUID of the command executed.
        :param context: gRPC :class:`~grpc.ServicerContext` object providing gRPC-specific information

        :returns: The return object defined for the command with the following fields:
            EmptyResponse (Empty Response): An empty response data type used if no response is required.
        """

        # Get the UUID of the command
        command_uuid = request.value

        # catch invalid CommandExecutionUUID:
        if not command_uuid and self.dosage_uuid != command_uuid:
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.INVALID_COMMAND_EXECUTION_UUID
            )

        # catch premature command call
        if self.pump.is_pumping():
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.COMMAND_EXECUTION_NOT_FINISHED
            )

        logging.info("Finished dosing! (UUID: %s)", self.dosage_uuid)
        self.dosage_uuid = ""
        return ContinuousFlowDosingService_pb2.GenerateFlow_Responses()
コード例 #3
0
    def _validate_uuid(self,
                       uuid: silaFW_pb2.CommandExecutionUUID,
                       check_premature_call=False):
        """
        Checks the given UUID for validity (i.e. if this is the UUID of the current
        movement command) and raises a SiLAFrameworkError if the UUID is not valid.
        Additionally, if `check_premature_call` is set to `True` then it is also
        checked that the axis system is not moving (this is only useful for
        `..._Result` functions). If this check fails, the corresponding FrameworkError
        will be raised, as well.

        :param uuid: The UUID to check
        :param check_premature_call: Whether to check if the axis system is still
                                     moving and raise an error if it is.
        """
        # catch invalid CommandExecutionUUID:
        if not uuid and self.movement_uuid != uuid:
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.INVALID_COMMAND_EXECUTION_UUID)

        # catch premature command call
        if check_premature_call and not self.axis_system.is_target_position_reached(
        ):
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.COMMAND_EXECUTION_NOT_FINISHED)
コード例 #4
0
    def GenerateFlow_Info(self, request, context: grpc.ServicerContext) \
            -> silaFW_pb2.ExecutionInfo:
        """
        Returns execution information regarding the command call :meth:`~.GenerateFlow`.

        :param request: A request object with the following properties
            commandId: The UUID of the command executed.
        :param context: gRPC :class:`~grpc.ServicerContext` object providing gRPC-specific information

        :returns: An ExecutionInfo response stream for the command with the following fields:
            commandStatus: Status of the command (enumeration)
            progressInfo: Information on the progress of the command (0 to 1)
            estimatedRemainingTime: Estimate of the remaining time required to run the command
            updatedLifetimeOfExecution: An update on the execution lifetime
        """
        # Get the UUID of the command
        command_uuid = request.value

        # catch invalid CommandExecutionUUID:
        if not command_uuid or self.dosage_uuid != command_uuid:
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.INVALID_COMMAND_EXECUTION_UUID
            )

        return self._wait_dosage_finished()
コード例 #5
0
    def Shutdown_Info(self, request, context: grpc.ServicerContext) \
            -> silaFW_pb2.ExecutionInfo:
        """
        Returns execution information regarding the command call :meth:`~.Shutdown`.

        :param request: A request object with the following properties
            commandId: The UUID of the command executed.
        :param context: gRPC :class:`~grpc.ServicerContext` object providing gRPC-specific information

        :returns: An ExecutionInfo response stream for the command with the following fields:
            commandStatus: Status of the command (enumeration)
            progressInfo: Information on the progress of the command (0 to 1)
            estimatedRemainingTime: Estimate of the remaining time required to run the command
            updatedLifetimeOfExecution: An update on the execution lifetime
        """
        # Get the UUID of the command
        command_uuid = request.value

        if not command_uuid or command_uuid != self.command_uuid:
            raise SiLAFrameworkError(error_type=SiLAFrameworkErrorType.
                                     INVALID_COMMAND_EXECUTION_UUID)

        yield silaFW_pb2.ExecutionInfo(
            commandStatus=silaFW_pb2.ExecutionInfo.CommandStatus.running)
        yield silaFW_pb2.ExecutionInfo(commandStatus=silaFW_pb2.ExecutionInfo.
                                       CommandStatus.finishedSuccessfully)
コード例 #6
0
    def _get_axis(self, invocation_metadata: Dict) -> Axis:
        """
        Retrieves the axis that is requested by the `invocation_metadata` of a RPC.
        If the axis cannot be found an appropriate error is raised.
        """

        axis_name = self._get_axis_name(invocation_metadata)
        try:
            return self.axes[axis_name]
        except KeyError:
            raise SiLAFrameworkError(SiLAFrameworkErrorType.INVALID_METADATA,
                                     f'Axis {axis_name} is invalid.')
コード例 #7
0
    def InitializePumpDrive_Result(self, request, context: grpc.ServicerContext) \
            -> PumpDriveControlService_pb2.InitializePumpDrive_Responses:
        """
        Returns the final result of the command call :meth:`~.InitializePumpDrive`.

        :param request: A request object with the following properties
            CommandExecutionUUID: The UUID of the command executed.
        :param context: gRPC :class:`~grpc.ServicerContext` object providing gRPC-specific information

        :returns: The return object defined for the command with the following fields:
            EmptyResponse (Empty Response): An empty response data type used if no response is required.
        """

        # Get the UUID of the command
        command_uuid = request.value

        # catch invalid CommandExecutionUUID:
        if not command_uuid or self.calibration_uuid != command_uuid:
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.INVALID_COMMAND_EXECUTION_UUID)

        # catch premature command call
        if not self.pump.is_calibration_finished():
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.COMMAND_EXECUTION_NOT_FINISHED)

        logging.info("Pump calibrated: %s",
                     self.pump.is_calibration_finished())
        last_error = self.pump.read_last_error()
        if not self.pump.is_calibration_finished() and last_error.code != 0:
            raise InitializationFailedError(
                f'The last error that occurred was {last_error}')

        logging.info("Finished calibration! (UUID: %s)", self.calibration_uuid)
        self.calibration_uuid = ""

        return PumpDriveControlService_pb2.InitializePumpDrive_Responses()
コード例 #8
0
 def _get_axis_name(self, invocation_metadata: Dict) -> str:
     """
     Retrieves the axis name that is given in the `invocation_metadata` of a RPC.
     If the metadatum is not present an appropriate error is raised.
     """
     invocation_metadata = {
         key: value
         for key, value in invocation_metadata
     }
     logging.debug(f"Received invocation metadata: {invocation_metadata}")
     try:
         message = AxisPositionController_pb2.Metadata_AxisIdentifier()
         message.ParseFromString(
             invocation_metadata[METADATA_AXIS_IDENTIFIER])
         return message.AxisIdentifier.value
     except KeyError:
         raise SiLAFrameworkError(
             SiLAFrameworkErrorType.INVALID_METADATA,
             'This Command requires the AxisIdentifier metadata!')
コード例 #9
0
    def __get_channel_id(self, metadata: Tuple[Tuple[str, str]],
                         type: str) -> str:
        """
        Get the requested channel index from the given `metadata`

        :param metdata: The metadata of the call. It should contain the requested channel index
        :param type: Either "Command" or "Property"
        :return: The channel index if it can be obtained, otherwise a SiLAFrameworkError will be raised
        """

        invocation_metadata = {key: value for key, value in metadata}
        logging.debug(f"Received invocation metadata: {invocation_metadata}")
        try:
            message = pb2.Metadata_ChannelIndex()
            message.ParseFromString(invocation_metadata[metadata_key])
            return message.ChannelIndex.value
        except KeyError:
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.INVALID_METADATA,
                f'This {type} requires the ChannelIndex metadata!')
コード例 #10
0
    def get_valve(self, metadata: Tuple[Tuple[str, str]], type: str) -> Valve:
        """
        Get the valve that is identified by the valve index given in `metadata`

        :param metdata: The metadata of the call. It should contain the requested valve index
        :param type: Either "Command" or "Property"
        :return: A valid valve object if the valve can be identified, otherwise a SiLAFrameworkError will be raised
        """

        valve_id = self._get_valve_index(metadata, type)

        logging.debug(f"Requested valve: {valve_id}")

        try:
            return self.valves[valve_id]
        except IndexError:
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.INVALID_METADATA,
                f"The sent valve index ({valve_id}) is invalid! "
                f"The index has to be between 0 and {self.num_valves - 1}.")
コード例 #11
0
    def _get_valve_index(self, metadata: Tuple[Tuple[str, str]],
                         type: str) -> int:
        """
        Get the requested valve index from the given `metadata`

        :param metdata: The metadata of the call. It should contain the requested valve index
        :param type: Either "Command" or "Property"
        :return: The valve index if it can be obtained, otherwise a SiLAFrameworkError will be raised
        """

        invocation_metadata = {key: value for key, value in metadata}
        logging.debug(f"Received invocation metadata: {invocation_metadata}")
        try:
            message = ValveGatewayService_pb2.Metadata_ValveIndex()
            message.ParseFromString(invocation_metadata[METADATA_VALVE_INDEX])
            return message.ValveIndex.value
        except KeyError:
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.INVALID_METADATA,
                f'This {type} requires the ValveIndex metadata!')
コード例 #12
0
    def GenerateFlow_Info(self, request, context: grpc.ServicerContext) \
            -> silaFW_pb2.ExecutionInfo:
        """
        Returns execution information regarding the command call :meth:`~.GenerateFlow`.

        :param request: A request object with the following properties
            commandId: The UUID of the command executed.
        :param context: gRPC :class:`~grpc.ServicerContext` object providing gRPC-specific information

        :returns: An ExecutionInfo response stream for the command with the following fields:
            commandStatus: Status of the command (enumeration)
            progressInfo: Information on the progress of the command (0 to 1)
            estimatedRemainingTime: Estimate of the remaining time required to run the command
            updatedLifetimeOfExecution: An update on the execution lifetime
        """
        # Get the UUID of the command
        command_uuid = request.value

        # catch invalid CommandExecutionUUID:
        if not command_uuid or self.dosage_uuid != command_uuid:
            raise SiLAFrameworkError(
                SiLAFrameworkErrorType.INVALID_COMMAND_EXECUTION_UUID
            )

        is_pumping = True
        while is_pumping:
            time.sleep(0.5)
            yield silaFW_pb2.ExecutionInfo(
                commandStatus=silaFW_pb2.ExecutionInfo.CommandStatus.running
            )
            is_pumping = self.pump.is_pumping()

        if not is_pumping and not self.pump.is_in_fault_state():
            yield silaFW_pb2.ExecutionInfo(
                commandStatus=silaFW_pb2.ExecutionInfo.CommandStatus.finishedSuccessfully
            )
        else:
            yield silaFW_pb2.ExecutionInfo(
                commandStatus=silaFW_pb2.ExecutionInfo.CommandStatus.finishedWithError
            )
            raise QmixSDKSiLAError(self.pump.read_last_error())
コード例 #13
0
    def RunControlLoop_Info(self, request, context: grpc.ServicerContext) \
            -> silaFW_pb2.ExecutionInfo:
        """
        Returns execution information regarding the command call :meth:`~.RunControlLoop`.

        :param request: A request object with the following properties
            CommandExecutionUUID: The UUID of the command executed.
        :param context: gRPC :class:`~grpc.ServicerContext` object providing gRPC-specific information

        :returns: An ExecutionInfo response stream for the command with the following fields:
            commandStatus: Status of the command (enumeration)
            progressInfo: Information on the progress of the command (0 to 1)
            estimatedRemainingTime: Estimate of the remaining time required to run the command
            updatedLifetimeOfExecution: An update on the execution lifetime
        """

        logging.debug(
            "RunControlLoop_Info called in {current_mode} mode".format(
                current_mode=(
                    'simulation' if self.simulation_mode else 'real')))

        # Get the UUID of the command
        command_uuid = request.value

        try:
            if command_uuid not in self.uuid_to_controller:
                raise SiLAFrameworkError(
                    error_type=SiLAFrameworkErrorType.
                    INVALID_COMMAND_EXECUTION_UUID,
                    msg="There is no command execution with the given UUID!")
            controller = self.uuid_to_controller[command_uuid]
            return self.implementation.RunControlLoop_Info(
                request, controller, context)
        except (SiLAError, DecoratorInvalidChannelIndex) as err:
            if isinstance(err, DecoratorInvalidChannelIndex):
                err = InvalidChannelIndexError(
                    err.invalid_index,
                    f"The index has to be between 0 and {self.num_channels - 1}."
                )
            err.raise_rpc_error(context=context)
コード例 #14
0
    def RunControlLoop(self, request, context: grpc.ServicerContext) \
            -> silaFW_pb2.CommandConfirmation:
        """
        Executes the observable command "Run Control Loop"
            Run the Control Loop

        :param request: gRPC request containing the parameters passed:
            request.EmptyParameter (Empty Parameter): An empty parameter data type used if no parameter is required.
        :param context: gRPC :class:`~grpc.ServicerContext` object providing gRPC-specific information

        :returns: A command confirmation object with the following information:
            commandId: A command id with which this observable command can be referenced in future calls
            lifetimeOfExecution: The (maximum) lifetime of this command call.
        """

        logging.debug("RunControlLoop called in {current_mode} mode".format(
            current_mode=('simulation' if self.simulation_mode else 'real')))

        try:
            controller: ControllerChannel = self._get_channel(
                context.invocation_metadata(), "Command")
            if controller.is_control_loop_enabled():
                raise SiLAFrameworkError(
                    error_type=SiLAFrameworkErrorType.
                    COMMAND_EXECUTION_NOT_ACCEPTED,
                    msg=
                    "There is a running control loop already. Cannot start a new loop!"
                )
            confirmation = self.implementation.RunControlLoop(
                request, controller, context)
            self.uuid_to_controller[
                confirmation.commandExecutionUUID.value] = controller
            return confirmation
        except (SiLAError, DecoratorInvalidChannelIndex) as err:
            if isinstance(err, DecoratorInvalidChannelIndex):
                err = InvalidChannelIndexError(
                    err.invalid_index,
                    f"The index has to be between 0 and {self.num_channels - 1}."
                )
            err.raise_rpc_error(context=context)
コード例 #15
0
    def RunControlLoop_Result(self, request, context: grpc.ServicerContext) \
            -> ControlLoopService_pb2.RunControlLoop_Responses:
        """
        Returns the final result of the command call :meth:`~.RunControlLoop`.

        :param request: A request object with the following properties
            CommandExecutionUUID: The UUID of the command executed.
        :param context: gRPC :class:`~grpc.ServicerContext` object providing gRPC-specific information

        :returns: The return object defined for the command with the following fields:
            EmptyResponse (Empty Response): An empty response data type used if no response is required.
        """

        logging.debug(
            "RunControlLoop_Result called in {current_mode} mode".format(
                current_mode=(
                    'simulation' if self.simulation_mode else 'real')))

        # Get the UUID of the command
        command_uuid = request.value

        try:
            if command_uuid not in self.uuid_to_controller:
                raise SiLAFrameworkError(
                    error_type=SiLAFrameworkErrorType.
                    INVALID_COMMAND_EXECUTION_UUID,
                    msg="There is no command execution with the given UUID!")
            controller = self.uuid_to_controller[command_uuid]
            del self.uuid_to_controller[command_uuid]
            return self.implementation.RunControlLoop_Result(
                request, controller, context)
        except (SiLAError, DecoratorInvalidChannelIndex) as err:
            if isinstance(err, DecoratorInvalidChannelIndex):
                err = InvalidChannelIndexError(
                    err.invalid_index,
                    f"The index has to be between 0 and {self.num_channels - 1}."
                )
            err.raise_rpc_error(context=context)