Community project

Automated Roti Pressing and Cooking

polas

Published August 16, 2026

ESP32
Photo of Automated Roti Pressing and CookingGenerated with AI

This guide builds an automated roti press that handles dough feeding, pressing, cooking, and ejection with precise temperature control. The system uses an ESP32 microcontroller to orchestrate multiple 24 V motors, monitor press position and dough presence, and maintain the heated press plate at the correct cooking temperature using a thermocouple sensor and solid-state relay.

Builders will receive a complete wiring diagram, parts list with sourcing guidance, safety-critical firmware with state machine control, and step-by-step assembly instructions covering food-contact fabrication, thermal protection integration, mains enclosure construction, and safe commissioning procedures before production use.

Wiring diagram

Interactive · read-only
Wiring diagram for Automated Roti Pressing and Cooking

Pan and zoom to explore the wiring. Remix the project to edit it in your own workspace.

Parts list

Bill of materials
ComponentQtyNotes
MAX31855 Thermocouple AmplifierMAX318551Cold-junction compensated K-type thermocouple-to-digital converter with SPI interface. Reads thermocouple temperatures up to +1350°C and performs on-chip cold-junction compensation. 3.3V compatible on the Adafruit breakout (includes onboard 3.3V regulator and level shifting). 14-bit thermocouple resolution (~0.25°C). Read-only SPI (SCK, CS, SO); no MOSI needed.
Grounded K-type thermocouple probe0–300 °C1Food-appliance-rated K-type probe mounted in a drilled blind hole near the lower cooking surface; never contacts dough.
20 cm heated non-stick press plate assembly230 VAC, 1200 W total1Fabricated upper and lower 200 mm food-contact cooking plates, each with 230 VAC heater. Specify PFOA-free food-contact non-stick coating, 1200 W total, 230 VAC, and a bonded protective-earth stud.
Zero-cross AC solid-state relay25 A minimum, zero-cross1Genuine DIN/heatsink-mounted 3–32 VDC-input, 24–280 VAC-output zero-cross SSR, rated at least 25 A; sized with an aluminium heatsink. Drives the heater only.
24 V DC press linear actuator with limit switches24 V, force set by fabricator1Fabricator-selected 24 V DC linear actuator and guided linkage that provides controlled closing force; includes normally-closed end-limit switches mechanically set for open and 2 mm finished roti thickness.
24 V dough-ball feeder gear motor24 V DC geared motor1Low-speed 24 V DC geared motor that indexes one pre-portioned dough ball from a covered hopper into the open press; use food-safe removable hopper and chute.
24 V cooked-roti ejector gear motor24 V DC geared motor1Low-speed 24 V DC geared motor operating a food-safe silicone-edged pusher to move a cooked roti to the collection tray after the press has opened.
24 V brushed-DC motor driver24 V H-bridge1Opto-isolated, 3.3 V logic-compatible H-bridge motor driver for the press actuator; choose a genuine driver with continuous-current rating above measured actuator stall current.
24 V brushed-DC motor driver24 V H-bridge13.3 V logic-compatible H-bridge driver for the dough feeder motor.
24 V brushed-DC motor driver24 V H-bridge13.3 V logic-compatible H-bridge driver for the cooked-roti ejector motor.
2-pole mains safety contactor and thermal safety chain230 VAC, ≥16 A, 2-pole1DIN-mounted 2-pole contactor whose coil is fed through a manual-reset 300 °C thermal cutoff and normally-closed emergency-stop contact; it removes live and neutral from the heater circuit. Fabricator/electrician must size it for the heater current.
Enclosed isolated 24 V DC power supply24 V, 10 A minimum1Certified enclosed 230 VAC to 24 VDC supply for all motors; select ≥10 A after actuator and motor stall-current measurement. Protective earth case where required.
Isolated 5 V DC power supply5 V, 1 A minimum1Certified isolated 230 VAC to 5 VDC supply for the ESP32 via its 5 V/VIN pin; 1 A minimum.
Start button and guarded safety-input module24 V field / 3.3 V logic124 V industrial input module with opto-isolated 3.3 V outputs: start pushbutton, door/guard switch, dough-present sensor, and normally-closed emergency-stop feedback. Its separate hard-wired safety-chain contact is in series with the contactor coil; the E-stop also directly breaks that coil circuit.
Fused 230 V IEC inlet with protective earth230 VAC, fused1Qualified appliance inlet with appropriately rated fuse, double-pole switch, strain relief, and protective-earth conductor. Fabricator must use Indian 230 VAC rated parts.
MCP23017 isolated digital-input expanderI2C address 0x201MCP23017 3.3 V I2C GPIO expander receiving opto-isolated start, guard, dough, E-stop feedback, and press limit outputs. Use its internal input pull-ups or verified external pull-ups.
3.3 V opto-isolated SSR input driver3.3 V logic / SSR input1DIN-mounted 3.3 V logic optocoupler/transistor output module that switches the SSR DC input. Verify it sources/sinks the chosen SSR input current; the ESP32 only drives this module input.
Dual-channel 3.3 V opto-isolated motor-command interface2-channel, 3.3 V logic1Two-channel industrial opto-isolated interface. Accepts ESP32 3.3 V PWM/DIR inputs and provides compatible isolated command outputs for the 24 V press motor driver; no 24 V signal reaches ESP32 GPIO.
Dual-channel 3.3 V opto-isolated motor-command interface2-channel, 3.3 V logic1Two-channel industrial opto-isolated interface for the feeder motor driver; no 24 V signal reaches ESP32 GPIO.
Dual-channel 3.3 V opto-isolated motor-command interface2-channel, 3.3 V logic1Two-channel industrial opto-isolated interface for the ejector motor driver; no 24 V signal reaches ESP32 GPIO.
Fused 24 V DC distribution terminal block24 V fused DIN terminal block1Finger-safe DIN terminal/fuse block distributing the isolated 24 V supply to the three motor drivers and safety-input module. Fit branch fuses based on measured loads.

