Conversion of seconds to days/hours/minutes/seconds with problems

I'm trying to convert seconds to days, hours, minutes and seconds. In theory, something simple. But return something like this:

10111:111000:101010

What is wrong?

void convertTime(unsigned long timeInSeconds, unsigned int &days, unsigned int &hours, unsigned int &minutes, unsigned int &seconds) {
  seconds = timeInSeconds % 60;
  timeInSeconds /= 60;
  minutes = timeInSeconds % 60;
  timeInSeconds /= 60;
  hours = timeInSeconds % 24;
  days = timeInSeconds / 24;
}

// Function to send temperature/time data to HTML
void handleTemperatureData() {
  float currentTemperature = readTemperature();
  float targetTemperature = temperatureData[currentTemperatureIndex].temperature;
  targetTime = temperatureData[currentTemperatureIndex].time;

  remainingTime = countElapsedTime(); // Calculate the elapsed time
  
  // Convert the elapsed time to a formatted string (days (days) hh:mm:ss)
  unsigned int days, hours, minutes, seconds;
  convertTime(remainingTime, days, hours, minutes, seconds);
  String formattedElapsedTime = String(days) + " (days) " + String(hours, 2) + ":" + String(minutes, 2) + ":" + String(seconds, 2);
  Serial.println(formattedElapsedTime);
  // Create JSON response
  String jsonResponse = "{";
  jsonResponse += "\"currentTemperature\": " + floatToString(currentTemperature, 2) + ",";
  jsonResponse += "\"targetTemperature\": " + floatToString(targetTemperature, 2) + ",";
  jsonResponse += "\"targetTime\": " + String(targetTime) + ",";
  jsonResponse += "\"formattedElapsedTime\": \"" + formattedElapsedTime + "\"";
  jsonResponse += "}";

  server.send(200, "application/json", jsonResponse);
}

In monitor, the result of 432000 seconds is:

4 (days) 10111:111000:101010

This is printing the value of hours in base 2, I assume your intent was to print the value in base 10 with two digits, which is not how that works.

On which plattform?
where does the second-timestamp come from?
Can you make a full compileable program?

on an ESP8266 having the runtime in seconds in a variable ss I'm using this to make it readable

  if (ss > 604800) {
    message += F("<span id='week'>");
    message +=  ((ss / 604800) % 52);
    message += F("</span> weeks ");
  }
  if (ss > 86400) {
    message += F("<span id='day'>");
    message += ((ss / 86400) % 7);
    message += F("</span> days ");
  }
  if (ss > 3600) {
    message += F("<span id='hour'>");
    message += ((ss / 3600) % 24);
    message += F("</span> hours ");
  }
  message += F("<span id='min'>");
  message += ((ss / 60) % 60);
  message += F("</span> minutes ");
  message += F("<span id='sec'>");
  message += (ss % 60);
  message += F("</span> seconds since startup | Version " VERSION );

It's an esp8266 too

The full sketch

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <FS.h>
#include "secrets.h"

const char* ssid = STASSID;
const char* pass = STAPSK;

// Sensor de temperatura conectado na GPIO 4 / D2
#define ONE_WIRE_BUS 4

// Pinos do relê
#define HEATER_RELAY_PIN D1
#define COOLER_RELAY_PIN D0

// Hysteresis da temperatura
#define HYSTERESIS 0.4

// Web server
ESP8266WebServer server(80);

// Sensor de temperatura
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// Temperaturas e tempos
struct TemperatureData {
  float temperature;
  unsigned long time;
};

// Function prototype declaration
unsigned long countElapsedTime();

const int MAX_TEMPERATURES = 15; // Limite de 15 passos
TemperatureData temperatureData[MAX_TEMPERATURES];

int numTemperatures = 0;
int currentTemperatureIndex = 0;
bool fermentationStarted = false;
unsigned long targetTime = 0;
unsigned long tempoFase = 0;
unsigned long tempoAtual = 0;
bool atualizaTarget = false;
bool contagemTempo = false;
unsigned long remainingTime = 0;
float targetTemperature = 0;
String formattedElapsedTime;

