Hey guys. I try to build an temperature controler with an esp for an pasteurisator barrel. The wireing is super fine and the hardware works fine as well. the only issues are a few nounches in the code.
Thats what CPT said to my problem…
…To implement the logic you need, we can structure your program using a finite state machine (FSM) to handle the four distinct states of the system: Heating up
, Cooking
, Cooling down
, and Finished
. We will also track the progress of the cooking process, update the button logic to control the heating element, and display the progress as a percentage from 0 to 100%.
Here’s a solution to address each point of your requirement:
1. Finite State Machine Implementation
We will define the four states:
- State 1 - Heating: The system is heating up until it reaches the
temperature_control
. - State 2 - Cooking: Once the target temperature is reached, the system maintains the temperature for the
temperature_duration
. - State 3 - Cooling: After the cooking time, the system enters cooling mode.
- State 4 - Finished: The cooling is complete, and the system is done.
We will also implement logic to calculate the percentage progress of cooking time and ensure the button acts as a kill switch to stop everything if turned off.
Code Modifications
Here is an updated version of your code with these changes:
// Constants for states
enum State { HEATING, COOKING, COOLING, FINISHED };
State systemState = HEATING; // Initial state is heating
#define RREF 430.0
#define RNOMINAL 100.0
#define BLYNK_TEMPLATE_ID "TMPL4jB2f7bc9"
#define BLYNK_TEMPLATE_NAME "Pasteurisator barrel"
#define BLYNK_FIRMWARE_VERSION "0.1.0"
#define USE_ESP32_DEV_MODULE
#define HEAT 15 // Pin for controlling the heating element
#include "BlynkEdgent.h"
#include <Wire.h>
#include <Adafruit_MAX31865.h>
Adafruit_MAX31865 thermo = Adafruit_MAX31865(5, 23, 19, 18); // RTD sensor
BlynkTimer timer;
float temperature_control = 0;
float temperature_duration = 0;
float button = 0;
float temperature = 0;
float progress = 0;
unsigned long startTime = 0;
unsigned long cookingStartTime = 0;
bool heating = false;
BLYNK_WRITE(V0) { temperature_control = param.asInt(); }
BLYNK_WRITE(V1) { temperature_duration = param.asInt() * 60 * 60; } // Convert hours to seconds
BLYNK_WRITE(V4) {
button = param.asInt();
if (button == 0) {
// Kill switch activated, turn off heating and reset everything
heating = false;
systemState = FINISHED;
digitalWrite(HEAT, LOW); // Turn off heating
}
}
BLYNK_CONNECTED() {
Blynk.syncVirtual(V0);
Blynk.syncVirtual(V1);
Blynk.syncVirtual(V4);
}
// Function to handle heating, cooking, cooling, and progress monitoring
void processControl() {
temperature = thermo.temperature(RNOMINAL, RREF); // Read temperature
Blynk.virtualWrite(V2, temperature); // Send temperature to app
switch(systemState) {
case HEATING:
if (temperature < temperature_control && button == 1) {
digitalWrite(HEAT, HIGH); // Turn on heating
heating = true;
} else {
systemState = COOKING; // Transition to cooking state
cookingStartTime = millis(); // Record the time cooking starts
}
break;
case COOKING:
if (heating && millis() - cookingStartTime < temperature_duration * 1000) {
digitalWrite(HEAT, HIGH); // Keep heating if needed
} else {
systemState = COOLING; // Transition to cooling state
digitalWrite(HEAT, LOW); // Turn off heating
heating = false;
}
// Update progress
unsigned long elapsedTime = millis() - cookingStartTime;
progress = (float)elapsedTime / (temperature_duration * 1000) * 100;
Blynk.virtualWrite(V3, progress); // Update progress on the app
break;
case COOLING:
if (temperature > 30) { // Assuming 30°C is a safe temperature
// Cooling down naturally
digitalWrite(HEAT, LOW); // Make sure the heater is off
} else {
systemState = FINISHED; // Transition to finished state
}
break;
case FINISHED:
Blynk.virtualWrite(V5, 1); // Notify the app that the process is finished
break;
}
}
// Function to read sensor data and handle faults
void sensor() {
uint16_t rtd = thermo.readRTD();
temperature = thermo.temperature(RNOMINAL, RREF); // Get the temperature
Blynk.virtualWrite(V2, temperature); // Update temperature on Blynk app
// Handle faults from the sensor
uint8_t fault = thermo.readFault();
if (fault) {
thermo.clearFault();
}
Serial.print("Temperature = ");
Serial.println(temperature);
}
void setup() {
Serial.begin(115200);
Wire.begin();
BlynkEdgent.begin();
thermo.begin(MAX31865_3WIRE); // Initialize MAX31865 sensor
timer.setInterval(5000L, sensor); // Read sensor every 5 seconds
timer.setInterval(1000L, processControl); // Process heating every 1 second
pinMode(HEAT, OUTPUT);
}
void loop() {
BlynkEdgent.run();
timer.run();
}
Explanation of Changes
-
Finite State Machine (FSM):
- We defined an
enum State
with four states:HEATING
,COOKING
,COOLING
, andFINISHED
. - Depending on the current state, the system checks temperature, manages heating, and transitions between states.
- We defined an
-
Heating Control:
- When the temperature is below
temperature_control
and the button is ON, the system heats up. - When the target temperature is reached, it enters the
COOKING
state and maintains the temperature for thetemperature_duration
.
- When the temperature is below
-
Progress Calculation:
- We track the progress during cooking and send the progress percentage to the app on virtual pin
V3
.
- We track the progress during cooking and send the progress percentage to the app on virtual pin
-
Cooling and Completion:
- After cooking, the system enters the cooling phase, and once it cools below 30°C, it transitions to the
FINISHED
state. - The system sends a notification to the app that the process is finished (
V5
).
- After cooking, the system enters the cooling phase, and once it cools below 30°C, it transitions to the
How it works:
- When the button is ON, the heating starts and follows the steps until it completes cooking and cools down.
- The system state is displayed via progress and different states are tracked.
- You can easily monitor the state of the cooking process from your Blynk app with temperature and progress displayed.
Let me know if you’d like more details or adjustments!
My old code:
/////////////////////////////////////////////////////////////////
//////////// ///////////////
//////////// M U S H C U B I X . O S ///////////////
//////////// Version 2.0 17/10/24 ///////////////
//////////// ///////////////
/////////////////////////////////////////////////////////////////
//ESP32 PINS:
// EN: nc
// VP: nc
// VN: nc
// G34: nc
// G35: nc
// G32: nc
// G33: nc
// G25: nc
// G26: nc
// G27: nc
// G14: nc
// G12: nc
// G13: nc
// GND: GND
// 5V: 5V VCC
// G23: SDI
// G22: nc
// TXD: nc
// RXD: nc
// G21: nc
// G19: SD0
// G18: CLK
// G5: CS
// TXD2: nc
// RXD2: nc
// G4: nc
// G2: nc
// G15: nc
// GND: GND
// 3V3: nc
#define RREF 430.0 // Reference resistor value for the RTD (used to calculate resistance from the ADC). Use 430.0 for PT100, 4300.0 for PT1000
#define RNOMINAL 100.0 // The nominal resistance of the RTD at 0°C. Use 100.0 for PT100, 1000.0 for PT1000
#define BLYNK_TEMPLATE_ID "TMPL4jB2f7bc9" // Blynk Template ID for the device
#define BLYNK_TEMPLATE_NAME "Pasteurisator barrel" // Blynk Template Name for the project
#define BLYNK_FIRMWARE_VERSION "0.1.0" // Firmware version of the project
#define APP_DEBUG // Enable debugging features for Blynk
#define USE_ESP32_DEV_MODULE // Specify the ESP32 development board being used
//#define BLYNK_DEBUG // Uncomment to enable detailed debug output for Blynk
// Data-Output:
#define HEAT 15 /// HEAT // Defines pin 15 for controlling the heating element
#include "BlynkEdgent.h" // Includes the BlynkEdgent library to manage communication with Blynk
#include <Wire.h> // Includes the Wire library for I2C communication
#include <Adafruit_MAX31865.h> // Includes the Adafruit_MAX31865 library to read the RTD sensor (PT100)
Adafruit_MAX31865 thermo = Adafruit_MAX31865(5, 23, 19, 18); // Defines a MAX31865 instance using software SPI on specified pins (CS, DI, DO, CLK)
BlynkTimer timer; // Timer object to schedule tasks at regular intervals
float timer_start_millis; // Variable to store the start time in milliseconds
float temperature_control; // Variable to store the user-defined temperature from the Blynk app
float temperature_duration; // Variable to store the user-defined duration for heating from the Blynk app
float button; // Variable to store the button state from the Blynk app
float temperature; // Variable to store the current temperature read from the sensor
float progress; // Variable to track the progress of the heating process
long unixtime; // Variable to store the Unix timestamp
unsigned long startTime; // Variable to store the start time of heating
unsigned long endTime; // Variable to store the end time of heating
bool heating = false; // Boolean to track whether the heating element is on or off
// BLYNK_WRITE - Receive values from the Blynk server
BLYNK_WRITE(V0) { // BLYNK_WRITE function to receive and handle temperature control values from the app (V0)
temperature_control = param.asInt(); // Store the received value in temperature_control
Serial.print("BLYNK_WRITE(V0) triggered - incoming value temperature_control= ");
Serial.println(temperature_control); // Print the value to the Serial Monitor
}
BLYNK_WRITE(V1) { // BLYNK_WRITE function to receive and handle duration values from the app (V1)
temperature_duration = param.asInt(); // Store the received value in temperature_duration
Serial.print("BLYNK_WRITE(V1) triggered - incoming value temperature_duration= ");
Serial.println(temperature_duration); // Print the value to the Serial Monitor
}
BLYNK_WRITE(V4) { // BLYNK_WRITE function to receive and handle button press state from the app (V4)
button = param.asInt(); // Store the received value in button
Serial.print("BLYNK_WRITE(V4) triggered - incoming value button= ");
Serial.println(button); // Print the value to the Serial Monitor
//temp_control(); // Optional function to control temperature based on the button state (currently commented out)
}
// Time schedule for light (work in progress)
BLYNK_WRITE(InternalPinRTC) { // BLYNK_WRITE function for syncing real-time clock (RTC) with the app (InternalPinRTC)
unixtime = param.asLong(); // Store the received Unix timestamp in unixtime
Serial.print(" Unix time: ");
Serial.print(unixtime); // Print the Unix timestamp to the Serial Monitor
Serial.println();
}
BLYNK_CONNECTED() {
Blynk.sendInternal("rtc", "sync"); // Request the current local time from the Blynk server
Blynk.syncVirtual(V0); // Synchronize temperature_control with the app
Blynk.syncVirtual(V1); // Synchronize temperature_duration with the app
Blynk.syncVirtual(V4); // Synchronize button state with the app
}
// Sensor function to read the RTD sensor and handle faults
void sensor() {
uint16_t rtd = thermo.readRTD(); // Read the RTD value from the sensor
float ratio = rtd / 32768.0; // Calculate the RTD ratio
Serial.print("RTD value: "); Serial.println(rtd); // Print the RTD value to the Serial Monitor
Serial.print("Ratio = "); Serial.println(ratio, 8); // Print the RTD ratio
Serial.print("Resistance = "); Serial.println(RREF * ratio, 8); // Print the calculated resistance based on RREF
Serial.print("Temperature = "); Serial.println(thermo.temperature(RNOMINAL, RREF)); // Print the calculated temperature
temperature = thermo.temperature(RNOMINAL, RREF); // Store the calculated temperature in the temperature variable
// Check and print any faults from the sensor
uint8_t fault = thermo.readFault();
if (fault) {
Serial.print("Fault 0x"); Serial.println(fault, HEX); // Print the fault code in hexadecimal format
if (fault & MAX31865_FAULT_HIGHTHRESH) {
Serial.println("RTD High Threshold"); // Fault: RTD value exceeds high threshold
}
if (fault & MAX31865_FAULT_LOWTHRESH) {
Serial.println("RTD Low Threshold"); // Fault: RTD value below low threshold
}
if (fault & MAX31865_FAULT_REFINLOW) {
Serial.println("REFIN- > 0.85 x Bias"); // Fault: Reference resistor low error
}
if (fault & MAX31865_FAULT_REFINHIGH) {
Serial.println("REFIN- < 0.85 x Bias - FORCE- open"); // Fault: Reference resistor high error
}
if (fault & MAX31865_FAULT_RTDINLOW) {
Serial.println("RTDIN- < 0.85 x Bias - FORCE- open"); // Fault: RTD input low error
}
if (fault & MAX31865_FAULT_OVUV) {
Serial.println("Under/Over voltage"); // Fault: Under or over voltage error
}
thermo.clearFault(); // Clear any existing fault conditions
}
Blynk.virtualWrite(V2, temperature); // Send the temperature value to the Blynk app on virtual pin V2
Serial.print("V2 virtual write: ");
Serial.println(temperature); // Print the sent temperature value to the Serial Monitor
// Additional output information for debugging and display purposes
Serial.println(" ");
Serial.println(" ");
Serial.println("------------------------------------------------------");
Serial.println(" Additional Outputs ");
Serial.println("------------------------------------------------------");
Serial.println(" ");
Blynk.sendInternal("rtc", "sync"); // Request current local time for device
Serial.println(" ");
Serial.println(" Blynk user settings:");
Serial.println(" ");
//Blynk Settings
Serial.print(" temperature_control = ");
Serial.print(temperature_control); // Print the user-defined temperature control setting
Serial.print("°C");
Serial.println(" ");
Serial.print(" temperature_duration = ");
Serial.print(temperature_duration); // Print the user-defined temperature duration
Serial.println("h");
Serial.println(" ");
//Sensor Values
Serial.println(" Sensor PT100:");
Serial.println(" ");
Serial.print(" temperature = ");
Serial.print(temperature); // Print the current sensor temperature
Serial.print("°C");
Serial.println(" ");
//Progress
Serial.print(" progress = ");
Serial.print(progress); // Print the progress percentage of the heating process
Serial.print("%");
Serial.println(" ");
}
void setup() {
Serial.begin(115200); // Initialize the serial communication at 115200 baud rate
delay(1000); // Wait 1 second for stabilization
Wire.begin(); // Initialize the Wire (I2C) library
BlynkEdgent.begin(); // Initialize BlynkEdgent for Blynk communication
Serial.println("Adafruit MAX31865 PT100 Sensor Test!"); // Print a message to the Serial Monitor
thermo.begin(MAX31865_3WIRE); // Initialize the MAX31865 sensor in 3-wire mode
timer.setInterval(5000L, sensor); // Set a timer to call the sensor() function every 5000 milliseconds (5 seconds)
pinMode(HEAT, OUTPUT); // Set the HEAT pin (pin 15) as an output
}
void loop() {
BlynkEdgent.run(); // Continuously run the BlynkEdgent process
timer.run(); // Continuously run the timer process
}
My Serial Monitor:
Adafruit MAX31865 PT100 Sensor Test!
Unix time: 1729185714
BLYNK_WRITE(V0) triggered - incoming value temperature_control= 200.00
BLYNK_WRITE(V1) triggered - incoming value temperature_duration= 17.00
BLYNK_WRITE(V4) triggered - incoming value button= 1.00
RTD value: 8324
Ratio = 0.25402832
Resistance = 109.23217773
Temperature = 23.74
V2 virtual write: 23.74
------------------------------------------------------
Additional Outputs
------------------------------------------------------
Blynk user settings:
temperature_control = 200.00°C
temperature_duration = 17.00h
Sensor PT100:
temperature = 23.74°C
progress = 0.00%
Unix time: 1729185715
RTD value: 8330
Ratio = 0.25421143
Resistance = 109.31091309
Temperature = 23.91
V2 virtual write: 23.87
------------------------------------------------------
Additional Outputs
------------------------------------------------------
Blynk user settings:
temperature_control = 200.00°C
temperature_duration = 17.00h
Sensor PT100:
temperature = 23.87°C
progress = 0.00%
Unix time: 1729185720
RTD value: 8332
Ratio = 0.25427246
Resistance = 109.33715820
Temperature = 23.98
V2 virtual write: 23.98