#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <OneButton.h>
const int SCREEN_WIDTH = 128;
const int SCREEN_HEIGHT = 64;
// Pin definitions for switches
const int SWITCH_PIN_1 = 2; // Switch 1 connected to pin D2
const int SWITCH_PIN_2 = 3; // Switch 2 connected to pin D3
const int SWITCH_PIN_3 = 4; // Switch 3 connected to pin D4
const int SWITCH_PIN_4 = 5; // Switch 4 connected to pin D5
const int SWITCH_PIN_5 = 6; // Switch 5 connected to pin D9 (new switch)
// LED indicators for each switch
const int LED_PIN_1 = 13; // LED 1 connected to pin D10
const int LED_PIN_2 = 12; // LED 2 connected to pin D11
const int LED_PIN_3 = 11; // LED 3 connected to pin D12
const int LED_PIN_4 = 10; // LED 4 connected to pin D13
const int LED_PIN_5 = 9; // LED 5 connected to pin A0 (analog pin as digital)
// Pin definitions for mode and buzzer
const int BUZZER_PIN = A0; // Buzzer connected to pin D8
const int RESET_BUZZER_PIN = A1; // Reset buzzer button on analog pin A1
// Relay Pin
const int RELAY_PIN = A2; // Relay connected to pin A2
// Create OneButton object
OneButton resetButton(RESET_BUZZER_PIN, true, true);
// // Bottle dimensions
// const int BOTTLE_WIDTH = 40;
// const int BOTTLE_HEIGHT = 50;
// const int NECK_WIDTH = 20;
// const int NECK_HEIGHT = 10;
// Alarm level
const int MAX_LEVEL_ALARM = 100;
const int MIN_LEVEL_ALARM = 0;
// Text positioning
const int TEXT_OFFSET_X = 10;
const int TEXT_OFFSET_Y = 15;
// Global variables for buzzer state
bool isBuzzerEnabled = true;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Function to handle button click
void handleBuzzerReset() {
isBuzzerEnabled = false;
noTone(BUZZER_PIN);
}
void setup() {
Serial.begin(9600);
// Setup switch pins as inputs with pull-up resistors
pinMode(SWITCH_PIN_1, INPUT_PULLUP);
pinMode(SWITCH_PIN_2, INPUT_PULLUP);
pinMode(SWITCH_PIN_3, INPUT_PULLUP);
pinMode(SWITCH_PIN_4, INPUT_PULLUP);
pinMode(SWITCH_PIN_5, INPUT_PULLUP); // Setup the new switch pin
// Setup LED pins as outputs
pinMode(LED_PIN_1, OUTPUT);
pinMode(LED_PIN_2, OUTPUT);
pinMode(LED_PIN_3, OUTPUT);
pinMode(LED_PIN_4, OUTPUT);
pinMode(LED_PIN_5, OUTPUT);
// Setup buzzer pin as output
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW); // Ensure buzzer is off
// Setup relay pin as output
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW); // Ensure relay is off initially
// Configure OneButton
resetButton.attachClick(handleBuzzerReset);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
while(true);
}
display.clearDisplay();
// Define main text, product, version, and trademark
String brandMessage = "Kleido";
String productMessage = "TandOn";
String versionText = "v1.0";
String trademarkText = "TM";
// Set text sizes
int textSizeLarge = 2;
int textSizeMedium = 1;
int textSizeSmall = 1;
// Calculate x position for "MyBrand" to be centered
int xBrand = (SCREEN_WIDTH - (brandMessage.length() * 6 * textSizeLarge)) / 2;
int yBrand = 5; // Vertical position for "MyBrand"
// Typing animation for "MyBrand"
display.setTextSize(textSizeLarge);
display.setTextColor(WHITE);
display.setCursor(xBrand, yBrand);
for (int i = 0; i < brandMessage.length(); i++) {
display.print(brandMessage[i]); // Print one character at a time
display.display(); // Update the display to show the character
delay(200); // Delay to simulate typing speed
}
// Display small "TM" in the top-right corner of "MyBrand"
display.setTextSize(textSizeSmall);
int xTM = xBrand + (brandMessage.length() * 6 * textSizeLarge) + 3; // Position TM right after "MyBrand"
int yTM = yBrand - 3; // Position TM slightly above "MyBrand"
display.setCursor(xTM, yTM);
display.print(trademarkText);
display.display();
// Display "myproduct" below "MyBrand"
int xProduct = (SCREEN_WIDTH - (productMessage.length() * 6 * textSizeMedium)) / 2;
int yProduct = 30; // Vertical position for "myproduct"
display.setTextSize(textSizeMedium);
display.setCursor(xProduct, yProduct);
display.print(productMessage);
display.display();
// Display "v1.0" below "myproduct"
int xVersion = (SCREEN_WIDTH - (versionText.length() * 6 * textSizeSmall)) / 2;
int yVersion = 50; // Vertical position for "v1.0"
display.setTextSize(textSizeSmall);
display.setCursor(xVersion, yVersion);
display.print(versionText);
display.display();
delay(1000); // Pause to let the user see the final result
}
int readWaterLevel() {
// Membaca status dari setiap switch
// Nilai switch akan 0 ketika ON (karena INPUT_PULLUP)
int switch1 = !digitalRead(SWITCH_PIN_1);
int switch2 = !digitalRead(SWITCH_PIN_2);
int switch3 = !digitalRead(SWITCH_PIN_3);
int switch4 = !digitalRead(SWITCH_PIN_4);
int switch5 = !digitalRead(SWITCH_PIN_5); // Read the new switch
digitalWrite(LED_PIN_1, switch1);
digitalWrite(LED_PIN_2, switch2);
digitalWrite(LED_PIN_3, switch3);
digitalWrite(LED_PIN_4, switch4);
digitalWrite(LED_PIN_5, switch5);
// Calculate total water level percentage based on switch values
int level = 0;
if (switch1) level += 10; // SW1 = 10%
if (switch2) level += 10; // SW2 = 10%
if (switch3) level += 20; // SW3 = 20%
if (switch4) level += 30; // SW4 = 30%
if (switch5) level += 30; // SW5 = 30%
return level;
}
// Global variables for buzzer state
// bool isBuzzerEnabled = true;
void checkBuzzer(int level) {
// Check if reset button is pressed
// if (digitalRead(RESET_BUZZER_PIN) == LOW) {
// // Button pressed - disable buzzer
// isBuzzerEnabled = false;
// noTone(BUZZER_PIN); // Immediately stop the buzzer
// delay(50); // Debounce delay
// }
// // Restore buzzer functionality if conditions change
// if (!isBuzzerEnabled) {
// // Re-enable buzzer if level changes
// if (level != MAX_LEVEL_ALARM && level != MIN_LEVEL_ALARM) {
// isBuzzerEnabled = true;
// }
// }
// Check for button events
resetButton.tick();
// Restore buzzer functionality if conditions change
if (!isBuzzerEnabled && level != MAX_LEVEL_ALARM && level != MIN_LEVEL_ALARM) {
isBuzzerEnabled = true;
}
// Original buzzer logic with enabled check
if (isBuzzerEnabled) {
if (level == MAX_LEVEL_ALARM) {
// Continuous tone when at 100%
tone(BUZZER_PIN, 1000); // Continuous 1 kHz tone
} else if (level == MIN_LEVEL_ALARM) {
tone(BUZZER_PIN, 1000, 200); // 1 kHz tone for 200ms
delay(300); // Wait for 300ms before next beep
} else {
noTone(BUZZER_PIN); // Turn off buzzer
}
}
}
void drawBottle(int level) {
display.clearDisplay();
// Blinking effect if level is 0%, display 10% with blink
static bool blink = true; // Track blink state
if (level == 0) {
level = 10; // Display 10% when level is 0
blink = !blink; // Toggle blink state each call
} else {
blink = true; // Ensure display is stable if not blinking
}
// Display percentage text with blinking for 10%
if (blink || level != 10) {
display.setTextSize(5); // Large text size
display.setTextColor(WHITE);
int xPos, yPos;
// Special positioning for 100%
if (level == 100) {
xPos = 10; // Geser sedikit ke kiri untuk 100%
yPos = (SCREEN_HEIGHT - (6 * 8)) / 2; // Tetap di tengah secara vertikal
} else {
// Calculate center position for other percentages
int textWidth = (level < 10) ? 3 * 6 * 6 : 4 * 6 * 6;
xPos = 30;
yPos = (SCREEN_HEIGHT - (6 * 8)) / 2;
}
display.setCursor(xPos, yPos + 5);
display.print(level);
// Small % sign
display.setTextSize(2);
display.print("%");
}
display.display();
}
void loop() {
// Read water level from switches
int waterLevel = readWaterLevel();
// Handle relay control
digitalWrite(RELAY_PIN, waterLevel < 10 ? HIGH : LOW);
// Update display
drawBottle(waterLevel);
// Check and activate buzzer based on conditions
checkBuzzer(waterLevel);
// Process button events
resetButton.tick();
delay(100);
}