/*
  Automatic, ultrasonic sewage control by Steve Barth. 2023.
  Ultrasonic sensor, Pro Mini 8MHz with Nokia 5110 screen and RGB led
  The display was designed with the help of https://lopaka.app
*********************************************************************
*********************************************************************
  RAM:   [====      ]  38.4% (used   786 bytes from  2048 bytes)
  Flash: [=======   ]  75.1% (used 23060 bytes from 30720 bytes)
    Building .pio\build\pro8MHzatmega328\firmware.hex
*********************************************************************/
//!             last modify: 2025.10.08.       v.4.3a
//******************************************   libraries   *************************************************
#include <Arduino.h>
#include <avr/wdt.h>     // watchdog timer library
#include <NewPing.h>
#include <U8g2lib.h>     //- https://github.com/olikraus/u8g2/wiki/u8g2reference#setdisplayrotation
//******************************************   declarations   **********************************************
#define BackLight 4
#define Pump 5
#define GreenLed 6
#define RedLed 7
#define TRIGGER_PIN A0          // Arduino pin tied to TRIGGER_PIN pin on ping sensor.
#define ECHO_PIN A1             // Arduino pin tied to ECHO_PIN pin on ping sensor.
#define MAX_DISTANCE 50        // Maximum Distance (in cm) to ping.
#define ITERATIONS 20           // Number of iterations.
// #define PING_INTERVAL 33        // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor ECHO_PIN).
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);        // NewPing setup of pins and maximum Distance.
float sound_time, Distance;                                                                      //
const unsigned int LOOP_DELAY = 50;                                                             // msec of additional loop delay
const unsigned int CLOCK_PIN = 13, DATA_PIN = 11, CS_PIN = 10, DC_PIN = 9, RESET_PIN = 8;        //
int PumpState = 0, temp = 0, level_Min = 42.5, level_Max = 31.5;                                                                    //
char dispStr[5];        // null terminated char array used to pass to renderer.
/*      Nokia 5110 blue pin assignments:
   RST:                  8
   DC/"D/C":             9              ( 10 ?)
   CE/CS/SCE:           10              (  9 ?)
   DIN/DN/MOSI/DATA:    11
   CLK/SCLK/SCK:        13
   VCC:                 3.3V
   LIGHT/LED:        sw 3.3V  (ground through 330 ohm resistor)
   GND: ground
*/
/*
  Controller "PCD8544", Display "84x48" [Description]
  U8G2_PCD8544_84X48_1_4W_SW_SPI(rotation, clock, data, cs, dc [, reset]) [page buffer, size = 88 bytes]
  U8G2_PCD8544_84X48_2_4W_SW_SPI(rotation, clock, data, cs, dc [, reset]) [page buffer, size = 176 bytes]
  U8G2_PCD8544_84X48_F_4W_SW_SPI(rotation, clock, data, cs, dc [, reset]) [full framebuffer, size = 528 bytes]
  U8G2_PCD8544_84X48_1_4W_HW_SPI(rotation, cs, dc [, reset]) [page buffer, size = 88 bytes]
  U8G2_PCD8544_84X48_2_4W_HW_SPI(rotation, cs, dc [, reset]) [page buffer, size = 176 bytes]
  U8G2_PCD8544_84X48_F_4W_HW_SPI(rotation, cs, dc [, reset]) [full framebuffer, size = 528 bytes]
  U8G2_PCD8544_84X48_1_2ND_4W_HW_SPI(rotation, cs, dc [, reset]) [page buffer, size = 88 bytes]
  U8G2_PCD8544_84X48_2_2ND_4W_HW_SPI(rotation, cs, dc [, reset]) [page buffer, size = 176 bytes]
  U8G2_PCD8544_84X48_F_2ND_4W_HW_SPI(rotation, cs, dc [, reset]) [full framebuffer, size = 528 bytes]
  U8G2_PCD8544_84X48_1_3W_SW_SPI(rotation, clock, data, cs [, reset]) [page buffer, size = 88 bytes]
  U8G2_PCD8544_84X48_2_3W_SW_SPI(rotation, clock, data, cs [, reset]) [page buffer, size = 176 bytes]
  U8G2_PCD8544_84X48_F_3W_SW_SPI(rotation, clock, data, cs [, reset]) [full framebuffer, size = 528 bytes]
  U8G2_PCD8544_84X48_1_3W_HW_SPI(rotation, cs [, reset]) [page buffer, size = 88 bytes]
  U8G2_PCD8544_84X48_2_3W_HW_SPI(rotation, cs [, reset]) [page buffer, size = 176 bytes]
  U8G2_PCD8544_84X48_F_3W_HW_SPI(rotation, cs [, reset]) [full framebuffer, size = 528 bytes]
*/
U8G2_PCD8544_84X48_1_4W_HW_SPI lcd(U8G2_R0, CS_PIN, DC_PIN, RESET_PIN);
//            if display rotation: U8G2_R0 : 0°; U8G2_R1 : 90°; U8G2_R2 : 180°; U8G2_R3 : 270°
//******************************************   setup   *****************************************************
void setup(void)
{
  Serial.begin(9600);
  pinMode(BackLight, OUTPUT);
  pinMode(Pump, OUTPUT);
  pinMode(GreenLed, OUTPUT);
  pinMode(RedLed, OUTPUT);
  pinMode(TRIGGER_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  digitalWrite(BackLight, LOW);
  digitalWrite(Pump, LOW);
  delay(500);
  digitalWrite(RedLed, HIGH);
  delay(500);
  digitalWrite(RedLed, LOW);
  delay(500);
  digitalWrite(GreenLed, HIGH);
  delay(500);
  digitalWrite(GreenLed, LOW);
  delay(500);
  lcd.begin();
  lcd.setContrast(160);   // display specific
  digitalWrite(BackLight, HIGH);
  delay(500);
  lcd.firstPage();        // start screen
  do
  {
    lcd.setFont(u8g2_font_6x13_tr);         // u8g2_font_6x13_tr
    lcd.drawRFrame(0, 1, 84, 46, 4);        // if needed
    lcd.drawStr(12, 12, "Ultrasonic");
    lcd.drawStr(1, 21, "sewage control");
    lcd.setFont(u8g2_font_6x10_tr);
    lcd.drawStr(8, 33, "2025.");
    lcd.drawStr(52, 33, "by:");             // 33, 34,
    lcd.setFont(u8g2_font_7x13B_tr);        // u8g2_font_7x13B_tr
    lcd.drawStr(4, 44, "Steve Barth");
  } while (lcd.nextPage());
  delay(4000);
  digitalWrite(BackLight, LOW);
  lcd.clearDisplay();
  delay(2000);
  wdt_enable(WDTO_1S);        // Watchdog Timer setting 1s
}
//******************************************   void's   ****************************************************
void ultrasonic_meter()        // ultrasonic sensor start
{
  sound_time = sonar.ping_median(ITERATIONS);
  Distance = (sound_time * 0.0343) / 2;        // Use 343 metres per second as speed of sound /
}
void Pump_Control()        // Pump control
{
  /* 250mm fixing ultrasonic sensor, the water level max: 110mm + 65mm berm , water level min: 15mm */
  if (Distance < level_Max && temp == 0)        // 110mm water level max ( = (250mm) fixing + (65mm) berm)
  {
    digitalWrite(Pump, HIGH);        // Pump on
    PumpState = 1;
    temp = 1;
  }
  else if (Distance < level_Max && temp == 1)
  {
    digitalWrite(Pump, HIGH);
    PumpState = 1;
  }
  else if (Distance > level_Min)        // 15mm water level min ( = (250mm) fixing + (65mm) berm + (95mm)water height)
  {
    digitalWrite(Pump, LOW);
    PumpState = 0;
    temp = 0;
  }
}
void Led_Control()        // led control
{
  /*
      red led on:   water level 50% - 100%   distance: 373mm - 325mm
      green led on: water level  0% -  90%   distance: 420mm - 334mm
  */
  if (Distance < 37.3)        // < 373mm / smaller 50%
  {
    digitalWrite(RedLed, HIGH);        // red led on
  }
  else
    digitalWrite(RedLed, LOW);
  if (Distance > 33.4)        // > 334mm / higher 90%
  {
    digitalWrite(GreenLed, HIGH);        // green led on
  }
  else
    digitalWrite(GreenLed, LOW);
}
void Lcd_display()        // display control
{
  digitalWrite(BackLight, HIGH);
  delay(200);
  lcd.firstPage();
  do
  {
    lcd.setFont(u8g2_font_7x13B_tr);
    //lcd.drawRFrame(9, 0, 67, 13, 4);    // if needed upper -frame
    //lcd.drawRFrame(1, 12, 83, 25, 4);   // if needed middle -frame
    lcd.drawRFrame(1, 1, 82, 35, 4);   // if needed upper half -frame
    lcd.drawStr(15, 11, "Distance");
    Serial.println(Distance);
    lcd.setFont(u8g2_font_logisoso20_tr);
    String(Distance).toCharArray(dispStr, 5);
    lcd.drawStr(5, 34, dispStr);
    lcd.setFont(u8g2_font_fub11_tr);
    lcd.drawStr(58, 33, "cm");
    lcd.setFontMode(1);        // activate transparent font mode
    lcd.setFont(u8g2_font_7x13B_tr);
    lcd.setDrawColor(2);
    lcd.drawStr(4, 46, "pump is");
    if (PumpState == 1)
    {
      lcd.drawButtonUTF8(68, 46, U8G2_BTN_HCENTER | U8G2_BTN_INV, 25, 1, 0, "on");
    }
    else
      lcd.drawStr(60, 46, "off");
  } while (lcd.nextPage());
}
//******************************************   loop   ******************************************************
void loop(void)
{
  ultrasonic_meter();
  Lcd_display();
  Led_Control();
  Pump_Control();
  wdt_reset();        // A watchdog timer reset
  delay(LOOP_DELAY);
}
//******************************************   loop end   **************************************************
//program end