Differences

This shows you the differences between two versions of the page.

Link to this comparison view

iothings:proiecte:2025sric:centralheatingmonitoring [2025/05/28 23:18]
george.tudurean [Hardware]
iothings:proiecte:2025sric:centralheatingmonitoring [2025/05/28 23:49] (current)
george.tudurean [Wood Central Heating Monitoring]
Line 4: Line 4:
   * Email: george.tudurean@stud.acs.pub.ro   * Email: george.tudurean@stud.acs.pub.ro
   * Master: SRIC   * Master: SRIC
 +  * Gitlab: https://​gitlab.cs.pub.ro/​tudu/​iot/​-/​tree/​firebase?​ref_type=heads
  
 ====== Context ====== ====== Context ======
Line 19: Line 20:
  
   * ESP32-S3-devkitc-1   * ESP32-S3-devkitc-1
-  ​* 2 DS18B20 temperature sensors +{{ iothings:​proiecte:​2025sric:​esp32-s3-devkitc-1-v1.1-isometric.png?​200 }} 
-  * SG-05010 servomotor+  ​* 2 DS18B20 temperature sensors 
 +{{ iothings:​proiecte:​2025sric:​ds18b20.jpg?​200 }} 
 +  * SG-05010 servomotor 
 +{{ iothings:​proiecte:​2025sric:​servomotor-sg5010.jpg?​200 }}
   * a breadboard   * a breadboard
   * a battery pack with 4 AAA batteries (6V)   * a battery pack with 4 AAA batteries (6V)