Assembly

6 steps
  1. Fabricate the food-contact press and hopper

    Have the qualified fabricator make two flat, parallel 200 mm cooking faces with a certified PFOA-free food-contact non-stick coating. Use a guided upper plate so it cannot tilt, set a fixed mechanical closing stop for about 2 mm roti thickness, and provide a removable covered food-safe hopper/chute that releases only one pre-portioned dough ball at a time. Use a food-safe silicone-edged ejector and removable collection tray.

    • Tip: Target dough balls of roughly 35–45 g; final diameter, thickness, and cooking time must be tuned with the actual flour hydration.
    • Tip: Make every food-contact part removable for washing; keep motors, grease, bearings, and wiring outside the food zone.
    • Tip: Do not use loose flour dust as the anti-stick method inside the machine; specify the coating and a repeatable low-stick dough recipe instead.
    • Do not use damaged, scratched, unknown, or unverified non-stick coating.
    • The guide frame must prevent finger access to the closing gap; use a guard/interlock designed by the fabricator.
  2. Fit heaters, sensing, and independent thermal protection

    Mount the plate heaters as specified by the fabricator. Install the K-type probe in a blind hole close to the lower cooking surface, using thermal compound compatible with its temperature rating; it must not enter the food area. Fit a manual-reset 300 °C thermal cutoff directly on the hottest credible plate/heater location, in series with the contactor coil.

    • Tip: Use a second independent temperature measurement during commissioning to calibrate the 225 °C firmware setpoint to actual plate temperature.
    • Tip: Route thermocouple wire away from mains and motor wires; use a proper thermocouple extension connector where needed.
    • The thermal cutoff and emergency stop must be hard-wired; they are not firmware-controlled.
    • A qualified appliance electrician must choose the cutoff temperature and placement after measuring worst-case heater temperatures.
  3. Build the earthed mains enclosure

    A qualified appliance electrician must mount the fused IEC inlet, 2-pole safety contactor, SSR on its required heatsink, and both enclosed isolated power supplies in a metal, earthed, finger-safe enclosure. Bond protective earth continuously from the inlet to the metal chassis and both heated plates. Keep 230 VAC wiring physically segregated from the 24 V and 3.3 V control wiring.

    • Tip: For 1200 W at 230 VAC, heater current is about 5.2 A; electrician must select approved wire, fuse, terminals, contactor and enclosure ratings with margin.
    • Tip: Mount the SSR on a correctly sized aluminium heatsink and provide ventilation; verify its case temperature during a sustained heating run.
    • Tip: Use strain relief at the mains inlet and cover all live terminals.
    • 230 VAC can kill or start a fire. Do not build, test, or service the mains section while energized unless you are qualified to do so.
    • Never rely on the SSR as the sole means of removing mains power: the 2-pole contactor and thermal/E-stop safety chain are mandatory.
  4. Install 24 V motion hardware and guarded inputs

    Wire the 24 V supply to the three motor drivers and isolated safety-input module. Connect each motor to its dedicated driver. Fit normally-closed open and close limit switches mechanically on the press motion, then route their isolated outputs to input-expander pins GPA4 and GPA5. Install the guard, start button, dough-present sensor, and emergency stop through the isolated input module; its separate normally-closed safety contact must be in series with the contactor coil.

    • Tip: Measure each motor's real stall current and replace the provisional 24 V supply/driver ratings if needed before regular use.
    • Tip: Verify physically that pressing E-stop removes contactor coil power and heater supply even with the ESP32 unplugged.
    • Tip: Set the dough sensor so it detects the ball seated in the feed pocket, not dough higher in the hopper.
    • Keep the mechanism de-energized while setting limit switches.
    • The press must stop mechanically at the calibrated thickness even if a limit switch fails.
  5. Connect the low-voltage controller

    Power the ESP32 from the isolated 5 V supply. Wire MAX31855 to ESP32 GPIO 18 (SCK), GPIO 19 (SO), and GPIO 23 (CS). Wire the MCP23017 expander to GPIO 21 (SDA) and GPIO 22 (SCL). Connect motor commands: press PWM/DIR to GPIO 26/27, feeder PWM/DIR to GPIO 32/33, ejector PWM/DIR to GPIO 13/14. GPIO 25 drives only the opto-isolated SSR-input driver.

    • Tip: Check the selected motor-driver modules accept 3.3 V PWM/DIR signals before installation.
    • Tip: Use ferrules, labelled terminal blocks, and separate cable ducts for mains, motor, and sensor wiring.
    • Tip: Do a low-voltage-only test first: unplug the heater mains feed and confirm directions and every sensor/limit state.
    • Do not connect 24 V or 5 V directly to ESP32 GPIO pins.
    • Do not power the ESP32 from a motor-driver logic pin.
  6. Commission safely before making food

    With an electrician present, verify protective-earth continuity, insulation, fuse operation, E-stop contactor dropout, guard fault behavior, thermal-cutoff dropout, limit-switch behavior, and SSR heatsink temperature. Then use the Deploy button in Schematik to load the controller. Make dry runs without dough, followed by supervised test batches, tuning feeder duration and cook duration until a 20 cm roti cooks evenly and ejects cleanly.

    • Tip: Start with the provided 225 °C / 28 s settings; adjust in small increments after measuring actual plate temperature and evaluating real rotis.
    • Tip: Keep a physical fire extinguisher appropriate for electrical equipment nearby during commissioning.
    • Tip: Clean the plates only when cool, using non-abrasive tools approved for the coating.
    • Never bypass the guard, E-stop, thermal cutoff, contactor, or earth bond for testing.
    • Stop immediately if temperature overshoots, the plate sticks, the press stalls, or an SSR/terminal becomes unusually hot.

