#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <EncoderButton.h>
#include <FlowSensor.h>
#define FLOW_SENSOR_PIN 2 // Пин подключения датчика потока
#define FLOW_SENSOR_TYPE YFS201 // Тип датчика потока
FlowSensor Sensor(FLOW_SENSOR_TYPE, FLOW_SENSOR_PIN); // Инициализация датчика потока
#define ENCODER_CLK_PIN 3 // Пин подключения энкодера
#define ENCODER_DT_PIN 4 // Пин подключения энкодера
#define ENCODER_SW_PIN 5 // Пин кнопки энкодера
EncoderButton enc(3, 4, 5);
#define LCD_ADDRESS 0x27 // Адрес LCD дисплея по шине I2C
#define LCD_COLUMNS 16 // Количество столбцов на LCD дисплее
#define LCD_ROWS 2 // Количество строк на LCD дисплее
LiquidCrystal_I2C lcd(LCD_ADDRESS, LCD_COLUMNS, LCD_ROWS);
enum class Screen {
MAIN,
GROUP,
CONTROLS,
SETTINGS,
PARAMETR_1,
PARAMETR_2,
PARAMETR_3,
PARAMETR_4
};
Screen currentScreen = Screen::MAIN;
enum class Group {
CONTROLS,
SETTINGS,
SAVEEXIT
};
Group currentGroup = Group::CONTROLS;
enum class Parametr1 {
PARAMETR_1,
PARAMETR_2,
BACK
};
Parametr1 currentParametr1 = Parametr1::PARAMETR_1;
enum class Parametr2 {
PARAMETR_3,
PARAMETR_4,
BACK
};
Parametr2 currentParametr2 = Parametr2::PARAMETR_3;
float tankVolume = 0.0; // Объем бака
float par1 = 0.0;
float par2 = 0.0;
float par3 = 0.0;
float par4 = 0.0;
unsigned long lastSensorReadTime = 0;
unsigned long lastResetTime = 0;
unsigned long lastBacklightTime = 0;
float totalWaterUsed = 0.0; // Общее количество использованной воды в литрах
float remainingWater = 0.0; // Остаток воды в баке
float currentFlowRate = 0.0; // Переменная для хранения текущего расхода воды
float currentVolume = 0.0; // Переменная для хранения текущего объема воды
bool isFlowSensorActivated = false; // Переменная, указывающая, активирован ли датчик потока при открытии крана
void sensorCount() {
Sensor.count();
}
void setup() {
Serial.begin(9600);
Sensor.begin(sensorCount);
lcd.init();
lcd.backlight();
//showSplashScreen();
enc.setClickHandler(handleEncoderButtonPress);
enc.setEncoderHandler(handleEncoderRotation);
}
void loop() {
enc.update();
updateSensorData();
displayScreen();
manageBacklight(); // Управление подсветкой дисплея
}
void handleEncoderButtonPress(EncoderButton& eb) {
Serial.print("eb1 clickCount: ");
Serial.println(eb.clickCount());
lastBacklightTime = millis(); // Записываем время последнего взаимодействия
lcd.backlight(); // Включаем подсветку дисплея при нажатии энкодера
switch (currentScreen) {
case Screen::MAIN:
handleMainScreenButtonPress();
break;
case Screen::GROUP:
handleGroupScreenButtonPress();
break;
case Screen::CONTROLS:
handleControlsScreenButtonPress();
break;
case Screen::SETTINGS:
handleSettingsScreenButtonPress();
break;
case Screen::PARAMETR_1:
handleParametr1ScreenButtonPress();
break;
case Screen::PARAMETR_2:
handleParametr2ScreenButtonPress();
break;
case Screen::PARAMETR_3:
handleParametr3ScreenButtonPress();
break;
case Screen::PARAMETR_4:
handleParametr4ScreenButtonPress();
break;
}
}
void handleEncoderRotation(EncoderButton& eb) {
Serial.print("eb1 incremented by: ");
Serial.println(eb.increment());
Serial.print("eb1 position is: ");
Serial.println(eb.position());
lastBacklightTime = millis(); // Записываем время последнего взаимодействия
lcd.backlight(); // Включаем подсветку дисплея при нажатии энкодера
switch (currentScreen) {
case Screen::GROUP:
handleGroupScreenRotation(eb);
break;
case Screen::CONTROLS:
handleControlsScreenRotation(eb);
break;
case Screen::SETTINGS:
handleSettingsScreenRotation(eb);
break;
case Screen::PARAMETR_1:
handleParametr1ScreenRotation(eb);
break;
case Screen::PARAMETR_2:
handleParametr2ScreenRotation(eb);
break;
case Screen::PARAMETR_3:
handleParametr3ScreenRotation(eb);
break;
case Screen::PARAMETR_4:
handleParametr4ScreenRotation(eb);
break;
}
}
void handleMainScreenButtonPress() {
currentScreen = Screen::GROUP;
}
void handleGroupScreenButtonPress() {
switch (currentGroup) {
case Group::CONTROLS:
currentScreen = Screen::CONTROLS;
break;
case Group::SETTINGS:
currentScreen = Screen::SETTINGS;
break;
case Group::SAVEEXIT:
currentScreen = Screen::MAIN;
break;
}
}
void handleControlsScreenButtonPress() {
switch (currentParametr1) {
case Parametr1::PARAMETR_1:
currentScreen = Screen::PARAMETR_1;
break;
case Parametr1::PARAMETR_2:
currentScreen = Screen::PARAMETR_2;
break;
case Parametr1::BACK:
currentScreen = Screen::GROUP;
break;
}
}
void handleSettingsScreenButtonPress() {
switch (currentParametr2) {
case Parametr2::PARAMETR_3:
currentScreen = Screen::PARAMETR_3;
break;
case Parametr2::PARAMETR_4:
currentScreen = Screen::PARAMETR_4;
break;
case Parametr2::BACK:
currentScreen = Screen::GROUP;
break;
}
}
void handleParametr1ScreenButtonPress() {
currentScreen = Screen::CONTROLS;
}
void handleParametr2ScreenButtonPress() {
currentScreen = Screen::CONTROLS;
}
void handleParametr3ScreenButtonPress() {
currentScreen = Screen::CONTROLS;
}
void handleParametr4ScreenButtonPress() {
currentScreen = Screen::CONTROLS;
}
void handleGroupScreenRotation(EncoderButton& eb) {
switch (currentGroup) {
case Group::CONTROLS:
if (eb.increment() == -1) currentGroup = Group::SETTINGS;
if (eb.increment() == 1) currentGroup = Group::SAVEEXIT;
break;
case Group::SETTINGS:
if (eb.increment() == -1) currentGroup = Group::SAVEEXIT;
if (eb.increment() == 1) currentGroup = Group::CONTROLS;
break;
case Group::SAVEEXIT:
if (eb.increment() == -1) currentGroup = Group::CONTROLS;
if (eb.increment() == 1) currentGroup = Group::SETTINGS;
break;
}
}
void handleControlsScreenRotation(EncoderButton& eb) {
switch (currentParametr1) {
case Parametr1::PARAMETR_1:
if (eb.increment() == -1) currentParametr1 = Parametr1::PARAMETR_2;
break;
case Parametr1::PARAMETR_2:
if (eb.increment() == -1) currentParametr1 = Parametr1::BACK;
break;
case Parametr1::BACK:
if (eb.increment() == -1) currentParametr1 = Parametr1::PARAMETR_1;
break;
}
}
void handleSettingsScreenRotation(EncoderButton& eb) {
switch (currentParametr2) {
case Parametr2::PARAMETR_3:
if (eb.increment() == -1) currentParametr2 = Parametr2::PARAMETR_4;
break;
case Parametr2::PARAMETR_4:
if (eb.increment() == -1) currentParametr2 = Parametr2::BACK;
break;
case Parametr2::BACK:
if (eb.increment() == -1) currentParametr2 = Parametr2::PARAMETR_3;
break;
}
}
void handleParametr1ScreenRotation(EncoderButton& eb) {
par1 += eb.increment();
}
void handleParametr2ScreenRotation(EncoderButton& eb) {
par2 += eb.increment() * 5;
}
void handleParametr3ScreenRotation(EncoderButton& eb) {
par3 += eb.increment() * 10;
}
void handleParametr4ScreenRotation(EncoderButton& eb) {
par4 += eb.increment() * 0.1;
}
void displayScreen() {
switch (currentScreen) {
case Screen::MAIN:
displayMainScreen();
break;
case Screen::GROUP:
displayGroupScreen();
break;
case Screen::CONTROLS:
displayControlsScreen();
break;
case Screen::SETTINGS:
displaySettingsScreen();
break;
case Screen::PARAMETR_1:
displayParametr1Screen();
break;
case Screen::PARAMETR_2:
displayParametr2Screen();
break;
case Screen::PARAMETR_3:
displayParametr3Screen();
break;
case Screen::PARAMETR_4:
displayParametr4Screen();
break;
}
}
void displaySplashScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Water Monitoring");
lcd.setCursor(2, 1);
lcd.print("Version 1.0");
delay(5000);
lcd.clear();
lcd.noBacklight();
}
void displayMainScreen() {
lcd.setCursor(0, 0);
if (isFlowSensorActivated) {
lcd.print("Flow Rate: ");
lcd.print(currentFlowRate); // Вывод показаний потока воды
lcd.print(" L/min");
} else {
lcd.print("Water Used: ");
lcd.print(totalWaterUsed); // Вывод показаний количества использованной воды
lcd.print(" L");
}
lcd.setCursor(0, 1);
lcd.print("Remaining: ");
lcd.print(remainingWater); // Вывод показаний остатка воды
lcd.print(" L");
}
void displayGroupScreen() {
lcd.setCursor(0, 0);
lcd.print("Group menu: ");
lcd.setCursor(0, 1);
switch (currentGroup) {
case Group::CONTROLS:
lcd.print("> Controls ");
break;
case Group::SETTINGS:
lcd.print("> Settings ");
break;
case Group::SAVEEXIT:
lcd.print("> Save and exit ");
break;
}
}
void displayControlsScreen() {
lcd.setCursor(0, 0);
lcd.print("Controls: ");
lcd.setCursor(0, 1);
switch (currentParametr1) {
case Parametr1::PARAMETR_1:
lcd.print("> Parametr 1 ");
break;
case Parametr1::PARAMETR_2:
lcd.print("> Parametr 2 ");
break;
case Parametr1::BACK:
lcd.print("> Back ");
break;
}
}
void displaySettingsScreen() {
lcd.setCursor(0, 0);
lcd.print("Settings: ");
lcd.setCursor(0, 1);
switch (currentParametr2) {
case Parametr2::PARAMETR_3:
lcd.print("> Parametr 3 ");
break;
case Parametr2::PARAMETR_4:
lcd.print("> Parametr 4 ");
break;
case Parametr2::BACK:
lcd.print("> Back ");
break;
}
}
void displayParametr1Screen() {
lcd.setCursor(0, 0);
lcd.print("Parametr 1:");
lcd.setCursor(0, 1);
lcd.print(par1);
lcd.print(" ");
}
void displayParametr2Screen() {
lcd.setCursor(0, 0);
lcd.print("Parametr 2:");
lcd.setCursor(0, 1);
lcd.print(par2);
lcd.print(" ");
}
void displayParametr3Screen() {
lcd.setCursor(0, 0);
lcd.print("Parametr 3:");
lcd.setCursor(0, 1);
lcd.print(par3);
lcd.print(" ");
}
void displayParametr4Screen() {
lcd.setCursor(0, 0);
lcd.print("Parametr 4:");
lcd.setCursor(0, 1);
lcd.print(par4);
lcd.print(" ");
}
void updateSensorData() {
unsigned long currentTime = millis();
unsigned long lastFlowDetectedTime = 0;
unsigned long flowInactiveTimeout = 5000; // Таймаут неактивности потока в миллисекундах
// Считывание данных с датчика потока каждую секунду
if (currentTime - lastSensorReadTime >= 1000) {
Sensor.read();
currentFlowRate = Sensor.getFlowRate_m(); // Сохраняем текущий расход воды
currentVolume = Sensor.getVolume(); // Сохраняем текущий объем воды
// Если поток воды обнаружен, устанавливаем флаг активации датчика потока в true
if (currentFlowRate > 0) {
isFlowSensorActivated = true;
lastFlowDetectedTime = currentTime; // Обновляем время последнего обнаружения потока
}
// Если поток воды не обнаружен и прошло время таймаута, считаем датчик потока неактивным
else if (currentTime - lastFlowDetectedTime > flowInactiveTimeout) {
isFlowSensorActivated = false;
}
lastSensorReadTime = currentTime;
}
// Сброс объема каждую минуту
if (currentTime - lastResetTime >= 60000) {
Sensor.resetVolume();
lastResetTime = currentTime;
}
if (isFlowSensorActivated) {
lastBacklightTime = millis(); // Записываем время последнего взаимодействия
lcd.backlight(); // Включаем подсветку дисплея при нажатии энкодера
}
}
void manageBacklight() {
unsigned long currentTime = millis();
const unsigned long backlightTimeout = 5000; // Таймаут неактивности для выключения подсветки в миллисекундах
// Выключаем подсветку, если прошло время таймаута
if (currentTime - lastBacklightTime > backlightTimeout) {
lcd.noBacklight();
}
}