#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>
// Pin setup
#define BUZZER_PIN 12
int stepperPins[4] = {17, 5, 18, 19}; // Pin untuk gulungan motor langsung
// WiFi & MQTT
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "dandyshaker262.cloud.shiftr.io";
const char* mqtt_user = "dandyshaker262";
const char* mqtt_pass = "auKlIMvIg0W59AXi";
WiFiClient espClient;
PubSubClient client(espClient);
// Thresholds and state
float lastTemp = 0;
unsigned long lastTempTime = 0;
unsigned long lastSendTime = 0;
const float TEMP_RISE_RATE_THRESHOLD = 5.0 / 60.0; // 5°C per minute
const float TEMP_MAX_THRESHOLD = 50.0; // Max temp 50°C
bool alarmActive = false;
// Stepper motor steps (untuk motor unipolar 4 fase)
int steps[8][4] = {
{1, 0, 0, 0},
{1, 1, 0, 0},
{0, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 1, 0},
{0, 0, 1, 1},
{0, 0, 0, 1},
{1, 0, 0, 1}
};
// Dummy temperature data (time in seconds, temperature in °C)
float dummyData[][2] = {
{0, 25.0}, {30, 25.3}, {60, 25.1}, {90, 25.4}, {120, 26.0},
{150, 26.5}, {180, 27.0}, {210, 27.5}, {240, 28.0}, {270, 38.0},
{300, 55.0}, {330, 52.0}, {360, 48.0}, {390, 44.0}, {420, 40.0},
{450, 36.0}, {480, 32.0}, {510, 29.0}, {540, 27.0}, {570, 26.5}
};
const int dummyDataSize = 20;
int dummyIndex = 0;
// Function declarations
float getDummyTemperature(unsigned long elapsedTime);
void connectWiFi();
void reconnectMQTT();
bool publishMQTT(const char* topic, const char* message);
void triggerAlarm();
void resetAlarm();
void runStepperMotor();
void stopStepperMotor();
void setup() {
Serial.begin(115200);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
for (int i = 0; i < 4; i++) {
pinMode(stepperPins[i], OUTPUT);
digitalWrite(stepperPins[i], LOW);
}
connectWiFi();
client.setServer(mqtt_server, 1883);
}
void loop() {
if (!client.connected()) {
reconnectMQTT();
}
client.loop();
unsigned long currentTime = millis();
unsigned long elapsedTime = currentTime / 1000; // Convert to seconds
// Read temperature every 500ms
static unsigned long lastReadTime = 0;
if (currentTime - lastReadTime >= 500) {
float temp = getDummyTemperature(elapsedTime);
if (temp == -127.0) {
Serial.println("Dummy Data Ended");
delay(1000);
return;
}
Serial.print("Current Temp: ");
Serial.print(temp);
Serial.println(" °C");
// Calculate temperature rise rate (°C per second)
float tempRiseRatePerMin = 0;
if (lastTempTime != 0) {
float timeDiff = (currentTime - lastTempTime) / 1000.0; // in seconds
float tempRiseRate = (temp - lastTemp) / timeDiff; // °C/s
tempRiseRatePerMin = tempRiseRate * 60; // °C/min
Serial.print("Temperature Rise Rate: ");
Serial.print(tempRiseRatePerMin);
Serial.println(" °C/min");
// Detect fire condition
if ((tempRiseRatePerMin > TEMP_RISE_RATE_THRESHOLD || temp >= TEMP_MAX_THRESHOLD) && !alarmActive) {
Serial.println("Fire Detected! Activating Alarm...");
triggerAlarm();
publishMQTT("fire/status", "{\"status\":\"ALERT\"}");
alarmActive = true;
} else if (temp < TEMP_MAX_THRESHOLD && tempRiseRatePerMin <= TEMP_RISE_RATE_THRESHOLD && alarmActive) {
Serial.println("Fire Condition Cleared. Resetting Alarm...");
resetAlarm();
publishMQTT("fire/status", "{\"status\":\"NORMAL\"}");
alarmActive = false;
}
}
Serial.print("Alarm Status: ");
Serial.println(alarmActive ? "ACTIVE" : "INACTIVE");
lastTemp = temp;
lastTempTime = currentTime;
lastReadTime = currentTime;
}
// Send temperature data every 60 seconds
if (currentTime - lastSendTime >= 60000) {
float temp = getDummyTemperature(elapsedTime);
if (temp != -127.0) {
char tempStr[32];
snprintf(tempStr, sizeof(tempStr), "{\"temperature\":%.2f}", temp);
if (publishMQTT("fire/temperature", tempStr)) {
lastSendTime = currentTime;
}
}
}
}
float getDummyTemperature(unsigned long elapsedTime) {
if (dummyIndex >= dummyDataSize) {
return -127.0; // Error code to indicate end of data
}
if (elapsedTime >= dummyData[dummyIndex][0]) {
float temp = dummyData[dummyIndex][1];
dummyIndex++;
return temp;
}
if (dummyIndex == 0) return dummyData[0][1];
return dummyData[dummyIndex - 1][1];
}
void connectWiFi() {
Serial.print("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" connected!");
}
void reconnectMQTT() {
int maxAttempts = 5;
int attempt = 0;
while (!client.connected() && attempt < maxAttempts) {
Serial.print("Connecting to MQTT...");
String clientId = "ESP32Client-" + String(random(0xffff), HEX);
if (client.connect(clientId.c_str(), mqtt_user, mqtt_pass)) {
Serial.println(" connected.");
} else {
Serial.print(" failed, rc=");
Serial.print(client.state());
delay(2000);
}
attempt++;
}
if (!client.connected()) {
Serial.println("MQTT connection failed. Continuing...");
}
}
bool publishMQTT(const char* topic, const char* message) {
if (client.publish(topic, message)) {
Serial.print("Published to ");
Serial.print(topic);
Serial.print(": ");
Serial.println(message);
return true;
} else {
Serial.print("Failed to publish to ");
Serial.println(topic);
return false;
}
}
void triggerAlarm() {
Serial.println("Triggering Alarm: Buzzer ON, Stepper Motor Running...");
digitalWrite(BUZZER_PIN, HIGH);
runStepperMotor();
}
void resetAlarm() {
Serial.println("Resetting Alarm: Buzzer OFF, Stepper Motor Stopped...");
digitalWrite(BUZZER_PIN, LOW);
stopStepperMotor();
}
void runStepperMotor() {
Serial.println("Running Stepper Motor...");
for (int i = 0; i < 512; i++) { // Jumlah langkah untuk satu putaran (disesuaikan dengan motor)
for (int j = 0; j < 8; j++) {
for (int pin = 0; pin < 4; pin++) {
digitalWrite(stepperPins[pin], steps[j][pin]);
}
delay(2); // Kecepatan langkah (dapat disesuaikan)
}
}
}
void stopStepperMotor() {
Serial.println("Stopping Stepper Motor...");
for (int i = 0; i < 4; i++) {
digitalWrite(stepperPins[i], LOW);
}
}