Pin assignments

Board wiring reference
PinConnectionType
3V3thermocouple_interface VCCpower
GNDthermocouple_interface GNDground
GPIO 18thermocouple_interface SCKspi
GPIO 19thermocouple_interface SOspi
EXTthermocouple_interface T+Grounded K-type thermocouple probe K+analog
EXTthermocouple_interface T-Grounded K-type thermocouple probe K-analog
GNDheater_ssr IN-ground
EXTheater_ssr AC_OUT_L20 cm heated non-stick press plate assembly HEATER_Lpower
EXTheated_press HEATER_N2-pole mains safety contactor and thermal safety chain SAFE_OUT_Npower
EXTheated_press PEFused 230 V IEC inlet with protective earth PEground
EXTpress_driver M+24 V DC press linear actuator with limit switches M+power
EXTpress_driver M-24 V DC press linear actuator with limit switches M-power
EXTfeeder_driver M+24 V dough-ball feeder gear motor M+power
EXTfeeder_driver M-24 V dough-ball feeder gear motor M-power
EXTejector_driver M+24 V cooked-roti ejector gear motor M+power
EXTejector_driver M-24 V cooked-roti ejector gear motor M-power
EXTmains_inlet L2-pole mains safety contactor and thermal safety chain MAINS_IN_Lpower
EXTmains_inlet N2-pole mains safety contactor and thermal safety chain MAINS_IN_Npower
EXTmains_safety_contactor SAFE_OUT_LZero-cross AC solid-state relay AC_IN_Lpower
EXTmains_safety_contactor COIL_Nprotected mains neutralpower
5Vpsu_5v V+power
GNDpsu_5v V-ground
3V3input_expander VCCpower
GNDinput_expander GNDground
GPIO 21input_expander SDAi2c
GPIO 22input_expander SCLi2c
EXTsafety_inputs START_OUTMCP23017 isolated digital-input expander GPA0digital
EXTsafety_inputs GUARD_OK_OUTMCP23017 isolated digital-input expander GPA1digital
EXTsafety_inputs DOUGH_OUTMCP23017 isolated digital-input expander GPA2digital
EXTsafety_inputs ESTOP_OK_OUTMCP23017 isolated digital-input expander GPA3digital
EXTpress_actuator OPEN_LIMITMCP23017 isolated digital-input expander GPA4digital
EXTpress_actuator CLOSE_LIMITMCP23017 isolated digital-input expander GPA5digital
EXTmains_safety_contactor COIL_LStart button and guarded safety-input module SAFETY_CHAINpower
GPIO 23thermocouple_interface CSspi
3V3heater_ssr_driver VCCpower
GNDheater_ssr_driver GNDground
GPIO 25heater_ssr_driver INdigital
EXTheater_ssr_driver OUT+Zero-cross AC solid-state relay IN+power
EXTheater_ssr_driver OUT-Zero-cross AC solid-state relay IN-ground
EXTpsu_24v AC_LFused 230 V IEC inlet with protective earth Lpower
EXTpsu_24v AC_NFused 230 V IEC inlet with protective earth Npower
EXTpsu_5v AC_LFused 230 V IEC inlet with protective earth Lpower
EXTpsu_5v AC_NFused 230 V IEC inlet with protective earth Npower
3V3press_logic_isolator VCCpower
GNDpress_logic_isolator GNDground
GPIO 26press_logic_isolator IN1digital
GPIO 27press_logic_isolator IN2digital
EXTpress_logic_isolator OUT124 V brushed-DC motor driver PWMdigital
EXTpress_logic_isolator OUT224 V brushed-DC motor driver DIRdigital
3V3feeder_logic_isolator VCCpower
GNDfeeder_logic_isolator GNDground
GPIO 32feeder_logic_isolator IN1digital
GPIO 33feeder_logic_isolator IN2digital
EXTfeeder_logic_isolator OUT124 V brushed-DC motor driver PWMdigital
EXTfeeder_logic_isolator OUT224 V brushed-DC motor driver DIRdigital
3V3ejector_logic_isolator VCCpower
GNDejector_logic_isolator GNDground
GPIO 13ejector_logic_isolator IN1digital
GPIO 14ejector_logic_isolator IN2digital
EXTejector_logic_isolator OUT124 V brushed-DC motor driver PWMdigital
EXTejector_logic_isolator OUT224 V brushed-DC motor driver DIRdigital
EXTpsu_24v V+Fused 24 V DC distribution terminal block IN+power
EXTpsu_24v V-Fused 24 V DC distribution terminal block IN-ground
EXTpress_driver VM+Fused 24 V DC distribution terminal block OUT1+power
EXTpress_driver VM-Fused 24 V DC distribution terminal block OUT1-ground
EXTfeeder_driver VM+Fused 24 V DC distribution terminal block OUT2+power
EXTfeeder_driver VM-Fused 24 V DC distribution terminal block OUT2-ground
EXTejector_driver VM+Fused 24 V DC distribution terminal block OUT3+power
EXTejector_driver VM-Fused 24 V DC distribution terminal block OUT3-ground
EXTsafety_inputs V24Fused 24 V DC distribution terminal block OUT4+power
EXTsafety_inputs GNDFused 24 V DC distribution terminal block OUT4-ground

