#include <Arduino.h>
#include <LiquidCrystal_I2C.h>
#include <ESP32Servo.h>
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include <WiFi.h>
#include <ReactESP.h>
#include "time.h"
reactesp::ReactESP app;
/* Miscellaneous constants */
const float flowrate = 61.111f; // mL/s, assuming we're using a 220L/h pump.
/* Proximity sensor related constants */
#define SENSOR_TRIG_PIN 13
#define SENSOR_ECHO_PIN 14
#define DISTANCE 5000
/* Pump related constants */
#define PUMP_PIN 4
/* Display related constants */
#define BAUDRATE 115200
LiquidCrystal_I2C lcd_water(0x26, 16, 2);
LiquidCrystal_I2C lcd_plastic(0x27, 16, 2);
/* Wifi related objects */
WiFiClient client;
HTTPClient http;
/* API related variables */
bool has_api_token = false;
String api_token = "";
/* Global state variables */
int state = 0; // Current state.
int last_state = 0; // Previous state.
int start_pressed = 0; // The moment the system was triggered.
int current_pressed = 0; // How long it has been triggered.
int end_pressed = 0; // The moment the system was untriggered.
int hold_time = 0; // How long the system's been triggered.
int idle_time = 0; // How long the system was idle.
void start(void) {
Serial.begin(BAUDRATE);
pinMode(SENSOR_TRIG_PIN, OUTPUT);
pinMode(SENSOR_ECHO_PIN, INPUT);
app.onRepeat(60000, [] () {
if (!client.connected())
connect_wifi();
if (!has_api_token)
has_api_token = authenticate_api();
});
app.onTick([] () {
// Read the sensor input
state = readSensorTrigger(DISTANCE);
// State changed
if (state != last_state)
update_state();
else
update_counter();
// Save state for next loop
last_state = state;
});
}
void loop(void) {
app.tick();
}
/* Other state functions */
void update_counter() {
if (state != HIGH)
return;
// Enable pump
digitalWrite(PUMP_PIN, HIGH);
current_pressed = millis() - start_pressed;
float volume = current_pressed / 1000.0f * flowrate;
// Update screen with current volume
show_water_result_screen(volume);
}
void update_state() {
// The sensor has just been triggered.
if (state == HIGH) {
start_pressed = millis();
idle_time = start_pressed - end_pressed;
Serial.print("Idle: ");
Serial.print(idle_time);
Serial.print("\n");
lcd_water.clear();
// The sensor has just been untriggered.
} else {
end_pressed = millis();
hold_time = end_pressed - start_pressed;
Serial.print("Hold: ");
Serial.print(hold_time);
Serial.print("\n");
// Disable pump
digitalWrite(PUMP_PIN, LOW);
// Testing with 1mL/s
float volume = hold_time / 1000.0f * flowrate;
Serial.print("Flow: ");
Serial.print(volume, 3);
Serial.print("\n");
// Update screen with final volume
show_water_result_screen(volume);
}
}
/* Other proximity sensor functions */
long readSensorTrigger(int maxDistance) {
digitalWrite(SENSOR_TRIG_PIN, LOW);
delayMicroseconds(2);
// Activate the trigger pin for 10 microseconds
digitalWrite(SENSOR_TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(SENSOR_TRIG_PIN, LOW);
// Read echo
long res = pulseIn(SENSOR_ECHO_PIN, HIGH);
return res <= maxDistance;
}