Programing assistance, MAX31855 lags at temp over 1024
Posted: Wed Dec 17, 2025 7:03 am
hi,
Not sure if this is the best spot to post, if not please let me know where is better.
I have a thermocouple (k type - is fine for my needseven if not the best)
the program i have works well upto 1024 deg C but then the program slows down and stops refreshing web.
it is for a gas kiln, to track the rate of change in temp, over 5 min and 30 min. (takes about 10 hours to fire kiln uptp 1230deg c.)
i assume it is because of the precision in floating point?
my programing skills are very basic,
code as follows,
Not sure if this is the best spot to post, if not please let me know where is better.
I have a thermocouple (k type - is fine for my needseven if not the best)
the program i have works well upto 1024 deg C but then the program slows down and stops refreshing web.
it is for a gas kiln, to track the rate of change in temp, over 5 min and 30 min. (takes about 10 hours to fire kiln uptp 1230deg c.)
i assume it is because of the precision in floating point?
my programing skills are very basic,
code as follows,
Code: Select all
#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <Preferences.h>
#include <SPI.h>
#include <time.h>
#include <Adafruit_MAX31855.h>
// Hardware Configuration
#define MAXDO 19 // Data out
#define MAXCS 5 // Chip Select
#define MAXCLK 18 // Clock
#define LED_LOW 25 //blue
#define LED_MID 26 //green
#define LED_HIGH 27 //red
const int shortBlinkDuration = 250; // milliseconds
const int longBlinkDuration = 750;
const int pauseDuration = 500;
float avgTCCelsius =0;
float icnt=0;
float TCCelsius=0;
// Data Logging
#define LOG_INTERVAL 30000 // 30 seconds ( 30000)
#define TEMP_INTERVAL 5000 // 5 seconds ( 5000)
#define BUFFER_SIZE 1400 // 12 hours at 30s intervals
// Default Settings
const char *AP_SSID = "ThermoConfig";
float LOW_THRESH = 100.0;
float HIGH_THRESH = 170.0;
// NTP Configuration for Australia (AEST/AEDT)
const char *ntpServer = "au.pool.ntp.org"; // Australian NTP pool
const char *tz = "AEST-10AEDT-11,M10.1.0,M4.1.0/3"; // Auto DST adjustment
struct TempReading
{
time_t timestamp; // Unix timestamp
float temperature;
float rate5min;
float rate30min;
float TCCelsius;
float temp_avgTCCelsius;
};
//MAX6675 thermocouple(MAX6675_SCK, MAX6675_CS, MAX6675_MISO);
Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO);
WebServer server(80);
Preferences prefs;
TempReading tempBuffer[BUFFER_SIZE];
int bufferIndex = 0;
int readingsCount = 0;
unsigned long lastReadingTime = 0;
unsigned long lastTEMPTime = 0;
float currentTemp = 0.0;
float rate5min = 0.0;
float rate30min = 0.0;
float currentRate5min = 0.0;
float currentRate30min = 0.0;
bool restartFlag = false;
unsigned long restartTime = 0;
bool timeSet = false;
void initSPI()
{
pinMode(MAXCS, OUTPUT);
digitalWrite(MAXCS, HIGH);
}
void updateRates() {
currentRate5min = NAN;
currentRate30min = NAN;
if (readingsCount >= 10)
{
int idx = (bufferIndex - 10 + BUFFER_SIZE) % BUFFER_SIZE;
rate5min = (currentTemp - tempBuffer[idx].temperature) * 12.0f; //f float
currentRate5min = rate5min;
}
if (readingsCount >= 60)
{
int idx = (bufferIndex - 60 + BUFFER_SIZE) % BUFFER_SIZE;
rate30min = (currentTemp - tempBuffer[idx].temperature) * 2.0f; //f float
currentRate30min = rate30min;
}
}
void updateLEDs() {
float rate = !isnan(currentRate5min) ? currentRate5min : currentRate30min;
digitalWrite(LED_LOW, LOW);
digitalWrite(LED_MID, LOW);
digitalWrite(LED_HIGH, LOW);
if (isnan(rate)) return;
if (rate < LOW_THRESH) digitalWrite(LED_LOW, HIGH);
else if (rate > HIGH_THRESH) digitalWrite(LED_HIGH, HIGH);
else digitalWrite(LED_MID, HIGH);
}
// Initialize NTP time synchronization with Australian settings
void initTime()
{
configTzTime(tz, ntpServer);
Serial.println("Waiting for NTP time sync...");
// Wait for time to be set
time_t now;
int attempts = 0;
while ((now = time(nullptr)) < 1000000000 && attempts < 20)
{
Serial.print(".");
delay(500);
attempts++;
}
if (now < 1000000000)
{
Serial.println("\nFailed to get NTP time");
timeSet = false;
}
else
{
Serial.println("\nTime synchronized!");
timeSet = true;
}
}
// Get current timestamp
time_t getCurrentTime()
{
return time(nullptr);
}
// Format timestamp as compact Australian time string (HH:MM:SS)
String formatTime(time_t timestamp)
{
if (timestamp == 0) return "N/A";
struct tm *timeinfo;
timeinfo = localtime(×tamp);
char buffer[10]; // HH:MM:SS format
strftime(buffer, sizeof(buffer), "%H:%M:%S", timeinfo);
return String(buffer);
}
// Format date for display (DD/MM/YYYY)
String formatDate(time_t timestamp)
{
if (timestamp == 0) return "N/A";
struct tm *timeinfo;
timeinfo = localtime(×tamp);
char buffer[11]; // DD/MM/YYYY format
strftime(buffer, sizeof(buffer), "%d/%m/%Y", timeinfo);
return String(buffer);
}
void handleRoot()
{
String html = R"rawhtml(
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Thermocouple Monitor</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body { font-family: Arial, sans-serif; }
.container { max-width: 1200px; margin: 0 auto; }
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; text-align:center;}
.status-card { background: #29cc00; padding: 15px; border-radius: 5px; }
button { padding: 12px; background: #29cc00; color: white; border: none; border-radius: 4px; cursor: pointer; }
canvas { margin-top: 20px; } // extra
.alert { padding: 10px; margin: 10px 0; border-radius: 4px; }
.success { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
</style>
</head>
<body>
<div class="container">
<h2 text-align:center;>Thermocouple Monitoring</h2>
<div id="message" class="alert" style="display:none;"></div>
<div class="grid">
<div class="status-card"; >
<p>Current Temp</p>
<h1 style="font-size:3rem;" id="currentTemp">0.0 °C</h1>
</div>
<div class="status-card">
<p>5-min Rate</p>
<h1 style="font-size:3rem;" id="rate5min">0.0 °C/h</h1>
</div>
<div class="status-card">
<p>30-min Rate</p>
<h1 style="font-size:3rem;" id="rate30min">0.0 °C/h</h1>
</div>
</div>
<canvas id="tempChart"></canvas>
<div style="margin-top:20px;">
<h3>Configuration</h3>
<div>
<label>Low Threshold: </label>
<input type="number" id="lowThresh" step="0.1" value=")rawhtml" + String(LOW_THRESH) + R"rawhtml(">
<label>High Threshold: </label>
<input type="number" id="highThresh" step="0.1" value=")rawhtml" + String(HIGH_THRESH) + R"rawhtml(">
<button onclick="updateThresholds()">Update</button>
</div>
<div style="margin-top:10px;">
<h3>Download CSV</h3>
<button onclick="downloadCSV()">Download</button>
</div>
<div style="margin-top:20px;">
<h3>WiFi Settings</h3>
<input type="text" id="ssid" placeholder="New SSID" value=")rawhtml" + String(WiFi.SSID()) + R"rawhtml(">
<input type="password" id="password" placeholder="New Password">
<button onclick="updateWiFi()">Update WiFi</button>
</div>
<div style="margin-top:20px;">
<h3>Time Sync</h3>
<button onclick="syncTime()">Sync Time</button>
</div>
</div>
</div>
<script>
const ctx = document.getElementById('tempChart').getContext('2d');
const chart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'Temperature (C)',
data: [],
borderColor: 'rgb(75, 192, 192)',
tension: 0.1
}]
},
options: { scales: { y: { beginAtZero: false } } }
});
function showMessage(text, isError) {
const msgDiv = document.getElementById('message');
msgDiv.textContent = text;
msgDiv.className = isError ? 'alert error' : 'alert success';
msgDiv.style.display = 'block';
setTimeout(() => msgDiv.style.display = 'none', 5000);
}
function updateData() {
fetch('/data')
.then(r => r.json())
.then(data => {
document.getElementById('currentTemp').textContent = data.currentTemp.toFixed(1) + ' C';
document.getElementById('rate5min').textContent = data.rate5min.toFixed(1) + ' C/h';
document.getElementById('rate30min').textContent = data.rate30min.toFixed(1) + ' C/h';
chart.data.labels = data.timestamps;
chart.data.datasets[0].data = data.temperature;
chart.update();
});
}
function updateThresholds() {
const low = document.getElementById('lowThresh').value;
const high = document.getElementById('highThresh').value;
fetch(`/config?low=${low}&high=${high}`)
.then(r => r.text())
.then(text => showMessage(text, false))
.catch(e => showMessage('Error: ' + e, true));
}
function downloadCSV() {
window.location.href = '/csv';
}
function updateWiFi() {
const ssid = document.getElementById('ssid').value;
const password = document.getElementById('password').value;
if(!ssid) {
showMessage('SSID cannot be empty!', true);
return;
}
fetch(`/wifi?ssid=${encodeURIComponent(ssid)}&pass=${encodeURIComponent(password)}`)
.then(r => r.text())
.then(text => {
showMessage(text, false);
setTimeout(() => showMessage('Reconnecting in 5 seconds...', false), 1000);
setTimeout(() => location.reload(), 6000);
})
.catch(e => showMessage('Error: ' + e, true));
}
function syncTime() {
fetch('/synctime')
.then(r => r.text())
.then(text => {
showMessage(text, false);
location.reload();
})
.catch(e => showMessage('Error: ' + e, true));
}
setInterval(updateData, 2000);
updateData();
</script>
</body>
</html>
)rawhtml";
server.send(200, "text/html; charset=utf-8", html);
}
void handleData()
{
String json = "{";
json += "\"currentTemp\":" + String(currentTemp) + ",";
json += "\"rate5min\":" + String(rate5min) + ",";
json += "\"rate30min\":" + String(rate30min) + ",";
json += "\"timestamps\":[";
for(int i = 0; i < min(readingsCount, 61); i++)
{
if(i > 0) json += ",";
json += "\"" + String(i*0.5f) + "m\"";
}
json += "],";
json += "\"temperature\":[";
for(int i = 0; i < min(readingsCount, 61); i++) {
if(i > 0) json += ",";
int idx = (bufferIndex - min(readingsCount, 61) + i + BUFFER_SIZE) % BUFFER_SIZE;
json += String(tempBuffer[idx].temperature);
}
json += "]}";
server.send(200, "application/json; charset=utf-8", json);
}
void handleCSV()
{
// Use "C" instead of "amp deg C" to avoid encoding issues in CSV
// String csv = "Time (s),Temperature (C)\n";
String csv = formatDate(getCurrentTime()) + "\n" + "Time,Temperature (C),5min Rate (C/h),30min Rate (C/h)\n";
for(int i = 0; i < readingsCount; i++) {
int idx = (bufferIndex - readingsCount + i + BUFFER_SIZE) % BUFFER_SIZE;
// Format timestamp to HH:MM:SS
csv += formatTime(tempBuffer[idx].timestamp) + ",";
csv += String(tempBuffer[idx].temperature, 1) + ",";
csv += String(tempBuffer[idx].rate5min, 1) + ",";
csv += String(tempBuffer[idx].rate30min, 1) + "\n";
//csv += String(i*10) + "," + String(tempBuffer[idx].temperature, 1) + "\n";
}
server.send(200, "text/csv", csv);
}
void handleConfig()
{
if(server.hasArg("low") && server.hasArg("high"))
{
LOW_THRESH = server.arg("low").toFloat();
HIGH_THRESH = server.arg("high").toFloat();
prefs.putFloat("lowThresh", LOW_THRESH);
prefs.putFloat("highThresh", HIGH_THRESH);
server.send(200, "text/plain", "Thresholds updated");
}
else
{
server.send(400, "text/plain", "Invalid parameters");
}
}
void handleWiFi()
{
if(server.hasArg("ssid") && server.hasArg("pass")) {
String ssid = server.arg("ssid");
String pass = server.arg("pass");
if(ssid.length() == 0) {
server.send(400, "text/plain", "SSID cannot be empty");
return;
}
prefs.putString("ssid", ssid);
prefs.putString("pass", pass);
prefs.end(); // Ensure data is committed
server.send(200, "text/plain", "WiFi credentials updated. Reconnecting...");
// Set flag to trigger reconnect in main loop
restartFlag = true;
restartTime = millis() + 2000; // Reconnect after 2 seconds
}
else
{
server.send(400, "text/plain", "Missing parameters");
}
}
void handleSyncTime()
{
initTime();
server.send(200, "text/plain", "Time synchronized: " + formatTime(getCurrentTime()));
}
void blink_octet(int octet)
{
if (octet ==10)
{
digitalWrite(LED_MID, HIGH);
delay(1000);
digitalWrite(LED_MID, LOW);
delay(pauseDuration);
}
else
{
for (int i = 0; i < octet; i++)
{
digitalWrite(LED_MID, HIGH);
delay(shortBlinkDuration);
digitalWrite(LED_MID, LOW);
if (i < octet - 1)
{
delay(pauseDuration);
}
}
}
}
void initWiFi()
{
prefs.begin("thermoConfig", false);
String ssid = prefs.getString("ssid", "");
String pass = prefs.getString("pass", "");
if(ssid == "")
{
WiFi.softAP(AP_SSID);
Serial.println("AP Mode: " + String(AP_SSID));
return;
}
WiFi.begin(ssid.c_str(), pass.c_str());
Serial.print("Connecting to WiFi...");
int attempts = 0;
while(WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if(WiFi.status() == WL_CONNECTED) {
Serial.println("\nConnected! IP: " + WiFi.localIP().toString());
// Initialize time after WiFi connection
initTime();
}
else
{
WiFi.softAP(AP_SSID);
Serial.println("\nFailed! Starting AP Mode");
}
}
void reconnectWiFi()
{
Serial.println("Reconnecting to WiFi...");
WiFi.disconnect();
delay(1000);
initWiFi();
restartFlag = false;
}
void setup()
{
Serial.begin(115200);
// Initialize hardware
pinMode(LED_LOW, OUTPUT);
pinMode(LED_MID, OUTPUT);
pinMode(LED_HIGH, OUTPUT);
initSPI();
// Load saved settings
prefs.begin("thermoConfig", false);
LOW_THRESH = prefs.getFloat("lowThresh", 100.0);
HIGH_THRESH = prefs.getFloat("highThresh", 175.0);
prefs.end();
// Start WiFi
initWiFi();
IPAddress ipAddress = WiFi.localIP();
int octet = ipAddress[3];
int val = octet;
int hundreds = val / 100;
val -= hundreds * 100;
int tens = val / 10;
val -= tens * 10;
int ones = val;
if (hundreds < 1) hundreds = 10;
if (tens < 1) tens = 10;
if (ones < 1) ones = 10;
blink_octet(hundreds);
delay(1000);
blink_octet(tens);
delay(1000);
blink_octet(ones);
delay(1000);
// Setup web server
server.on("/", handleRoot);
server.on("/data", handleData);
server.on("/csv", handleCSV);
server.on("/config", handleConfig);
server.on("/wifi", handleWiFi);
server.begin();
Serial.println("HTTP server started");
}
void loop()
{
server.handleClient();
delay(490);
// Handle WiFi reconnect if needed
if (restartFlag && millis() >= restartTime) {
reconnectWiFi();
}
// Handle temperature readings
unsigned long currentTime = millis();
TCCelsius = thermocouple.readCelsius();
//float avgTCCelsius1 = avgTCCelsius + TCCelsius;
//avgTCCelsius=avgTCCelsius1;
avgTCCelsius=avgTCCelsius + TCCelsius;
++icnt;
Serial.print(" temp ");
Serial.print(TCCelsius);
Serial.print('\n');
if (currentTime - lastTEMPTime >= TEMP_INTERVAL) {
lastTEMPTime = currentTime;
currentTemp = avgTCCelsius/icnt;
avgTCCelsius = 0 ; //james
icnt = 0 ;
Serial.print(" avtemp ");
Serial.print(currentTemp);
Serial.print('\n');
}
if (currentTime - lastReadingTime >= LOG_INTERVAL) {
lastReadingTime = currentTime;
if (!isnan(currentTemp))
{
// Calculate rates
updateRates();
// Store reading with rates and timestamp
tempBuffer[bufferIndex] = {
.timestamp = getCurrentTime(),
.temperature = currentTemp,
.rate5min = currentRate5min,
.rate30min = currentRate30min
};
// Update buffer position
bufferIndex = (bufferIndex + 1) % BUFFER_SIZE;
if (readingsCount < BUFFER_SIZE) readingsCount++;
// Update LEDs
updateLEDs();
}
}
}
[/code