Firmware

ESP32
main.cppDeploy to device
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_MAX31855.h>
#include <Adafruit_MCP23X17.h>

// ESP32 wiring. PWM/DIR outputs pass through opto-isolated interfaces before the motor drivers.

enum class State : uint8_t { WARMING, IDLE, FEEDING, CLOSING, COOKING, OPENING, EJECTING, FAULT };


// Forward declarations
bool inputHealthy(uint8_t pin);
bool guardOk();
bool eStopOk();
bool pressIsOpen();
bool pressIsClosed();
bool doughPresent();
void driveMotor(int pwmPin, int dirPin, bool forward, bool enabled);
void stopAllMotors();
void setHeater(bool enabled);
void enterState(State next);
void enterFault();
void controlHeater(float temperatureC);
bool startPressed();

constexpr int THERMO_SCK = 18;
constexpr int THERMO_CS = 23;
constexpr int THERMO_SO = 19;
constexpr int HEATER_ENABLE_PIN = 25;
constexpr int PRESS_PWM_PIN = 26;
constexpr int PRESS_DIR_PIN = 27;
constexpr int FEED_PWM_PIN = 32;
constexpr int FEED_DIR_PIN = 33;
constexpr int EJECT_PWM_PIN = 13;
constexpr int EJECT_DIR_PIN = 14;
constexpr int I2C_SDA_PIN = 21;
constexpr int I2C_SCL_PIN = 22;