// Função auxiliar para converter float em string com determinada precisão
String floatToString(float value, int precision) {
  char buffer[20];
  sprintf(buffer, "%.*f", precision, value);
  return String(buffer);
}

// Carregar dados de temperatura do arquivo
void loadTemperatureData() {
  if (SPIFFS.begin()) {
    if (SPIFFS.exists("/temperatures.txt")) {
      File file = SPIFFS.open("/temperatures.txt", "r");
      if (file) {
        numTemperatures = 0;
        while (file.available() && numTemperatures < MAX_TEMPERATURES) {
          String line = file.readStringUntil('\n');
          int separatorIndex = line.indexOf(',');
          if (separatorIndex != -1) {
            temperatureData[numTemperatures].temperature = line.substring(0, separatorIndex).toFloat();
            temperatureData[numTemperatures].time = line.substring(separatorIndex + 1).toInt();
            numTemperatures++;
          }
        }
        file.close();
      }
    }
    SPIFFS.end();
  }
}

// Salvar dados de temperatura em arquivo
void saveTemperatureData() {
  if (SPIFFS.begin()) {
    File file = SPIFFS.open("/temperatures.txt", "w");
    if (file) {
      for (int i = 0; i < numTemperatures; i++) {
        file.println(floatToString(temperatureData[i].temperature, 2) + "," + String(temperatureData[i].time));
      }
      file.close();
    }
    SPIFFS.end();
  }
}

// Script da página html
void handleRootPage() {
  String html;

  if (SPIFFS.begin()) {
    File file = SPIFFS.open("/index.html", "r");
    if (file) {
      html = file.readString();
      file.close();
    }
    SPIFFS.end();
  }

  String temperaturesHtml = "";
  for (int i = 0; i < numTemperatures; i++) {
    temperaturesHtml += "<li>";
    temperaturesHtml += "Temperatura: " + floatToString(temperatureData[i].temperature, 2) + " °C, ";
    temperaturesHtml += "Tempo: " + String(temperatureData[i].time) + " segundos";
    temperaturesHtml += " [<a href='/delete?index=" + String(i) + "'>Deletar</a>]";
    temperaturesHtml += " [<a href='/edit?index=" + String(i) + "'>Editar</a>]";
    temperaturesHtml += "</li>";
  }

  html.replace("{{temperatures}}", temperaturesHtml);

  server.send(200, "text/html", html);
}

void handleEditTemperature() {
  int index = server.arg("index").toInt();

  if (index >= 0 && index < numTemperatures) {
    // Exemplo de página de edição com formulário
    String html = "<html><head><title>Editar Temperatura</title></head><body>";
    html += "<h1>Editar Temperatura</h1>";
    html += "<form action='/update' method='POST'>";
    html += "<input type='hidden' name='index' value='" + String(index) + "'>";
    html += "Temperatura: <input type='text' name='temperature' value='" + floatToString(temperatureData[index].temperature, 2) + "'><br>";
    html += "Tempo: <input type='text' name='time' value='" + String(temperatureData[index].time) + "'><br>";
    html += "<input type='submit' value='Salvar'>";
    html += "</form>";
    html += "</body></html>";

    server.send(200, "text/html", html);
  } else {
    server.send(404, "text/plain", "Índice inválido");
  }
}

void handleUpdateTemperature() {
  int index = server.arg("index").toInt();
  float newTemperature = server.arg("temperature").toFloat();
  int newTime = server.arg("time").toInt();

  if (index >= 0 && index < numTemperatures) {
    temperatureData[index].temperature = newTemperature;
    temperatureData[index].time = newTime;
    saveTemperatureData();
    server.sendHeader("Location", "/");
    server.send(303);
  } else {
    server.send(404, "text/plain", "Índice inválido");
  }
}

