#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <WiFi.h>
#include <SPI.h>
#include <SD.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
// OLED display settings
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// DHT22 settings
#define DHTPIN 15
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// LDR settings
#define LDR_PIN 2
// LED settings
//#define LED_PIN 5
// SD card settings
#define SD_CS_PIN 5
bool sdConnected = SD.begin(SD_CS_PIN);
// Wi-Fi settings
const char* ssid = "Wokwi-GUEST";
const char* password = "";
///Battery settings
#define BATTERY_PIN 35
int previousBatteryLevel = 0;
// Sensor data variables
float temperature = 0.0;
float humidity = 0.0;
float lux = 0.0;
// 'wifi connected', 16x16px
const unsigned char wifi_icon [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x1f, 0xf8, 0x7c, 0x3e, 0xe7, 0xe7, 0xdf, 0xfb, 0x39, 0x1c,
0x37, 0xec, 0x0f, 0xf0, 0x0f, 0xf0, 0x03, 0xc0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00
};
// 'wifi disconnected', 16x16px
const unsigned char wifi_dc [] PROGMEM = {
0x00, 0x00, 0x00, 0x04, 0x03, 0xce, 0x1f, 0xdc, 0x7f, 0xba, 0xf8, 0x77, 0x60, 0xe6, 0x05, 0xc0,
0x0b, 0xb0, 0x07, 0x70, 0x0e, 0x20, 0x1c, 0x00, 0x1b, 0x80, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00
};
const unsigned char sd_card_dc [] PROGMEM = {
0x88, 0xa0,
0x88, 0x90,
0xff, 0xd0,
0xff, 0xd0,
0xff, 0xf0,
0xff, 0xf0,
0xff, 0xf0,
0xff, 0xb0,
0xff, 0x70,
0xfe, 0xf0,
0xfd, 0xf0,
0xfb, 0xf0,
0xf7, 0xf0,
0xef, 0xf0,
0xdf, 0xf0,
0xff, 0xf0,
0xff, 0xf0,
0xff, 0xf0,
0xff, 0xf0,
0xff, 0xf0
};
const unsigned char sd_card_con [] PROGMEM = {
0x88, 0xa0,
0x88, 0x90,
0xff, 0xd0,
0xff, 0xd0,
0xff, 0xf0,
0xff, 0xf0,
0xff, 0xf0,
0xff, 0xf0,
0xf0, 0xf0,
0xef, 0x70,
0xdf, 0xb0,
0xdf, 0xb0,
0xdf, 0xb0,
0xdf, 0xb0,
0xef, 0x70,
0xf0, 0xf0,
0xff, 0xf0,
0xff, 0xf0,
0xff, 0xf0,
0xff, 0xf0
};
// Bitmap data for WiFi icons (from previous response)
static const uint8_t wifi_connected [264] PROGMEM = {
0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00,
0x00, 0x07, 0xff, 0xff, 0x80, 0x00,
0x00, 0x1f, 0xff, 0xff, 0xe0, 0x00,
0x00, 0x7f, 0xff, 0xff, 0xf8, 0x00,
0x01, 0xff, 0xff, 0xff, 0xfe, 0x00,
0x03, 0xff, 0xff, 0xff, 0xff, 0x00,
0x0f, 0xff, 0x00, 0x03, 0xff, 0x80,
0x1f, 0xf8, 0x00, 0x00, 0x7f, 0xe0,
0x3f, 0xe0, 0x00, 0x00, 0x1f, 0xf0,
0x7f, 0xc0, 0x00, 0x00, 0x0f, 0xf8,
0xff, 0x00, 0x03, 0x00, 0x03, 0xfc,
0xfe, 0x00, 0xff, 0xfc, 0x01, 0xfc,
0x78, 0x03, 0xff, 0xff, 0x00, 0xf8,
0x70, 0x0f, 0xff, 0xff, 0xc0, 0x70,
0x30, 0x3f, 0xff, 0xff, 0xe0, 0x20,
0x00, 0x7f, 0xff, 0xff, 0xf8, 0x00,
0x00, 0xff, 0xe0, 0x1f, 0xfc, 0x00,
0x01, 0xff, 0x00, 0x03, 0xfe, 0x00,
0x03, 0xfc, 0x00, 0x00, 0xff, 0x00,
0x01, 0xf8, 0x00, 0x00, 0x7e, 0x00,
0x01, 0xf0, 0x00, 0x00, 0x3c, 0x00,
0x00, 0xc0, 0x03, 0x80, 0x18, 0x00,
0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00,
0x00, 0x00, 0xff, 0xfc, 0x00, 0x00,
0x00, 0x01, 0xff, 0xfe, 0x00, 0x00,
0x00, 0x07, 0xff, 0xff, 0x00, 0x00,
0x00, 0x07, 0xff, 0xff, 0x80, 0x00,
0x00, 0x03, 0xf0, 0x3f, 0x00, 0x00,
0x00, 0x03, 0xc0, 0x0e, 0x00, 0x00,
0x00, 0x01, 0x80, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x80, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x07, 0x80, 0x00, 0x00
};
const unsigned char wifi_disconnected [264] PROGMEM = {
0x00, 0x00, 0x5f, 0xe0, 0x00, 0x00,
0x00, 0x07, 0xdf, 0xef, 0x00, 0x00,
0x00, 0x1f, 0xdf, 0xff, 0xc0, 0x00,
0x00, 0x7f, 0xdf, 0xdf, 0xf8, 0x00,
0x01, 0xff, 0xdf, 0xdf, 0xfc, 0x00,
0x03, 0xff, 0xdf, 0xdf, 0xff, 0x00,
0x0f, 0xff, 0x1f, 0xc7, 0xff, 0x80,
0x1f, 0xf8, 0x1f, 0xc0, 0xff, 0xe0,
0x3f, 0xe0, 0x1f, 0xc0, 0x1f, 0xf0,
0x7f, 0xc0, 0x1f, 0xc0, 0x0f, 0xf0,
0xff, 0x00, 0x0f, 0xc0, 0x03, 0xfc,
0xfe, 0x00, 0xef, 0xd8, 0x01, 0xfc,
0x78, 0x07, 0xef, 0xff, 0x00, 0xf8,
0x70, 0x0f, 0xef, 0xff, 0xc0, 0x70,
0x20, 0x3f, 0xef, 0xbf, 0xe0, 0x20,
0x00, 0x7f, 0xef, 0xbf, 0xf8, 0x00,
0x00, 0xff, 0xcf, 0x9f, 0xfc, 0x00,
0x01, 0xff, 0x0f, 0x87, 0xfe, 0x00,
0x03, 0xfc, 0x0f, 0x81, 0xff, 0x00,
0x01, 0xf0, 0x0f, 0x80, 0x7e, 0x00,
0x01, 0xe0, 0x0f, 0x80, 0x3c, 0x00,
0x00, 0xc0, 0x07, 0x80, 0x18, 0x00,
0x00, 0x00, 0x37, 0xb0, 0x08, 0x00,
0x00, 0x00, 0xf7, 0xfc, 0x00, 0x00,
0x00, 0x03, 0xf7, 0xfe, 0x00, 0x00,
0x00, 0x07, 0xf7, 0xff, 0x00, 0x00,
0x00, 0x07, 0xf7, 0xff, 0x80, 0x00,
0x00, 0x07, 0xe7, 0xbf, 0x00, 0x00,
0x00, 0x03, 0xc7, 0x0e, 0x00, 0x00,
0x00, 0x01, 0x87, 0x06, 0x00, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0f, 0x80, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x07, 0x80, 0x00, 0x00
};
// Logo petir
static const uint8_t lightningLogo[34] PROGMEM = {
0x0f, 0xf0,
0x08, 0x20,
0x18, 0x20,
0x10, 0x60,
0x30, 0x40,
0x20, 0xfc,
0x20, 0x18,
0x60, 0x30,
0x7c, 0x60,
0xf8, 0xc0,
0x19, 0x80,
0x12, 0x00,
0x34, 0x00,
0x38, 0x00,
0x30, 0x00,
0x60, 0x00,
0x40, 0x00
};
// Function to initialize OLED
void initOLED() {
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
while (true);
}
display.clearDisplay();
display.display();
}
// Function to initialize SD card
void initSDCard() {
if (!SD.begin(SD_CS_PIN)) {
Serial.println("SD card initialization failed!");
return;
}
Serial.println("SD card initialized.");
}
// Function to save sensor data to SD card
void saveToSDCard(float temp, float hum, float light) {
File dataFile = SD.open("/sensor_data.txt", FILE_APPEND);
if (dataFile) {
dataFile.print("Temperature: ");
dataFile.print(temp);
dataFile.print(" C, Humidity: ");
dataFile.print(hum);
dataFile.print(" %, Lux: ");
dataFile.println(light);
dataFile.close();
Serial.println("Data saved to SD card.");
} else {
Serial.println("Failed to open file for writing.");
}
}
// Function to display Wi-Fi status on OLED
void displayWiFiStatus(bool connected) {
display.clearDisplay();
display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, WHITE);
if (connected) {
// Display WiFi connected icon
display.drawBitmap(40, 10, wifi_connected, 46, 44, WHITE);
} else {
// Display WiFi disconnected icon
display.drawBitmap(40, 10, wifi_disconnected, 46, 44, WHITE);
}
// Update OLED display
display.display();
}
// Function to display loading message and logo
void displayLoading() {
display.clearDisplay();
display.drawBitmap(100, 26, lightningLogo, 14, 17, WHITE);
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(5, 26);
display.print("Loading");
display.display();
delay(2000); // Display for 2 seconds
}
// Modified function to connect to Wi-Fi
void connectToWiFi() {
displayWiFiStatus(false); // Initially display disconnected icon
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
// Optionally, show some animation or signal for trying to connect (not implemented here)
}
Serial.println("\nWiFi connected");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// Display connected icon when connected
displayWiFiStatus(true);
}
float convertToVoltage(int adcValue) {
return (adcValue / 4096.0*7.445); // 12-bit ADC, tegangan referensi 3.3V
}
int calculateBatteryPercentage(float voltage) {
return map(voltage, 0, 4.3, 0, 100); // Konversi tegangan ke persentase
}
// Task to read sensors
void readSensorTask(void *pvParameters) {
for (;;) {
// Read temperature and humidity
temperature = dht.readTemperature();
humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity)) {
Serial.println("Failed to read from DHT sensor!");
}
// Read LDR value and calculate lux (this is a placeholder calculation)
int ldrValue = analogRead(LDR_PIN);
lux = (ldrValue / 4095.0) * 1000.0; // Convert to arbitrary lux value
// Display sensor values on Serial Monitor
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" C");
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.println(" %");
Serial.print("Lux: ");
Serial.println(lux);
// Save data to SD card
//saveToSDCard(temperature, humidity, lux);
// Control LED
/*
if (temperature > 30.0 && humidity > 75.0) {
digitalWrite(LED_PIN, HIGH); // Turn on LED
} else {
digitalWrite(LED_PIN, LOW); // Turn off LED
}
*/
vTaskDelay(2000 / portTICK_PERIOD_MS); // Delay for 2 seconds
}
}
// Task to display sensor data on OLED
void displayTask(void *pvParameters) {
for (;;) {
// Baca level baterai
int batteryLevel = analogRead(BATTERY_PIN);
float batteryVoltage = convertToVoltage(batteryLevel);
int batteryPercentage = calculateBatteryPercentage(batteryVoltage);
batteryPercentage = constrain(batteryPercentage, 0, 100);
// Clear OLED
display.clearDisplay();
// Draw UI elements (e.g., borders, labels)
display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, WHITE);
display.setTextSize(1);
display.setTextColor(WHITE);
// Display temperature
display.setCursor(10, 10);
display.print("Temp: ");
display.print(temperature);
display.println(" C");
// Display humidity
display.setCursor(10, 25);
display.print("Hum : ");
display.print(humidity);
display.println(" %");
// Display lux
display.setCursor(10, 40);
display.print("Lux : ");
display.print(lux);
// Display WIFI status
if (WiFi.status() != WL_CONNECTED) {
display.drawBitmap(107, 43, wifi_dc, 16, 16, WHITE);
} else {
display.drawBitmap(107, 43, wifi_icon, 16, 16, WHITE);
}
if (sdConnected) {
display.drawBitmap(94, 43, sd_card_con, 12, 20, WHITE);
} else {
display.drawBitmap(94, 43, sd_card_dc, 12, 20, WHITE);
}
// Tampilan Baterai
int batteryHeight = map(batteryPercentage, 0, 100, 0, 28);
int batteryX = SCREEN_WIDTH - 20;
int batteryY = 10;
int batteryWidth = 13;
int batteryTopHeight = 2;
int batteryBottomHeight = 30;
int batteryFillHeight = map(batteryPercentage, 0, 100, 0, batteryBottomHeight);
// Ensure that the battery fill height doesn't exceed the battery block's height
batteryFillHeight = min(batteryFillHeight, batteryBottomHeight);
display.drawRect(batteryX, batteryY + batteryTopHeight, batteryWidth, batteryBottomHeight, SSD1306_WHITE);
display.fillRect(batteryX + 1, batteryY + batteryTopHeight + (batteryBottomHeight - batteryFillHeight), batteryWidth - 2, batteryFillHeight, SSD1306_WHITE);
display.setCursor(107 - (batteryPercentage >= 100 ? 6 : 0), 2); // Adjusted cursor position
display.print(String(batteryPercentage) + "%");
display.display();
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay for 2 seconds
}
}
void setup() {
// Initialize serial communication
Serial.begin(115200);
// Initialize DHT sensor
dht.begin();
// Initialize Battery PIN
pinMode(BATTERY_PIN, INPUT);
// Initialize OLED display
initOLED();
// Initialize SD card
initSDCard();
// Display loading message
displayLoading();
// Initialize Wi-Fi
connectToWiFi();
// Set LED pin mode
//pinMode(LED_PIN, OUTPUT);
// Create tasks for reading sensors and displaying data
xTaskCreate(readSensorTask, "ReadSensor", 4096, NULL, 1, NULL);
xTaskCreate(displayTask, "Display", 2048, NULL, 1, NULL);
}
void loop() {
// FreeRTOS manages tasks; loop does not need to do anything
}