Errors for custom dosing programs

I am trying to implement additional pumps to the Pioreactor using an external motor driver. I have had success with controlling a third pump using separate test programs and through the command line, but am encountering errors when implementing it through custom automations following the Pioreactor docs.

I am using the Adafruit DC & Stepper Motor HAT and have it mounted to an RPi 3A+. The Pioreactor HAT sits on top of that.

For now I simply want to test the functionality of the third pump and Motor HAT by semi-recreating the fed-batch and chemostat automations. In both of which, I am replacing the default media pump on PWM 2 of the Pioreactor HAT with M1 on the Motor HAT. I have both automations successfully showing up in the UI so the .yaml files have no issues and I believe it is only the Python files. Below are the Python programs I’ve written utilizing the external pump instead of the built-in media pump.

three_pumps.py

# -*- coding: utf-8 -*-
# Exchange X mL every period
import time

from adafruit_motorkit import MotorKit
from pioreactor.automations import events
from pioreactor.automations.dosing.base import DosingAutomationJobContrib


class ThreePumps(DosingAutomationJobContrib):
    automation_name = "three_pumps"
    published_settings = {
        "exchange_volume_ml": {"datatype": "float", "settable": True, "unit": "mL"},
    }

    def __init__(self, exchange_volume_ml, **kwargs):
        super().__init__(**kwargs)
        
        # Initialize Motor HAT
        self.kit = MotorKit(address=0x60) # TODO: Check I2C address

        self.exchange_volume_ml = float(exchange_volume_ml)

    def add_third_media_to_bioreactor(self, ml: float, unit: str, experiment: str, source_of_event: str, mqtt_client) -> float:
        seconds_per_ml = 3.0  # TODO: Calibration
        duration = ml * seconds_per_ml

        self.kit.motor1.throttle = 1.0
        time.sleep(duration)
        self.kit.motor1.throttle = 0.0

        self.logger.info(f"Pumped {ml}")

        return ml

    def execute(self) -> None:
        results = self.execute_io_action(third_media_ml=self.exchange_volume_ml, waste_ml=self.exchange_volume_ml)

        return

This chemostat-style automation starts and runs when starting from the UI, but I encounter the following error everytime the pump is supposed to run: ThreePumps.add_third_media_to_bioreactor() got an unexpected keyword argument 'logger'.

fed_batch_ext.py

# -*- coding: utf-8 -*-
# Add X mL every period
import time

from adafruit_motorkit import MotorKit
from pioreactor.automations import events
from pioreactor.automations.dosing.base import DosingAutomationJobContrib


class FedBatchExt(DosingAutomationJobContrib):
    automation_name = "fed_batch_ext"
    published_settings = {
        "dosing_volume_ml": {"datatype": "float", "unit": "mL", "settable": True},
    }

    def __init__(self, dosing_volume_ml, **kwargs) -> None:
        super().__init__(**kwargs)

        # Initialize Motor HAT
        self.kit = MotorKit(address=0x60) # TODO: Check I2C address

        self.logger.warning("When using the fed-batch automation, no liquid is removed. Carefully monitor the level of liquid to avoid overflow!")

        self.dosing_volume_ml = float(dosing_volume_ml)

    def add_third_media_to_bioreactor(self, ml: float, unit: str, experiment: str, source_of_event: str, mqtt_client) -> float:
        seconds_per_ml = 3.0  # TODO: Calibration
        duration = ml * seconds_per_ml

        self.kit.motor1.throttle = 1.0
        time.sleep(duration)
        self.kit.motor1.throttle = 0.0
        return ml

    def execute(self):
        vol = self.add_third_media_to_bioreactor(ml=self.dosing_volume_ml, unit=self.unit, experiment=self.experiment, source_of_event=f"{self.job_name}:{self.automation_name}")
        if vol != self.dosing_volume_ml:
            self.logger.warning("Under-dosed!")

        return events.AddMediaEvent(f"Added {vol} mL")

With this automation to mimic a fed-batch operation except using an external pump, I get this error: FedBatchExt.add_third_media_to_bioreactor() missing 1 required positional argument: 'mqtt_client'

The error codes are pretty self explanatory in that there are unexpected/missing arguments, but I am confused on why. For the first program I am not passing logger so I am unsure why it is getting a logger argument. Similarly for the second program I am unsure why it is saying mqtt_client is missing when it is being passed as an argument in the functions.

Thank you for any assistance you can provide!

Hi @awong787,

I think our docs are out of date - sorry about this. Use the following for both custom automations:

    def add_third_media_to_bioreactor(self, ml: float, unit: str, experiment: str, source_of_event: str, mqtt_client, logger) -> float:

In the second case, where you call the add_third_media_to_bioreactor directly (instead of implicitly with execute_io_action), use:

        vol = self.add_third_media_to_bioreactor(ml=self.dosing_volume_ml, unit=self.unit, experiment=self.experiment, source_of_event=f"{self.job_name}:{self.automation_name}", logger=self.logger, mqtt_client=self.pub_client)

Thank you for the fixes! Those solved my issues.