#!/usr/bin/env python3

import sys
import RPi.GPIO as GPIO
import time
from settings import UR, PUMP_CONFIG


class PumpInterface:
    """
    Stepper pump interface.
    """

    @staticmethod
    def _get_step_period(step_angle, max_frequency):
        step_freq = max_frequency * UR.turn / step_angle
        return 1 / step_freq

    def __init__(self, config):
        self.gpio_sleep = config['gpio_sleep']
        self.gpio_step = config['gpio_step']
        self.wake_up_time_s = config['wake_up_time'].m_as('s')
        self.steps_per_volume = config['steps_per_volume']
        self.microsteps = config['microsteps']
        self.step_period_s = self._get_step_period(
            step_angle=config['step_angle'], max_frequency=config['max_frequency']).m_as('s')

        GPIO.setmode(GPIO.BCM)

        GPIO.setup(self.gpio_sleep, GPIO.OUT)
        GPIO.setup(self.gpio_step, GPIO.OUT)

        GPIO.output(self.gpio_sleep, False)
        GPIO.output(self.gpio_step, False)

    def __del__(self):
        GPIO.cleanup()

    def step(self, count):
        GPIO.output(self.gpio_sleep, True)
        time.sleep(self.wake_up_time_s)

        for t in range(0, int(count * self.microsteps)):
            GPIO.output(self.gpio_step, True)
            time.sleep(0.5 * self.step_period_s / self.microsteps)
            GPIO.output(self.gpio_step, False)
            time.sleep(0.5 * self.step_period_s / self.microsteps)

        GPIO.output(self.gpio_sleep, False)

    def pump(self, volume):
        self.step(volume * self.steps_per_volume)


def main():
    volume_mL = float(sys.argv[1])
    p = PumpInterface(PUMP_CONFIG)
    p.pump(volume_mL * UR.mL)


if __name__ == '__main__':
    main()

#!/usr/bin/env python3

import sys
import RPi.GPIO as GPIO
import time
from settings import UR, PUMP_CONFIG


class PumpInterface:
    """
    Stepper pump interface.
    """

    @staticmethod
    def _get_step_period(step_angle, max_frequency):
        step_freq = max_frequency * UR.turn / step_angle
        return 1 / step_freq

    def __init__(self, config):
        self.gpio_sleep = config['gpio_sleep']
        self.gpio_step = config['gpio_step']
        self.wake_up_time_s = config['wake_up_time'].m_as('s')
        self.steps_per_volume = config['steps_per_volume']
        self.microsteps = config['microsteps']
        self.step_period_s = self._get_step_period(
            step_angle=config['step_angle'], max_frequency=config['max_frequency']).m_as('s')

        GPIO.setmode(GPIO.BCM)

        GPIO.setup(self.gpio_sleep, GPIO.OUT)
        GPIO.setup(self.gpio_step, GPIO.OUT)

        GPIO.output(self.gpio_sleep, False)
        GPIO.output(self.gpio_step, False)

    def __del__(self):
        GPIO.cleanup()

    @staticmethod
    def sleep(secs):
        start = time.monotonic()
        while secs > 0:
            end = time.monotonic()
            secs -= end - start
            start = end

    def step(self, count):
        GPIO.output(self.gpio_sleep, True)
        time.sleep(self.wake_up_time_s)

        delay_s = 0.5 * self.step_period_s / self.microsteps

        for t in range(0, int(count * self.microsteps)):
            GPIO.output(self.gpio_step, True)
            self.sleep(delay_s)
            GPIO.output(self.gpio_step, False)
            self.sleep(delay_s)

        GPIO.output(self.gpio_sleep, False)

    def pump(self, volume):
        self.step(volume * self.steps_per_volume)


def main():
    volume_mL = float(sys.argv[1])
    p = PumpInterface(PUMP_CONFIG)
    p.pump(volume_mL * UR.mL)


if __name__ == '__main__':
    main()

use time polling loop for precise timing