Here is the timing example modified for blowing and sucking actuating a syringe in a timed loop.

IMG_1645.MOV

I modified the Timing example to add suck and made it loop indefinitely.

// Programmable-Air
// Author: tinkrmind
// <https://github.com/orgs/Programmable-Air>
//
// Basic example of using Suck function of the Programmable-Air board.
// The neopixels show pressure. Cyan for low pressure and Purple for high pressure
// Brighter color means more extreme pressure. Bright cyan means lower pressure than dim cyan and brighter purple means higher pressure tham dim purple. At atmospheric presure,lights will be off.
//
// PCB v0.3/v0.4/v0.5

#include "programmable_air.h"

#define DEBUG 1
const unsigned long LOOP_DURATION = 300000;

void setup() {
  initializePins();
}

void loop() {
  if (readBtn(RED)) {
    unsigned long startTime = millis();
    
    while(millis - startTime > LOOP_DURATION){
    switchOnPump(2);
    blow(); // setValve(2, OPEN); setValve(1, CLOSED); setValve(3, CLOSED);
    delayWhileReadingPressure(2000);
    
    switchOnPump(1);
    suck(1);
    delayWhileReadingPressure(2000);
    }

  }
  else {
    switchOffPumps();
    vent();
    delayWhileReadingPressure(5000);
    }
    delayWhileReadingPressure(100);
  }

// Programmable-Air
// Author: tinkrmind
// <https://github.com/orgs/Programmable-Air>
//
// Basic example of using Suck function of the Programmable-Air board.
// The neopixels show pressure. Cyan for low pressure and Purple for high pressure
// Brighter color means more extreme pressure. Bright cyan means lower pressure than dim cyan and brighter purple means higher pressure tham dim purple. At atmospheric presure,lights will be off.
//
// PCB v0.3/v0.4/v0.5

#include "programmable_air.h"

#define DEBUG 1
const unsigned long LOOP_DURATION = 300000;

void setup() {
  initializePins();
}

void loop() {
  if (readBtn(RED)) {
    unsigned long startTime = millis();
    
    while(millis - startTime > LOOP_DURATION){
    switchOnPump(2);
    blow(); // setValve(2, OPEN); setValve(1, CLOSED); setValve(3, CLOSED);
    delayWhileReadingPressure(2000);
    
    switchOnPump(1);
    suck(1);
    delayWhileReadingPressure(2000);
    }

  }
  else {
    switchOffPumps();
    vent();
    delayWhileReadingPressure(5000);
    }
    delayWhileReadingPressure(100);
  }

IMG_1644.mov

This is code I edited with Claude to include tracking the button with a boolean so that I can run the breathing loop indefinitely and then just exit out when I wanted. I used claude because it was quicker to put the variable tracking in rather than me typing it. It did add button debounces but I am not sure if this board needs them.

#include "programmable_air.h"
#define DEBUG 1
const unsigned long LOOP_DURATION = 300000;
bool isRunning = false;

void setup() {
  initializePins();
}

void loop() {
  // Check if button is pressed (with simple debounce)
  if (readBtn(RED)) {
    delay(50);  // Simple debounce
    
    // Wait until button is released
    while (readBtn(RED)) {
      delay(10);
    }
    
    // Toggle the running state
    isRunning = !isRunning;
    
    // If we just turned it off, make sure to vent
    if (!isRunning) {
      switchOffPumps();
      vent();
    }
  }
  
  // Check if system should be running
  if (isRunning) {
    // Start the blow cycle
    switchOnPump(2);
    blow(); /
    
    // Check button during the blow delay
    unsigned long startTime = millis();
    while (millis() - startTime < 5000) {
      if (readBtn(RED)) {
        delay(50);  // Simple debounce
        while (readBtn(RED)) { delay(10); }  // Wait for release
        
        // Turn everything off and exit
        switchOffPumps();
        vent();
        isRunning = false;
        return;  // Exit the loop function immediately
      }
      delay(10);  // Small delay to prevent CPU hogging
    }
    
    // Only continue if still running
    if (isRunning) {
      switchOffPumps();
      vent();
      
      // Check button during the vent delay
      startTime = millis();
      while (millis() - startTime < 5000) {
        if (readBtn(RED)) {
          delay(50);  // Simple debounce
          while (readBtn(RED)) { delay(10); }  // Wait for release
          
          isRunning = false;
          return;  // Exit the loop function immediately
        }
        delay(10);  // Small delay to prevent CPU hogging
      }
    }
  }
  else {
    delayWhileReadingPressure(100);
  }
}