IvoryOS Demo

IvoryOS dynamically inspects functions from any Python script, rendering them as draggable method cards in the browser.

The source code below is the source script used to build this demo. Three instances "pump", "balance" and "sdl" are created in this script, and can be either called in Device tab, or used to build a workflow in Design tab.

⚠️ Note: Real-time progress tracking via SocketIO is currently not working.
Workflow will still work, results can be tracked via the Data tab.

Source Code

import logging
import time
from abc import ABC


class AbstractPump:

    def __init__(self, com_port: str):
        self.com_port = com_port
        self.logger = logging.getLogger("pump")

    def dose_liquid(self, amount_in_ml: float, rate_ml_per_minute: float = 1):
        """dose liquid"""
        self.logger.info(f"pretending dosing {amount_in_ml} at {rate_ml_per_minute} ml/min")
        return 1



class AbstractBalance:

    def __init__(self, com_port: str):
        self.com_port = com_port
        self._value = None
        self.logger = logging.getLogger("balance")

    @property
    def setter_value(self):
        return self._value

    @setter_value.setter
    def setter_value(self, value):
        self._value = value

    def weigh_sample(self):
        self.logger.info(f"Weighing sample using {self.com_port}")
        return 1

    def dose_solid(self, amount_in_mg: float):
        """this function is used to dose solid"""
        self.logger.info(f"Dosing {amount_in_mg} mg using {self.com_port}")
        return 1

    def _helper(self):
        """helper function will not be extracted and displayed over function panel"""
        pass


class AbstractSDL(ABC):
    def __init__(self, pump: AbstractPump, balance: AbstractBalance):
        self.pump = pump
        self.balance = balance
        self.logger = logging.getLogger(f"logger_name")

    def analyze(self):
        self.logger.info("analyze")
        return 1


    def dose_solid(self,
                   amount_in_mg: float = 5,
                   solid_name: str = "Acetaminophen"
                   ):
        """dose current chemical"""
        self.balance.dose_solid(amount_in_mg=amount_in_mg)
        self.balance.weigh_sample()
        self.logger.info(f"dosing solid {amount_in_mg} mg of {solid_name}")
        return 1

    def dose_solvent(self,
                     solvent_name: str = "Methanol",
                     amount_in_ml: float = 5,
                     rate_ml_per_minute: float = 1
                     ):
        self.logger.info(f"dosing {amount_in_ml} ml of {solvent_name} solvent at {rate_ml_per_minute} ml/min")
        return 1


    def equilibrate(self,
                    temp: float,
                    duration: float
                    ):
        self.logger.info(f"equilibrate at {temp} for {duration}")

    def simulate_error(self):
        raise ValueError("some error")

    def _send_command(self):
        """helper function"""
        pass



# initializing hardware
balance = AbstractBalance("Fake com port 1")
pump = AbstractPump("Fake com port 2")
sdl = AbstractSDL(pump, balance)


if __name__ == "__main__":
    import ivoryos
    ivoryos.run(__name__)