Line 26: Line 30:
 ====== Software ====== ====== Software ======
  
 +There is a lot of logic that controls the icons that are displayed in the interface, I'll stick them below in the code snippets because talking about them is really really boring, I just thought of all the possible cases and coded them in.
  
 === Code Snippets === === Code Snippets ===
 +Initial checks when ESP32 starts (maybe the user resets it manually):
 +<​code>​
 +if (initialTempC >= 30.0) {
 +    // If temperature is already high, set servo to triggered position and fan OFF
 +    lastServoPos = SERVO_TRIGGER_POS;​
 +    fanState = false;
 +    fireState = "​off";​
 +    Serial.println("​Initial state: Temperature above 30°C - Setting servo to 30° and fan OFF");
 +    ​
 +    // Actually move the servo to 30° position
 +    myServo.attach(SERVO_PIN,​ 700, 2300);
 +    myServo.write(SERVO_TRIGGER_POS);​
 +    delay(700); // Give servo time to move to position
 +    myServo.detach();​
 +    Serial.println("​Servo physically positioned at 30° and detached"​);​
 +  } else {
 +    // If temperature is normal at startup, initialize to 0° position
 +    lastServoPos = SERVO_RESET_POS;​
 +    fanState = true;
 +    fireState = "​starting";​
 +    Serial.println("​Initial state: Temperature below 30°C - Setting servo to 0° and fan ON");
 +    ​
 +    // Actually move the servo to 0° position
 +    myServo.attach(SERVO_PIN,​ 700, 2300);
 +    myServo.write(SERVO_RESET_POS);​
 +    delay(700); // Give servo time to move to position
 +    myServo.detach();​
 +    Serial.println("​Servo physically positioned at 0° and detached"​);​
 +    ​
 +    // Clean database at startup
 +    Serial.println("​Performing initial database cleanup..."​);​
 +    cleanupDatabase();​
 +  }
 +</​code>​
 +
 +Standard checks:
 +<​code>​
 +if (Firebase.ready() && signupOK && (millis() - commandCheckPrevMillis > commandCheckDelay || commandCheckPrevMillis == 0)) {
 +    commandCheckPrevMillis = millis();
 +    ​
 +    // Check for reset button commands
 +    if (Firebase.RTDB.getInt(&​fbdo,​ "/​commands/​resetServo"​)) {
 +      int resetCommand = fbdo.intData();​
 +      Serial.print("​Reset command received: ");
 +      Serial.println(resetCommand);​
 +      ​
 +      if (resetCommand > 0) {
 +        Serial.println("​Reset button pressed - checking if temperature allows reset..."​);​
 +        ​
 +        // Read latest temperature values when reset button is pressed
 +        sensors.requestTemperatures();​
 +        smokeSensors.requestTemperatures();​
 +        tempC = sensors.getTempCByIndex(0);​
 +        smokeTempC = smokeSensors.getTempCByIndex(0);​
 +        ​
 +        Serial.print("​Water Temperature:​ ");
 +        Serial.print(tempC);​
 +        Serial.println("​ °C");
 +        Serial.print("​Smoke Temperature:​ ");
 +        Serial.print(smokeTempC);​
 +        Serial.println("​ °C");
 +        ​
 +        // Check if temperature allows reset
 +        if (tempC < 30.0) {
 +          // If temperature is normal, set fan ON
 +          targetPos = SERVO_RESET_POS;​
 +          fanState = true;
 +          fireState = "​starting";​
 +          Serial.println("​Reset accepted: Temperature is below 30°C - Moving servo to 0°");
 +          // Clean the entire database
 +          Serial.println("​Clearing all historical data..."​);​
 +          cleanupDatabase();​
 +        } else {
 +          // If temperature is high, don't allow reset - keep servo at 30° and fan OFF
 +          targetPos = SERVO_TRIGGER_POS;​
 +          fanState = false; ​
 +          fireState = "​off";​
 +          Serial.println("​Reset rejected: Temperature is above 30°C - Servo remains at 30°"​);​
 +          ​
 +          // Even when reset is rejected, update the current data in Firebase immediately
 +          updateLatestFirebaseData(tempC,​ smokeTempC, targetPos);
 +        }
 +        ​
 +        // Verify that the temperature and servo position follow the rules:
 +        // - If temp ≥ 30°C, servo MUST be at 30° (safety critical)
 +        // - If reset was accepted, servo MUST be at 0° (just pressed)
 +        // - If reset was rejected, servo MUST be at 30° (just verified)
 +        Serial.println("​RESET VERIFICATION:​ Checking temperature and servo consistency"​);​
 +        if (tempC >= 30.0 && targetPos != SERVO_TRIGGER_POS) {
 +          // This is a safety-critical error and needs immediate correction
 +          Serial.println("​CRITICAL ERROR: Temperature ≥30°C but servo not at 30°!"​);​
 +          Serial.println("​SAFETY ACTION: Overriding to ensure servo at 30° position!"​);​
 +          targetPos = SERVO_TRIGGER_POS;​
 +          fanState = false;
 +          ​
 +          // Physically move servo to safe position ​
 +          myServo.attach(SERVO_PIN,​ 700, 2300);
 +          myServo.write(SERVO_TRIGGER_POS);​
 +          lastServoPos = SERVO_TRIGGER_POS;​
 +          delay(700);
 +          myServo.detach();​
 +        } else if (tempC < 30.0 && resetCommand > 0 && targetPos != SERVO_RESET_POS) {
 +          // Only fix position if reset was explicitly requested and temperature allows it
 +          Serial.println("​ERROR:​ Reset requested with temp <30°C but servo not at 0°");
 +          Serial.println("​Fixing:​ Moving servo to 0° position"​);​
 +          targetPos = SERVO_RESET_POS;​
 +          fanState = true;
 +          ​
 +          // Physically move servo
 +          myServo.attach(SERVO_PIN,​ 700, 2300);
 +          myServo.write(SERVO_RESET_POS);​
 +          lastServoPos = SERVO_RESET_POS;​
 +          delay(700);
 +          myServo.detach();​
 +        } else {
 +          Serial.println("​VERIFICATION PASSED: Temperature and servo position are consistent"​);​
 +        }
 +        ​
 +        // Acknowledge the command by setting it to 0
 +        Firebase.RTDB.setInt(&​fbdo,​ "/​commands/​resetServo",​ 0);
 +      }
 +    }
 +  }
 +  ​
 +  // Always check smoke temperature - this takes precedence over Start Fire
 +  if (smokeTempC > 0) {  // Only update if we've read the sensors during this loop
 +    if (smokeTempC >= 28.0) {
 +      // If smoke temp is high, always show fire icon regardless of fan state
 +      fireState = "​on";​
 +    } else if (fanState) {
 +      // If smoke temp is low and fan is ON, show bolt
 +      fireState = "​starting";​
 +    } else {
 +      // If smoke temp is low and fan is OFF, show extinguisher
 +      fireState = "​off";​
 +    }
 +  }
 +  ​
 +  // --- Fan/fire logic based on temperatures ---
 +  if (tempC > 0) {  // Only update if we've read the sensors during this loop
 +    if (tempC >= 30.0) {
 +      // CRITICAL: High temperature needs immediate servo action!
 +      if (lastServoPos != SERVO_TRIGGER_POS) {
 +        // Servo is not in correct position for this high temperature!
 +        targetPos = SERVO_TRIGGER_POS; ​
 +        fanState = false; ​ // Always turn fan OFF when temperature is high
 +        Serial.println("​HIGH TEMP SAFETY: Temperature >= 30°C with servo not at 30° - Moving servo NOW!"​);​
 +      } else {
 +        // Servo is already in correct position but emphasize high temp state
 +        Serial.println("​Temperature still >= 30°C: Maintaining servo at 30° and fan OFF");
 +      }
 +    } else if (tempC < 30.0) {
 +      // When temperature drops below 30°C, DO NOT automatically move servo to 0°
 +      // Only update fan state based on current servo position
 +      fanState = (lastServoPos == SERVO_RESET_POS);​
 +      if (lastServoPos == SERVO_TRIGGER_POS) {
 +        Serial.println("​Temperature now < 30°C but servo will remain at 30° until reset button is pressed"​);​
 +      }
 +    }
 +  }
 +  ​
 +  // Only move the servo if the target position is different from the current position
 +  if (targetPos != lastServoPos) {
 +    Serial.print("​Servo position change needed: current = ");
 +    Serial.print(lastServoPos);​
 +    Serial.print("​°,​ target = ");
 +    Serial.print(targetPos);​
 +    Serial.println("​°"​);​
 +    ​
 +    // Attach servo, move it, then detach to prevent jitter and reduce power consumption
 +    myServo.attach(SERVO_PIN,​ 700, 2300);
 +    myServo.write(targetPos);​
 +    ​
 +    // Update logical state
 +    lastServoPos = targetPos;
 +    ​
 +    // Update fan state based on servo position
 +    // SERVO_RESET_POS (0°) = fan ON, SERVO_TRIGGER_POS (30°) = fan OFF
 +    bool previousFanState = fanState;
 +    fanState = (targetPos == SERVO_RESET_POS);​
 +    ​
 +    if (previousFanState != fanState) {
 +      Serial.print("​Fan state updated to: ");
 +      Serial.println(fanState ? "​ON"​ : "​OFF"​);​
 +    }
 +    ​
 +    // Wait for servo to complete movement
 +    delay(500);
 +    ​
 +    // Detach servo to prevent jitter and reduce power consumption
 +    myServo.detach();​
 +    Serial.println("​Servo detached after movement"​);​
 +    ​
 +    // Short delay after servo movement for stability
 +    delay(500);
 +  }
 +  ​
 +  // Small delay for loop stability - this doesn'​t affect command responsiveness
 +  delay(200);
 +  ​
 +  // Check if it's time to send sensor data (every 1 second)
 +  if (signupOK && Firebase.ready() && (millis() - lastSend > sensorDataDelay)) {
 +    lastSend = millis();
 +    ​
 +    // Read sensors every time we check (every 1s)
 +    sensors.requestTemperatures();​
 +    smokeSensors.requestTemperatures();​
 +    tempC = sensors.getTempCByIndex(0);​
 +    smokeTempC = smokeSensors.getTempCByIndex(0);​
 +    ​
 +    Serial.print("​Water Temperature:​ ");
 +    Serial.print(tempC);​
 +    Serial.println("​ °C");
 +    Serial.print("​Smoke Temperature:​ ");
 +    Serial.print(smokeTempC);​
 +    Serial.println("​ °C");
 +    ​
 +    // IMPORTANT: Only move servo to 30° when temperature rises above 30°C
 +    // DO NOT move servo back to 0° automatically - this only happens with reset button
 +    if (tempC >= 30.0 && lastServoPos != SERVO_TRIGGER_POS) {
 +      // Critical temperature detected, servo needs to move!
 +      Serial.println("​CRITICAL:​ Temperature ≥30°C but servo not at 30° - Moving servo now!"​);​
 +      targetPos = SERVO_TRIGGER_POS;​
 +      fanState = false;
 +      ​
 +      // Move servo immediately - don't wait for next loop
 +      Serial.println("​Moving servo to 30° position due to high temperature"​);​
 +      myServo.attach(SERVO_PIN,​ 700, 2300);
 +      myServo.write(targetPos);​
 +      lastServoPos = targetPos;
 +      delay(500); // Wait for servo to complete movement
 +      myServo.detach();​
 +      Serial.println("​Servo moved to 30° and detached"​);​
 +    }
 +    // We don't auto-reset to 0° when temperature drops - only reset button can do this
 +    ​
 +    // Now update Firebase with the latest data (including potentially updated servo position)
 +    updateLatestFirebaseData(tempC,​ smokeTempC, lastServoPos);​
 +  }
 +</​code>​
 +
 +I really hate just throwing code in here and calling it a day but I'm really tired and also otherwise the page would be empty.
  
 ==== Firebase ==== ==== Firebase ====
 +{{ iothings:​proiecte:​2025sric:​tudu-firebase-app.png?​600 }}
  
 +The entire application is hosted in firebase using a realtime database that contains:
 +  * history of sensor readings
 +  * latest reading
 +  * status of "Start Fire" button
 +
 +The entire communication between the ESP32 and the Firebase application is done using the realtime database:
 +{{ iothings:​proiecte:​2025sric:​tudu-realtime-database.png?​600 }}
 ====== Challenges ====== ====== Challenges ======
 +How the hell can someone open a store that sells something and have no knowledge about it? There is one store in Pitesti that sells electronics and Arduino stuff, and they have no idea what they are selling. Literally. I went there asking for parts and some advice, and they asked me for the codes of stuff on their website. They even gave me the wrong thing because I wasn't paying attention. HOW? (It's also my fault, I suppose, but still)
 +
 +Another challenge was getting the interface to be responsive:
 +{{ iothings:​proiecte:​2025sric:​tudu-firebase-app-phone.png?​600 }}
  
 +And also all of the other stuff that can go wrong when using this hellish spawn of a platform called ESP32/​Arduino,​ I really hope someone pays for the suffering they have upon the world.
 ====== References ====== ====== References ======
 +Idk, stuff online I guess?
iothings/proiecte/2025sric/centralheatingmonitoring.1748463481.txt.gz · Last modified: 2025/05/28 23:18 by george.tudurean
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0