
// ====Ports====
#define pressure_port A0
#define relay_port 5

// ====Encoder====
#define S1 2
#define S2 3
#define KEY 4

// ====Display====
#define CLK 6
#define DIO 7


#if DEBUG
  #define DEBUG_MSG(x) Serial.println(x)
#else
  #define DEBUG_MSG(x)
#endif

// ====Consts====
#define MIN_PRESSURE 60
#define MAX_PRESSURE 800


// ====Libs====
#include <EncButton.h>
#include <EEPROM.h>
#include <GyverTM1637.h>


int pressure, pressure_low, pressure_high;
bool is_on_pump, is_on_display, display_cur_pressure;
unsigned long last_time1, last_time2, last_time3, last_time_pressure;
const int NUM_READ = 3;

EncButton eb(S1, S2, KEY);
GyverTM1637 disp(CLK, DIO);


// ограничивает нижний порог от 0 до верхнего порога
int get_constrained_pressure_low(int pressure_low_local) {
  return constrain(pressure_low_local, MIN_PRESSURE, pressure_high-10);
}

// ограничивает верхний порог от нижнего порога до 800(8 атмосфер)
int get_constrained_pressure_high(int pressure_high_local) {
  return constrain(pressure_high_local, pressure_low+10, MAX_PRESSURE);
}

// растянутое среднее арифметическое
int midArifm2(int newVal) {
  static byte counter = 0;     // счётчик
  static int prevResult = 0; // хранит предыдущее готовое значение
  static int sum = 0;  // сумма
  sum += newVal;   // суммируем новое значение
  counter++;       // счётчик++
  if (counter == NUM_READ) {      // достигли кол-ва измерений
    prevResult = sum / NUM_READ;  // считаем среднее
    sum = 0;                      // обнуляем сумму
    counter = 0;                  // сброс счётчика
  }
  return prevResult;
}

void setup() {
  #if DEBUG
  Serial.begin(9600);
  #endif

  DEBUG_MSG("pressure");
  DEBUG_MSG(',');
  DEBUG_MSG("low");
  DEBUG_MSG(',');
  DEBUG_MSG("high");
  DEBUG_MSG(',');
  DEBUG_MSG("status");

  pinMode(relay_port, OUTPUT);

  // загрузить пороги из памяти
  EEPROM.get(0, pressure_low);
  EEPROM.get(2, pressure_high);

  disp.clear();
  disp.brightness(5);  // яркость, 0 - 7 (минимум - максимум)
  disp.clear();
}

void loop() {
  eb.tick();
  if (eb.turn()) {
    disp.clear();
    if (eb.right()) {
      pressure_low = get_constrained_pressure_low(pressure_low+10);
      disp.displayInt(pressure_low);
      disp.displayByte(0, _L);
    }
    if (eb.left()) {
      pressure_low = get_constrained_pressure_low(pressure_low-10);
      disp.displayInt(pressure_low);
      disp.displayByte(0, _L);
    }
    if (eb.rightH()) {
      pressure_high = get_constrained_pressure_high(pressure_high+10);
      disp.displayInt(pressure_high);
      disp.displayByte(0, _U);
    }
    if (eb.leftH()) {
      pressure_high = get_constrained_pressure_high(pressure_high-10);
      disp.displayInt(pressure_high);
      disp.displayByte(0, _U);
    }
    is_on_display = true;
    display_cur_pressure = false;
    last_time2 = millis();
  }

  // нажать на энкодер - показать текущее давление
  if (eb.click()) {
    display_cur_pressure = true;
    is_on_display = true;
    last_time2 = millis();
  }


  // Если энкодер зажат то записать текущие пороги в энергонезависимую память
  if (eb.hold()) {
    EEPROM.put(0, pressure_low);
    EEPROM.put(2, pressure_high);
    disp.displayByte(_S, _A, _U, _E);
    display_cur_pressure = false;
    last_time2 = millis();
  }

  // Датчик давления 0 - 1000 0 - 10 атмосфер
  pressure = analogRead(pressure_port);
  pressure = midArifm2(pressure);

  if (millis() - last_time1 > 350) {
      last_time1 = millis();
      if (display_cur_pressure & is_on_display) {
        disp.displayInt(pressure);
      }
  }

  if (millis() - last_time2 > 5000) {
      display_cur_pressure = true;
      last_time2 = millis();
  }

  if (millis() - last_time3 > 30000) {
      display_cur_pressure = false;
      last_time3 = millis();
      disp.clear();
  }

  // измерение каждые 1500 мс
  if (millis() - last_time_pressure > 1500) {
    last_time_pressure = millis();

    // Если текущее давление ниже нижнего порога - включить насос
    if (pressure < pressure_low) {
      if (!is_on_pump) {
        digitalWrite(relay_port, HIGH);
        is_on_pump = true;
      }

    }
    // Иначе если давление выше верхнего порога - выключить насос
    else if (pressure > pressure_high) {
      if (is_on_pump) {
        digitalWrite(relay_port, LOW);
        is_on_pump = false;
      }
    }
  }

  DEBUG_MSG(pressure);
  DEBUG_MSG(',');
  DEBUG_MSG(pressure_low);
  DEBUG_MSG(',');
  DEBUG_MSG(pressure_high);
  DEBUG_MSG(',');
  DEBUG_MSG(is_on_pump*100);
}
