def _get_initialization_state(self) -> silaFW_pb2.ExecutionInfo:
        """
        Method to fill an ExecutionInfo message from the SiLA server for the InitializeContiflow observable command

        :return: An execution info object with the current command state
        """

        #: Enumeration of silaFW_pb2.ExecutionInfo.CommandStatus
        command_status = silaFW_pb2.ExecutionInfo.CommandStatus.waiting
        if self.pump.is_initializing() and not self.timer.is_expired():
            command_status = silaFW_pb2.ExecutionInfo.CommandStatus.running
        elif self.pump.is_initialized():
            command_status = silaFW_pb2.ExecutionInfo.CommandStatus.finishedSuccessfully
        else:
            command_status = silaFW_pb2.ExecutionInfo.CommandStatus.finishedWithError
        #: Duration silaFW_pb2.Duration(seconds=<seconds>, nanos=<nanos>)
        command_estimated_remaining = self.timer.get_msecs_to_expiration(
        ) / 1000

        return silaFW_pb2.ExecutionInfo(
            commandStatus=command_status,
            estimatedRemainingTime=silaFW_pb2.Duration(
                seconds=int(command_estimated_remaining)),
            updatedLifetimeOfExecution=silaFW_pb2.Duration(
                seconds=int(self.timer.period_ms / 1000)))
Exemplo n.º 2
0
    def InitializePumpDrive(self, request, context: grpc.ServicerContext) \
            -> silaFW_pb2.CommandConfirmation:
        """
        Executes the observable command "Initialize Pump Drive"
            Initialize the pump drive (e.g. by executing a reference move).

        :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.
        """

        if not self.system.state.is_operational():
            raise SystemNotOperationalError(
                'de.cetoni/pumps.syringepumps/PumpDriveControlService/v1/Command/InitializePumpDrive'
            )

        if self.calibration_uuid:
            raise InitializationNotFinishedError()

        self.pump.calibrate()

        self.calibration_uuid = str(uuid.uuid4())
        return silaFW_pb2.CommandConfirmation(
            commandExecutionUUID=silaFW_pb2.CommandExecutionUUID(
                value=self.calibration_uuid),
            lifetimeOfExecution=silaFW_pb2.Duration(
                seconds=self.CALIBRATION_TIMEOUT + 1))
    def InitializeContiflow(self, request, context: grpc.ServicerContext) \
            -> silaFW_pb2.CommandConfirmation:
        """
        Executes the observable command "Initialize Contiflow"
            Initialize the continuous flow pump.
            Call this command after all parameters have been set, to prepare the conti flow pump for the start of the continuous flow. The initialization procedure ensures, that the syringes are sufficiently filled to start the continuous flow. So calling this command may cause a syringe refill if the syringes are not sufficiently filled. So before calling this command you should ensure, that syringe refilling properly works an can be executed. If you have a certain syringe refill procedure, you can also manually refill the syringes with the normal syringe pump functions. If the syringes are sufficiently filled if you call this function, no refilling will take place.

        :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.
        """

        self.pump.initialize()
        self.timer.restart()

        # respond with UUID and lifetime of execution
        self.command_uuid = silaFW_pb2.CommandExecutionUUID(
            value=str(uuid.uuid4()))
        return silaFW_pb2.CommandConfirmation(
            commandExecutionUUID=self.command_uuid,
            lifetimeOfExecution=silaFW_pb2.Duration(
                seconds=int(self.timer.period_ms / 1000)))
