The Community Water Allocation Simulator

SS 3 ESP32 Simulation first Fair Quota State Machine
Simulation lab
Board: 📶 ESP32
Open in Wokwi ↗
Simulator preview
ESP-WROOM-32 Wi-Fi + BT SoC

Press the pushbutton to test connected Wi-Fi/sensor logic.

>_ Web Serial
ESP32 Ready — Wi-Fi beacon listening.
📦 Components ▴
  • ESP32 NodeMCU Development Board
  • LED indicator (green)
  • 220 ohm resistor
  • Tactile pushbutton switch
  • Jumper wires (male-male)

🔧 Build Your Water Allocation FSM

1 Define an enum state machine: IDLE, AUTHENTICATED, DISPENSING, QUOTA_DEPLETED, and EMERGENCY.
2 Control a 12V solenoid valve output on GPIO 23 and read simulated flow pulses on GPIO 18.
3 Program state transitions strictly in response to verified token swipes and volume thresholds.
4 Lock the solenoid instantly when household daily quota (20 Liters) is reached to guarantee equity!
🧩 Block plan / Starter code ▴
enum DispenserState {
  IDLE,
  AUTHENTICATED,
  DISPENSING,
  QUOTA_DEPLETED,
  EMERGENCY
};

DispenserState currentState = IDLE;
float dailyQuota = 20.0; // 20 Liters per household
float dispensedToday = 0.0;

const int SOLENOID_PIN = 23;
const int FLOW_PULSE_PIN = 18;

void setSolenoid(bool state) {
  digitalWrite(SOLENOID_PIN, state ? HIGH : LOW);
}

void setup() {
  pinMode(SOLENOID_PIN, OUTPUT);
  pinMode(FLOW_PULSE_PIN, INPUT_PULLUP);
  Serial.begin(115200);
  Serial.println("Smart Water Dispenser FSM Active.");
}

void loop() {
  switch (currentState) {
    case IDLE:
      setSolenoid(false);
      // Awaiting RFID user card authentication...
      break;

    case AUTHENTICATED:
      Serial.println("Token Verified. Solenoid Energizing.");
      currentState = DISPENSING;
      break;

    case DISPENSING:
      setSolenoid(true);
      dispensedToday += 0.5; // Simulate flow sensor pulse increment
      Serial.print("Dispensing: "); Serial.print(dispensedToday);
      Serial.println(" / 20.0 Liters");
      if (dispensedToday >= dailyQuota) {
        currentState = QUOTA_DEPLETED;
      }
      break;

    case QUOTA_DEPLETED:
      setSolenoid(false);
      Serial.println("Daily Quota Met! Tap Locked until tomorrow.");
      currentState = IDLE;
      break;

    case EMERGENCY:
      setSolenoid(false);
      Serial.println("EMERGENCY SHUTOFF ACTIVATED!");
      break;
  }
  delay(1000);
}

A deterministic Finite State Machine (FSM) guarantees safe, verifiable actuator states under all operating conditions.

⚗️ Test your model

Test Condition / ActionExpected Result
RFID Token SwipedTransitions from IDLE to AUTHENTICATED to DISPENSING; Solenoid opens
Water Flowing (0 to 20L)Accumulates volume accurately via flow meter pulses
Quota Exceeded (20.0L reached)State forces QUOTA_DEPLETED; Solenoid closes immediately; tap locks
Emergency Button PressedForces EMERGENCY state; valve locks shut regardless of token balance
⚑ Try a challenge

Connect an RFID RC522 card reader that tracks distinct household account IDs and independent quota balances!

❓ Quick check
What is the primary architectural purpose of using a formal Finite State Machine (FSM) in embedded control firmware?

📖 Our Story & Concepts

In semi-arid communities, solar water kiosks are shared lifeline resources. If a valve sticks open or someone hacks the dispenser to siphon 2,000 liters, the aquifer runs dry and neighbors go without drinking water.

Mission-critical embedded firmware is engineered around a Finite State Machine (FSM). An FSM mathematically guarantees that a system can only exist in one valid state at any instant, with strictly controlled transitions. This eliminates race conditions, rogue actuator commands, and resource depletion.

</> Full Annotated Code Walkthrough

// Complete Deterministic Water Dispenser State Engine
#include 

enum State { ST_IDLE, ST_AUTH, ST_DISPENSE, ST_LOCKED, ST_EMERGENCY };
State st = ST_IDLE;

float quota = 20.0;
float dispensed = 0.0;
const int VALVE_PIN = 23;
const int ESTOP_PIN = 0;

void setup() {
  pinMode(VALVE_PIN, OUTPUT);
  pinMode(ESTOP_PIN, INPUT_PULLUP);
  Serial.begin(115200);
}

void loop() {
  // Global Emergency Override
  if (digitalRead(ESTOP_PIN) == LOW) {
    st = ST_EMERGENCY;
  }

  switch (st) {
    case ST_IDLE:
      digitalWrite(VALVE_PIN, LOW);
      Serial.println("[STATE: IDLE] Waiting for card swipe...");
      delay(1500);
      st = ST_AUTH; // Simulate user card tap
      break;

    case ST_AUTH:
      Serial.println("[STATE: AUTH] Household #104 Verified. Remaining: 20L");
      dispensed = 0.0;
      st = ST_DISPENSE;
      break;

    case ST_DISPENSE:
      digitalWrite(VALVE_PIN, HIGH);
      dispensed += 2.0; // Simulate 2L water draw
      Serial.printf("[STATE: DISPENSING] Flow: %.1f / %.1f Liters
", dispensed, quota);
      if (dispensed >= quota) {
        st = ST_LOCKED;
      }
      delay(800);
      break;

    case ST_LOCKED:
      digitalWrite(VALVE_PIN, LOW);
      Serial.println("[STATE: LOCKED] Daily quota exhausted! Valve shut.");
      delay(2000);
      st = ST_IDLE;
      break;

    case ST_EMERGENCY:
      digitalWrite(VALVE_PIN, LOW);
      Serial.println("[CRITICAL EMERGENCY] Hardware interlock trip! Manual reboot required.");
      while(1) { delay(1000); }
  }
}

A deterministic Finite State Machine (FSM) guarantees safe, verifiable actuator states under all operating conditions.

▷ Expected Results & Troubleshooting

Test Condition / ActionExpected Result
RFID Token SwipedTransitions from IDLE to AUTHENTICATED to DISPENSING; Solenoid opens
Water Flowing (0 to 20L)Accumulates volume accurately via flow meter pulses
Quota Exceeded (20.0L reached)State forces QUOTA_DEPLETED; Solenoid closes immediately; tap locks
Emergency Button PressedForces EMERGENCY state; valve locks shut regardless of token balance

⚑ Extension Challenges & Blueprints

⚑ Extension Challenges
  • Level 1: Attach a flow pulse interrupt handler on GPIO 18 to measure actual water milliliters.
  • Level 2: Display live volume and household credit balance on a 16x2 I2C LCD screen.
  • Level 3: Sync household usage transactions to an encrypted cloud billing endpoint via MQTT.

❓ Check Your Understanding

Question 1: What is the primary architectural purpose of using a formal Finite State Machine (FSM) in embedded control firmware?

Question 2: In our community water allocator, what triggers the transition from STATE_DISPENSING to STATE_QUOTA_EXCEEDED?

Question 3: Why is an automated fair water quota system essential for community-managed solar boreholes in drought-prone regions?

Question 4: Which C++ control structure is universally used to execute Finite State Machine logic in embedded firmware loops?

Feedback appears after you check your answer.