5.0 5. Build Guide
Step 1 — Set up the ESP32 and read one pressure sensor
What you need for this step
- 1 × ESP32 dev board
- 1 × pressure sensor
- jumper wires
- USB cable
- computer with Arduino IDE installed
Before you start
For this step, do not connect mains power. Only power the ESP32 through USB.
Step 1A — Install Arduino IDE and ESP32 support
- Install Arduino IDE
- Open Arduino IDE
- Go to File → Preferences
- Add this URL to Additional Boards Manager URLs:
https://dl.espressif.com/dl/package_esp32_index.json
- Go to Tools → Board → Boards Manager
- Search for ESP32
- Install the ESP32 board package
Step 1B — Connect the ESP32
- Plug the ESP32 into your computer with USB
- In Arduino IDE, go to Tools → Board and select the ESP32 board that matches your dev board
- Go to Tools → Port and choose the correct COM port
If no port appears:
- try another USB cable
- unplug and reconnect the board
- install the proper USB driver for your board, usually CP2102 or CH340
Step 1C — Wire the pressure sensor
| Pressure Sensor Pin | Connect To |
|---|---|
| VCC | 3.3V or 5V, depending on the sensor board requirements |
| GND | GND |
| OUT | GPIO34 |
Step 1D — Upload the test code
const int pressurePin = 34;
void setup() {
Serial.begin(115200);
}
void loop() {
int raw = analogRead(pressurePin);
Serial.println(raw);
delay(500);
}
Step 1E — View the sensor values
- Open Serial Monitor
- Set the baud rate to 115200
- Watch the values scroll
If it does not work
- check board and COM port selection
- check sensor ground
- check the output pin wiring
- check that the sensor is powered correctly
Step 2 — Wire and test one valve with one MOSFET
What you need for this step
- ESP32 from Step 1
- 1 × 12V normally closed valve
- 1 × IRLZ44N MOSFET
- 1 × 220Ω resistor
- 1 × 10kΩ resistor
- 1 × 1N4007 diode
- 12V power supply for the valve
- jumper wires / perfboard
For this step, still do not connect mains power. This step uses only the low-voltage DC side.
What each part does
- Valve: opens or closes airflow
- MOSFET: lets the ESP32 control a 12V load
- 220Ω resistor: protects and stabilizes the gate drive
- 10kΩ resistor: keeps the MOSFET off when the ESP32 pin is floating
- 1N4007 diode: suppresses the voltage spike from the valve coil when it turns off
Wire the MOSFET and valve
ESP32 GPIO18 -> 220Ω resistor -> MOSFET Gate MOSFET Gate -> 10kΩ resistor -> GND Valve + -> +12V Valve - -> MOSFET Drain MOSFET Source -> GND Flyback diode across valve: Diode stripe (cathode) -> +12V Other side (anode) -> Valve - / MOSFET Drain
Make sure grounds are shared
The ESP32 ground and the 12V supply ground must be connected together. If they are not shared, the ESP32 signal will not control the MOSFET correctly.
Upload the valve test code
const int valvePin = 18;
void setup() {
pinMode(valvePin, OUTPUT);
Serial.begin(115200);
}
void loop() {
Serial.println("Valve ON");
digitalWrite(valvePin, HIGH);
delay(3000);
Serial.println("Valve OFF");
digitalWrite(valvePin, LOW);
delay(3000);
}
Test the valve
- Apply 12V power
- Open Serial Monitor
- Listen for the valve clicking every 3 seconds
- Feel for airflow if tubing is attached
Common mistakes
- diode reversed
- MOSFET source and drain swapped
- no shared ground
- missing 10k pulldown, causing the valve to stay on or behave randomly
Step 3 — Wire and test the relay and pump
What you need for this step
- ESP32
- relay module or relay + driver stage
- pump
- fused AC input
- insulated terminals
- power supply
- enclosure or safe temporary test arrangement
Before doing anything:
- unplug AC power
- use insulated connectors
- do not leave exposed AC terminals where they can be touched
- if you are not confident with mains wiring, have someone experienced inspect your work before powering it
Wire the relay control side
| Relay Control Pin | Connect To |
|---|---|
| IN | GPIO23 |
| VCC | appropriate relay control voltage |
| GND | GND |
If using a bare relay instead of a module, use a transistor or MOSFET driver and a flyback diode on the coil.
Wire the AC side
AC LIVE -> Fuse -> Relay COM Relay NO -> Pump LIVE AC NEUTRAL -> Pump NEUTRAL AC GROUND -> Pump chassis
If the same AC input also powers the Mean Well PSU, wire it in parallel after the fused input:
AC LIVE -> Fuse -> Split
-> Relay COM -> Relay NO -> Pump LIVE
-> PSU L
AC NEUTRAL -> Split
-> Pump NEUTRAL
-> PSU N
AC GROUND -> Split
-> Pump chassis
-> PSU ground
Upload the relay test code
const int relayPin = 23;
void setup() {
pinMode(relayPin, OUTPUT);
Serial.begin(115200);
}
void loop() {
Serial.println("Pump ON");
digitalWrite(relayPin, HIGH);
delay(5000);
Serial.println("Pump OFF");
digitalWrite(relayPin, LOW);
delay(5000);
}
Test carefully
- Power the low-voltage side first
- Verify the relay clicks
- Then power the AC side
- Confirm the pump turns on and off with the relay
Step 4 — Build single-zone closed-loop pressure control
What you need for this step
- 1 pressure sensor
- 1 fill valve
- 1 vent valve
- 1 relay-controlled pump
- tubing connected to a test air chamber or mattress zone
Step 4A — Define the first variables
You need:
pressuretargetdeadbandstate
float pressure = 0.0; float target = 500.0; float deadband = 20.0;
Step 4B — Read and filter the pressure
float filteredPressure = 0.0;
float readPressure() {
int raw = analogRead(34);
filteredPressure = 0.9 * filteredPressure + 0.1 * raw;
return filteredPressure;
}
This reduces sensor noise and small fluctuations.
Step 4C — Add fill and vent control functions
const int fillValvePin = 18;
const int ventValvePin = 19;
const int relayPin = 23;
void startFill() {
digitalWrite(relayPin, HIGH);
digitalWrite(fillValvePin, HIGH);
digitalWrite(ventValvePin, LOW);
}
void startVent() {
digitalWrite(relayPin, LOW);
digitalWrite(fillValvePin, LOW);
digitalWrite(ventValvePin, HIGH);
}
void stopAll() {
digitalWrite(relayPin, LOW);
digitalWrite(fillValvePin, LOW);
digitalWrite(ventValvePin, LOW);
}
Step 4D — Add basic control logic
void loop() {
float pressure = readPressure();
Serial.println(pressure);
if (pressure < target - deadband) {
startFill();
}
else if (pressure > target + deadband) {
startVent();
}
else {
stopAll();
}
delay(100);
}
Deadband creates a no-action zone around the target pressure so the system does not constantly toggle valves when it is already close enough.
Step 4E — Test the behavior
- Run the code
- Watch pressure in Serial Monitor
- Confirm:
- below target → fill starts
- above target → vent starts
- within deadband → everything stops
Step 5 — Add predictive control and tune it
Why this is needed
When a valve closes, airflow does not stop instantly. Pressure may keep changing briefly, so stopping exactly at the target can still overshoot.
Step 5A — Track rate of change
float previousPressure = 0.0;
unsigned long previousTime = 0;
float computeDpDt(float pressure) {
unsigned long now = millis();
float dt = (now - previousTime) / 1000.0;
float dpdt = 0.0;
if (dt > 0) {
dpdt = (pressure - previousPressure) / dt;
}
previousPressure = pressure;
previousTime = now;
return dpdt;
}
Step 5B — Use the trend to stop a little early
Start simple:
- if filling fast, stop slightly before the target
- if venting fast, stop slightly before the target in the opposite direction
This can begin as a fixed margin before becoming adaptive.
Step 5C — Add auto-tuning concept
Over repeated fills and vents, record:
- pressure at valve close
- final settled pressure
- overshoot or undershoot amount
Then slowly adjust the stopping margin based on real behavior.
What to tune
- deadband
- sample interval
- stop margin
- settle time
- transient thresholds
Step 6 — Expand to dual-zone operation
What you add
- second pressure sensor
- second fill valve
- second vent valve
- second tee node
- second zone logic
Example GPIO expansion
| Function | GPIO |
|---|---|
| Left Fill | 18 |
| Left Vent | 19 |
| Right Fill | 21 |
| Right Vent | 22 |
| Relay | 23 |
| Sensor Left | 34 |
| Sensor Right | 35 |
How to proceed
- Keep the left-zone code working
- Duplicate the sensor read path for the right zone
- Duplicate the fill/vent logic for the right zone
- Keep targets, deadbands, and state variables separate per zone
- Coordinate the shared pump so only the required fill action is active
Important rule: Do not share pressure readings between zones. Each zone must keep its own independent control state.