/*
    Level Contorl       Inlet Pump              Outlet Pump
    Tank Level: 10 m³   Flow Rate: 3,600 m³/h   Flow Rate: 3,600 m³/h

    Level Alarm->       Low Alarm:  2 m³        High Alarm: 8 m³


*/

#include "ExponentialFilter.h"

#define LEVEL_AI_PIN                A0
#define START_DI_PIN                7
#define STOP_DI_PIN                 6
#define INLET_VALVE_DO_PIN          11
#define OUTLET_VALVE_DO_PIN         10
#define INLET_VALVE_STATUS_DO_PIN   5
#define OUTLET_VALVE_STATUS_DO_PIN  4
#define RUNNING_STATUS_DO_PIN       3

#define TANK_LEVEL_MIN  0.0
#define TANK_LEVEL_MAX  10.0
#define LEVEL_LOW       2.0
#define LEVEL_HIGH      8.0

#define INTERVAL_PLOT   10  // 10 Milliseconds

bool start;
bool stop;
bool running;
bool risingRun;

bool inletPump;
bool outletPump;

ExponentialFilter expLevel;

void setup() {
  Serial.begin(115200);
  pinMode(START_DI_PIN, INPUT_PULLUP);
  pinMode(STOP_DI_PIN, INPUT_PULLUP);

  pinMode(INLET_VALVE_DO_PIN, OUTPUT);
  pinMode(OUTLET_VALVE_DO_PIN, OUTPUT);
  pinMode(INLET_VALVE_STATUS_DO_PIN, OUTPUT);
  pinMode(OUTLET_VALVE_STATUS_DO_PIN, OUTPUT);
  pinMode(RUNNING_STATUS_DO_PIN, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  expLevel.expMode(AUTO);             // Exponential Filter in Auto Mode
  expLevel.expCutoffTime(MS2S(3000));   // Debounce Period = 20 milliseconds
  expLevel.expInit(TANK_LEVEL_MIN);              // INPUT = 0.0, INPUT_PULLUP = 1.0
}

void loop() {
  RuningCommand();
  Filter();
  PumpControl();
  SerialPlot();
}

void RuningCommand() {
  bool prevRun = running;
  start = !digitalRead(START_DI_PIN);
  stop = digitalRead(STOP_DI_PIN);
  running = (running | start) & stop;
  risingRun = running & !prevRun;
  digitalWrite(RUNNING_STATUS_DO_PIN, running);
}

void PumpControl() {
  bool highLevelAlarm = expLevel.output >= LEVEL_HIGH;
  bool lowLevelAlarm = expLevel.output <= LEVEL_LOW;

  inletPump =  (inletPump | lowLevelAlarm | risingRun) & !highLevelAlarm & running;
  outletPump =  (outletPump | highLevelAlarm) & !lowLevelAlarm & running;
  digitalWrite(INLET_VALVE_DO_PIN, inletPump);
  digitalWrite(OUTLET_VALVE_DO_PIN, outletPump);
  digitalWrite(INLET_VALVE_STATUS_DO_PIN, inletPump);
  digitalWrite(OUTLET_VALVE_STATUS_DO_PIN, outletPump);
}

void Filter() {
  int rawLevel = analogRead(LEVEL_AI_PIN);
  float level = rawLevel * (TANK_LEVEL_MAX - TANK_LEVEL_MIN) / 1023.0f + TANK_LEVEL_MIN;
  float returnValue = expLevel.expFilter(level);
}

void SerialPlot() {
  static unsigned long startTime;
  unsigned long currTime = millis();
  if (currTime - startTime < INTERVAL_PLOT) return;
  startTime = currTime;
  Serial.println(
    ", Exp-Input:" + String(expLevel.input, 2)
    + ", Exp-Output:" + String(expLevel.output, 2)
    + ", Low-Alarm:" + String(LEVEL_LOW, 2)
    + ", High-Alarm:" + String(LEVEL_HIGH, 2)
    + ", Tank-Level-Min:" + String(TANK_LEVEL_MIN, 2)
    + ", Tank-Level-Max:" + String(TANK_LEVEL_MAX, 2)
  );
}
Tank SimulationBreakout
INLET
RATE (m³/h)
OUTLET
RATE (m³/h)
INLET-PUMP
OUTLET-PUMP
3600.0 -------------------------------
0.0 -------------------------------