// MCP23017 pins are active LOW because the isolated field-input outputs pull down.
constexpr uint8_t START_INPUT = 0;
constexpr uint8_t GUARD_OK_INPUT = 1;
constexpr uint8_t DOUGH_PRESENT_INPUT = 2;
constexpr uint8_t ESTOP_OK_INPUT = 3;
constexpr uint8_t PRESS_OPEN_INPUT = 4;
constexpr uint8_t PRESS_CLOSED_INPUT = 5;

constexpr float SETPOINT_C = 225.0F;
constexpr float HEATER_HYSTERESIS_C = 5.0F;
constexpr float MAX_SAFE_TEMP_C = 280.0F;
constexpr unsigned long WARMUP_TIMEOUT_MS = 8UL * 60UL * 1000UL;
constexpr unsigned long FEED_TIME_MS = 1300UL;      // Fabricator tunes for exactly one 35-45 g ball.
constexpr unsigned long PRESS_TIMEOUT_MS = 7000UL;
constexpr unsigned long COOK_TIME_MS = 28000UL;     // Tune with flour hydration and target browning.
constexpr unsigned long EJECT_TIME_MS = 2200UL;
constexpr unsigned long START_DEBOUNCE_MS = 80UL;

Adafruit_MAX31855 thermocouple(THERMO_SCK, THERMO_CS, THERMO_SO);
Adafruit_MCP23X17 inputs;


State state = State::WARMING;
unsigned long stateStartedAt = 0;
unsigned long lastStartEdgeAt = 0;
bool heaterOn = false;

bool inputHealthy(uint8_t pin) {
  return inputs.digitalRead(pin) == LOW;
}

bool guardOk() { return inputHealthy(GUARD_OK_INPUT); }
bool eStopOk() { return inputHealthy(ESTOP_OK_INPUT); }
bool pressIsOpen() { return inputHealthy(PRESS_OPEN_INPUT); }
bool pressIsClosed() { return inputHealthy(PRESS_CLOSED_INPUT); }
bool doughPresent() { return inputHealthy(DOUGH_PRESENT_INPUT); }

void driveMotor(int pwmPin, int dirPin, bool forward, bool enabled) {
  digitalWrite(dirPin, forward ? HIGH : LOW);
  digitalWrite(pwmPin, enabled ? HIGH : LOW);
}

void stopAllMotors() {
  digitalWrite(PRESS_PWM_PIN, LOW);
  digitalWrite(FEED_PWM_PIN, LOW);
  digitalWrite(EJECT_PWM_PIN, LOW);
}

void setHeater(bool enabled) {
  heaterOn = enabled;
  digitalWrite(HEATER_ENABLE_PIN, enabled ? HIGH : LOW);
}

void enterState(State next) {
  stopAllMotors();
  state = next;
  stateStartedAt = millis();
}