// Script para adicionar nova temperatura/tempo
void handleAddTemperature() {
  float temperature = server.arg("temperature").toFloat();
  unsigned long time = server.arg("time").toInt();

  Serial.print("Temperatura recebida: ");
  Serial.println(temperature);
  Serial.print("Tempo recebido: ");
  Serial.println(time);

  if (numTemperatures < MAX_TEMPERATURES) {
    temperatureData[numTemperatures].temperature = temperature;
    temperatureData[numTemperatures].time = time;
    numTemperatures++;
    saveTemperatureData();
  }

  server.send(200, "text/html", "<script>window.location.href = '/';</script>");
}

// Script para deletar temperature/tempo
void handleDeleteTemperature() {
  int index = server.arg("index").toInt();
  Serial.print("Deletar o cadastro: ");
  Serial.println(index);
  
  if (index >= 0 && index < numTemperatures) {
    for (int i = index; i < numTemperatures - 1; i++) {
      temperatureData[i] = temperatureData[i + 1];
    }
    numTemperatures--;
    saveTemperatureData();
  }

  server.sendHeader("Location", "/");
  server.send(303);
}

// Leitura da temperatura do sensor DS18B20
float readTemperature() {
  sensors.requestTemperatures();
  return sensors.getTempCByIndex(0);
}

// Initialização dos relays
void initializeRelays() {
  pinMode(HEATER_RELAY_PIN, OUTPUT);
  digitalWrite(HEATER_RELAY_PIN, LOW);
  pinMode(COOLER_RELAY_PIN, OUTPUT);
  digitalWrite(COOLER_RELAY_PIN, LOW);
}

// Controle dos relays basedo na temperatura corrente e temperatura alvo
void controlRelays(float currentTemperature, float targetTemperature) {
  static unsigned long lastCoolerOffTime = 0;
 
  bool heaterState = digitalRead(HEATER_RELAY_PIN);
  bool coolerState = digitalRead(COOLER_RELAY_PIN);

  if (currentTemperature < targetTemperature - HYSTERESIS) {
    digitalWrite(HEATER_RELAY_PIN, HIGH);
    heaterState = true;
    Serial.println("Aquecedor ligado");
  } else if (currentTemperature > targetTemperature + HYSTERESIS) {
    if (!coolerState && millis() - lastCoolerOffTime >= 5 * 60 * 1000) {
      digitalWrite(COOLER_RELAY_PIN, HIGH);
      Serial.println("Geladeira ligada");
      coolerState = true;
    }
  }

  if (targetTemperature - HYSTERESIS <= currentTemperature && currentTemperature <= targetTemperature + HYSTERESIS && coolerState) {
    digitalWrite(COOLER_RELAY_PIN, LOW);
    Serial.println("Geladeira desligada");
    coolerState = false;
    lastCoolerOffTime = millis();
  }

  if (targetTemperature - HYSTERESIS <= currentTemperature && currentTemperature <= targetTemperature + HYSTERESIS && heaterState) {
    digitalWrite(HEATER_RELAY_PIN, LOW);
    Serial.println("Aquecedor desligado");
    heaterState = false;
  }
}

// Verifica se o processo de fermentatação está completo
bool isFermentationComplete() {
  return currentTemperatureIndex == numTemperatures;
}

// Recebe o comando para iniciar a fermentação alterando para true, que vai ser lido no loop
void handleStartTemperatureControl() {
  fermentationStarted = true;
  Serial.println("Fermentação Iniciada");
  server.send(200, "text/plain", "Fermentação Iniciada");
}

// Envia para html indicação de fermentação completa
void handleFermentationComplete() {
  String html = "<html><head><title>Fermentação Concluída</title></head><body>";
  html += "<h1>Fermentação Concluída!</h1>";
  html += "<p>A fermentação atingiu todas as temperaturas alvo.</p>";
  html += "</body></html>";

  server.send(200, "text/html", html);
}

void convertTime(unsigned long timeInSeconds, unsigned int &days, unsigned int &hours, unsigned int &minutes, unsigned int &seconds) {
  seconds = timeInSeconds % 60;
  timeInSeconds /= 60;
  minutes = timeInSeconds % 60;
  timeInSeconds /= 60;
  hours = timeInSeconds % 24;
  days = timeInSeconds / 24;
}

