TKK_E32222572/sketch_buzzer.ino

216 lines
5.9 KiB
C++

#include <WiFi.h>
#include <Wire.h>
#include <ThingerESP32.h>
#include "MAX30105.h"
#include "heartRate.h"
#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>
#include <SPI.h>
#define BUZZER_PIN 27
// --- WiFi & Thinger ---
#define SSID "AR ID"
#define PASSWORD "012345678"
#define USERNAME "amalia_lia"
#define DEVICE_ID "esp32-mood"
#define DEVICE_CREDENTIAL "esp32-mood"
ThingerESP32 thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL);
// --- MAX30102 ---
MAX30105 particleSensor;
const int SDA_PIN = 21;
const int SCL_PIN = 22;
const int GSR_PIN = 34;
// --- TFT ST7789 ---
#define TFT_CS 5
#define TFT_DC 2
#define TFT_RST 4
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);
// --- Variabel Global ---
float beatAvg = 0;
float gsrLevel = 0;
String currentMood = "Unknown";
// --- Fungsi Mood ---
String determineMood(float bpm, float gsr) {
if (bpm == 0 || gsr == 0) return "Gagal";
String moodHR = (bpm <= 90) ? "Tenang" : (bpm <= 100 ? "Cemas" : "Tegang");
String moodGSR = (gsr <= 4.0) ? "Tenang" : (gsr <= 6.0 ? "Cemas" : "Tegang");
if (moodHR == "Tenang" && moodGSR == "Tenang") return "Tenang";
if (moodHR == "Cemas" && moodGSR == "Cemas") return "Cemas";
if (moodHR == "Tegang" || moodGSR == "Tegang") return "Tegang";
return "Cemas";
}
// --- TFT Gambar Wajah ---
void drawArc(int x, int y, int r1, int r2, int start_angle, int end_angle, uint16_t color) {
for (int angle = start_angle; angle <= end_angle; angle++) {
float rad = angle * PI / 180;
int x1 = x + cos(rad) * r1;
int y1 = y + sin(rad) * r1;
int x2 = x + cos(rad) * r2;
int y2 = y + sin(rad) * r2;
tft.drawLine(x1, y1, x2, y2, color);
}
}
void drawFace(String mood) {
uint16_t faceColor = ST77XX_WHITE;
if (mood == "Tenang") faceColor = ST77XX_YELLOW;
else if (mood == "Cemas") faceColor = 0xFD20;
else if (mood == "Tegang") faceColor = ST77XX_RED;
tft.fillScreen(ST77XX_BLACK);
tft.fillCircle(120, 90, 50, faceColor);
// Mata
if (mood == "Tegang") {
tft.fillCircle(100, 75, 8, ST77XX_BLACK);
tft.fillCircle(140, 75, 8, ST77XX_BLACK);
tft.fillCircle(85, 60, 4, ST77XX_BLUE);
tft.fillCircle(155, 60, 3, ST77XX_BLUE);
} else {
tft.fillCircle(100, 75, 5, ST77XX_BLACK);
tft.fillCircle(140, 75, 5, ST77XX_BLACK);
}
// Mulut
if (mood == "Tenang") {
drawArc(120, 105, 18, 21, 45, 135, ST77XX_BLACK);
} else if (mood == "Cemas") {
tft.fillRect(105, 110, 30, 4, ST77XX_BLACK);
} else if (mood == "Tegang") {
drawArc(120, 120, 18, 21, 225, 315, ST77XX_BLACK);
}
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(2);
tft.setCursor(10, 160); tft.print("HR : "); tft.print(beatAvg, 1); tft.println(" BPM");
tft.setCursor(10, 185); tft.print("GSR : "); tft.print(gsrLevel, 2);
tft.setCursor(10, 210); tft.print("Mood : "); tft.println(mood);
}
// --- SETUP ---
void setup() {
Serial.begin(115200);
WiFi.begin(SSID, PASSWORD);
Wire.begin(SDA_PIN, SCL_PIN);
pinMode(GSR_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW); // Awalnya mati
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {
Serial.println("[ERROR] MAX30102 tidak terdeteksi!");
while (1);
}
particleSensor.setup(0x1F, 4, 2, 100, 411, 4096);
SPI.begin(18, -1, 23);
tft.init(240, 240); tft.setRotation(1); tft.fillScreen(ST77XX_BLACK);
thing.add_wifi(SSID, PASSWORD);
thing["mood"] >> [](pson &out) {
out["bpm"] = beatAvg;
out["gsr"] = gsrLevel;
out["mood"] = currentMood;
};
Serial.println("[READY] Silakan sentuhkan jari ke sensor.");
}
// --- LOOP ---
void loop() {
Serial.println("=== Mulai Pengukuran (10 detik) ===");
unsigned long startTime = millis();
unsigned long lastBeat = 0;
float bpmSum = 0;
int validBeats = 0;
unsigned long gsrSum = 0;
int gsrSamples = 0;
while (millis() - startTime < 10000) {
particleSensor.check();
long irValue = particleSensor.getIR();
int gsrValue = analogRead(GSR_PIN);
gsrSum += gsrValue;
gsrSamples++;
if (checkForBeat(irValue)) {
unsigned long now = millis();
if (lastBeat > 0) {
float delta = (now - lastBeat) / 1000.0;
float bpm = 60.0 / delta;
if (bpm >= 40 && bpm <= 180) {
bpmSum += bpm;
validBeats++;
Serial.print("[BEAT] BPM valid: ");
Serial.println(bpm, 1);
}
}
lastBeat = now;
}
delay(10);
}
// Hitung rata-rata
beatAvg = (validBeats > 0) ? bpmSum / validBeats : 0;
float avgGSR = gsrSum / gsrSamples;
bool isFingerDetected = (avgGSR > 200);
if (!isFingerDetected || beatAvg == 0) {
beatAvg = 0;
gsrLevel = 0;
currentMood = "Gagal";
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(2);
tft.setCursor(20, 100);
tft.println("Tempel jari Anda");
tft.setCursor(20, 130);
tft.println("untuk mulai");
} else {
gsrLevel = map(avgGSR, 300, 2500, 100, 700) / 100.0;
gsrLevel = constrain(gsrLevel, 1.0, 7.0);
currentMood = determineMood(beatAvg, gsrLevel);
drawFace(currentMood);
if (currentMood == "Tegang") {
// Buzzer bunyi panjang (beepppppppppp)
digitalWrite(BUZZER_PIN, HIGH);
delay(2000); // 2 detik
digitalWrite(BUZZER_PIN, LOW);
} else if (currentMood == "Cemas") {
// Buzzer bunyi pendek berulang (beep beep beep)
for (int i = 0; i < 3; i++) {
digitalWrite(BUZZER_PIN, HIGH);
delay(300); // 0.3 detik bunyi
digitalWrite(BUZZER_PIN, LOW);
delay(300); // 0.3 detik jeda
}
}
}
// Kirim ke Thinger.io
thing.write_bucket("Emotion_data", "mood", [](pson &data) {
data["bpm"] = beatAvg;
data["gsr"] = gsrLevel;
data["mood"] = currentMood;
});
thing.handle();
Serial.print("BPM: "); Serial.println(beatAvg, 1);
Serial.print("GSR: "); Serial.println(gsrLevel, 2);
Serial.print("Mood: "); Serial.println(currentMood);
Serial.println("=========================");
delay(1000);
}