void enterFault() {
  setHeater(false);
  stopAllMotors();
  state = State::FAULT;
  stateStartedAt = millis();
}

void controlHeater(float temperatureC) {
  if (isnan(temperatureC) || temperatureC > MAX_SAFE_TEMP_C || !eStopOk()) {
    enterFault();
    return;
  }
  if (temperatureC <= SETPOINT_C - HEATER_HYSTERESIS_C) {
    setHeater(true);
  } else if (temperatureC >= SETPOINT_C + HEATER_HYSTERESIS_C) {
    setHeater(false);
  }
}

bool startPressed() {
  if (!inputHealthy(START_INPUT)) return false;
  const unsigned long now = millis();
  if (now - lastStartEdgeAt < START_DEBOUNCE_MS) return false;
  lastStartEdgeAt = now;
  return true;
}

void setup() {
  pinMode(HEATER_ENABLE_PIN, OUTPUT);
  pinMode(PRESS_PWM_PIN, OUTPUT);
  pinMode(PRESS_DIR_PIN, OUTPUT);
  pinMode(FEED_PWM_PIN, OUTPUT);
  pinMode(FEED_DIR_PIN, OUTPUT);
  pinMode(EJECT_PWM_PIN, OUTPUT);
  pinMode(EJECT_DIR_PIN, OUTPUT);
  setHeater(false);
  stopAllMotors();

  Serial.begin(115200);
  Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
  if (!inputs.begin_I2C(0x20)) {
    enterFault();
    return;
  }
  for (uint8_t pin = START_INPUT; pin <= PRESS_CLOSED_INPUT; ++pin) {
    inputs.pinMode(pin, INPUT_PULLUP);
  }
  enterState(State::WARMING);
}

void loop() {
  const float temperatureC = thermocouple.readCelsius();
  controlHeater(temperatureC);
  if (state == State::FAULT) {
    setHeater(false);
    stopAllMotors();
    delay(25);
    return;
  }

  // A guard opening or E-stop feedback loss aborts motion immediately.
  if (!guardOk() || !eStopOk()) {
    enterFault();
    delay(25);
    return;
  }

  const unsigned long elapsed = millis() - stateStartedAt;
  switch (state) {
    case State::WARMING:
      if (elapsed > WARMUP_TIMEOUT_MS) enterFault();
      else if (temperatureC >= SETPOINT_C - HEATER_HYSTERESIS_C && pressIsOpen()) enterState(State::IDLE);
      break;

    case State::IDLE:
      if (!pressIsOpen()) {
        driveMotor(PRESS_PWM_PIN, PRESS_DIR_PIN, false, true); // retract to open
        if (elapsed > PRESS_TIMEOUT_MS) enterFault();
      } else if (startPressed() && doughPresent() && temperatureC >= SETPOINT_C - HEATER_HYSTERESIS_C) {
        enterState(State::FEEDING);
      }
      break;

    case State::FEEDING:
      driveMotor(FEED_PWM_PIN, FEED_DIR_PIN, true, true);
      if (elapsed >= FEED_TIME_MS) enterState(State::CLOSING);
      break;

    case State::CLOSING:
      if (pressIsClosed()) enterState(State::COOKING);
      else if (elapsed > PRESS_TIMEOUT_MS) enterFault();
      else driveMotor(PRESS_PWM_PIN, PRESS_DIR_PIN, true, true);
      break;

    case State::COOKING:
      // Plates remain mechanically closed at the calibrated 2 mm stop.
      if (!pressIsClosed()) enterFault();
      else if (elapsed >= COOK_TIME_MS) enterState(State::OPENING);
      break;

    case State::OPENING:
      if (pressIsOpen()) enterState(State::EJECTING);
      else if (elapsed > PRESS_TIMEOUT_MS) enterFault();
      else driveMotor(PRESS_PWM_PIN, PRESS_DIR_PIN, false, true);
      break;

    case State::EJECTING:
      driveMotor(EJECT_PWM_PIN, EJECT_DIR_PIN, true, true);
      if (elapsed >= EJECT_TIME_MS) enterState(State::IDLE);
      break;

    case State::FAULT:
      break;
  }
  delay(20);
}

“Deploy to device” opens this project in Schematik, where you can flash it to your board over USB.

Remix this project

Make it yours in one click

Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.

Open in Schematik