HydroZoner IoT
This commit is contained in:
commit
d8cd33e003
|
@ -0,0 +1,426 @@
|
||||||
|
//Handle main app routine
|
||||||
|
//........................
|
||||||
|
//#include "ButtonRotaryHandler.h"
|
||||||
|
//#include "MenuHandler.h"
|
||||||
|
//#include "DisplayHandler.h"
|
||||||
|
|
||||||
|
#define MENU_NONE 0
|
||||||
|
#define MENU_DASHBOARD 1
|
||||||
|
#define MENU_SELECT_OPTION 2
|
||||||
|
#define MENU_DURATION_MAIN 3
|
||||||
|
#define MENU_DURATION_POST_UV 4
|
||||||
|
#define MENU_CONNECTION 5
|
||||||
|
#define MENU_ABOUT 6
|
||||||
|
|
||||||
|
#define SUBMENU_SELECT_NONE 0
|
||||||
|
|
||||||
|
int8_t displayIdx = MENU_NONE;
|
||||||
|
int8_t menuIdx = 0;
|
||||||
|
int8_t menuDisplayLowerBound = 0;
|
||||||
|
int8_t menuDisplayUpperBound = 0;
|
||||||
|
|
||||||
|
uint32_t waitDelay = 0;
|
||||||
|
uint32_t waitTick = 0;
|
||||||
|
bool responseCleanupButton = false;
|
||||||
|
bool responseCleanupRotary = false;
|
||||||
|
|
||||||
|
const char* textStartStop[] = {
|
||||||
|
"Mulai Sterilisasi",
|
||||||
|
"Stop Sterilisasi"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* textStartStopRefill[] = {
|
||||||
|
"Mulai Refill",
|
||||||
|
"Stop Refill"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* textAutoMode[] = {
|
||||||
|
"Otomasi Steril: Ya",
|
||||||
|
"Otomasi Steril: Tidak"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* textAutoRefillMode[] = {
|
||||||
|
"Otomasi Refill: Ya",
|
||||||
|
"Otomasi Refill: Tidak"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* menus[] = {
|
||||||
|
"Mulai/Stop Sterilisasi",
|
||||||
|
"Mulai/Stop Refill",
|
||||||
|
"Otomasi Steril: Ya/Tidak",
|
||||||
|
"Otomasi Refill: Ya/Tidak",
|
||||||
|
"Durasi Sterilisasi",
|
||||||
|
"Post-Sterilisasi UV",
|
||||||
|
"Koneksi",
|
||||||
|
"Tentang Aplikasi",
|
||||||
|
"Kembali"
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SUBMENU_START_STOP 0
|
||||||
|
#define SUBMENU_START_STOP_REFILL 1
|
||||||
|
#define SUBMENU_AUTOMODE 2
|
||||||
|
#define SUBMENU_AUTOMODE_REFILL 3
|
||||||
|
#define SUBMENU_DURATION 4
|
||||||
|
#define SUBMENU_POST_UV 5
|
||||||
|
#define SUBMENU_CONNECTION 6
|
||||||
|
#define SUBMENU_ABOUT 7
|
||||||
|
#define SUBMENU_BACK 8
|
||||||
|
|
||||||
|
const char* durationSelect[] = {
|
||||||
|
"5 Menit",
|
||||||
|
"10 Menit",
|
||||||
|
"15 Menit",
|
||||||
|
"20 Menit",
|
||||||
|
"25 Menit",
|
||||||
|
"30 Menit"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* durationSelect2[] = {
|
||||||
|
"Non-Aktifan",
|
||||||
|
"5 Menit",
|
||||||
|
"10 Menit",
|
||||||
|
"15 Menit",
|
||||||
|
"20 Menit",
|
||||||
|
"25 Menit",
|
||||||
|
"30 Menit"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* apSelect2[] = {
|
||||||
|
"Kembali",
|
||||||
|
"Aktifkan/Nonaktifkan",
|
||||||
|
"Password Baru"
|
||||||
|
"Tanpa Password"
|
||||||
|
};
|
||||||
|
|
||||||
|
int dialogSelectionIndex = 0;
|
||||||
|
|
||||||
|
int SelectDialog(const char *title, const char *text, const char* durationList[], int indexLimit){
|
||||||
|
//limit index
|
||||||
|
if (dialogSelectionIndex>indexLimit) dialogSelectionIndex = indexLimit;
|
||||||
|
if (dialogSelectionIndex<0) dialogSelectionIndex = 0;
|
||||||
|
|
||||||
|
if (ButtonSwitchedEvent()==BUTTON_UNPRESSED_EVENT){
|
||||||
|
Serial.println("OK");
|
||||||
|
return dialogSelectionIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
int direction = RotaryEvent();
|
||||||
|
if (direction==DIRECTION_CW){
|
||||||
|
dialogSelectionIndex++;
|
||||||
|
if (dialogSelectionIndex>indexLimit) dialogSelectionIndex = indexLimit;
|
||||||
|
Serial.println(">>");
|
||||||
|
}else if (direction==DIRECTION_CCW){
|
||||||
|
dialogSelectionIndex--;
|
||||||
|
if (dialogSelectionIndex<0) dialogSelectionIndex = 0;
|
||||||
|
Serial.println("<<");
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearDisplayBuffer();
|
||||||
|
DrawCenteredText(title, 0, false, false, false, true);
|
||||||
|
DrawCenteredText(text, 2, false);
|
||||||
|
//DrawCenteredText("30 Menit", 3, true, true, true);
|
||||||
|
DrawCenteredText(durationList[dialogSelectionIndex], 3, true, (dialogSelectionIndex>0), (dialogSelectionIndex<indexLimit));
|
||||||
|
SendDisplayBuffer();
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetWaitResponse(uint32_t delayMillis, bool needButtonCleanup=false, bool needRotaryCleanup = false){
|
||||||
|
waitDelay = delayMillis;
|
||||||
|
waitTick = millis();
|
||||||
|
responseCleanupButton = needButtonCleanup;
|
||||||
|
responseCleanupRotary = needRotaryCleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppStartSterilizationSystem(){
|
||||||
|
Serial.println("AppStartSterilizationSystem()");
|
||||||
|
//copy configuration and start
|
||||||
|
bool useUV = GetPostUVTimeIndex()>0;
|
||||||
|
uint32_t uvDuration = ((uint32_t)GetPostUVTimeIndex()) * (5 * 60 * 1000);
|
||||||
|
ChamberSetPostUvDuration(uvDuration);
|
||||||
|
uint32_t ozoneDuration = ((uint32_t) (1+GetSterilizationTimeIndex())) * (5 * 60 * 1000);
|
||||||
|
//uint32_t ozoneDuration = ((uint32_t) (1+GetSterilizationTimeIndex())) * (1 * 60 * 1000);
|
||||||
|
ChamberSetSterlizationDuration(ozoneDuration);
|
||||||
|
bool autoMode = GetSettingAutoMode();
|
||||||
|
StartChamberSystem(autoMode, true, useUV);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppStartRefillSystem(){
|
||||||
|
Serial.println("AppStartRefillSystem()");
|
||||||
|
//copy configuration and start
|
||||||
|
StartWaterBankSystem(GetSettingAutoRefillMode(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//handle app logic
|
||||||
|
void AppRoutine(){
|
||||||
|
|
||||||
|
//background task
|
||||||
|
//..................
|
||||||
|
|
||||||
|
if ((millis()-waitTick)<waitDelay){
|
||||||
|
if (responseCleanupButton) ButtonResetEvent();
|
||||||
|
if (responseCleanupRotary) RotaryResetEvent();
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
if (responseCleanupButton) {
|
||||||
|
responseCleanupButton = false;
|
||||||
|
ButtonResetEvent();
|
||||||
|
}
|
||||||
|
if (responseCleanupRotary) {
|
||||||
|
responseCleanupRotary = false;
|
||||||
|
RotaryResetEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (displayIdx){
|
||||||
|
case MENU_NONE:{
|
||||||
|
SetWaitResponse(2000, true, true);
|
||||||
|
displayIdx = MENU_DASHBOARD;
|
||||||
|
SplashScreen();
|
||||||
|
//u8g2.setPowerSave(1); //not working :(
|
||||||
|
Serial.println("Switch: MENU_DASHBOARD");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_DASHBOARD:{
|
||||||
|
|
||||||
|
//DashboardDemoRoutine();
|
||||||
|
DashboardRoutine();
|
||||||
|
|
||||||
|
//handle button to enter select option
|
||||||
|
if (ButtonSwitchedEvent()==BUTTON_UNPRESSED_EVENT){
|
||||||
|
displayIdx = MENU_SELECT_OPTION;
|
||||||
|
menuIdx = 0;
|
||||||
|
menuDisplayLowerBound = 0;
|
||||||
|
int maxMenuCount = sizeof(menus) / sizeof(menus[0]);;
|
||||||
|
menuDisplayUpperBound = min(DrawTextRowCount(), maxMenuCount)-1;
|
||||||
|
Serial.print("Menu upper bound: ");
|
||||||
|
Serial.println(menuDisplayUpperBound);
|
||||||
|
Serial.println("Switch: MENU_SELECT_OPTION");
|
||||||
|
SetWaitResponse(50, true, true);
|
||||||
|
}else{
|
||||||
|
SetWaitResponse(5, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_SELECT_OPTION:{
|
||||||
|
//handle rotary
|
||||||
|
int maxDisplayTextRow = DrawTextRowCount();
|
||||||
|
int maxMenuCount = sizeof(menus) / sizeof(menus[0]);
|
||||||
|
int boundDiff = (min(DrawTextRowCount(), maxMenuCount)-1);
|
||||||
|
int direction = RotaryEvent();
|
||||||
|
bool rotaryChanged = false;
|
||||||
|
if (direction==DIRECTION_CW){
|
||||||
|
rotaryChanged = true;
|
||||||
|
menuIdx++;
|
||||||
|
if (menuIdx>=maxMenuCount){
|
||||||
|
menuIdx = 0;
|
||||||
|
menuDisplayLowerBound = 0;
|
||||||
|
menuDisplayUpperBound = boundDiff;
|
||||||
|
}
|
||||||
|
if (menuIdx>menuDisplayUpperBound){
|
||||||
|
menuDisplayUpperBound = menuIdx;
|
||||||
|
menuDisplayLowerBound = menuDisplayUpperBound-boundDiff;
|
||||||
|
}
|
||||||
|
}else if (direction==DIRECTION_CCW){
|
||||||
|
Serial.println("handle CCW");
|
||||||
|
rotaryChanged = true;
|
||||||
|
menuIdx--;
|
||||||
|
if (menuIdx<0){
|
||||||
|
menuIdx=maxMenuCount-1;
|
||||||
|
menuDisplayUpperBound = menuIdx;
|
||||||
|
menuDisplayLowerBound = menuDisplayUpperBound-boundDiff;
|
||||||
|
}
|
||||||
|
//Serial.print("lowerbound "); Serial.println(menuDisplayLowerBound);
|
||||||
|
//Serial.print("upperbound "); Serial.println(menuDisplayUpperBound);
|
||||||
|
|
||||||
|
// if (menuDisplayUpperBound<menuIdx){
|
||||||
|
// menuDisplayUpperBound = menuIdx;
|
||||||
|
// menuDisplayLowerBound = menuDisplayUpperBound-boundDiff;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (menuIdx<menuDisplayLowerBound){
|
||||||
|
menuDisplayLowerBound = menuIdx;
|
||||||
|
menuDisplayUpperBound = menuDisplayLowerBound+boundDiff;
|
||||||
|
if (menuDisplayUpperBound>=maxMenuCount) menuDisplayUpperBound = maxMenuCount-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rotaryChanged){
|
||||||
|
SetWaitResponse(50);//next response is 50 (best)
|
||||||
|
}
|
||||||
|
|
||||||
|
//handle button
|
||||||
|
if (ButtonSwitchedEvent()==BUTTON_UNPRESSED_EVENT){
|
||||||
|
Serial.print("Clicking sub menu: ");
|
||||||
|
Serial.println(menuIdx);
|
||||||
|
switch(menuIdx){
|
||||||
|
case SUBMENU_START_STOP:{
|
||||||
|
if (IsChamberSystemRunning()){
|
||||||
|
Serial.println("Call: StopChamberSystem()");
|
||||||
|
StopChamberSystem();
|
||||||
|
}else{
|
||||||
|
Serial.println("Call: AppStartSterilizationSystem()");
|
||||||
|
ClearWaterBankError();//clear error juga buat water tank
|
||||||
|
AppStartSterilizationSystem();
|
||||||
|
}
|
||||||
|
displayIdx = MENU_DASHBOARD;
|
||||||
|
Serial.println("Switch: MENU_DASHBOARD");
|
||||||
|
SetWaitResponse(0, true, true);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
case SUBMENU_START_STOP_REFILL:{
|
||||||
|
if (IsWaterBankSystemRunning()){
|
||||||
|
StopWaterBankSystem();
|
||||||
|
}else{
|
||||||
|
ClearChamberError();//clear error juga buat chamber
|
||||||
|
AppStartRefillSystem();
|
||||||
|
}
|
||||||
|
displayIdx = MENU_DASHBOARD;
|
||||||
|
Serial.println("Switch: MENU_DASHBOARD");
|
||||||
|
SetWaitResponse(0, true, true);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case SUBMENU_AUTOMODE:{
|
||||||
|
SetSettingAutoMode(!GetSettingAutoMode());
|
||||||
|
SetWaitResponse(0, true, true);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case SUBMENU_AUTOMODE_REFILL:{
|
||||||
|
SetSettingAutoRefillMode(!GetSettingAutoRefillMode());
|
||||||
|
SetWaitResponse(0, true, true);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case SUBMENU_DURATION:{
|
||||||
|
dialogSelectionIndex = GetSterilizationTimeIndex();
|
||||||
|
displayIdx = MENU_DURATION_MAIN;
|
||||||
|
Serial.println("Switch: MENU_DURATION_MAIN");
|
||||||
|
SetWaitResponse(0, true, true);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case SUBMENU_POST_UV:{
|
||||||
|
dialogSelectionIndex = GetUVTimeIndex();
|
||||||
|
displayIdx = MENU_DURATION_POST_UV;
|
||||||
|
Serial.println("Switch: MENU_DURATION_POST_UV");
|
||||||
|
SetWaitResponse(0, true, true);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case SUBMENU_CONNECTION:{
|
||||||
|
displayIdx = MENU_CONNECTION;
|
||||||
|
Serial.println("Switch: MENU_CONNECTION");
|
||||||
|
SetWaitResponse(0, true, true);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case SUBMENU_ABOUT:{
|
||||||
|
displayIdx = MENU_ABOUT;
|
||||||
|
Serial.println("Switch: MENU_ABOUT");
|
||||||
|
SetWaitResponse(0, true, true);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case SUBMENU_BACK:{
|
||||||
|
displayIdx = MENU_DASHBOARD;
|
||||||
|
Serial.println("Switch: MENU_DASHBOARD");
|
||||||
|
SetWaitResponse(200, true, true);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//adapt state
|
||||||
|
if (!IsChamberSystemRunning()){
|
||||||
|
menus[SUBMENU_START_STOP] = textStartStop[0];
|
||||||
|
}else{
|
||||||
|
menus[SUBMENU_START_STOP] = textStartStop[1];
|
||||||
|
}
|
||||||
|
//adapt state for refill
|
||||||
|
if (!IsWaterBankSystemRunning()){
|
||||||
|
menus[SUBMENU_START_STOP_REFILL] = textStartStopRefill[0];
|
||||||
|
}else{
|
||||||
|
menus[SUBMENU_START_STOP_REFILL] = textStartStopRefill[1];
|
||||||
|
}
|
||||||
|
//adapt sterilization auto mode text:
|
||||||
|
if (GetSettingAutoRefillMode()){
|
||||||
|
menus[SUBMENU_AUTOMODE_REFILL] = textAutoRefillMode[0];
|
||||||
|
}else{
|
||||||
|
menus[SUBMENU_AUTOMODE_REFILL] = textAutoRefillMode[1];
|
||||||
|
}
|
||||||
|
//adapt refill auto mode text:
|
||||||
|
if (GetSettingAutoMode()){
|
||||||
|
menus[SUBMENU_AUTOMODE] = textAutoMode[0];
|
||||||
|
}else{
|
||||||
|
menus[SUBMENU_AUTOMODE] = textAutoMode[1];
|
||||||
|
}
|
||||||
|
ClearDisplayBuffer();
|
||||||
|
//DrawSectionPlaceholder();
|
||||||
|
int pointerIdx = menuIdx;
|
||||||
|
int row = 0;
|
||||||
|
for (int i=menuDisplayLowerBound;i<=menuDisplayUpperBound;i++){
|
||||||
|
DrawTextMenuAtRow(menus[i], row, i==pointerIdx);
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
SendDisplayBuffer();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_DURATION_MAIN:{
|
||||||
|
int idx = SelectDialog("Durasi Sterilisasi", "Pilihan Durasi:", durationSelect, 5);
|
||||||
|
if (idx>=0){
|
||||||
|
displayIdx = MENU_SELECT_OPTION;
|
||||||
|
SetSterilizationTimeIndex(idx);
|
||||||
|
SetWaitResponse(0, true, true);
|
||||||
|
}else{
|
||||||
|
SetWaitResponse(50, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_DURATION_POST_UV:{
|
||||||
|
int limit = 6;
|
||||||
|
int idx = SelectDialog("Post-Sterilisasi UV", "Pilihan Durasi:", durationSelect2, limit);
|
||||||
|
if (idx>=0){
|
||||||
|
displayIdx = MENU_SELECT_OPTION;
|
||||||
|
SetPostUVTimeIndex(idx);
|
||||||
|
SetWaitResponse(0, true, true);
|
||||||
|
}else{
|
||||||
|
SetWaitResponse(50, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_CONNECTION:{
|
||||||
|
//DrawUnderConstruction();
|
||||||
|
ClearDisplayBuffer();
|
||||||
|
DrawCenteredText("Koneksi", 0, false, false, false, true);
|
||||||
|
DrawCenteredText("SSID: HYDROZONER_V1", 1, false);
|
||||||
|
String pwd = "Password: " + GetApPassword();
|
||||||
|
DrawCenteredText(pwd.c_str(), 2, false);
|
||||||
|
SendDisplayBuffer();
|
||||||
|
displayIdx = MENU_SELECT_OPTION;
|
||||||
|
SetWaitResponse(5000, true, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_ABOUT:{
|
||||||
|
DrawAbout();
|
||||||
|
if (ButtonSwitchedEvent()==BUTTON_UNPRESSED_EVENT){
|
||||||
|
displayIdx = MENU_SELECT_OPTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitApp(){
|
||||||
|
//cek setingan kalau mode auto maka dijalankan
|
||||||
|
if (GetSettingAutoMode()){
|
||||||
|
AppStartSterilizationSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetSettingAutoRefillMode()){
|
||||||
|
AppStartRefillSystem();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
#define CLK_PIN 12 // BTN ENC1
|
||||||
|
#define DT_PIN 14 // BTN ENC2
|
||||||
|
#define SW_PIN 13 // BTN ENC
|
||||||
|
|
||||||
|
#define DIRECTION_NONE 0 // no change
|
||||||
|
#define DIRECTION_CCW 1 // counter-clockwise direction
|
||||||
|
#define DIRECTION_CW 2 // clockwise direction
|
||||||
|
|
||||||
|
|
||||||
|
#define BUTTON_PRESSED_EVENT 1
|
||||||
|
#define BUTTON_UNPRESSED_EVENT 2
|
||||||
|
#define BUTTON_NO_CHANGE_EVENT 0
|
||||||
|
|
||||||
|
|
||||||
|
volatile uint8_t rotaryDirection = DIRECTION_NONE;
|
||||||
|
volatile uint8_t rotaryDirectionPrev = DIRECTION_NONE;
|
||||||
|
volatile uint32_t rotaryLastTick;
|
||||||
|
volatile int rotaryCounter = 0;
|
||||||
|
volatile int rotaryCounterPrev = 0;
|
||||||
|
volatile int rotaryCounterPrevDebug = 0;
|
||||||
|
|
||||||
|
volatile bool buttonPressed = false;
|
||||||
|
volatile bool buttonPressedPrev = false;
|
||||||
|
volatile bool buttonPressedPrevDebug = false;
|
||||||
|
volatile uint32_t buttonLastTick = 0;
|
||||||
|
|
||||||
|
volatile int16_t rotaryPosition = 0;
|
||||||
|
volatile int16_t rotaryLastPosition = 0;
|
||||||
|
|
||||||
|
//volatile int16_t rotaryEncodedPrev = 0;
|
||||||
|
|
||||||
|
// Debounce time in milliseconds
|
||||||
|
const int debounceTime = 2;//2; //default is 2 (best)
|
||||||
|
volatile unsigned long lastInterruptTimeA = 0;
|
||||||
|
volatile unsigned long lastInterruptTimeB = 0;
|
||||||
|
volatile unsigned long lastInterruptTimeButton = 0;
|
||||||
|
// Variables to keep track of encoder state
|
||||||
|
volatile int lastEncoded = 0;
|
||||||
|
volatile long encoderValue = 0;
|
||||||
|
long lastEncoderValue = 0;
|
||||||
|
|
||||||
|
// ISR for encoder A pin
|
||||||
|
void IRAM_ATTR handleEncoderA() {
|
||||||
|
unsigned long currentTime = millis();
|
||||||
|
if ((currentTime - lastInterruptTimeA) > debounceTime) {
|
||||||
|
int MSB = digitalRead(CLK_PIN);
|
||||||
|
int LSB = digitalRead(DT_PIN);
|
||||||
|
|
||||||
|
int encoded = (MSB << 1) | LSB;
|
||||||
|
int sum = (lastEncoded << 2) | encoded;
|
||||||
|
|
||||||
|
if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011){
|
||||||
|
encoderValue--;
|
||||||
|
rotaryDirection = DIRECTION_CCW;
|
||||||
|
}
|
||||||
|
if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000){
|
||||||
|
encoderValue++;
|
||||||
|
rotaryDirection = DIRECTION_CW;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastEncoded = encoded;
|
||||||
|
lastInterruptTimeA = currentTime;
|
||||||
|
|
||||||
|
rotaryCounter=encoderValue; //copy to rotaryCounter
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ISR for encoder B pin
|
||||||
|
void IRAM_ATTR handleEncoderB() {
|
||||||
|
unsigned long currentTime = millis();
|
||||||
|
if ((currentTime - lastInterruptTimeB) > debounceTime) {
|
||||||
|
handleEncoderA(); // Call handleEncoderA to handle B changes in the same way
|
||||||
|
lastInterruptTimeB = currentTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitButtonRotaryHandler(){
|
||||||
|
Serial.print("Initializing Button and Rotary Encoder: ");
|
||||||
|
buttonPressedPrev = false;
|
||||||
|
buttonPressedPrevDebug = false;
|
||||||
|
rotaryCounter = 0;
|
||||||
|
rotaryCounterPrev = 0;
|
||||||
|
rotaryCounterPrevDebug = 0;
|
||||||
|
rotaryDirection = DIRECTION_NONE;
|
||||||
|
rotaryDirectionPrev = DIRECTION_NONE;
|
||||||
|
rotaryLastTick = millis();
|
||||||
|
buttonLastTick = millis();
|
||||||
|
pinMode(DT_PIN, INPUT_PULLUP);
|
||||||
|
pinMode(CLK_PIN, INPUT_PULLUP);
|
||||||
|
pinMode(SW_PIN, INPUT_PULLUP);
|
||||||
|
// button.setDebounceTime(5);
|
||||||
|
attachInterrupt(digitalPinToInterrupt(CLK_PIN), handleEncoderA, CHANGE);
|
||||||
|
attachInterrupt(digitalPinToInterrupt(DT_PIN), handleEncoderB, CHANGE);
|
||||||
|
|
||||||
|
// Initialize button pin
|
||||||
|
//pinMode(SW_PIN, INPUT_PULLUP); // Assuming the button is active low
|
||||||
|
//attachInterrupt(digitalPinToInterrupt(SW_PIN), ButtonInterrupt, CHANGE);
|
||||||
|
|
||||||
|
Serial.println("OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ButtonIsPressed(){
|
||||||
|
if (millis() - buttonLastTick < 10 ) return buttonPressed; //debounce
|
||||||
|
buttonPressed = digitalRead(SW_PIN) == LOW;
|
||||||
|
buttonLastTick = millis();
|
||||||
|
return buttonPressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
//return 0 = no change, 1 = pressed, 2 = unpressed
|
||||||
|
uint8_t ButtonSwitchedEvent(){
|
||||||
|
//Serial.println("A");
|
||||||
|
if (millis() - buttonLastTick < 10 ) return BUTTON_NO_CHANGE_EVENT; //debounce
|
||||||
|
//Serial.println("B");
|
||||||
|
buttonPressed = digitalRead(SW_PIN) == LOW;
|
||||||
|
buttonLastTick = millis();
|
||||||
|
if (buttonPressed!=buttonPressedPrev){
|
||||||
|
buttonPressedPrev = buttonPressed;
|
||||||
|
if (buttonPressed) return BUTTON_PRESSED_EVENT;
|
||||||
|
return BUTTON_UNPRESSED_EVENT;
|
||||||
|
}else{
|
||||||
|
return BUTTON_NO_CHANGE_EVENT; //no change
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reset Button flag for event
|
||||||
|
void ButtonResetEvent(){
|
||||||
|
buttonPressed = digitalRead(SW_PIN) == LOW;
|
||||||
|
buttonPressedPrev = buttonPressed;
|
||||||
|
buttonLastTick = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reset Rotary flag for event
|
||||||
|
void RotaryResetEvent(){
|
||||||
|
rotaryCounter = 0;
|
||||||
|
rotaryCounterPrev = 0;
|
||||||
|
encoderValue = 0;
|
||||||
|
rotaryDirection = DIRECTION_NONE;
|
||||||
|
rotaryDirectionPrev = DIRECTION_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get rotary last direction then clear flag
|
||||||
|
uint8_t RotaryEvent(){
|
||||||
|
if (rotaryDirection!=DIRECTION_NONE) lastInterruptTimeB = millis(); //debounce it again from last consume
|
||||||
|
uint8_t v = rotaryDirection;
|
||||||
|
rotaryDirection = DIRECTION_NONE;
|
||||||
|
rotaryDirectionPrev = DIRECTION_NONE;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
//for debug testing
|
||||||
|
void ButtonRotaryDebugRoutine(){
|
||||||
|
if (buttonPressedPrevDebug!=buttonPressed){
|
||||||
|
buttonPressedPrevDebug = buttonPressed;
|
||||||
|
Serial.print("Button: ");
|
||||||
|
Serial.println((buttonPressed?"1":"0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rotaryCounter!=rotaryCounterPrevDebug){
|
||||||
|
rotaryCounterPrevDebug = rotaryCounter;
|
||||||
|
if (rotaryDirection!=DIRECTION_NONE){
|
||||||
|
Serial.print("Rotary: ");
|
||||||
|
Serial.print((rotaryDirection==DIRECTION_CW?">":"<"));
|
||||||
|
Serial.print(" (");
|
||||||
|
Serial.print(rotaryCounterPrevDebug);
|
||||||
|
Serial.println(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
uint8_t settingSterilizationTimeIdx = 1; //in index. 1 = default
|
||||||
|
uint8_t settingUvTimeIdx = 2; //in index. 0 = off
|
||||||
|
uint8_t settingPostUvTimeIdx = 1; //in index. 0 = off
|
||||||
|
bool settingAutoMode = false;
|
||||||
|
bool settingAutoRefillMode = false;
|
||||||
|
|
||||||
|
String settingApPassword = "12345678";
|
||||||
|
|
||||||
|
int settingTick = 0;
|
||||||
|
int settingTickPrev = 0;
|
||||||
|
|
||||||
|
bool GetSettingAutoMode(){
|
||||||
|
return settingAutoMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSettingAutoMode(bool v){
|
||||||
|
if (v!=settingAutoMode){
|
||||||
|
settingAutoMode = v;
|
||||||
|
settingTick++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetSettingAutoRefillMode(){
|
||||||
|
return settingAutoRefillMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSettingAutoRefillMode(bool v){
|
||||||
|
if (v!=settingAutoRefillMode){
|
||||||
|
settingAutoRefillMode = v;
|
||||||
|
settingTick++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t GetSterilizationTimeIndex(){
|
||||||
|
return settingSterilizationTimeIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSterilizationTimeIndex(int v){
|
||||||
|
if (v!=settingSterilizationTimeIdx){
|
||||||
|
settingSterilizationTimeIdx = v;
|
||||||
|
settingTick++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t GetUVTimeIndex(){
|
||||||
|
return settingUvTimeIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetUVTimeIndex(int v){
|
||||||
|
if (v!=settingUvTimeIdx){
|
||||||
|
settingUvTimeIdx = v;
|
||||||
|
settingTick++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t GetPostUVTimeIndex(){
|
||||||
|
return settingUvTimeIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPostUVTimeIndex(int v){
|
||||||
|
if (v!=settingPostUvTimeIdx){
|
||||||
|
settingPostUvTimeIdx = v;
|
||||||
|
settingTick++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenerateNewApPassword(){
|
||||||
|
//generate character with letter and number
|
||||||
|
Serial.println("not impelemented");
|
||||||
|
//................
|
||||||
|
settingTick++;
|
||||||
|
}
|
||||||
|
|
||||||
|
String GetApPassword(){
|
||||||
|
return settingApPassword;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,348 @@
|
||||||
|
#include "Raindrop.h"
|
||||||
|
|
||||||
|
const float pi = 3.14159265359;
|
||||||
|
//float displayPropellerAngle = 0;
|
||||||
|
int displayPropellerAngle = 0;
|
||||||
|
int diplayAniTick = 0;
|
||||||
|
int diplayAniDropTick = 0;
|
||||||
|
|
||||||
|
int displayStateTick3 = 0;
|
||||||
|
int displayDemoTick = 0;
|
||||||
|
|
||||||
|
uint32_t footerScrollSpeed = 3;
|
||||||
|
String footerText = "";
|
||||||
|
uint32_t footerDelayTick = 0;
|
||||||
|
int footerX = 4;
|
||||||
|
int footerY = 61;
|
||||||
|
int footerDisplayLength = 0;
|
||||||
|
uint32_t footerScrollTick = 0;
|
||||||
|
|
||||||
|
void DisplayFooterText(String v){
|
||||||
|
if (footerText!=v){
|
||||||
|
//reset and delay
|
||||||
|
footerX = 4;
|
||||||
|
footerText = v;
|
||||||
|
footerDisplayLength = DrawTextAtWitdh(v.c_str());
|
||||||
|
footerDelayTick = millis();
|
||||||
|
footerScrollTick = millis();
|
||||||
|
DrawTextAt(footerX, footerY, footerText.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
//animation of text
|
||||||
|
if (footerDisplayLength<=120){
|
||||||
|
DrawTextAt(footerX, footerY, footerText.c_str());
|
||||||
|
}else{
|
||||||
|
//scrolling animation
|
||||||
|
if ((millis()-footerDelayTick) > 2000){
|
||||||
|
if (millis()-footerScrollTick >= 20){
|
||||||
|
footerScrollTick = millis();
|
||||||
|
footerX-=footerScrollSpeed;
|
||||||
|
if (footerX+footerDisplayLength+8<0){
|
||||||
|
footerScrollTick = millis();
|
||||||
|
footerX = 128;
|
||||||
|
}
|
||||||
|
DrawTextAt(footerX, footerY, footerText.c_str());
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
DrawTextAt(footerX, footerY, footerText.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatTime(int minutes, int seconds) {
|
||||||
|
char buffer[6];
|
||||||
|
sprintf(buffer, "%02d:%02d", minutes, seconds);
|
||||||
|
return String(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
String MillisToMMSS(uint32_t v){
|
||||||
|
uint32_t sec = v / 1000;
|
||||||
|
uint32_t m = sec / 60;
|
||||||
|
sec = sec - (m*60);
|
||||||
|
String timeString = formatTime(m, sec);
|
||||||
|
return timeString;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DashboardRoutine(){
|
||||||
|
ClearDisplayBuffer();
|
||||||
|
//gambar bingkai
|
||||||
|
DrawFrame(0,0,128,64);
|
||||||
|
|
||||||
|
DrawFrame(0,0,128,12); //kotak kiri atas
|
||||||
|
DrawFrame(0,0,43,12); //kotak tengah atas
|
||||||
|
DrawFrame(42,0,43,12); //kotak kanan atas
|
||||||
|
|
||||||
|
DrawFrame(0,52,128,12); //kotak bawah
|
||||||
|
|
||||||
|
DrawTextAt(4, 9, "pH ---"); //isi dengan PH
|
||||||
|
DrawTextAt(46, 9, "NTU ---"); //isi dengan NTU
|
||||||
|
DrawTextAt(88, 9, "Auto"); //isi dengan apalah: sinyal wifi kek, sisa batre kek ya apalah gitu. Asal jangan isi dengan perasaanmu padanya.
|
||||||
|
|
||||||
|
//draw tank ==================================
|
||||||
|
int x = 0;
|
||||||
|
int y = 15;
|
||||||
|
int w = 25;
|
||||||
|
int h = 34;
|
||||||
|
int gap = 11;
|
||||||
|
//int startX = (128 - ((2*(w+gap)) + w)) / 2; //center, ignore pump draw
|
||||||
|
int startX = (128 - ((3*(w+gap)) + 0)) / 2; //center includes pump draw
|
||||||
|
String v = "";
|
||||||
|
for (int i = 0; i<3; i++){
|
||||||
|
|
||||||
|
//tong
|
||||||
|
x = startX + (i*(w+gap));
|
||||||
|
//DrawTank(x,y,w,h);
|
||||||
|
|
||||||
|
//kotak pompa samping
|
||||||
|
DrawFrame(x+w-1, y+4, gap+2, gap+2);
|
||||||
|
|
||||||
|
//animasi ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
bool drawPump = false;
|
||||||
|
if (i==0){
|
||||||
|
//pompa in 1 (ke tong penampung setelah sterilisasi)
|
||||||
|
drawPump = GetSwitchState(STERILIZED_CHAMBER_FILL_PUMP_SWITCH);
|
||||||
|
}else if (i==1){
|
||||||
|
//pompa in 2 (tong sterilisasi)
|
||||||
|
drawPump = GetSwitchState(STERILIZATION_CHAMBER_FILL_PUMP_SWITCH);
|
||||||
|
}else{
|
||||||
|
//pompa in 3 (tong penampung air kotor)
|
||||||
|
drawPump = GetSwitchState(WATER_BANK_FILL_PUMP_SWITCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drawPump){
|
||||||
|
//propeller
|
||||||
|
drawPropeller(x+w+5,y+4+6,10,displayPropellerAngle);
|
||||||
|
//bulatan propeller
|
||||||
|
DrawCircle(x+w+5,y+4+6,5);
|
||||||
|
}
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
if (i==1){
|
||||||
|
//large propeller on tank 2
|
||||||
|
bool drawSterilizationFX = false;
|
||||||
|
drawSterilizationFX = GetSwitchState(STERILIZATION_OZONE_AND_UV_SWITCH);
|
||||||
|
if (drawSterilizationFX){
|
||||||
|
//draw big propeller
|
||||||
|
drawPropeller(x+(w/2),y+4+17,11,displayPropellerAngle);
|
||||||
|
//drawPropeller(x+(w/2),y+4+15,11,displayPropellerAngle+45);
|
||||||
|
//draw waves
|
||||||
|
DrawCircle(x+(w/2),y+4+17,0+diplayAniTick<10?7+diplayAniTick:10);
|
||||||
|
DrawCircle(x+(w/2),y+4+17,5+diplayAniTick<10?5+diplayAniTick:10);
|
||||||
|
DrawCircle(x+(w/2),y+4+17,7+diplayAniTick<10?7+diplayAniTick:10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//wave animation on tank 1
|
||||||
|
if (i==0){
|
||||||
|
bool drawUvFX = false;
|
||||||
|
drawUvFX = GetSwitchState(STERILIZED_UV_SWITCH);
|
||||||
|
if (drawUvFX){
|
||||||
|
DrawCircle(x+(w/2),y+4+17,0+diplayAniTick<10?diplayAniTick:10);
|
||||||
|
DrawCircle(x+(w/2),y+4+17,5+diplayAniTick<10?5+diplayAniTick:10);
|
||||||
|
DrawCircle(x+(w/2),y+4+17,7+diplayAniTick<10?7+diplayAniTick:10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//draw between empty-lower-upper with xor mode
|
||||||
|
int waterState = 0;
|
||||||
|
if (i==0){
|
||||||
|
//(tong penampung setelah sterilisasi)
|
||||||
|
if (GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER)) waterState = 1;
|
||||||
|
if (GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_UPPER)) waterState = 2;
|
||||||
|
}else if (i==1){
|
||||||
|
//(tong sterilisasi)
|
||||||
|
if (GetInSwitchState(STERILIZATION_CHAMBER_FLOAT_SWITCH_LOWER)) waterState = 1;
|
||||||
|
if (GetInSwitchState(STERILIZATION_CHAMBER_FLOAT_SWITCH_UPPER)) waterState = 2;
|
||||||
|
}else{
|
||||||
|
//(tong penampung air kotor)
|
||||||
|
if (GetInSwitchState(WATER_BANK_FLOAT_SWITCH_LOWER)) waterState = 1;
|
||||||
|
if (GetInSwitchState(WATER_BANK_FLOAT_SWITCH_UPPER)) waterState = 2;
|
||||||
|
}
|
||||||
|
//drawing
|
||||||
|
if (waterState==1){
|
||||||
|
//lower
|
||||||
|
DrawTankFilled(x+2,y+(h-10)-2,w-4,10); //h harus minimal radius*2 hedeh
|
||||||
|
}else if (waterState==2){
|
||||||
|
//upper
|
||||||
|
DrawTankFilled(x+2,y+(h-24)-1,w-4,23); //h harus minimal radius*2 hedeh
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawTank(x,y,w,h);
|
||||||
|
|
||||||
|
if (drawPump){
|
||||||
|
//watering animation on all tank
|
||||||
|
initRaindrops(6, h-11);
|
||||||
|
animateRain(diplayAniDropTick, (x+w)-9, y+7, 6, h-11);
|
||||||
|
}
|
||||||
|
|
||||||
|
//angka pada tong
|
||||||
|
v = (String) (i+1);
|
||||||
|
DrawTextAt(x+10, y+8, v.c_str());
|
||||||
|
}
|
||||||
|
//===========================================
|
||||||
|
|
||||||
|
diplayAniTick++;
|
||||||
|
if (diplayAniTick>5) diplayAniTick = 0;
|
||||||
|
diplayAniDropTick++;
|
||||||
|
if (diplayAniDropTick>8) diplayAniDropTick = 8;
|
||||||
|
|
||||||
|
if (millis()-displayDemoTick>2000){
|
||||||
|
displayDemoTick = millis();
|
||||||
|
displayStateTick3++;
|
||||||
|
if (displayStateTick3>=3) displayStateTick3 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//footer info
|
||||||
|
//ni nih paling susah karena harus sinkronasi sama error dan perubahan text error
|
||||||
|
String footerToDisplay = "";
|
||||||
|
if (ChamberIsError()){
|
||||||
|
footerToDisplay = ChamberErrorString();
|
||||||
|
}else if (IsWaterBankError()){
|
||||||
|
footerToDisplay = WaterBankErrorString();
|
||||||
|
}else{
|
||||||
|
if (ChamberIsIdle()){
|
||||||
|
if (ChamberIsSuccess()){
|
||||||
|
footerToDisplay = "Selesai.";
|
||||||
|
}else{
|
||||||
|
if (IsWaterBankSystemRunning()){
|
||||||
|
footerToDisplay = "Mengisi Tangki 3...";
|
||||||
|
}else{
|
||||||
|
footerToDisplay = "Sistem siap."; //ready
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if (IsChamberSystemRunning()){
|
||||||
|
//display state
|
||||||
|
if (IsChamberFilling()){
|
||||||
|
footerToDisplay = "Mengisi Tangki 2...";
|
||||||
|
}else if (IsChamberUnload()){
|
||||||
|
footerToDisplay = "Memindahkan ke Tangki 1...";
|
||||||
|
}else{
|
||||||
|
uint32_t t = GetSterilizationRemainingMillis();
|
||||||
|
if (t>0){
|
||||||
|
bool onPostUV = OnPostUV();
|
||||||
|
bool onOzone = OnOzoneStrelization();
|
||||||
|
if (onOzone){
|
||||||
|
footerToDisplay = "Sedang Sterilisasi " + MillisToMMSS(t);
|
||||||
|
}else if (onPostUV){
|
||||||
|
footerToDisplay = "Post UV " + MillisToMMSS(t);
|
||||||
|
}else{
|
||||||
|
footerToDisplay = "Sedang Sterilisasi..."; //aneh sih kalau disini, dahlah
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
footerToDisplay = "Sedang Sterilisasi...";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayFooterText(footerToDisplay);
|
||||||
|
//DrawTextAt(4, 61, "Ready.");
|
||||||
|
|
||||||
|
|
||||||
|
SendDisplayBuffer();
|
||||||
|
|
||||||
|
//displayPropellerAngle+=pi/10;
|
||||||
|
//if (displayPropellerAngle>=pi) displayPropellerAngle-=pi;
|
||||||
|
displayPropellerAngle-=15;
|
||||||
|
if (displayPropellerAngle<=-360) displayPropellerAngle=-(abs(displayPropellerAngle)%360);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DashboardDemoRoutine(){
|
||||||
|
ClearDisplayBuffer();
|
||||||
|
//gambar bingkai
|
||||||
|
DrawFrame(0,0,128,64);
|
||||||
|
|
||||||
|
DrawFrame(0,0,128,12); //kotak kiri atas
|
||||||
|
DrawFrame(0,0,43,12); //kotak tengah atas
|
||||||
|
DrawFrame(42,0,43,12); //kotak kanan atas
|
||||||
|
|
||||||
|
DrawFrame(0,52,128,12); //kotak bawah
|
||||||
|
//draw lines for
|
||||||
|
|
||||||
|
//DrawDashboardBackground(); //not implemented yet
|
||||||
|
DrawTextAt(4, 9, "pH 14.0"); //isi dengan PH
|
||||||
|
DrawTextAt(46, 9, "NTU 999"); //isi dengan NTU
|
||||||
|
DrawTextAt(88, 9, "Auto"); //isi dengan apalah: sinyal wifi kek, sisa batre kek
|
||||||
|
|
||||||
|
//draw tank ==================================
|
||||||
|
int x = 0;
|
||||||
|
int y = 15;
|
||||||
|
int w = 25;
|
||||||
|
int h = 34;
|
||||||
|
int gap = 11;
|
||||||
|
//int startX = (128 - ((2*(w+gap)) + w)) / 2; //center, ignore pump draw
|
||||||
|
int startX = (128 - ((3*(w+gap)) + 0)) / 2; //center includes pump draw
|
||||||
|
String v = "";
|
||||||
|
for (int i = 0; i<3; i++){
|
||||||
|
|
||||||
|
//tong
|
||||||
|
x = startX + (i*(w+gap));
|
||||||
|
//DrawTank(x,y,w,h);
|
||||||
|
|
||||||
|
//pompa samping
|
||||||
|
DrawFrame(x+w-1, y+4, gap+2, gap+2);
|
||||||
|
//propeller
|
||||||
|
drawPropeller(x+w+5,y+4+6,10,displayPropellerAngle);
|
||||||
|
//bulatan propeller
|
||||||
|
DrawCircle(x+w+5,y+4+6,5);
|
||||||
|
|
||||||
|
if (i==1){
|
||||||
|
//large propeller on tank 2
|
||||||
|
drawPropeller(x+(w/2),y+4+17,11,displayPropellerAngle);
|
||||||
|
//drawPropeller(x+(w/2),y+4+15,11,displayPropellerAngle+45);
|
||||||
|
DrawCircle(x+(w/2),y+4+17,0+diplayAniTick<10?0+diplayAniTick:10);
|
||||||
|
DrawCircle(x+(w/2),y+4+17,5+diplayAniTick<10?5+diplayAniTick:10);
|
||||||
|
DrawCircle(x+(w/2),y+4+17,7+diplayAniTick<10?7+diplayAniTick:10);
|
||||||
|
}
|
||||||
|
|
||||||
|
//wave animation on tank 1
|
||||||
|
if (i==0){
|
||||||
|
DrawCircle(x+(w/2),y+4+17,0+diplayAniTick<10?diplayAniTick:10);
|
||||||
|
DrawCircle(x+(w/2),y+4+17,5+diplayAniTick<10?5+diplayAniTick:10);
|
||||||
|
DrawCircle(x+(w/2),y+4+17,7+diplayAniTick<10?7+diplayAniTick:10);
|
||||||
|
}
|
||||||
|
|
||||||
|
//draw between empty-lower-upper with xor mode
|
||||||
|
if (displayStateTick3==1){
|
||||||
|
//lower
|
||||||
|
DrawTankFilled(x+2,y+(h-10)-2,w-4,10); //h harus minimal radius*2 hedeh
|
||||||
|
}else if (displayStateTick3==2){
|
||||||
|
//upper
|
||||||
|
DrawTankFilled(x+2,y+(h-24)-1,w-4,23); //h harus minimal radius*2 hedeh
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawTank(x,y,w,h);
|
||||||
|
|
||||||
|
//watering animation on all tank
|
||||||
|
initRaindrops(6, h-11);
|
||||||
|
animateRain(diplayAniDropTick, (x+w)-9, y+7, 6, h-11);
|
||||||
|
|
||||||
|
//angka pada tong
|
||||||
|
v = (String) (i+1);
|
||||||
|
DrawTextAt(x+10, y+8, v.c_str());
|
||||||
|
}
|
||||||
|
//===========================================
|
||||||
|
|
||||||
|
diplayAniTick++;
|
||||||
|
if (diplayAniTick>5) diplayAniTick = 0;
|
||||||
|
diplayAniDropTick++;
|
||||||
|
if (diplayAniDropTick>8) diplayAniDropTick = 8;
|
||||||
|
|
||||||
|
if (millis()-displayDemoTick>2000){
|
||||||
|
displayDemoTick = millis();
|
||||||
|
displayStateTick3++;
|
||||||
|
if (displayStateTick3>=3) displayStateTick3 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//footer info
|
||||||
|
|
||||||
|
DrawTextAt(4, 61, "Ready.");
|
||||||
|
|
||||||
|
SendDisplayBuffer();
|
||||||
|
|
||||||
|
//displayPropellerAngle+=pi/10;
|
||||||
|
//if (displayPropellerAngle>=pi) displayPropellerAngle-=pi;
|
||||||
|
displayPropellerAngle-=15;
|
||||||
|
if (displayPropellerAngle<=-360) displayPropellerAngle=-(abs(displayPropellerAngle)%360);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,244 @@
|
||||||
|
#include <U8g2lib.h>
|
||||||
|
|
||||||
|
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 18, 23, 5, U8X8_PIN_NONE);
|
||||||
|
|
||||||
|
//splashscreen
|
||||||
|
const unsigned char logo [] U8X8_PROGMEM = {
|
||||||
|
0x00,0x00,0xff,0x07,0x00,0x00,0x00,0xe0,0x20,0x18,0x00,0x00,0x00,0x18,0x40,0x60,0x00,0x00,0x00,0x06,0x00,0x80,
|
||||||
|
0x01,0x00,0x00,0x07,0x00,0x00,0x06,0x00,0x80,0x05,0x00,0x00,0x0c,0x00,0xc0,0x00,0x40,0x00,0x08,0x00,0x40,0x00,
|
||||||
|
0x02,0x00,0x10,0x00,0x20,0x00,0x02,0x08,0x10,0x00,0x20,0x08,0x00,0x08,0x20,0x00,0x30,0x10,0x20,0x04,0x20,0x00,
|
||||||
|
0x30,0x10,0x20,0x00,0x21,0x00,0x51,0x20,0x22,0x80,0x21,0x02,0x91,0x20,0x24,0x82,0x20,0x02,0x11,0x40,0x24,0x42,
|
||||||
|
0x20,0x02,0x11,0x42,0x24,0x42,0x20,0x02,0x11,0x86,0x24,0x21,0x20,0x02,0x31,0x84,0x24,0x21,0x22,0x02,0x71,0x08,
|
||||||
|
0x25,0x11,0x23,0x02,0xd1,0x10,0x29,0x99,0x21,0x02,0x91,0x33,0xaa,0xc9,0x30,0x02,0x11,0x46,0xfe,0x65,0x2c,0x02,
|
||||||
|
0x31,0xdc,0x03,0x27,0x22,0x02,0xf1,0xf1,0x00,0x9c,0x21,0x02,0x11,0x67,0x00,0xd8,0x20,0x02,0x31,0x38,0x00,0x70,
|
||||||
|
0x20,0x02,0xf1,0x31,0x00,0x20,0x3e,0x02,0x11,0x13,0x00,0x40,0x21,0x02,0x31,0x0c,0x07,0xc0,0x23,0x02,0x71,0xe8,
|
||||||
|
0x18,0x60,0x2c,0x02,0xd1,0x39,0xe0,0x1c,0x30,0x02,0x11,0x07,0x00,0x03,0x20,0x02,0x11,0x00,0x00,0x00,0x20,0x02,
|
||||||
|
0x31,0xc0,0x1f,0xe0,0x27,0x02,0xf1,0x60,0x60,0x18,0x38,0x02,0x11,0x1f,0x80,0x07,0x20,0x02,0x11,0x00,0x00,0x00,
|
||||||
|
0x20,0x02,0x31,0x80,0x0f,0xc0,0x27,0x02,0x71,0x60,0x30,0x30,0x38,0x02,0x91,0x3f,0xc0,0x0f,0x20,0x02,0x11,0x00,
|
||||||
|
0x00,0x00,0x20,0x02,0x11,0x00,0x00,0x00,0x20,0x02,0x11,0x00,0x07,0x80,0x23,0x02,0x71,0xc0,0x18,0x60,0x3c,0x02,
|
||||||
|
0xe3,0x3f,0xe0,0x1c,0x30,0x02,0x23,0x00,0x00,0x03,0x10,0x02,0x22,0x00,0x00,0x00,0x10,0x03,0x42,0xc0,0x1f,0xe0,
|
||||||
|
0x0f,0x01,0x84,0x39,0x60,0x18,0x0c,0x01,0x04,0x07,0x80,0x07,0x86,0x01,0x08,0x06,0x00,0x00,0xc3,0x00,0x18,0x38,
|
||||||
|
0x00,0xe0,0x60,0x00,0x30,0xc0,0xff,0x1f,0x30,0x00,0xc0,0x00,0x00,0x00,0x0c,0x00,0x00,0x03,0x00,0x00,0x03,0x00,
|
||||||
|
0x00,0xfc,0xff,0xff,0x00,0x00};
|
||||||
|
|
||||||
|
|
||||||
|
void SplashScreen(){
|
||||||
|
u8g2.clearBuffer();
|
||||||
|
u8g2.setDrawColor(1); //set to 1
|
||||||
|
u8g2.setFont(u8g2_font_helvB08_tr);
|
||||||
|
u8g2.drawStr(51, 32, "HYDROZONER");
|
||||||
|
u8g2.drawXBMP(6, 4, 42, 56, logo);
|
||||||
|
u8g2.setFont(u8g2_font_profont11_tr);
|
||||||
|
u8g2.drawStr(55, 41, "PKM-KC 2024");
|
||||||
|
u8g2.sendBuffer();
|
||||||
|
//delay(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitDisplay(){
|
||||||
|
//u8g2.setBusClock(1000000);
|
||||||
|
u8g2.setBusClock(8000000);
|
||||||
|
u8g2.begin();
|
||||||
|
//u8g2.clearBuffer();
|
||||||
|
u8g2.setFontMode(1);
|
||||||
|
u8g2.setBitmapMode(1);
|
||||||
|
u8g2.clear();
|
||||||
|
delay(2);
|
||||||
|
u8g2.initDisplay();
|
||||||
|
delay(2);
|
||||||
|
//u8g2.sendBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearDisplayBuffer(){
|
||||||
|
u8g2.clearBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendDisplayBuffer(){
|
||||||
|
u8g2.sendBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawDashboardBackground(){
|
||||||
|
//Not implemented
|
||||||
|
//u8g2.clearBuffer();
|
||||||
|
u8g2.setFont(u8g2_font_profont11_tr);
|
||||||
|
u8g2.setDrawColor(1);
|
||||||
|
u8g2.drawStr(0, 10, "Dashboard not coded!");
|
||||||
|
|
||||||
|
//u8g2.drawXBM(0, 0, 32, 32, tangki_kosong);
|
||||||
|
|
||||||
|
//u8g2.sendBuffer();
|
||||||
|
//...................................
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DrawSectionPlaceholder(){
|
||||||
|
u8g2.setFont(u8g2_font_profont12_tr); //8 pixel height font
|
||||||
|
u8g2.setDrawColor(1);
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
int h = 12;
|
||||||
|
int w = 128;
|
||||||
|
for (int i=0;i<5;i++){
|
||||||
|
y = (i*12);
|
||||||
|
if ((i%2)==0){
|
||||||
|
u8g2.drawBox(x,y,w,h);
|
||||||
|
u8g2.setDrawColor(2); //set to xor
|
||||||
|
//u8g2.setFontMode(1);
|
||||||
|
}else{
|
||||||
|
//u8g2.setFontMode(0);
|
||||||
|
u8g2.setDrawColor(1); //set to 1
|
||||||
|
}
|
||||||
|
y = 10 + (i*12);
|
||||||
|
u8g2.drawStr(x, y, "123456789ABCDEFGHIJKL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int DrawTextRowCount(){
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawTextMenuAtRow(const char *v, byte row, bool highlight){
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
int h = 12;
|
||||||
|
int w = 128;
|
||||||
|
u8g2.setFont(u8g2_font_profont12_tr); //8 pixel height font
|
||||||
|
|
||||||
|
u8g2.setDrawColor(1);
|
||||||
|
|
||||||
|
//highlight
|
||||||
|
if (highlight){
|
||||||
|
x = 0;
|
||||||
|
y = row*12;
|
||||||
|
u8g2.drawBox(x,y,w,h);
|
||||||
|
u8g2.setDrawColor(2); //set to xor
|
||||||
|
}
|
||||||
|
|
||||||
|
//text
|
||||||
|
x = 2;
|
||||||
|
y = 10 + (row*12);
|
||||||
|
u8g2.drawStr(x, y, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawAbout(){
|
||||||
|
u8g2.clearBuffer();
|
||||||
|
u8g2.setDrawColor(1); //set to 1
|
||||||
|
u8g2.setFont(u8g2_font_helvB08_tr);
|
||||||
|
u8g2.drawStr(51, 22, "HYDROZONER");
|
||||||
|
u8g2.drawXBMP(6, 4, 42, 56, logo);
|
||||||
|
u8g2.setFont(u8g2_font_profont11_tr);
|
||||||
|
u8g2.drawStr(55, 35, "PKM-KC 2024");
|
||||||
|
u8g2.drawStr(55, 45, "V1.0");
|
||||||
|
u8g2.sendBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUnderConstruction(){
|
||||||
|
u8g2.clearBuffer();
|
||||||
|
u8g2.setFont(u8g2_font_profont12_tr); //8 pixel height font
|
||||||
|
u8g2.setDrawColor(1);
|
||||||
|
u8g2.drawStr(5, 35, "<Under Construction>");
|
||||||
|
u8g2.sendBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawCenteredText(const char *v, byte row, bool highlight=false, bool arrowLeft = false, bool arrowRight = false, bool horizontalLine=false){
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
int h = 12;
|
||||||
|
int w = 128;
|
||||||
|
u8g2.setFont(u8g2_font_profont12_tr); //8 pixel height font
|
||||||
|
|
||||||
|
u8g2.setDrawColor(1);
|
||||||
|
|
||||||
|
//highlight
|
||||||
|
if (highlight){
|
||||||
|
x = 0;
|
||||||
|
y = row*12;
|
||||||
|
u8g2.drawBox(x,y,w,h);
|
||||||
|
u8g2.setDrawColor(2); //set to xor
|
||||||
|
}
|
||||||
|
|
||||||
|
//text
|
||||||
|
x = (128-u8g2.getStrWidth(v)) / 2;
|
||||||
|
y = 10 + (row*12);
|
||||||
|
u8g2.drawStr(x, y, v);
|
||||||
|
|
||||||
|
if (arrowLeft){
|
||||||
|
u8g2.setFont(u8g2_font_profont12_tr); //8 pixel height font
|
||||||
|
x = 10;
|
||||||
|
u8g2.drawStr(x, y, "<");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arrowRight){
|
||||||
|
u8g2.setFont(u8g2_font_profont12_tr); //8 pixel height font
|
||||||
|
x = 108;
|
||||||
|
u8g2.drawStr(x+u8g2.getStrWidth(">"), y, ">");
|
||||||
|
}
|
||||||
|
|
||||||
|
u8g2.setDrawColor(1);
|
||||||
|
if (horizontalLine){
|
||||||
|
u8g2.drawHLine(0, y+2, 128);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawTank(int x, int y, int w, int h){
|
||||||
|
//draw rounded
|
||||||
|
u8g2.setDrawColor(1);
|
||||||
|
//u8g2.drawRBox(x, y, w, h, 4);
|
||||||
|
u8g2.drawRFrame(x, y, w, h, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawTankFilled(int x, int y, int w, int h){
|
||||||
|
//draw rounded
|
||||||
|
//u8g2.drawRBox(x, y, w, h, 4);
|
||||||
|
u8g2.setDrawColor(2); //set to xor
|
||||||
|
u8g2.drawRBox(x, y, w, h, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawTextAt(int x, int y, const char *v){
|
||||||
|
u8g2.setFont(u8g2_font_profont10_tr); //6 pixel height font
|
||||||
|
u8g2.setDrawColor(1);
|
||||||
|
u8g2.drawStr(x, y, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DrawTextAtWitdh(const char *v){
|
||||||
|
u8g2.setFont(u8g2_font_profont10_tr); //6 pixel height font
|
||||||
|
return u8g2.getStrWidth(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawFrame(int x, int y, int w, int h){
|
||||||
|
u8g2.setDrawColor(1);
|
||||||
|
u8g2.drawFrame(x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to draw a propeller
|
||||||
|
void drawPropeller(int x, int y, int diameter, float angle, bool xorMode=false) {
|
||||||
|
int radius = diameter / 2;
|
||||||
|
float radAngle = angle * (PI / 180.0); // Convert angle to radians
|
||||||
|
|
||||||
|
// Calculate positions of the blades
|
||||||
|
int x1 = x + radius * cos(radAngle);
|
||||||
|
int y1 = y + radius * sin(radAngle);
|
||||||
|
int x2 = x - radius * cos(radAngle);
|
||||||
|
int y2 = y - radius * sin(radAngle);
|
||||||
|
|
||||||
|
int x3 = x + radius * cos(radAngle + PI / 2);
|
||||||
|
int y3 = y + radius * sin(radAngle + PI / 2);
|
||||||
|
int x4 = x - radius * cos(radAngle + PI / 2);
|
||||||
|
int y4 = y - radius * sin(radAngle + PI / 2);
|
||||||
|
|
||||||
|
// Draw the blades
|
||||||
|
if (xorMode){
|
||||||
|
u8g2.setDrawColor(2);
|
||||||
|
}else{
|
||||||
|
u8g2.setDrawColor(1);
|
||||||
|
}
|
||||||
|
u8g2.drawLine(x, y, x1, y1);
|
||||||
|
u8g2.drawLine(x, y, x2, y2);
|
||||||
|
u8g2.drawLine(x, y, x3, y3);
|
||||||
|
u8g2.drawLine(x, y, x4, y4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawCircle(int x, int y, int r){
|
||||||
|
u8g2.setDrawColor(1);
|
||||||
|
u8g2.drawCircle(x,y,r);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
#define IN_SWITCH_INVERT false
|
||||||
|
#define IN_SWITCH_PULLUP false
|
||||||
|
|
||||||
|
#define IN_SWITCH_NUM 6
|
||||||
|
#define PINOUT_WATER_BANK_FLOAT_SWITCH_LOWER 26
|
||||||
|
#define PINOUT_WATER_BANK_FLOAT_SWITCH_UPPER 27
|
||||||
|
#define PINOUT_STERILIZATION_CHAMBER_FLOAT_SWITCH_LOWER 33
|
||||||
|
#define PINOUT_STERILIZATION_CHAMBER_FLOAT_SWITCH_UPPER 25
|
||||||
|
#define PINOUT_STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER 32
|
||||||
|
#define PINOUT_STERILIZED_CHAMBER_FLOAT_SWITCH_UPPER 35
|
||||||
|
|
||||||
|
#define WATER_BANK_FLOAT_SWITCH_LOWER 0
|
||||||
|
#define WATER_BANK_FLOAT_SWITCH_UPPER 1
|
||||||
|
#define STERILIZATION_CHAMBER_FLOAT_SWITCH_LOWER 2
|
||||||
|
#define STERILIZATION_CHAMBER_FLOAT_SWITCH_UPPER 3
|
||||||
|
#define STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER 4
|
||||||
|
#define STERILIZED_CHAMBER_FLOAT_SWITCH_UPPER 5
|
||||||
|
|
||||||
|
static byte IN_SWITCH_OFF = LOW;
|
||||||
|
static byte IN_SWITCH_ON = HIGH;
|
||||||
|
|
||||||
|
static int8_t inSwitchPin[IN_SWITCH_NUM] = {PINOUT_WATER_BANK_FLOAT_SWITCH_LOWER,
|
||||||
|
PINOUT_WATER_BANK_FLOAT_SWITCH_UPPER,
|
||||||
|
PINOUT_STERILIZATION_CHAMBER_FLOAT_SWITCH_LOWER,
|
||||||
|
PINOUT_STERILIZATION_CHAMBER_FLOAT_SWITCH_UPPER,
|
||||||
|
PINOUT_STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER,
|
||||||
|
PINOUT_STERILIZED_CHAMBER_FLOAT_SWITCH_UPPER
|
||||||
|
};
|
||||||
|
|
||||||
|
static byte inSwitchState[IN_SWITCH_NUM];
|
||||||
|
|
||||||
|
void ClearInSwitch(){
|
||||||
|
for (int i=0; i<IN_SWITCH_NUM; i++){
|
||||||
|
int8_t pin = inSwitchPin[i];
|
||||||
|
//if (pin>=0){
|
||||||
|
inSwitchState[i] = IN_SWITCH_OFF;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitInSwitchHandler(){
|
||||||
|
if (!IN_SWITCH_INVERT){
|
||||||
|
IN_SWITCH_OFF = LOW;
|
||||||
|
IN_SWITCH_ON = HIGH;
|
||||||
|
}else{
|
||||||
|
IN_SWITCH_OFF = LOW;
|
||||||
|
IN_SWITCH_ON = HIGH;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearInSwitch();
|
||||||
|
|
||||||
|
for (int i=0; i<IN_SWITCH_NUM; i++){
|
||||||
|
int8_t pin = inSwitchPin[i];
|
||||||
|
if ((pin>=0) && ((pin>=34 && pin<=36) || (pin==39))){
|
||||||
|
//Input only pins (should be use external pull up)
|
||||||
|
pinMode(pin, INPUT);
|
||||||
|
}else if (pin>=0){
|
||||||
|
//use internal pullup
|
||||||
|
if (IN_SWITCH_PULLUP){
|
||||||
|
pinMode(pin, INPUT_PULLUP);
|
||||||
|
}else{
|
||||||
|
pinMode(pin, INPUT_PULLDOWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RefreshInSwitchState(){
|
||||||
|
for (int i=0; i<IN_SWITCH_NUM; i++){
|
||||||
|
int8_t pin = inSwitchPin[i];
|
||||||
|
if (pin>=0){
|
||||||
|
inSwitchState[i] = digitalRead(pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetInSwitchState(byte idx){
|
||||||
|
if (idx<0 || idx>=IN_SWITCH_NUM) return false;
|
||||||
|
return (inSwitchState[idx] == IN_SWITCH_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
//used for unit test
|
||||||
|
void SetInSwitchState(byte idx, bool state){
|
||||||
|
if (idx<0 || idx>=IN_SWITCH_NUM) return;
|
||||||
|
inSwitchState[idx] = state?IN_SWITCH_ON:IN_SWITCH_OFF;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include "ConfigHandler.h"
|
||||||
|
#include "BuzzerHdlr.h"
|
||||||
|
#include "SwitchHandler.h"
|
||||||
|
#include "FloatSwitchHandler.h"
|
||||||
|
#include "ButtonRotaryHandler.h"
|
||||||
|
#include "WaterBankHandler.h"
|
||||||
|
#include "SterilizationHandler.h"
|
||||||
|
#include "DisplayHandler.h"
|
||||||
|
#include "Dashboard.h"
|
||||||
|
#include "App.h"
|
||||||
|
|
||||||
|
uint32_t switchRefreshDuration = 2000;
|
||||||
|
uint32_t switchRefreshTick = 0;
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
Serial.begin(115200);
|
||||||
|
InitSwitchHandler();
|
||||||
|
InitInSwitchHandler();
|
||||||
|
|
||||||
|
InitButtonRotaryHandler();
|
||||||
|
for(int i=0; i<2; i++){
|
||||||
|
delay(1000);
|
||||||
|
InitDisplay();
|
||||||
|
}
|
||||||
|
delay(50);
|
||||||
|
InitDisplay();
|
||||||
|
//delay(2000); //wait voltage stabilize
|
||||||
|
|
||||||
|
delay(5);
|
||||||
|
//bool b = WaterBankTestUnit();
|
||||||
|
InitApp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
// SwitchDemo();
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// checkRelay();
|
||||||
|
ButtonRotaryDebugRoutine();
|
||||||
|
|
||||||
|
AppRoutine();
|
||||||
|
|
||||||
|
//Wifi and AP routine here
|
||||||
|
//..............................
|
||||||
|
|
||||||
|
//lazy update floating switch states
|
||||||
|
if (millis()-switchRefreshTick>switchRefreshDuration){
|
||||||
|
switchRefreshTick = millis();
|
||||||
|
RefreshInSwitchState();
|
||||||
|
}
|
||||||
|
|
||||||
|
WaterBankSystemRoutine();
|
||||||
|
ChamberSystemRoutine();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
const int numDrops = 8; // Number of raindrops
|
||||||
|
|
||||||
|
// Structure to store raindrop positions
|
||||||
|
struct Raindrop {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Array to store raindrops
|
||||||
|
Raindrop drops[numDrops];
|
||||||
|
|
||||||
|
// Function to initialize raindrops within the specified area
|
||||||
|
void initRaindrops(int w, int h) {
|
||||||
|
for (int i = 0; i < numDrops; i++) {
|
||||||
|
//mod for like waterfall from right side
|
||||||
|
drops[i].x = random(0, w);
|
||||||
|
drops[i].y = random(0, h);
|
||||||
|
if ((drops[i].y<(w/2)) && (drops[i].x<(w/2)) ){
|
||||||
|
drops[i].x = random(w/2, w);
|
||||||
|
drops[i].y = random(w/2, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to update raindrop positions within the specified area
|
||||||
|
void updateRaindrops(int w, int h) {
|
||||||
|
for (int i = 0; i < numDrops; i++) {
|
||||||
|
//drops[i].y += random(1, 4); // Update y position
|
||||||
|
drops[i].y += random(1, 3); // Update y position. 2 more looks like water from pipe
|
||||||
|
if (drops[i].y >= h) { // Reset position if it goes out of bounds
|
||||||
|
drops[i].x = random(0, w);
|
||||||
|
drops[i].y = 0;
|
||||||
|
if ((drops[i].y<(w/2)) && (drops[i].x<(w/2)) ){
|
||||||
|
drops[i].x = random(w/2, w);
|
||||||
|
drops[i].y = random(w/2, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to draw raindrops within the specified area
|
||||||
|
void drawRaindrops(int x, int y) {
|
||||||
|
for (int i = 0; i < numDrops; i++) {
|
||||||
|
u8g2.drawPixel(drops[i].x+x, drops[i].y+y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to animate rain with keyframes, position, and size
|
||||||
|
void animateRain(int keyframes, int x, int y, int w, int h) {
|
||||||
|
for (int frame = 0; frame < keyframes; frame++) {
|
||||||
|
//u8g2.clearBuffer();
|
||||||
|
drawRaindrops(x, y);
|
||||||
|
//u8g2.sendBuffer();
|
||||||
|
updateRaindrops(w, h);
|
||||||
|
//delay(100); // Adjust delay for animation speed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,629 @@
|
||||||
|
//Sterilization Chamber => Tank 2, used for sterilizing the water
|
||||||
|
// -> Handle the Sterilization Chamber and Post UV on storage
|
||||||
|
// -> Dependency: water bank's float switch Low and High
|
||||||
|
// chamber's float switch Low and High
|
||||||
|
// storage's float switch Low and High
|
||||||
|
|
||||||
|
#define CHAMBER_STATE_NONE 0
|
||||||
|
#define CHAMBER_STATE_IDLE 1
|
||||||
|
#define CHAMBER_STATE_START_FILLING 2
|
||||||
|
#define CHAMBER_STATE_CHECK_FILLING_TO_LOWER 3
|
||||||
|
#define CHAMBER_STATE_CHECK_FILLING_TO_UPPER 4
|
||||||
|
#define CHAMBER_STATE_STERILIZING 5
|
||||||
|
#define CHAMBER_STATE_START_UNLOAD 6
|
||||||
|
#define CHAMBER_STATE_START_UNLOAD_TO_LOWER 7
|
||||||
|
#define CHAMBER_STATE_START_UNLOAD_TO_UPPER 8
|
||||||
|
|
||||||
|
//uint32_t chamberSterilizationOzoneDuration = 1*60*1000;
|
||||||
|
uint32_t chamberSterilizationUvDuration = 5*60*1000;
|
||||||
|
//uint32_t chamberSterilizationPostUvDuration = 5*60*1000;
|
||||||
|
|
||||||
|
uint32_t chamberExpectedTimeToFilledLower = 1*60*1000;//in mulliseconds
|
||||||
|
uint32_t chamberExpectedTimeToFilledUpper = 3*60*1000;//in mulliseconds
|
||||||
|
uint32_t chamberExpectedTimeToUnloadFilledLower = 1*60*1000;//in mulliseconds
|
||||||
|
uint32_t chamberExpectedTimeToUnloadFilledUpper = 3*60*1000;//in mulliseconds
|
||||||
|
uint32_t chamberTick = 0;
|
||||||
|
bool chamberPostUvEnable = true;
|
||||||
|
uint32_t chamberPostUvDuration = 1*60*1000;
|
||||||
|
uint32_t chamberPostUvTick = 0;
|
||||||
|
uint32_t chamberInverterStartupTick = 0;
|
||||||
|
|
||||||
|
int chamberState = WATER_BANK_STATE_NONE;
|
||||||
|
bool chamberAutomatic = false;
|
||||||
|
|
||||||
|
#define CHAMBER_ERROR_NONE 0
|
||||||
|
#define CHAMBER_ERROR_LOWER_FLOAT_SWITCH 1 //lower switch error
|
||||||
|
#define CHAMBER_ERROR_UPPER_FLOAT_SWITCH 2 //upper switch error
|
||||||
|
#define CHAMBER_ERROR_UPPER_FLOAT_SWITCH_OR_NO_WATER 3
|
||||||
|
#define CHAMBER_ERROR_LOWER_FLOAT_SWITCH_OR_NO_WATER 4
|
||||||
|
#define CHAMBER_ERROR_STORAGE_LOWER_FLOAT_SWITCH 5 //lower switch error
|
||||||
|
#define CHAMBER_ERROR_STORAGE_UPPER_FLOAT_SWITCH 6 //upper switch error
|
||||||
|
#define CHAMBER_ERROR_STORAGE_UPPER_FLOAT_SWITCH_OR_NO_WATER 7
|
||||||
|
#define CHAMBER_ERROR_STORAGE_LOWER_FLOAT_SWITCH_OR_NO_WATER 8
|
||||||
|
#define CHAMBER_ERROR_TANK_LOWER_FLOAT_SWITCH 9 //lower switch error
|
||||||
|
#define CHAMBER_ERROR_TANK_UPPER_FLOAT_SWITCH 10 //upper switch error
|
||||||
|
#define CHAMBER_ERROR_TANK_UPPER_FLOAT_SWITCH_OR_NO_WATER 11
|
||||||
|
#define CHAMBER_ERROR_TANK_LOWER_FLOAT_SWITCH_OR_NO_WATER 12
|
||||||
|
#define CHAMBER_ERROR_LOWER_FLOAT_SWITCH_OR_LEAKED 13
|
||||||
|
|
||||||
|
bool chamberError = false;
|
||||||
|
byte chamberErrorCode = CHAMBER_ERROR_NONE;
|
||||||
|
String chamberErrorString = "";
|
||||||
|
|
||||||
|
//penampungan hasil sterilisasi (tank 3)
|
||||||
|
bool chamber_SterilizedLowerFloatSwitchStateCurrent = false;
|
||||||
|
bool chamber_SterilizedLowerFloatSwitchStatePrevious = false;
|
||||||
|
bool chamber_SterilizedUpperFloatSwitchStateCurrent = false;
|
||||||
|
bool chamber_SterilizedUpperFloatSwitchStatePrevious = false;
|
||||||
|
//ruang sterilisasi
|
||||||
|
bool chamber_SterilizationLowerFloatSwitchStateCurrent = false;
|
||||||
|
bool chamber_SterilizationLowerFloatSwitchStatePrevious = false;
|
||||||
|
bool chamber_SterilizationUpperFloatSwitchStateCurrent = false;
|
||||||
|
bool chamber_SterilizationUpperFloatSwitchStatePrevious = false;
|
||||||
|
//water tank sebelum sterilisasi
|
||||||
|
bool chamber_TankLowerFloatSwitchStateCurrent = false;
|
||||||
|
bool chamber_TankLowerFloatSwitchStatePrevious = false;
|
||||||
|
bool chamber_TankUpperFloatSwitchStateCurrent = false;
|
||||||
|
bool chamber_TankUpperFloatSwitchStatePrevious = false;
|
||||||
|
|
||||||
|
bool chamberSterilizationSuccess = false;
|
||||||
|
|
||||||
|
uint32_t GetSterilizationRemainingMillis(){
|
||||||
|
uint32_t t = 0;
|
||||||
|
if (chamberState==CHAMBER_STATE_STERILIZING){
|
||||||
|
t = (chamberSterilizationOzoneDuration - (millis()-chamberTick));
|
||||||
|
if (t>chamberSterilizationOzoneDuration) t = 0;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetSwitchState(STERILIZED_UV_SWITCH)){
|
||||||
|
t = chamberPostUvDuration - (millis()-chamberPostUvTick);
|
||||||
|
if (t>chamberPostUvDuration) t = 0;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnOzoneStrelization(){
|
||||||
|
if (GetSwitchState(STERILIZATION_OZONE_AND_UV_SWITCH)) return true;
|
||||||
|
return (chamberState==CHAMBER_STATE_STERILIZING);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnPostUV(){
|
||||||
|
if (GetSwitchState(STERILIZED_UV_SWITCH)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsChamberFilling(){
|
||||||
|
return (chamberState>=CHAMBER_STATE_START_FILLING) && (chamberState<=CHAMBER_STATE_CHECK_FILLING_TO_UPPER);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsChamberUnload(){
|
||||||
|
return (chamberState>=CHAMBER_STATE_START_UNLOAD) && (chamberState<=CHAMBER_STATE_START_UNLOAD_TO_UPPER);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChamberIsSuccess(){
|
||||||
|
return chamberSterilizationSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChamberIsError(){
|
||||||
|
return chamberError;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ChamberErrorString(){
|
||||||
|
if (chamberError) return chamberErrorString;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChamberIsIdle(){
|
||||||
|
return (chamberState==CHAMBER_STATE_IDLE) || (chamberState==WATER_BANK_STATE_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsChamberSystemRunning(){
|
||||||
|
if (GetSwitchState(STERILIZATION_OZONE_AND_UV_SWITCH) || GetSwitchState(INVERTER_SWITCH)) return true;
|
||||||
|
if (!chamberAutomatic) return (chamberState!=WATER_BANK_STATE_NONE);
|
||||||
|
return (chamberState>CHAMBER_STATE_IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearChamberError(){
|
||||||
|
chamberError = false;
|
||||||
|
chamberErrorCode = CHAMBER_ERROR_NONE;
|
||||||
|
chamberErrorString = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChamberTurnOffAllSwitch(bool exceptInverterAndPostUv=true){
|
||||||
|
//make sure ozone, cycling pump, fill in pump, fill out pump, uv1, uv2 is off
|
||||||
|
//inverter
|
||||||
|
if (!exceptInverterAndPostUv){
|
||||||
|
if (GetSwitchState(INVERTER_SWITCH)){
|
||||||
|
Serial.println("ChamberSystemRoutine: INVERTER_SWITCH OFF");
|
||||||
|
SetSwitchState(INVERTER_SWITCH, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//ozone
|
||||||
|
if (GetSwitchState(STERILIZATION_OZONE_AND_UV_SWITCH)){
|
||||||
|
Serial.println("ChamberSystemRoutine: STERILIZATION_OZONE_AND_UV_SWITCH OFF");
|
||||||
|
SetSwitchState(STERILIZATION_OZONE_AND_UV_SWITCH, false);
|
||||||
|
}
|
||||||
|
//post uv
|
||||||
|
if (!exceptInverterAndPostUv){
|
||||||
|
if (GetSwitchState(STERILIZED_UV_SWITCH)){
|
||||||
|
Serial.println("ChamberSystemRoutine: ");
|
||||||
|
SetSwitchState(STERILIZED_UV_SWITCH, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//fill in pump
|
||||||
|
if (GetSwitchState(STERILIZATION_CHAMBER_FILL_PUMP_SWITCH)){
|
||||||
|
Serial.println("ChamberSystemRoutine: STERILIZATION_CHAMBER_FILL_PUMP_SWITCH OFF");
|
||||||
|
SetSwitchState(STERILIZATION_CHAMBER_FILL_PUMP_SWITCH, false);
|
||||||
|
}
|
||||||
|
//fill out pump
|
||||||
|
if (GetSwitchState(STERILIZED_CHAMBER_FILL_PUMP_SWITCH)){
|
||||||
|
Serial.println("ChamberSystemRoutine: STERILIZED_CHAMBER_FILL_PUMP_SWITCH OFF");
|
||||||
|
SetSwitchState(STERILIZED_CHAMBER_FILL_PUMP_SWITCH, false);
|
||||||
|
}
|
||||||
|
//circulation pump
|
||||||
|
if (GetSwitchState(STERILIZATION_CHAMBER_CIRCULATION_PUMP_SWITCH)){
|
||||||
|
Serial.println("ChamberSystemRoutine: STERILIZATION_CHAMBER_CIRCULATION_PUMP_SWITCH OFF");
|
||||||
|
SetSwitchState(STERILIZATION_CHAMBER_CIRCULATION_PUMP_SWITCH, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//system running state =====================================================
|
||||||
|
void ChamberSystemRoutine(){
|
||||||
|
|
||||||
|
//handle the post uv timer independently ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
bool ctrlLowerSwitchState = GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
if ((!ctrlLowerSwitchState) || ((GetSwitchState(STERILIZED_UV_SWITCH) && (millis()-chamberPostUvTick)>=chamberPostUvDuration)) || (!chamberPostUvEnable)){
|
||||||
|
if (GetSwitchState(STERILIZED_UV_SWITCH)){
|
||||||
|
Serial.println("ChamberSystemRoutine: ");
|
||||||
|
SetSwitchState(STERILIZED_UV_SWITCH, false);
|
||||||
|
}
|
||||||
|
//if ((chamberState==CHAMBER_STATE_NONE) || (chamberState==CHAMBER_STATE_IDLE) || ((chamberState>=CHAMBER_STATE_START_FILLING) && (chamberState<=CHAMBER_STATE_START_FILLING_TO_UPPER))){
|
||||||
|
if (chamberState==CHAMBER_STATE_NONE){
|
||||||
|
//ChamberTurnOffAllSwitch(false);//turn off all
|
||||||
|
}else if ((chamberState!=CHAMBER_STATE_NONE) && (chamberState!=CHAMBER_STATE_STERILIZING)){
|
||||||
|
SetSwitchState(STERILIZED_UV_SWITCH, false);//turn off post uv
|
||||||
|
SetSwitchState(INVERTER_SWITCH, false);//turn off inverter
|
||||||
|
//ChamberTurnOffAllSwitch(false);//turn off all
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
switch(chamberState){
|
||||||
|
case CHAMBER_STATE_NONE:{
|
||||||
|
ChamberTurnOffAllSwitch(true);
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case CHAMBER_STATE_IDLE:{
|
||||||
|
//this is the state when use automatic mode
|
||||||
|
ChamberTurnOffAllSwitch(true); //except inverter if post uv if running
|
||||||
|
|
||||||
|
//in case mismatch, prevent auto monitoring
|
||||||
|
if (!chamberAutomatic){
|
||||||
|
chamberState = CHAMBER_STATE_NONE;
|
||||||
|
Serial.println("CHAMBER_STATE_IDLE -> CHAMBER_STATE_NONE");
|
||||||
|
}
|
||||||
|
|
||||||
|
//trigger condition:
|
||||||
|
// state => STORAGE_STATE_CHECK_IF_EMPTY: sterilized bank is empty
|
||||||
|
chamber_SterilizedLowerFloatSwitchStateCurrent = GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
bool intoFilling = false;
|
||||||
|
if ((chamber_SterilizedLowerFloatSwitchStateCurrent!=chamber_SterilizedLowerFloatSwitchStatePrevious) && (!chamber_SterilizedLowerFloatSwitchStateCurrent)){
|
||||||
|
intoFilling = true;
|
||||||
|
Serial.println("CHAMBER_STATE_IDLE -> Trigger reason: Storage empty");
|
||||||
|
}
|
||||||
|
//storage kosong dan water tank menjadi penuh
|
||||||
|
chamber_TankLowerFloatSwitchStateCurrent = GetInSwitchState(WATER_BANK_FLOAT_SWITCH_LOWER);
|
||||||
|
chamber_TankUpperFloatSwitchStateCurrent = GetInSwitchState(WATER_BANK_FLOAT_SWITCH_UPPER);
|
||||||
|
if (!chamber_SterilizedLowerFloatSwitchStateCurrent && (chamber_TankUpperFloatSwitchStateCurrent!=chamber_TankUpperFloatSwitchStatePrevious) && (chamber_TankUpperFloatSwitchStateCurrent && chamber_TankLowerFloatSwitchStateCurrent)){
|
||||||
|
intoFilling = true;
|
||||||
|
//Serial.println("Tank baru penuh dan pemampungan sterilisasi kosong.");
|
||||||
|
Serial.println("CHAMBER_STATE_IDLE -> Trigger reason: Storage empty and Water Tank just full");
|
||||||
|
}
|
||||||
|
//update state
|
||||||
|
chamber_SterilizedLowerFloatSwitchStatePrevious = chamber_SterilizedLowerFloatSwitchStateCurrent;
|
||||||
|
chamber_TankLowerFloatSwitchStatePrevious = chamber_TankLowerFloatSwitchStateCurrent;
|
||||||
|
chamber_TankUpperFloatSwitchStatePrevious = chamber_TankUpperFloatSwitchStateCurrent;
|
||||||
|
if (intoFilling){
|
||||||
|
chamberSterilizationSuccess = false;
|
||||||
|
ClearChamberError();
|
||||||
|
chamberState = CHAMBER_STATE_START_FILLING;
|
||||||
|
Serial.println("CHAMBER_STATE_IDLE -> CHAMBER_STATE_START_FILLING");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case CHAMBER_STATE_START_FILLING:{
|
||||||
|
chamberSterilizationSuccess = false;
|
||||||
|
chamber_SterilizedLowerFloatSwitchStateCurrent = GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
chamber_SterilizedUpperFloatSwitchStateCurrent = GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_UPPER);
|
||||||
|
//cek error lain dari float switch:
|
||||||
|
// -> storage switch upper lower harus benar
|
||||||
|
// -> tank switch upper lower harus benar (water tank penuh)
|
||||||
|
|
||||||
|
//cek penampungan harus kosong
|
||||||
|
if (chamber_SterilizedLowerFloatSwitchStateCurrent){
|
||||||
|
//switch back to idle
|
||||||
|
chamberError = true;
|
||||||
|
chamberErrorString = "Penampungan harus kosong dahulu untuk memulai sterilisasi.";
|
||||||
|
chamberState = CHAMBER_STATE_IDLE;
|
||||||
|
Serial.print("Error: ");
|
||||||
|
Serial.println(chamberErrorString);
|
||||||
|
Serial.println("CHAMBER_STATE_START_FILLING -> CHAMBER_STATE_IDLE");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//check if: full -> CHAMBER_STATE_STERILIZING
|
||||||
|
// empty -> CHAMBER_STATE_CHECK_FILLING_TO_LOWER
|
||||||
|
// lower -> CHAMBER_STATE_CHECK_FILLING_TO_UPPER
|
||||||
|
//jika chamber penuh langsung ke sterilisasi
|
||||||
|
chamber_SterilizationLowerFloatSwitchStateCurrent = GetInSwitchState(STERILIZATION_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
chamber_SterilizationUpperFloatSwitchStateCurrent = GetInSwitchState(STERILIZATION_CHAMBER_FLOAT_SWITCH_UPPER);
|
||||||
|
if (chamber_SterilizationLowerFloatSwitchStateCurrent && chamber_SterilizationUpperFloatSwitchStateCurrent){
|
||||||
|
chamberTick = millis();
|
||||||
|
chamberState = CHAMBER_STATE_STERILIZING;
|
||||||
|
Serial.println("Sterilization chamber already full.");
|
||||||
|
Serial.println("CHAMBER_STATE_START_FILLING -> CHAMBER_STATE_STERILIZING");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
chamber_TankLowerFloatSwitchStateCurrent = GetInSwitchState(WATER_BANK_FLOAT_SWITCH_LOWER);
|
||||||
|
chamber_TankUpperFloatSwitchStateCurrent = GetInSwitchState(WATER_BANK_FLOAT_SWITCH_UPPER);
|
||||||
|
Serial.print("Water Tank lower float switch: "); Serial.println(chamber_TankLowerFloatSwitchStateCurrent);
|
||||||
|
Serial.print("Water Tank upper float switch: "); Serial.println(chamber_TankUpperFloatSwitchStateCurrent);
|
||||||
|
//tank penampung harus penuh dulu baru mau dong
|
||||||
|
if (chamber_TankLowerFloatSwitchStateCurrent && chamber_TankUpperFloatSwitchStateCurrent){
|
||||||
|
//cek jika chamber kosong total
|
||||||
|
if (!chamber_SterilizationLowerFloatSwitchStateCurrent && !chamber_SterilizationUpperFloatSwitchStateCurrent){
|
||||||
|
//kosong total
|
||||||
|
chamberTick = millis();
|
||||||
|
chamberState = CHAMBER_STATE_CHECK_FILLING_TO_LOWER;
|
||||||
|
Serial.println("CHAMBER_STATE_START_FILLING -> CHAMBER_STATE_CHECK_FILLING_TO_LOWER");
|
||||||
|
}else if (chamber_SterilizationLowerFloatSwitchStateCurrent && !chamber_SterilizationUpperFloatSwitchStateCurrent){
|
||||||
|
//ada sedikit, mayan
|
||||||
|
chamberTick = millis();
|
||||||
|
chamberState = CHAMBER_STATE_CHECK_FILLING_TO_UPPER;
|
||||||
|
Serial.println("CHAMBER_STATE_START_FILLING -> CHAMBER_STATE_CHECK_FILLING_TO_UPPER");
|
||||||
|
}else{
|
||||||
|
//float switch error ini hadeh
|
||||||
|
chamberError = true;
|
||||||
|
chamberErrorString = "Float switch sterilisasi error.";
|
||||||
|
chamberState = CHAMBER_STATE_IDLE;
|
||||||
|
Serial.print("Error: ");
|
||||||
|
Serial.println(chamberErrorString);
|
||||||
|
Serial.println("CHAMBER_STATE_START_FILLING -> CHAMBER_STATE_IDLE");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
chamberError = true;
|
||||||
|
chamberErrorString = "Tangki penampung air harus penuh dahulu untuk dapat memulai pengisian tangki sterilisasi.";
|
||||||
|
Serial.print("Error: ");
|
||||||
|
Serial.println(chamberErrorString);
|
||||||
|
if (chamberAutomatic){
|
||||||
|
chamberState = CHAMBER_STATE_IDLE;
|
||||||
|
Serial.println("CHAMBER_STATE_START_FILLING -> CHAMBER_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
chamberState = CHAMBER_STATE_NONE;
|
||||||
|
Serial.println("CHAMBER_STATE_START_FILLING -> CHAMBER_STATE_NONE");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case CHAMBER_STATE_CHECK_FILLING_TO_LOWER:{
|
||||||
|
//waiting for filling into lower level, or stop when timeout
|
||||||
|
//switch on the pump
|
||||||
|
if (!GetSwitchState(STERILIZATION_CHAMBER_FILL_PUMP_SWITCH)){
|
||||||
|
Serial.println("ChamberSystemRoutine: TURN ON FILL PUMP SWITCH");
|
||||||
|
SetSwitchState(STERILIZATION_CHAMBER_FILL_PUMP_SWITCH, true);
|
||||||
|
}
|
||||||
|
//monitoring water level or timed out
|
||||||
|
bool lowerSwitchState = GetInSwitchState(STERILIZATION_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
bool upperSwitchState = GetInSwitchState(STERILIZATION_CHAMBER_FLOAT_SWITCH_UPPER);
|
||||||
|
//chamber_TankLowerFloatSwitchStateCurrent = GetInSwitchState(WATER_BANK_FLOAT_SWITCH_LOWER);
|
||||||
|
//if (lowerSwitchState || upperSwitchState || !chamber_TankLowerFloatSwitchStateCurrent){
|
||||||
|
if (lowerSwitchState || upperSwitchState){
|
||||||
|
//check if lower float switch on
|
||||||
|
//try to fill till full
|
||||||
|
ClearChamberError();
|
||||||
|
chamberTick = millis();
|
||||||
|
chamberState = CHAMBER_STATE_CHECK_FILLING_TO_UPPER;
|
||||||
|
Serial.println("CHAMBER_STATE_CHECK_FILLING_TO_LOWER -> CHAMBER_STATE_CHECK_FILLING_TO_UPPER");
|
||||||
|
}else{
|
||||||
|
//check if timed out
|
||||||
|
if (millis()-chamberTick>=chamberExpectedTimeToFilledLower){
|
||||||
|
chamberError = true;
|
||||||
|
chamberErrorCode = CHAMBER_ERROR_LOWER_FLOAT_SWITCH;
|
||||||
|
chamberErrorString = "Tank 2 insufficient input water, or lower float switch error, or input pump error.";
|
||||||
|
Serial.println("Chamber Error -> CHAMBER_ERROR_LOWER_FLOAT_SWITCH");
|
||||||
|
if (chamberAutomatic){
|
||||||
|
chamberState = CHAMBER_STATE_IDLE;
|
||||||
|
Serial.println("CHAMBER_STATE_CHECK_FILLING_TO_LOWER -> CHAMBER_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
chamberState = CHAMBER_STATE_NONE;
|
||||||
|
Serial.println("CHAMBER_STATE_CHECK_FILLING_TO_LOWER -> CHAMBER_STATE_NONE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case CHAMBER_STATE_CHECK_FILLING_TO_UPPER:{
|
||||||
|
//waiting for filling into lower level, or stop when timeout
|
||||||
|
//switch on the pump
|
||||||
|
if (!GetSwitchState(STERILIZATION_CHAMBER_FILL_PUMP_SWITCH)){
|
||||||
|
Serial.println("ChamberSystemRoutine: TURN ON FILL PUMP SWITCH");
|
||||||
|
SetSwitchState(STERILIZATION_CHAMBER_FILL_PUMP_SWITCH, true);
|
||||||
|
}
|
||||||
|
//monitoring water level or timed out
|
||||||
|
bool upperSwitchState = GetInSwitchState(STERILIZATION_CHAMBER_FLOAT_SWITCH_UPPER);
|
||||||
|
chamber_TankLowerFloatSwitchStateCurrent = GetInSwitchState(WATER_BANK_FLOAT_SWITCH_LOWER);
|
||||||
|
if (upperSwitchState || (!chamber_TankLowerFloatSwitchStateCurrent)){
|
||||||
|
//check if upper float switch on or chamber's water below switch
|
||||||
|
SetSwitchState(STERILIZATION_CHAMBER_FILL_PUMP_SWITCH, false); //matiin pompa
|
||||||
|
ClearChamberError();
|
||||||
|
chamberTick = millis();
|
||||||
|
chamberState = CHAMBER_STATE_STERILIZING;
|
||||||
|
Serial.println("CHAMBER_STATE_CHECK_FILLING_TO_UPPER -> CHAMBER_STATE_STERILIZING");
|
||||||
|
}else{
|
||||||
|
//check if timed out
|
||||||
|
if (millis()-chamberTick>=chamberExpectedTimeToFilledUpper){
|
||||||
|
SetSwitchState(STERILIZATION_CHAMBER_FILL_PUMP_SWITCH, false); //matiin pompa
|
||||||
|
chamberError = true;
|
||||||
|
chamberErrorCode = CHAMBER_ERROR_UPPER_FLOAT_SWITCH;
|
||||||
|
chamberErrorString = "Tank 2 insufficient input water, or upper float switch error, or input pump error.";
|
||||||
|
Serial.println("Chamber Error -> CHAMBER_ERROR_UPPER_FLOAT_SWITCH");
|
||||||
|
if (chamberAutomatic){
|
||||||
|
chamberState = CHAMBER_STATE_IDLE;
|
||||||
|
Serial.println("CHAMBER_STATE_CHECK_FILLING_TO_UPPER -> CHAMBER_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
chamberState = CHAMBER_STATE_NONE;
|
||||||
|
Serial.println("CHAMBER_STATE_CHECK_FILLING_TO_UPPER -> CHAMBER_STATE_NONE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case CHAMBER_STATE_STERILIZING:{
|
||||||
|
//make sure turn off filling in and filling out pump
|
||||||
|
if (GetSwitchState(STERILIZATION_CHAMBER_FILL_PUMP_SWITCH)) SetSwitchState(STERILIZATION_CHAMBER_FILL_PUMP_SWITCH, false);
|
||||||
|
if (GetSwitchState(STERILIZED_CHAMBER_FILL_PUMP_SWITCH)) SetSwitchState(STERILIZED_CHAMBER_FILL_PUMP_SWITCH, false);
|
||||||
|
//if inverter not turned -> switch it first, but wait for 2 seconds
|
||||||
|
if (!GetSwitchState(INVERTER_SWITCH)){
|
||||||
|
//make sure turn off ozone and circulation
|
||||||
|
if (GetSwitchState(STERILIZATION_OZONE_AND_UV_SWITCH)) SetSwitchState(STERILIZATION_OZONE_AND_UV_SWITCH, false);
|
||||||
|
if (GetSwitchState(STERILIZATION_CHAMBER_CIRCULATION_PUMP_SWITCH)) SetSwitchState(STERILIZATION_CHAMBER_CIRCULATION_PUMP_SWITCH, false);
|
||||||
|
chamberInverterStartupTick = millis();
|
||||||
|
SetSwitchState(INVERTER_SWITCH, true);
|
||||||
|
Serial.println("Starting up the inveter.");
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
if ((millis()-chamberInverterStartupTick)<2000){
|
||||||
|
chamberTick = millis(); //keep reset it
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//turn on ozone and circulation pump
|
||||||
|
if (!GetSwitchState(STERILIZATION_OZONE_AND_UV_SWITCH)) SetSwitchState(STERILIZATION_OZONE_AND_UV_SWITCH, true);
|
||||||
|
if (!GetSwitchState(STERILIZATION_CHAMBER_CIRCULATION_PUMP_SWITCH)) SetSwitchState(STERILIZATION_CHAMBER_CIRCULATION_PUMP_SWITCH, true);
|
||||||
|
|
||||||
|
//wait till done, or if water is empty by accident (leaking) => back to idle with error state
|
||||||
|
bool lowerSwitchState = GetInSwitchState(STERILIZATION_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
if (!lowerSwitchState){
|
||||||
|
//wah error atau bocor nih
|
||||||
|
ChamberTurnOffAllSwitch(false); //turn off all switch including inverter
|
||||||
|
chamberError = true;
|
||||||
|
chamberErrorCode = CHAMBER_ERROR_LOWER_FLOAT_SWITCH_OR_LEAKED;
|
||||||
|
chamberErrorString = "Tank 2 leaked, or lower float switch error";
|
||||||
|
Serial.print("Error: ");
|
||||||
|
Serial.println(chamberErrorString);;
|
||||||
|
chamberState = CHAMBER_STATE_NONE;
|
||||||
|
Serial.println("CHAMBER_STATE_STERILIZING -> CHAMBER_STATE_NONE");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//tunggu hingga selesai sterilisasi
|
||||||
|
if ((millis()-chamberTick)>=chamberSterilizationOzoneDuration){
|
||||||
|
chamberPostUvTick = millis();//reset uv post tick too
|
||||||
|
bool keepInverter = chamberPostUvEnable && (chamberPostUvDuration>0);
|
||||||
|
ChamberTurnOffAllSwitch(keepInverter);
|
||||||
|
chamberTick = millis(); //keep reset it
|
||||||
|
chamberState = CHAMBER_STATE_START_UNLOAD;
|
||||||
|
Serial.println("CHAMBER_STATE_STERILIZING -> CHAMBER_STATE_START_UNLOAD");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case CHAMBER_STATE_START_UNLOAD:{
|
||||||
|
bool lowerSwitchState = GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
bool upperSwitchState = GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
chamberTick = millis(); //reset it
|
||||||
|
if (!lowerSwitchState && !upperSwitchState){
|
||||||
|
//fill to lower first
|
||||||
|
chamberState = CHAMBER_STATE_START_UNLOAD_TO_LOWER;
|
||||||
|
Serial.println("CHAMBER_STATE_START_UNLOAD -> CHAMBER_STATE_START_UNLOAD_TO_LOWER");
|
||||||
|
}else if (lowerSwitchState && !upperSwitchState){
|
||||||
|
//fill to upper
|
||||||
|
chamberState = CHAMBER_STATE_START_UNLOAD_TO_UPPER;
|
||||||
|
Serial.println("CHAMBER_STATE_START_UNLOAD -> CHAMBER_STATE_START_UNLOAD_TO_UPPER");
|
||||||
|
}else if (lowerSwitchState && upperSwitchState){
|
||||||
|
//already full
|
||||||
|
ChamberTurnOffAllSwitch(false); //turn off all switch including inverter
|
||||||
|
if (chamberAutomatic){
|
||||||
|
chamberState = CHAMBER_STATE_IDLE;
|
||||||
|
Serial.println("CHAMBER_STATE_START_UNLOAD -> CHAMBER_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
chamberState = CHAMBER_STATE_NONE;
|
||||||
|
Serial.println("CHAMBER_STATE_START_UNLOAD -> CHAMBER_STATE_NONE");
|
||||||
|
}
|
||||||
|
chamberSterilizationSuccess = true;
|
||||||
|
}else{
|
||||||
|
//float switch error
|
||||||
|
ChamberTurnOffAllSwitch(false); //turn off all switch including inverter
|
||||||
|
chamberError = true;
|
||||||
|
chamberErrorCode = CHAMBER_ERROR_STORAGE_LOWER_FLOAT_SWITCH;
|
||||||
|
chamberErrorString = "Tank 3 float switch error";
|
||||||
|
Serial.print("Error: ");
|
||||||
|
Serial.println(chamberErrorString);;
|
||||||
|
chamberState = CHAMBER_STATE_NONE;
|
||||||
|
Serial.println("CHAMBER_STATE_START_UNLOAD -> CHAMBER_STATE_NONE");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//switch post uv when it reach at least lowest level and used
|
||||||
|
if (chamberPostUvEnable && lowerSwitchState){
|
||||||
|
chamberPostUvTick = millis();//reset uv post tick too
|
||||||
|
if (chamberPostUvEnable && (chamberPostUvDuration>0)){
|
||||||
|
//turn on uv
|
||||||
|
SetSwitchState(STERILIZED_UV_SWITCH, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case CHAMBER_STATE_START_UNLOAD_TO_LOWER:{
|
||||||
|
//switch on the pump
|
||||||
|
if (!GetSwitchState(STERILIZED_CHAMBER_FILL_PUMP_SWITCH)){
|
||||||
|
Serial.println("ChamberSystemRoutine: TURN ON OUT PUMP SWITCH");
|
||||||
|
SetSwitchState(STERILIZED_CHAMBER_FILL_PUMP_SWITCH, true);
|
||||||
|
}
|
||||||
|
bool lowerSwitchState = GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
bool upperSwitchState = GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_UPPER);
|
||||||
|
if (lowerSwitchState || upperSwitchState){
|
||||||
|
//check if lower float switch on
|
||||||
|
//try to fill till full
|
||||||
|
ClearChamberError();
|
||||||
|
chamberTick = millis();
|
||||||
|
chamberState = CHAMBER_STATE_START_UNLOAD_TO_UPPER;
|
||||||
|
Serial.println("CHAMBER_STATE_START_UNLOAD_TO_LOWER -> CHAMBER_STATE_START_UNLOAD_TO_UPPER");
|
||||||
|
}else{
|
||||||
|
//check if timed out
|
||||||
|
if (millis()-chamberTick>=chamberExpectedTimeToUnloadFilledLower){
|
||||||
|
ChamberTurnOffAllSwitch(false); //turn off all switch including inverter
|
||||||
|
chamberError = true;
|
||||||
|
chamberErrorCode = CHAMBER_ERROR_STORAGE_LOWER_FLOAT_SWITCH_OR_NO_WATER;
|
||||||
|
chamberErrorString = "Tank 2 leaked, or Tank 3 lower float switch error, or output pump error.";
|
||||||
|
Serial.println("Chamber Error -> CHAMBER_ERROR_STORAGE_LOWER_FLOAT_SWITCH_OR_NO_WATER");
|
||||||
|
if (chamberAutomatic){
|
||||||
|
chamberState = CHAMBER_STATE_IDLE;
|
||||||
|
Serial.println("CHAMBER_STATE_CHECK_FILLING_TO_LOWER -> CHAMBER_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
chamberState = CHAMBER_STATE_NONE;
|
||||||
|
Serial.println("CHAMBER_STATE_CHECK_FILLING_TO_LOWER -> CHAMBER_STATE_NONE");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//check if tank 2 empty. indicate leaking
|
||||||
|
chamber_SterilizationLowerFloatSwitchStateCurrent = GetInSwitchState(STERILIZATION_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
if (!chamber_SterilizationLowerFloatSwitchStateCurrent){
|
||||||
|
ChamberTurnOffAllSwitch(false); //turn off all switch including inverter
|
||||||
|
chamberError = true;
|
||||||
|
chamberErrorCode = CHAMBER_ERROR_LOWER_FLOAT_SWITCH;
|
||||||
|
chamberErrorString = "Tank 2 leaked or lower float switch error";
|
||||||
|
Serial.println("Chamber Error -> CHAMBER_ERROR_LOWER_FLOAT_SWITCH");
|
||||||
|
if (chamberAutomatic){
|
||||||
|
chamberState = CHAMBER_STATE_IDLE;
|
||||||
|
Serial.println("CHAMBER_STATE_CHECK_FILLING_TO_LOWER -> CHAMBER_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
chamberState = CHAMBER_STATE_NONE;
|
||||||
|
Serial.println("CHAMBER_STATE_CHECK_FILLING_TO_LOWER -> CHAMBER_STATE_NONE");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//manage post uv
|
||||||
|
if (chamberPostUvEnable && lowerSwitchState){
|
||||||
|
chamberPostUvTick = millis();//reset uv post tick too
|
||||||
|
if (chamberPostUvEnable && (chamberPostUvDuration>0)){
|
||||||
|
//turn on uv
|
||||||
|
SetSwitchState(STERILIZED_UV_SWITCH, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case CHAMBER_STATE_START_UNLOAD_TO_UPPER:{
|
||||||
|
//switch on the pump
|
||||||
|
if (!GetSwitchState(STERILIZED_CHAMBER_FILL_PUMP_SWITCH)){
|
||||||
|
Serial.println("ChamberSystemRoutine: TURN ON OUT PUMP SWITCH");
|
||||||
|
SetSwitchState(STERILIZED_CHAMBER_FILL_PUMP_SWITCH, true);
|
||||||
|
}
|
||||||
|
//manage post uv
|
||||||
|
bool lowerSwitchState = GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
if (chamberPostUvEnable && lowerSwitchState){
|
||||||
|
if (chamberPostUvEnable && (chamberPostUvDuration>0) && (!GetSwitchState(STERILIZED_UV_SWITCH) && (millis()-chamberPostUvTick<chamberPostUvDuration))){
|
||||||
|
//turn on uv but do not update the timer
|
||||||
|
SetSwitchState(STERILIZED_UV_SWITCH, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//bool lowerSwitchState = GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
bool upperSwitchState = GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_UPPER);
|
||||||
|
chamber_SterilizationLowerFloatSwitchStateCurrent = GetInSwitchState(STERILIZATION_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
if (upperSwitchState || !chamber_SterilizationLowerFloatSwitchStateCurrent){
|
||||||
|
chamberSterilizationSuccess = false; //done!
|
||||||
|
ChamberTurnOffAllSwitch(true); //turn off all switch excluding inverter
|
||||||
|
ClearChamberError();
|
||||||
|
chamberTick = millis();
|
||||||
|
if (chamberAutomatic){
|
||||||
|
chamberState = CHAMBER_STATE_IDLE;
|
||||||
|
Serial.println("CHAMBER_STATE_START_UNLOAD_TO_UPPER -> CHAMBER_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
chamberState = CHAMBER_STATE_NONE;
|
||||||
|
Serial.println("CHAMBER_STATE_START_UNLOAD_TO_UPPER -> CHAMBER_STATE_NONE");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//check if timed out
|
||||||
|
if (millis()-chamberTick>=chamberExpectedTimeToUnloadFilledUpper){
|
||||||
|
ChamberTurnOffAllSwitch(false); //turn off all switch including inverter
|
||||||
|
chamberError = true;
|
||||||
|
chamberErrorCode = CHAMBER_ERROR_STORAGE_UPPER_FLOAT_SWITCH_OR_NO_WATER;
|
||||||
|
chamberErrorString = "Tank 2 leaked, or Tank 1 upper float switch error, or output pump error.";
|
||||||
|
Serial.println("Chamber Error -> CHAMBER_ERROR_STORAGE_UPPER_FLOAT_SWITCH_OR_NO_WATER");
|
||||||
|
if (chamberAutomatic){
|
||||||
|
chamberState = CHAMBER_STATE_IDLE;
|
||||||
|
Serial.println("CHAMBER_STATE_CHECK_FILLING_TO_UPPER -> CHAMBER_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
chamberState = CHAMBER_STATE_NONE;
|
||||||
|
Serial.println("CHAMBER_STATE_CHECK_FILLING_TO_UPPER -> CHAMBER_STATE_NONE");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void StartChamberSystem(bool automatic, bool forceRunIfAutomatic = false, bool usePostUv=false){
|
||||||
|
ClearChamberError();
|
||||||
|
chamberAutomatic = automatic;
|
||||||
|
chamberPostUvEnable = usePostUv;
|
||||||
|
chamberSterilizationSuccess = false;
|
||||||
|
|
||||||
|
bool runNow = false;
|
||||||
|
|
||||||
|
if (chamberAutomatic){
|
||||||
|
RefreshInSwitchState();
|
||||||
|
chamberState = CHAMBER_STATE_IDLE;
|
||||||
|
runNow = forceRunIfAutomatic;
|
||||||
|
if (!runNow) Serial.println("StartChamberSystem -> CHAMBER_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
runNow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runNow){
|
||||||
|
RefreshInSwitchState();
|
||||||
|
chamberState = CHAMBER_STATE_START_FILLING;
|
||||||
|
Serial.println("StartChamberSystem -> CHAMBER_STATE_START_FILLING");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopChamberSystem(){
|
||||||
|
ClearChamberError();
|
||||||
|
chamberState = CHAMBER_STATE_NONE;
|
||||||
|
ChamberSystemRoutine(); //call it once
|
||||||
|
ChamberTurnOffAllSwitch(false);//make sure to turn off all
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChamberSetPostUvDuration(uint32_t v){
|
||||||
|
chamberPostUvDuration = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChamberSetSterlizationDuration(uint32_t v){
|
||||||
|
chamberSterilizationOzoneDuration = v;
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
#define SWITCH_NUM 8
|
||||||
|
#define SWITCH_INVERT true
|
||||||
|
|
||||||
|
#define PINOUT_WATER_BANK_FILL_PUMP_SWITCH 1
|
||||||
|
#define PINOUT_STERILIZATION_CHAMBER_FILL_PUMP_SWITCH 3
|
||||||
|
#define PINOUT_STERILIZATION_CHAMBER_CIRCULATION_PUMP_SWITCH 17
|
||||||
|
#define PINOUT_STERILIZED_CHAMBER_FILL_PUMP_SWITCH 16
|
||||||
|
#define PINOUT_STERILIZATION_OZONE_AND_UV_SWITCH 4
|
||||||
|
#define PINOUT_STERILIZED_UV_SWITCH 0
|
||||||
|
#define PINOUT_INVERTER_SWITCH 2
|
||||||
|
#define PINOUT_INSTRUMENTATION_SWITCH 15
|
||||||
|
|
||||||
|
static byte SWITCH_OFF = LOW;
|
||||||
|
static byte SWITCH_ON = HIGH;
|
||||||
|
|
||||||
|
static byte switchState[SWITCH_NUM];
|
||||||
|
static int8_t switchPin[SWITCH_NUM] = {PINOUT_WATER_BANK_FILL_PUMP_SWITCH,
|
||||||
|
PINOUT_STERILIZATION_CHAMBER_FILL_PUMP_SWITCH,
|
||||||
|
PINOUT_STERILIZATION_CHAMBER_CIRCULATION_PUMP_SWITCH,
|
||||||
|
PINOUT_STERILIZED_CHAMBER_FILL_PUMP_SWITCH,
|
||||||
|
PINOUT_STERILIZATION_OZONE_AND_UV_SWITCH,
|
||||||
|
PINOUT_STERILIZED_UV_SWITCH,
|
||||||
|
PINOUT_INVERTER_SWITCH,
|
||||||
|
PINOUT_INSTRUMENTATION_SWITCH}; //set -1 to mark as unused
|
||||||
|
|
||||||
|
//old code
|
||||||
|
//#define WATER_BANK_FILL_PUMP_SWITCH 0
|
||||||
|
//#define STERILIZATION_CHAMBER_FILL_PUMP_SWITCH 1
|
||||||
|
//#define STERILIZATION_CHAMBER_CIRCULATION_PUMP_SWITCH 2
|
||||||
|
//#define STERILIZED_CHAMBER_FILL_PUMP_SWITCH 3
|
||||||
|
//#define STERILIZATION_OZONE_AND_UV_SWITCH 4
|
||||||
|
//#define STERILIZED_UV_SWITCH 5 //aka post uv switch
|
||||||
|
//#define INVERTER_SWITCH 6
|
||||||
|
//#define INSTRUMENTATION_SWITCH 7 //for sensors and display power
|
||||||
|
|
||||||
|
#define WATER_BANK_FILL_PUMP_SWITCH 0
|
||||||
|
#define STERILIZATION_CHAMBER_FILL_PUMP_SWITCH 1
|
||||||
|
#define STERILIZATION_CHAMBER_CIRCULATION_PUMP_SWITCH 2
|
||||||
|
#define STERILIZED_CHAMBER_FILL_PUMP_SWITCH 3
|
||||||
|
#define STERILIZATION_OZONE_AND_UV_SWITCH 4
|
||||||
|
#define STERILIZED_UV_SWITCH 5 //aka post uv switch
|
||||||
|
#define INSTRUMENTATION_SWITCH 6 //for sensors and display power
|
||||||
|
#define INVERTER_SWITCH 7
|
||||||
|
|
||||||
|
void TurnOffAllRelay(){
|
||||||
|
for (int i=0; i<SWITCH_NUM; i++){
|
||||||
|
if (switchPin[i]>=0){
|
||||||
|
digitalWrite(switchPin[i], SWITCH_OFF);
|
||||||
|
}
|
||||||
|
switchState[i] = SWITCH_OFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitSwitchHandler(){
|
||||||
|
if (!SWITCH_INVERT){
|
||||||
|
SWITCH_OFF = LOW;
|
||||||
|
SWITCH_ON = HIGH;
|
||||||
|
}else{
|
||||||
|
SWITCH_OFF = HIGH;
|
||||||
|
SWITCH_ON = LOW;
|
||||||
|
}
|
||||||
|
Serial.println("switch init");
|
||||||
|
for (int i=0; i<SWITCH_NUM; i++){
|
||||||
|
if (switchPin[i]>=0){
|
||||||
|
pinMode(switchPin[i], OUTPUT);
|
||||||
|
digitalWrite(switchPin[i], SWITCH_OFF);
|
||||||
|
}
|
||||||
|
switchState[i] = SWITCH_OFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkRelay(){
|
||||||
|
|
||||||
|
for(int i=0; i < SWITCH_NUM; i++){
|
||||||
|
digitalWrite(PINOUT_WATER_BANK_FILL_PUMP_SWITCH, SWITCH_OFF);
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0; i<SWITCH_NUM;i++){
|
||||||
|
digitalWrite(PINOUT_WATER_BANK_FILL_PUMP_SWITCH, SWITCH_ON);
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// digitalWrite(PINOUT_WATER_BANK_FILL_PUMP_SWITCH, SWITCH_OFF);
|
||||||
|
// digitalWrite(PINOUT_STERILIZED_CHAMBER_FILL_PUMP_SWITCH, SWITCH_ON);
|
||||||
|
// delay(1000);
|
||||||
|
// digitalWrite(PINOUT_WATER_BANK_FILL_PUMP_SWITCH, SWITCH_ON);
|
||||||
|
// digitalWrite(PINOUT_STERILIZED_CHAMBER_FILL_PUMP_SWITCH, SWITCH_OFF);
|
||||||
|
// delay(1000);
|
||||||
|
|
||||||
|
// for (int i=0; i<SWITCH_NUM; i++){
|
||||||
|
// Serial.println(switchPin[i]);
|
||||||
|
// // digitalWrite(switchPin[i], SWITCH_ON);
|
||||||
|
// // delay(1000);
|
||||||
|
// digitalWrite(switchPin[i], SWITCH_OFF);
|
||||||
|
// delay(350);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetSwitchState(int idx){
|
||||||
|
if (idx<0 || idx>=SWITCH_NUM) return false;
|
||||||
|
return (switchState[idx]==SWITCH_ON?true:false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSwitchState(int idx, bool v){
|
||||||
|
if (idx<0 || idx>=SWITCH_NUM) return;
|
||||||
|
byte state = v?SWITCH_ON:SWITCH_OFF;
|
||||||
|
if (switchPin[idx]>=0) digitalWrite(switchPin[idx], state);
|
||||||
|
switchState[idx] = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
//used for unit test
|
||||||
|
void SetSwitchStateSimulated(int idx, bool v){
|
||||||
|
if (idx<0 || idx>=SWITCH_NUM) return;
|
||||||
|
byte state = v?SWITCH_ON:SWITCH_OFF;
|
||||||
|
switchState[idx] = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t swDemoT = 0;
|
||||||
|
int swx = 0;
|
||||||
|
void SwitchDemo(){
|
||||||
|
if (millis()-swDemoT<1000) return;
|
||||||
|
swDemoT = millis();
|
||||||
|
|
||||||
|
for(int i=0;i<SWITCH_NUM;i++){
|
||||||
|
SetSwitchState(i,i==swx?true:false);
|
||||||
|
}
|
||||||
|
swx++;
|
||||||
|
if (swx>=SWITCH_NUM) swx = 0;
|
||||||
|
}
|
|
@ -0,0 +1,311 @@
|
||||||
|
//Water Bank => Tank 3, used for unsterilized water storage
|
||||||
|
// -> Handle the Refill Water Bank Pump
|
||||||
|
// -> Dependency: water bank's float switch Low and High
|
||||||
|
|
||||||
|
//STERILIZATION Bank => Tank 2, used for sterilizing the water
|
||||||
|
//PURED Bank => Tank 3, used for store sterilized water
|
||||||
|
|
||||||
|
#define WATER_BANK_STATE_NONE 0
|
||||||
|
#define WATER_BANK_STATE_IDLE 1
|
||||||
|
#define WATER_BANK_STATE_START_FILLING 2
|
||||||
|
#define WATER_BANK_STATE_CHECK_FILLING_TO_LOWER 3
|
||||||
|
#define WATER_BANK_STATE_CHECK_FILLING_TO_UPPER 4
|
||||||
|
|
||||||
|
uint32_t waterBankExpectedTimeToFilledLower = 1*60*1000;//in mulliseconds
|
||||||
|
uint32_t waterBankExpectedTimeToFilledUpper = 3*60*1000;//in mulliseconds
|
||||||
|
uint32_t waterBankTick = 0;
|
||||||
|
bool waterBankSterilizationFloatSwitchStatePrevious = false;
|
||||||
|
bool waterBankSterilizationFloatSwitchStateCurrent = false;
|
||||||
|
bool waterBankSterilizedFloatSwitchStatePrevious = false;
|
||||||
|
bool waterBankSterilizedFloatSwitchStateCurrent = false;
|
||||||
|
bool waterBankFloatSwitchStatePrevious = false;
|
||||||
|
bool waterBankFloatSwitchStateCurrent = false;
|
||||||
|
bool waterBankSterilizationUpperFloatSwitchStatePrevious = false;
|
||||||
|
bool waterBankSterilizationUpperFloatSwitchStateCurrent = false;
|
||||||
|
|
||||||
|
//bool waterBankSystemIsRunning = false;//if true, water bank is starting once
|
||||||
|
//bool waterBankSystemIsAutomatic = false; //if true, it will keep check float switch for water refill
|
||||||
|
|
||||||
|
int waterBankState = WATER_BANK_STATE_NONE;
|
||||||
|
bool waterBankAutomatic = false;
|
||||||
|
|
||||||
|
#define WATER_BANK_ERROR_NONE 0
|
||||||
|
#define WATER_BANK_ERROR_LOWER_FLOAT_SWITCH 1 //lower switch error
|
||||||
|
#define WATER_BANK_ERROR_UPPER_FLOAT_SWITCH 2 //upper switch error
|
||||||
|
#define WATER_BANK_ERROR_UPPER_FLOAT_SWITCH_OR_NO_WATER 3
|
||||||
|
#define WATER_BANK_ERROR_LOWER_FLOAT_SWITCH_OR_NO_WATER 4
|
||||||
|
bool waterBankError = false;
|
||||||
|
byte waterBankErrorCode = WATER_BANK_ERROR_NONE;
|
||||||
|
String waterBankErrorString = "";
|
||||||
|
|
||||||
|
bool IsWaterBankError(){
|
||||||
|
return waterBankError;
|
||||||
|
}
|
||||||
|
|
||||||
|
String WaterBankErrorString(){
|
||||||
|
if (waterBankError) return waterBankErrorString;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsWaterBankSystemRunning(){
|
||||||
|
if (!waterBankAutomatic) return (waterBankState!=WATER_BANK_STATE_NONE);
|
||||||
|
return (waterBankState>WATER_BANK_STATE_IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearWaterBankError(){
|
||||||
|
waterBankError = false;
|
||||||
|
waterBankErrorCode = WATER_BANK_ERROR_NONE;
|
||||||
|
waterBankErrorString = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
//system running state =====================================================
|
||||||
|
void WaterBankSystemRoutine(){
|
||||||
|
switch(waterBankState){
|
||||||
|
case WATER_BANK_STATE_NONE:{
|
||||||
|
//do nothing but make sure the pump is off
|
||||||
|
if (GetSwitchState(WATER_BANK_FILL_PUMP_SWITCH)){
|
||||||
|
Serial.println("WaterBank: TURN OFF PUMP SWITCH");
|
||||||
|
SetSwitchState(WATER_BANK_FILL_PUMP_SWITCH, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case WATER_BANK_STATE_IDLE:{
|
||||||
|
if (waterBankAutomatic){
|
||||||
|
//make sure the pump is off first
|
||||||
|
if (GetSwitchState(WATER_BANK_FILL_PUMP_SWITCH)){
|
||||||
|
Serial.println("WaterBank: TURN OFF PUMP SWITCH");
|
||||||
|
SetSwitchState(WATER_BANK_FILL_PUMP_SWITCH, false);
|
||||||
|
}
|
||||||
|
//trigger condition:
|
||||||
|
// state => WATER_BANK_STATE_CHECK_IF_EMPTY: sterilization bank is empty or sterilized bank is empty or water bank is empty
|
||||||
|
waterBankFloatSwitchStateCurrent = GetInSwitchState(WATER_BANK_FLOAT_SWITCH_LOWER);
|
||||||
|
waterBankSterilizationFloatSwitchStateCurrent = GetInSwitchState(STERILIZATION_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
waterBankSterilizedFloatSwitchStateCurrent = GetInSwitchState(STERILIZED_CHAMBER_FLOAT_SWITCH_LOWER);
|
||||||
|
waterBankSterilizationUpperFloatSwitchStateCurrent = GetInSwitchState(STERILIZATION_CHAMBER_FLOAT_SWITCH_UPPER);
|
||||||
|
bool intoFillingWaterBank = false;
|
||||||
|
//check if water bank empty
|
||||||
|
if ((waterBankFloatSwitchStateCurrent!=waterBankFloatSwitchStatePrevious) && (!waterBankFloatSwitchStatePrevious)){
|
||||||
|
intoFillingWaterBank = true;
|
||||||
|
Serial.println("WaterBank -> Trigger reason: Water Bank empty");
|
||||||
|
}
|
||||||
|
//check if sterilization chamber empty
|
||||||
|
if ((waterBankSterilizationFloatSwitchStateCurrent!=waterBankSterilizationFloatSwitchStatePrevious) && (!waterBankSterilizationFloatSwitchStateCurrent)){
|
||||||
|
intoFillingWaterBank = true;
|
||||||
|
Serial.println("WaterBank -> Trigger reason: Sterilization chamber empty");
|
||||||
|
}
|
||||||
|
//check if sterilized chamber empty
|
||||||
|
if ((waterBankSterilizedFloatSwitchStateCurrent!=waterBankSterilizedFloatSwitchStatePrevious) && (!waterBankSterilizedFloatSwitchStatePrevious)){
|
||||||
|
intoFillingWaterBank = true;
|
||||||
|
Serial.println("WaterBank -> Trigger reason: Sterilized chamber empty");
|
||||||
|
}
|
||||||
|
//check if sterilization chamber just full lower switch 1, and upper switch from 1 to 0 (indicate begin to unload)
|
||||||
|
if (waterBankSterilizationFloatSwitchStateCurrent && (waterBankSterilizationUpperFloatSwitchStateCurrent!=waterBankSterilizationUpperFloatSwitchStatePrevious) && (!waterBankSterilizationUpperFloatSwitchStateCurrent)){
|
||||||
|
intoFillingWaterBank = true;
|
||||||
|
Serial.println("WaterBank -> Trigger reason: Sterilized chamber unload");
|
||||||
|
}
|
||||||
|
//update state
|
||||||
|
waterBankFloatSwitchStatePrevious = waterBankFloatSwitchStateCurrent;
|
||||||
|
waterBankSterilizationFloatSwitchStatePrevious = waterBankSterilizationFloatSwitchStateCurrent;
|
||||||
|
waterBankSterilizedFloatSwitchStatePrevious = waterBankSterilizedFloatSwitchStateCurrent;
|
||||||
|
waterBankSterilizationUpperFloatSwitchStatePrevious = waterBankSterilizationUpperFloatSwitchStateCurrent;
|
||||||
|
if (intoFillingWaterBank){
|
||||||
|
ClearWaterBankError();
|
||||||
|
waterBankState = WATER_BANK_STATE_START_FILLING;
|
||||||
|
Serial.println("WaterBank -> WATER_BANK_STATE_START_FILLING");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
waterBankState = WATER_BANK_STATE_NONE;
|
||||||
|
Serial.println("WaterBank -> WATER_BANK_STATE_NONE");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case WATER_BANK_STATE_START_FILLING:{
|
||||||
|
//call to this state to check if water is fully empty or lower level is filled
|
||||||
|
bool lowerSwitchState = GetInSwitchState(WATER_BANK_FLOAT_SWITCH_LOWER);
|
||||||
|
bool upperSwitchState = GetInSwitchState(WATER_BANK_FLOAT_SWITCH_UPPER);
|
||||||
|
if (lowerSwitchState && (!upperSwitchState)){
|
||||||
|
//try to fill till full
|
||||||
|
ClearWaterBankError();
|
||||||
|
waterBankTick = millis();
|
||||||
|
waterBankState = WATER_BANK_STATE_CHECK_FILLING_TO_UPPER;
|
||||||
|
Serial.println("WaterBank -> WATER_BANK_STATE_CHECK_FILLING_TO_UPPER");
|
||||||
|
}else if ((!lowerSwitchState) && (!upperSwitchState)){
|
||||||
|
//try to fill to lower first
|
||||||
|
ClearWaterBankError();
|
||||||
|
waterBankTick = millis();
|
||||||
|
waterBankState = WATER_BANK_STATE_CHECK_FILLING_TO_LOWER;
|
||||||
|
Serial.println("WaterBank -> WATER_BANK_STATE_CHECK_FILLING_TO_LOWER");
|
||||||
|
}else if (!lowerSwitchState && upperSwitchState){
|
||||||
|
//float switch error! Cancel the action
|
||||||
|
waterBankError = true;
|
||||||
|
waterBankErrorCode = WATER_BANK_ERROR_LOWER_FLOAT_SWITCH;
|
||||||
|
//waterBankErrorString = "Tank 1 lower float switch error.";
|
||||||
|
waterBankErrorString = "Tangki 3 float switch bawah error.";
|
||||||
|
Serial.println("WaterBank Error -> WATER_BANK_ERROR_LOWER_FLOAT_SWITCH");
|
||||||
|
if (waterBankAutomatic){
|
||||||
|
waterBankState = WATER_BANK_STATE_IDLE;
|
||||||
|
Serial.println("WaterBank -> WATER_BANK_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
waterBankState = WATER_BANK_STATE_NONE;
|
||||||
|
Serial.println("WaterBank -> WATER_BANK_STATE_NONE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case WATER_BANK_STATE_CHECK_FILLING_TO_LOWER:{
|
||||||
|
//waiting for filling into lower level, or stop when timeout
|
||||||
|
//switch on the pump
|
||||||
|
if (!GetSwitchState(WATER_BANK_FILL_PUMP_SWITCH)){
|
||||||
|
Serial.println("WaterBank: TURN ON PUMP SWITCH");
|
||||||
|
SetSwitchState(WATER_BANK_FILL_PUMP_SWITCH, true);
|
||||||
|
}
|
||||||
|
bool lowerSwitchState = GetInSwitchState(WATER_BANK_FLOAT_SWITCH_LOWER);
|
||||||
|
bool upperSwitchState = GetInSwitchState(WATER_BANK_FLOAT_SWITCH_UPPER);
|
||||||
|
if (lowerSwitchState || upperSwitchState){
|
||||||
|
//check if lower float switch on
|
||||||
|
//try to fill till full
|
||||||
|
ClearWaterBankError();
|
||||||
|
waterBankTick = millis();
|
||||||
|
waterBankState = WATER_BANK_STATE_CHECK_FILLING_TO_UPPER;
|
||||||
|
Serial.println("WaterBank -> WATER_BANK_STATE_CHECK_FILLING_TO_UPPER");
|
||||||
|
}else{
|
||||||
|
//check if timed out
|
||||||
|
if (millis()-waterBankTick>=waterBankExpectedTimeToFilledLower){
|
||||||
|
//error
|
||||||
|
waterBankError = true;
|
||||||
|
waterBankErrorCode = WATER_BANK_ERROR_LOWER_FLOAT_SWITCH_OR_NO_WATER;
|
||||||
|
//waterBankErrorString = "Tank 1 insufficient input water, or lower float switch error, or input pump error.";
|
||||||
|
waterBankErrorString = "Tidak ada air untuk mengisi tangki 3, atau float switch error, atau pompa rusak.";
|
||||||
|
Serial.println("WaterBank Error -> WATER_BANK_ERROR_LOWER_FLOAT_SWITCH");
|
||||||
|
if (waterBankAutomatic){
|
||||||
|
waterBankState = WATER_BANK_STATE_IDLE;
|
||||||
|
Serial.println("WaterBank -> WATER_BANK_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
waterBankState = WATER_BANK_STATE_NONE;
|
||||||
|
Serial.println("WaterBank -> WATER_BANK_STATE_NONE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case WATER_BANK_STATE_CHECK_FILLING_TO_UPPER:{
|
||||||
|
//waiting for filling into upper level, or stop when timeout
|
||||||
|
//switch on the pump
|
||||||
|
if (!GetSwitchState(WATER_BANK_FILL_PUMP_SWITCH)){
|
||||||
|
Serial.println("WaterBank: TURN ON PUMP SWITCH");
|
||||||
|
SetSwitchState(WATER_BANK_FILL_PUMP_SWITCH, true);
|
||||||
|
}
|
||||||
|
bool upperSwitchState = GetInSwitchState(WATER_BANK_FLOAT_SWITCH_UPPER);
|
||||||
|
bool stopFill = false;
|
||||||
|
if (upperSwitchState){
|
||||||
|
//check if upper float switch on
|
||||||
|
ClearWaterBankError();
|
||||||
|
stopFill = true;
|
||||||
|
Serial.println("WaterBank -> Full");
|
||||||
|
}else{
|
||||||
|
//check if timed out
|
||||||
|
if (millis()-waterBankTick>=waterBankExpectedTimeToFilledUpper){
|
||||||
|
//error
|
||||||
|
stopFill = true;
|
||||||
|
waterBankError = true;
|
||||||
|
waterBankErrorCode = WATER_BANK_ERROR_UPPER_FLOAT_SWITCH_OR_NO_WATER;
|
||||||
|
waterBankErrorString = "Tank 3 insufficient input water, or upper float switch error, or input pump error.";
|
||||||
|
Serial.println("WaterBank Error -> WATER_BANK_ERROR_UPPER_FLOAT_SWITCH_OR_NO_WATER");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stopFill){
|
||||||
|
SetSwitchState(WATER_BANK_FILL_PUMP_SWITCH, false); //matiin pompa
|
||||||
|
if (waterBankAutomatic){
|
||||||
|
waterBankState = WATER_BANK_STATE_IDLE;
|
||||||
|
Serial.println("WaterBank -> WATER_BANK_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
waterBankState = WATER_BANK_STATE_NONE;
|
||||||
|
Serial.println("WaterBank -> WATER_BANK_STATE_NONE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartWaterBankSystem(bool automatic, bool forceRunIfAutomatic = false){
|
||||||
|
RefreshInSwitchState();
|
||||||
|
ClearWaterBankError();
|
||||||
|
waterBankAutomatic = automatic;
|
||||||
|
bool runNow = false;
|
||||||
|
if (waterBankAutomatic){
|
||||||
|
waterBankState = WATER_BANK_STATE_IDLE;
|
||||||
|
runNow = forceRunIfAutomatic;
|
||||||
|
if (!runNow) Serial.println("StartWaterBankSystem -> WATER_BANK_STATE_IDLE");
|
||||||
|
}else{
|
||||||
|
runNow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runNow){
|
||||||
|
waterBankState = WATER_BANK_STATE_START_FILLING;
|
||||||
|
Serial.println("StartWaterBankSystem -> WATER_BANK_STATE_START_FILLING");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopWaterBankSystem(){
|
||||||
|
waterBankState = WATER_BANK_STATE_NONE;
|
||||||
|
ClearWaterBankError();
|
||||||
|
WaterBankSystemRoutine(); //call it once to stop the switch
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
//Test unit for WaterBankSystemRoutine
|
||||||
|
bool WaterBankTestUnit(){
|
||||||
|
bool testA = false;
|
||||||
|
bool testB = false;
|
||||||
|
bool testC = false;
|
||||||
|
bool testD = false;
|
||||||
|
bool testE = false;
|
||||||
|
|
||||||
|
//normal test with automatic mode
|
||||||
|
ClearInSwitch(); //clear floating switch state
|
||||||
|
StopWaterBankSystem();
|
||||||
|
StartWaterBankSystem(true, false);
|
||||||
|
WaterBankSystemRoutine();
|
||||||
|
testA = waterBankState==WATER_BANK_STATE_IDLE;
|
||||||
|
Serial.println("Test idle state " + (String) (testA?"OK":"FAIL"));
|
||||||
|
//simulate float switching
|
||||||
|
SetInSwitchState(WATER_BANK_FLOAT_SWITCH_LOWER, true);
|
||||||
|
WaterBankSystemRoutine();
|
||||||
|
SetInSwitchState(WATER_BANK_FLOAT_SWITCH_LOWER, false); //simulate trigger to fill water
|
||||||
|
WaterBankSystemRoutine();
|
||||||
|
testB = (waterBankState==WATER_BANK_STATE_START_FILLING) || (waterBankState==WATER_BANK_STATE_CHECK_FILLING_TO_LOWER);
|
||||||
|
Serial.println("Test start filling " + (String) (testB?"OK":"FAIL"));
|
||||||
|
WaterBankSystemRoutine();
|
||||||
|
testC = waterBankState==WATER_BANK_STATE_CHECK_FILLING_TO_LOWER;
|
||||||
|
Serial.println("Test filling to lower " + (String) (testC?"OK":"FAIL"));
|
||||||
|
//simulate water on lower
|
||||||
|
SetInSwitchState(WATER_BANK_FLOAT_SWITCH_LOWER, true);
|
||||||
|
WaterBankSystemRoutine();
|
||||||
|
testD = waterBankState==WATER_BANK_STATE_CHECK_FILLING_TO_UPPER;
|
||||||
|
Serial.println("Test filling to upper " + (String) (testD?"OK":"FAIL"));
|
||||||
|
//simulate tank full
|
||||||
|
SetInSwitchState(WATER_BANK_FLOAT_SWITCH_UPPER, true);
|
||||||
|
WaterBankSystemRoutine();
|
||||||
|
testE = waterBankState==WATER_BANK_STATE_IDLE;
|
||||||
|
Serial.println("Test filling to full " + (String) (testE?"OK":"FAIL"));
|
||||||
|
StopWaterBankSystem();
|
||||||
|
bool passNormalTest = testA && testB && testC && testD && testE;
|
||||||
|
Serial.println("All Normal Test: " + (String) (passNormalTest?"OK":"FAIL"));
|
||||||
|
|
||||||
|
//bool passFloatSwitchErrorTest = false;
|
||||||
|
|
||||||
|
//bool passFillLowerTimeoutTest = false;
|
||||||
|
|
||||||
|
//bool passFillUpperTimeoutTest = false;
|
||||||
|
|
||||||
|
// return passNormalTest;
|
||||||
|
|
||||||
|
//cleanup test
|
||||||
|
ClearInSwitch(); //clear floating switch state
|
||||||
|
StopWaterBankSystem();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//=========================================================================
|
||||||
|
|
Loading…
Reference in New Issue