unsigned long countElapsedTime() {
  if (contagemTempo) {
    unsigned long tempo = millis() / 1000 - tempoAtual;
    return tempo >= targetTime ? 0 : targetTime - tempo;
  } else {
    return 0;
  }
}

// Função para enviar dados de temperatura/tempo para o HTML
void handleTemperatureData() {
  float currentTemperature = readTemperature();
  float targetTemperature = temperatureData[currentTemperatureIndex].temperature;
  targetTime = temperatureData[currentTemperatureIndex].time;

  remainingTime = countElapsedTime(); // Calculate the elapsed time
  
  // Converta o tempo decorrido em uma string formatada (dias (dias) hh:mm:ss)
  unsigned int days, hours, minutes, seconds;
  convertTime(remainingTime, days, hours, minutes, seconds);
  String formattedElapsedTime = String(days) + " (dias) " + String(hours, 2) + ":" + String(minutes, 2) + ":" + String(seconds, 2);
  Serial.println(formattedElapsedTime);
  // Criar resposta JSON
  String jsonResponse = "{";
  jsonResponse += "\"currentTemperature\": " + floatToString(currentTemperature, 2) + ",";
  jsonResponse += "\"targetTemperature\": " + floatToString(targetTemperature, 2) + ",";
  jsonResponse += "\"targetTime\": " + String(targetTime) + ",";
  jsonResponse += "\"formattedElapsedTime\": \"" + formattedElapsedTime + "\"";
  jsonResponse += "}";

  server.send(200, "application/json", jsonResponse);
}

void setup() {
  Serial.begin(115200);

  // Connecta ao Wi-Fi
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");

  // Inicia o servidor web
  server.on("/", handleRootPage);
  server.on("/add", handleAddTemperature);
  server.on("/edit", handleEditTemperature);
  server.on("/delete", handleDeleteTemperature);
  server.on("/update", handleUpdateTemperature);
  server.on("/temperature", handleTemperatureData);
  server.on("/start", handleStartTemperatureControl);
  server.begin();

  // Inicializa o sensor de temperatura
  sensors.begin();

  // Lê o arquivo de temperatura/tempo
  loadTemperatureData();

  // Inicializa os relays
  initializeRelays();

  // Seta o currentTemperatureIndex para 0 inicialmente
  currentTemperatureIndex = 0;
}

void loop() {
  server.handleClient();

  // Lê a temperatura atual
  float currentTemperature = readTemperature();
  Serial.println(currentTemperature);
  // Controla o início e término da fermentação
  if (isFermentationComplete()) {
    handleFermentationComplete();
  } else if (fermentationStarted && currentTemperatureIndex < numTemperatures) {
    float targetTemperature = temperatureData[currentTemperatureIndex].temperature;
    controlRelays(currentTemperature, targetTemperature);

    if (currentTemperature >= targetTemperature - HYSTERESIS && currentTemperature <= targetTemperature + HYSTERESIS) {
      Serial.println("Temperatura alvo atingida! Início da contagem do tempo!");
      atualizaTarget = true;
    }
    
    if (atualizaTarget == true){
      tempoAtual = millis() / 1000;
      tempoFase = tempoAtual + targetTime;
      atualizaTarget = false;
      contagemTempo = true;
    }

      countElapsedTime();
    
   if (tempoFase < (millis()/1000) && contagemTempo == true) {
     Serial.println("Tempo no alvo alcançado. Passando para a próxima etapa!");
     currentTemperatureIndex++;
     contagemTempo = false;
    }
    
    }
  delay(500);
  }

I tried this but not working.

Discover!!! The problem was printing on the monitor:
String formatElapsedTime = String(days) + " (days) " + String(hours, DEC) + ":" + String(minutes, DEC) + ":" + String(seconds, DEC);

Did you not see post #2, which clearly identified the problem?

"DEC" is the default option to .print(integer) and can be left out.

Yes... but #2 says that it is being printed in base 2 and not that the "print" command by default prints in base 2.

That is because the default is base 10, which is used when you omit the comma and 2nd argument to the function.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.