#include #include #include "MAX30105.h" #include "heartRate.h" #include "spo2_algorithm.h" #include #include #include #include #include #define LED_R D6 #define LED_G D7 #define LED_B D8 #define LED_ON HIGH #define LED_OFF LOW MAX30105 particleSensor; LiquidCrystal_I2C lcd(0x27, 16, 2); // Inisialisasi alamat I2C dan ukuran LCD WiFiManager wm; ESP8266WebServer server(80); const char* mqtt_server = "test.mosquitto.org"; // Inisialisasi WiFi dan MQTT client WiFiClient espClient; PubSubClient client(espClient); String lastReceivedID = ""; String lastReceivedName = ""; unsigned long lastSendTime = 0; const unsigned long interval = 60000; // 1 menit dalam milidetik String serverIP = ""; // Variabel global untuk menyimpan alamat IP server const char* URL = ""; // Alamat server, akan diinisialisasi setelah mendapat IP dari handleUpdateServerIP const int serverPort = 80; // Port server HTTP const byte RATE_SIZE = 4; // Increase this for more averaging. 4 is good. byte rates[RATE_SIZE]; // Array of heart rates byte rateSpot = 0; long lastBeat = 0; // Time at which the last beat occurred // nilai SPO2 uint32_t irBuffer[100]; // infrared LED sensor data uint32_t redBuffer[100]; // red LED sensor data int32_t bufferLength; // data length int32_t spo2; // SPO2 value int8_t validSPO2; // indicator to show if the SPO2 calculation is valid int32_t heartRate; // heart rate value int8_t validHeartRate; // indicator to show if the heart rate calculation is valid float beatsPerMinute; int beatAvg; int buttonState = 0; int lastButtonState = 0; long lastDebounceTime = 0; long debounceDelay = 50; enum SensorMode { BPM_MODE, SPO2_MODE }; float predictedGlucose; SensorMode currentMode = BPM_MODE; // Default mode String receivedValue = ""; void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); String message = ""; for (int i = 0; i < length; i++) { message += (char)payload[i]; } Serial.println(message); // Extract ID and name from the JSON message StaticJsonDocument<200> doc; DeserializationError error = deserializeJson(doc, message); if (error) { Serial.print("deserializeJson() failed: "); Serial.println(error.c_str()); return; } // Mengambil nilai id sebagai integer lastReceivedID = doc["id"].as(); // Mengambil nilai name sebagai string lastReceivedName = doc["nama"].as(); lastSendTime = millis(); // Reset the timer Serial.print("Id: "); Serial.println(lastReceivedID); Serial.print("Nama: "); Serial.println(lastReceivedName); lcd.clear(); lcd.setCursor(0, 0); lcd.print("SELAMAT DATANG"); lcd.setCursor(0, 1); int nameLength = lastReceivedName.length(); int spaces = (16 - nameLength) / 2; // Assuming 16 characters per line String paddedName = ""; for (int i = 0; i < spaces; i++) { paddedName += " "; } paddedName += lastReceivedName; lcd.print(paddedName); startSensor(); } void reconnect() { // Loop sampai terkoneksi while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Buat client ID String clientId = "ESP8266Client-"; clientId += String(random(0xffff), HEX); // Coba koneksi if (client.connect(clientId.c_str())) { Serial.println("connected"); // Subscribe ke topic client.subscribe("amantuzh"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Tunggu 5 detik sebelum mencoba lagi delay(5000); } } } void startSensor() { if (!particleSensor.begin(Wire, I2C_SPEED_STANDARD)) { // Gunakan port I2C default ESP8266, kecepatan 100kHz Serial.println("MAX30105 was not found. Please check wiring/power."); while (1); } Serial.println("Place your index finger on the sensor with steady pressure."); delay(3000); lcd.clear(); lcd.setCursor(0, 0); lcd.print(" TEKAN MULAI"); lcd.setCursor(0, 1); lcd.print("UNTUK PENGUKURAN"); digitalWrite(LED_R, LED_OFF); digitalWrite(LED_G, LED_ON); digitalWrite(LED_B, LED_OFF); particleSensor.setup(); // Konfigurasi sensor dengan pengaturan default particleSensor.setPulseAmplitudeRed(0x0A); // Menyalakan LED merah untuk menunjukkan sensor berjalan particleSensor.setPulseAmplitudeGreen(0); // Matikan LED hijau } void setup() { WiFi.mode(WIFI_STA); Serial.begin(115200); Serial.println("Initializing..."); pinMode(D1, OUTPUT); pinMode(D2, OUTPUT); pinMode(LED_R, OUTPUT); pinMode(LED_G, OUTPUT); pinMode(LED_B, OUTPUT); pinMode(D3, INPUT_PULLUP); // Internal pull-up resistor digitalWrite(LED_R, LED_OFF); digitalWrite(LED_G, LED_OFF); digitalWrite(LED_B, LED_OFF); lcd.init(); // Inisialisasi LCD lcd.backlight(); // Nyalakan backlight LCD Wire.begin(); // Inisialisasi I2C pada ESP8266 wm.setDebugOutput(false); // Remove any previous network settings // wm.resetSettings(); // Define a text box, 50 characters maximum WiFiManagerParameter custom_text_box("my_text", "Enter your string here", "default string", 50); // Add custom parameter wm.addParameter(&custom_text_box); // Blink LED B while searching for WiFi digitalWrite(LED_B, LED_ON); digitalWrite(LED_G, LED_OFF); lcd.clear(); lcd.print("NOT CONNECT WIFI"); bool res = wm.autoConnect("GlucoseMetter", "password"); // password protected ap if (!res) { Serial.println("Failed to connect"); ESP.restart(); delay(1000); } // Connected! digitalWrite(LED_B, LED_OFF); digitalWrite(LED_G, LED_ON); Serial.println("WiFi connected"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); Serial.print("SSID: "); Serial.println(WiFi.SSID()); lcd.clear(); lcd.setCursor(0, 0); lcd.print(" CONNECTED TO"); lcd.setCursor(0, 1); int SsidLength = WiFi.SSID().length(); int spaces = (16 - SsidLength) / 2; // Assuming 16 characters per line String paddedSsid = ""; for (int i = 0; i < spaces; i++) { paddedSsid += " "; } paddedSsid += WiFi.SSID(); lcd.print(paddedSsid); delay(2000); client.setServer(mqtt_server, 1883); client.setCallback(callback); server.begin(); // Display "Pilih ID" until data is received lcd.clear(); lcd.setCursor(0, 0); lcd.print(" PILIH PENGGUNA"); } void loop() { wm.process(); if (!client.connected()) { reconnect(); } client.loop(); // Check if 1 minute has passed since the last ID was received if (lastReceivedID.length() > 0) { unsigned long currentMillis = millis(); if (currentMillis - lastSendTime >= interval) { // sendID(lastReceivedID.c_str()); lastSendTime = currentMillis; // Reset the timer for the next send } } int reading = digitalRead(D3); // Check if the button state has changed if (reading != lastButtonState) { // Reset the debounce timer lastDebounceTime = millis(); } // Check if the debounce delay has passed if ((millis() - lastDebounceTime) > debounceDelay) { // If the reading has changed, update the button state if (reading != buttonState) { buttonState = reading; // If the button is pressed if (buttonState == LOW) { // Toggle sensor mode if (currentMode == BPM_MODE) { runBPMMode(); runSPO2Mode(); KalibrasiGLucosa(); startSensor(); } } } } lastButtonState = reading; } void runBPMMode() { Serial.println("Mulai BPM Mode"); unsigned long startTime = millis(); while (millis() - startTime < 30000) { digitalWrite(LED_B, LED_OFF); digitalWrite(LED_G, LED_OFF); long irValue = particleSensor.getIR(); if (irValue < 50000) { beatsPerMinute = 0.0; beatAvg = 0.0; } else { if (checkForBeat(irValue)) { long delta = millis() - lastBeat; lastBeat = millis(); beatsPerMinute = 60 / (delta / 1000.0); if (beatsPerMinute < 255 && beatsPerMinute > 20) { rates[rateSpot++] = (byte)beatsPerMinute; rateSpot %= RATE_SIZE; beatAvg = 0; for (byte x = 0; x < RATE_SIZE; x++) beatAvg += rates[x]; beatAvg /= RATE_SIZE; } } } Serial.print("IR="); Serial.print(irValue); Serial.print(", BPM="); Serial.print(beatsPerMinute); Serial.print(", Avg BPM="); Serial.print(beatAvg); Serial.println(); if (irValue > 100000){ digitalWrite(LED_R, LED_ON); } else { digitalWrite(LED_R, LED_OFF); } // Update LCD lcd.clear(); // Bersihkan layar LCD lcd.setCursor(0, 0); lcd.print("BPM: "); lcd.print(beatAvg); lcd.setCursor(0, 1); lcd.print("SPO2: "); } Serial.print("Hasil BPM Mode: "); Serial.println(beatAvg); } void runSPO2Mode() { Serial.println("Mulai SPO2 Mode"); unsigned long startTime = millis(); while (millis() - startTime < 16000) { bufferLength = 100; // buffer length of 100 stores 4 seconds of samples running at 25sps // read the first 100 samples, and determine the signal range for (byte i = 0 ; i < bufferLength ; i++) { while (particleSensor.available() == false) // do we have new data? particleSensor.check(); // Check the sensor for new data redBuffer[i] = particleSensor.getRed(); irBuffer[i] = particleSensor.getIR(); particleSensor.nextSample(); // We're finished with this sample so move to next sample } // calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples) maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate); // Send data to Serial Monitor Serial.print(F("BPM=")); Serial.print(heartRate); Serial.print(F(", ValidHR=")); Serial.print(validHeartRate); Serial.print(F(", SPO2=")); Serial.print(spo2, DEC); Serial.print(F(", SPO2Valid=")); Serial.println(validSPO2, DEC); // Update LCD lcd.clear(); // Bersihkan layar LCD lcd.setCursor(0, 0); lcd.print("BPM: "); lcd.print(beatAvg); lcd.setCursor(0, 1); lcd.print("SPO2: "); lcd.print(spo2); delay(3000); } Serial.print("Hasil BPM Mode: "); Serial.println(beatAvg); Serial.print("Hasil SPO2 Mode: "); Serial.println(spo2); } void KalibrasiGLucosa() { // Rumus Prediksi GLucosa predictedGlucose = 16714.61 + (0.47 * beatAvg) - (351.045 * spo2) + (1.85 * (spo2 * spo2)); Serial.print("Predicted Glucose= "); Serial.println(predictedGlucose); lcd.clear(); lcd.setCursor(0, 0); lcd.print("PREDIKSI GLUKOSA "); lcd.setCursor(0, 1); lcd.print(" "); lcd.print(predictedGlucose); lcd.print("mg/dl"); sendData(); delay(10000); // Mengirim data setelah perhitungan prediksi glukosa selesai lcd.clear(); beatsPerMinute = 0; beatAvg = 0; digitalWrite(LED_R, LED_OFF); lcd.clear(); lcd.setCursor(0, 0); lcd.print(" PENGUKURAN"); lcd.setCursor(0, 1); lcd.print(" SELESAI"); delay(1000); } void sendData() { // Pastikan klien MQTT terhubung if (!client.connected()) { Serial.println("MQTT client not connected, attempting to reconnect..."); reconnect(); } // Membuat objek JSON untuk mengirim data StaticJsonDocument<200> jsonDoc; jsonDoc["id"] = lastReceivedID; jsonDoc["BPM"] = beatAvg; jsonDoc["SpO2"] = spo2; jsonDoc["PredictedGlucose"] = predictedGlucose; // Mengonversi objek JSON menjadi string char buffer[256]; size_t n = serializeJson(jsonDoc, buffer); // Mencetak data yang akan dikirim ke Serial Monitor untuk debug Serial.print("Sending data: "); Serial.println(buffer); // Mengirim data ke broker MQTT dengan topik "postdataGluc" if (client.publish("postdataGluc", buffer, n)) { Serial.println("Data sent successfully"); } else { Serial.println("Failed to send data"); } }