Exemplo n.º 4
0
    def _wait_calibration_finished(self, timeout_sec):
        """
        The function waits until pump calibration has finished or
        until the timeout occurs.
        """

        if self.pump.is_calibration_finished():
            yield silaFW_pb2.ExecutionInfo(
                commandStatus=silaFW_pb2.ExecutionInfo.CommandStatus.
                finishedSuccessfully,
                progressInfo=silaFW_pb2.Real(value=1))
            return

        timer = qmixbus.PollingTimer(timeout_sec * 1000)
        message_timer = qmixbus.PollingTimer(period_ms=500)
        is_calibrating = False
        while not (is_calibrating or timer.is_expired()):
            time.sleep(0.1)
            timeout_sec -= 0.1
            if message_timer.is_expired():
                yield silaFW_pb2.ExecutionInfo(
                    commandStatus=silaFW_pb2.ExecutionInfo.CommandStatus.
                    running,
                    progressInfo=silaFW_pb2.Real(
                        value=(self.CALIBRATION_TIMEOUT - timeout_sec) /
                        self.CALIBRATION_TIMEOUT),
                    estimatedRemainingTime=silaFW_pb2.Duration(
                        seconds=int(timeout_sec)))
                message_timer.restart()
            is_calibrating = self.pump.is_calibration_finished()

        if not is_calibrating and not self.pump.is_in_fault_state():
            yield silaFW_pb2.ExecutionInfo(
                commandStatus=silaFW_pb2.ExecutionInfo.CommandStatus.
                finishedSuccessfully,
                progressInfo=silaFW_pb2.Real(value=1),
                estimatedRemainingTime=silaFW_pb2.Duration())
        else:
            yield silaFW_pb2.ExecutionInfo(
                commandStatus=silaFW_pb2.ExecutionInfo.CommandStatus.
                finishedWithError,
                progressInfo=silaFW_pb2.Real(value=1),
                estimatedRemainingTime=silaFW_pb2.Duration())
            logging.error("An unexpected error occurred: %s",
                          self.pump.read_last_error())
    def _wait_dosage_finished(self):
        """
        The function waits until the last dosage command has finished or
        until a timeout occurs. The timeout is estimated from the dosage's flow
        and target volume
        """

        if not self.pump.is_pumping():
            yield silaFW_pb2.ExecutionInfo(
                commandStatus=silaFW_pb2.ExecutionInfo.CommandStatus.finishedSuccessfully,
                progressInfo=silaFW_pb2.Real(value=1)
            )
            return

        target_volume = self.pump.get_target_volume()
        logging.debug("target volume: %f", target_volume)
        flow_in_sec = self.pump.get_flow_is() / self.pump.get_flow_unit().time_unitid.value
        if flow_in_sec == 0:
            # try again, maybe the pump didn't start pumping yet
            time.sleep(0.5)
            flow_in_sec = self.pump.get_flow_is() / self.pump.get_flow_unit().time_unitid.value
        if flow_in_sec == 0:
            yield silaFW_pb2.ExecutionInfo(
                commandStatus=silaFW_pb2.ExecutionInfo.CommandStatus.finishedWithError,
                progressInfo=silaFW_pb2.Real(value=1)
            )
            logging.error("The pump didn't start pumping. Last error: %s", self.pump.read_last_error())

        logging.debug("flow_in_sec: %f", flow_in_sec)
        dosing_time_s = self.pump.get_target_volume() / flow_in_sec + 2 # +2 sec buffer
        logging.debug("dosing_time_s: %fs", dosing_time_s)

        timer = qmixbus.PollingTimer(period_ms=dosing_time_s * 1000)
        message_timer = qmixbus.PollingTimer(period_ms=500)
        is_pumping = True
        while is_pumping and not timer.is_expired():
            time.sleep(0.1)
            dosing_time_s -= 0.1
            if message_timer.is_expired():
                logging.info("Fill level: %s", self.pump.get_fill_level())
                yield silaFW_pb2.ExecutionInfo(
                    commandStatus=silaFW_pb2.ExecutionInfo.CommandStatus.running,
                    progressInfo=silaFW_pb2.Real(value=self.pump.get_dosed_volume()/target_volume),
                    estimatedRemainingTime=silaFW_pb2.Duration(
                        seconds=int(dosing_time_s),
                        nanos=int(dosing_time_s-int(dosing_time_s)) * 1000000000
                    )
                )
                message_timer.restart()
            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,
                progressInfo=silaFW_pb2.Real(value=1),
                estimatedRemainingTime=silaFW_pb2.Duration()
            )
        else:
            yield silaFW_pb2.ExecutionInfo(
                commandStatus=silaFW_pb2.ExecutionInfo.CommandStatus.finishedWithError,
                progressInfo=silaFW_pb2.Real(value=1),
                estimatedRemainingTime=silaFW_pb2.Duration()
            )
            logging.error("An unexpected error occurred: %s", self.pump.read_last_error())