Hi @xykb86,
This is definitely possible, but requires a custom job or automation to do it.
First, the two chemostat Pioreactors will have the software available - it’s just the chemostat
automation, but with your sink tube from the waste pump going to the third Pioreactor.
On that third Pioreactor, you’ll need to create a custom dosing automation. There are probably a few ways to solve this, but here’s a simple solution. At high level, this automation updates it’s internal tracking of the liquid volume by listening to the other Pioreactor’s dosing events. In parallel, every 20 seconds, see if the current liquid volume > desired volume (probably the initial volume), and if so, remove waste to get back to desired volume.
This, on average, removes the added volume after 10 seconds, but it can be any duration between 0 and 20 seconds.
Put the following code in ~/.pioreactor/plugins/pioreactor_as_sink.py
:
# -*- coding: utf-8 -*-
from __future__ import annotations
from pioreactor.config import config
from pioreactor.automations.dosing.base import DosingAutomationJobContrib
from pioreactor.structs import DosingEvent
from msgspec.json import decode
__plugin_name__ = "pioreactor_as_sink"
__plugin_author__ = "Cam DP"
__plugin_summary__ = "This Pioreactors will be the sink for other Pioreactor's waste. This automation controls removing that waste."
class PioreactorAsSink(DosingAutomationJobContrib):
automation_name = "pioreactor_as_sink"
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.desired_volume = config.getfloat("bioreactor", "initial_volume_ml")
def _update_dosing_metrics(self, message) -> None:
dosing_event = decode(message.payload, type=DosingEvent)
self._update_liquid_volume(dosing_event)
def start_passive_listeners(self):
super().start_passive_listeners()
self.subscribe_and_callback(
self._update_dosing_metrics,
"pioreactor/+/+/dosing_events", # listen to any pioreactors dosing events and update.
)
def execute(self):
if self.liquid_volume > self.desired_volume:
self.execute_io_action(waste_ml=self.liquid_volume - self.desired_volume)
And put the following in ~/.pioreactor/plugins/ui/contrib/automations/dosing/pioreactor_as_sink.yaml
---
display_name: Pioreactor as Sink
automation_name: pioreactor_as_sink
description: This Pioreactors will be the sink for other Pioreactor's waste. This automation controls removing that waste.
fields:
- key: duration
default: 0.333
unit: min
label: Duration between checks
disabled: True
type: numeric