Making furnace thermostat, but I need it to count time.

I use a propane furnace to heat my man cave, and it runs off of 100 pound cylinders. It has a 24v supplied power from the furnace to use for a power source for the arduino.

The issue is I have to run out of propane to know that I am out of propane, and then my man cave gets cold. I would like to have an arduino operate the furnace control AND keep a count of how long that the furnace heat relay pin has been active. With some calculations of my furnace output and how many BTUs are in a 100 pound cylinder, I could then know how long I can fire the burners before the tank is empty, and have it pretty darn close, so I could switch propane tanks just before I run out.

The temp control is simple, I have that part down.

My question is how do I keep either a countdown going or accumulating time, display it on a screen, and have a reset button?

Thanks in advance!

Rat_Patrol:
keep a count of how long that the furnace heat relay pin has been active

Basically you need to track pin changes.

When it's triggered you note what time it is and when it drops you calculate how much time has elapsed and add this into your global counter.

dealing with power issues or arduino reboot can add a bit of complexity as you'll need some sort of permanent storage for your running data. EEPROM has 100k cycles, so it depends how often that pin would change status...

You could also weigh the tank to determine how much is left. That's what I do for my IoT Kegerator Monitor:

It predicts empty keg within +/-1 pint (out of a 123 pint full keg). As you can see, it's time to head to the beer store.

J-M-L:
Basically you need to track pin changes.

When it's triggered you note what time it is and when it drops you calculate how much time has elapsed and add this into your global counter.

dealing with power issues or arduino reboot can add a bit of complexity as you'll need some sort of permanent storage for your running data. EEPROM has 100k cycles, so it depends how often that pin would change status...

Actually, loosing (or resetting) the count when the Arduino looses power would be just fine. I have to turn off the furnace when I change tanks anyway, and that would kill power to the arduino as well.

If the purpose is to utilize an Arduino as a project that's cool. But, if all you really need is to know when to buy propane maybe a simple run time meter could work for you.

OK, what about using a real time clock, like a DS1337, and then have the arduino note time of pin on, note time of pin off, calculate the seconds, and add it up with a running total or subtract it from the starting (full tank) value of burn time and display the remainder?

You still need to keep track of the running total in some kind of non-volatile memory. Otherwise you'll lose the information when your program crashes or processor resets or loses power.

As mentioned EEPROM would work with some sort of limitation on write frequency. Or, perhaps cycling through multiple locations to level out the write load.

I'm really not worried about loosing the time data if the program crashes or I loose power. Its not the end of the world by any stretch, especially if not worrying about it simplifies the sketch.

Losing the time data means you lose your estimate of how much propane is left. If you're not concerned about that, why are you bothering with the project?

I will have to re-set the data every time I switch tanks anyway. I have Uno's that have run 24/7 monitoring my chest freezers for months on end w/o issue. A propane tank typically lasts about a week.

Even if it works 90% of the time, I'd be happy.

Rat_Patrol:
OK, what about using a real time clock, like a DS1337, and then have the arduino note time of pin on, note time of pin off, calculate the seconds, and add it up with a running total or subtract it from the starting (full tank) value of burn time and display the remainder?

The real time clock is unnecessary, the millis() function will work fine for an elapsed time.
Should be a fairly easy project if the furnace burner has a constant fuel consumption rate, basically just a run-time meter.

Get an LCD display to act as display.

Keep track of how many pounds of propane remain, starting with 100 on a restart me button push (Not arduino reset).

Calculate or establish by experiment how long it takes you to burn a pound.

Keep track of the runtime using millis and decrement pounds remaining appropriately.

If desired, store pounds remaining (integer part only) in EEPROM and read it on power up.

If it’s a week and you are not worried about a reset then yes easy to track pin change and monitor duration

So I did some work and calculations.

I figure that my furnace will run on a full 100 pound propane cylinder for just over 3060 minutes, or just over 51 hours burn time. This is based on input BTU consumed by the furnace and total BTU contained within a filled 100 pound cylinder.

I wrote up this code:

#include <Chrono.h>
#include <LightChrono.h>
#include <OneWire.h>
#include <DallasTemperature.h>
OneWire oneWire(2);
DallasTemperature sensors(&oneWire);
DeviceAddress ambient = {};
float tempC;
const int heater = 13;
const int set = 22.22;
Chrono chrono;


void setup() {
  pinMode(heater, OUTPUT);
  Serial.begin(9600);
  sensors.begin();
  sensors.setResolution(ambient, 12);
}

void loop() {

  if
  (sensors.getTempC(ambient) <= (set - .2))
  {
    digitalWrite(heater, HIGH);
    chrono.resume();
    Serial.print((chrono.elapsed() / 60000));
    Serial.println(" mins of 3060 used");
    Serial.print("Room Temp Is ");
    Serial.println((tempC * 9 / 5 + 32));
    delay(5000);
  }
  else
  {
    chrono.stop();
    digitalWrite(heater, LOW);
    Serial.print("Minutes out of 3060 used is ");
    Serial.println((chrono.elapsed() / 60000));
    Serial.print("Room Temp Is ");
    Serial.println((tempC * 9 / 5 + 32));
  }

}

Its just the uno running on serial monitor right now, but it will track the temp, activate a relay, keep a run timer going when relay is active, and shut down the timer when the room temp is at set-point. It seems to be working, but I don't have the temp sensor hooked up yet, but that makes it read cold, which turns the "heat" on.

Needs refining yet, but thoughts?

Rat_Patrol:
Needs refining yet, but thoughts?

yes if you actually drive the ON/OFF cycle of your furnace from the Arduino, then you can capture the time spent on and off right there.

I noticed you rightly implemented an hysteresis
if (sensors.getTempC(ambient) <= (set - .2))to trigger the furnace if the temperature is 0.2° below the target temperature, but in the else you did not test against set and so your hysteresis is not really working. The else should be an
else if (sensors.getTempC(ambient) >= set) {...this way in the interval ]set - 0.2°, set[ you just don't do anything.

(and to not read the temperature twice in the if and the else, you could first read the temperature into a variable and use that variable in the if and in the else.

also instead of using delay() to pause the loop(), you could use the millis() technique to check the temperature only every x seconds so that your Arduino keeps running and being reactive if you want to add features over time.

Also, integers don't store decimal numbers, so this will just initialize set with 22const int set = 22.22;

I'm also unsure you are using the library correctly (based on the examples)

I would recommend you start from the WaitForConversion example and modify it to suit your needs.

that would become something like this

// based on https://github.com/milesburton/Arduino-Temperature-Control-Library/blob/99db3898322c55b5b52febf6468625763d2acc6a/examples/WaitForConversion2/WaitForConversion2.pde
#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

DeviceAddress tempDeviceAddress;

const int resolution = 12;
unsigned long lastTempRequest = 0;
unsigned long delayInMillis = 750.0 / (1 << (12 - resolution)); // according to the spec

float tempC = 0.0;

const byte heaterPin = 13;
const float targetTemp = 22.22;

unsigned long chronoMS, totalTimeMS;


//
// SETUP
//
void setup(void)
{
  Serial.begin(115200);
  pinMode(heaterPin, OUTPUT);

  sensors.begin();
  sensors.getAddress(tempDeviceAddress, 0);
  sensors.setResolution(tempDeviceAddress, resolution);
  sensors.setWaitForConversion(false);
  sensors.requestTemperatures();
  totalTimeMS = 0;
  lastTempRequest = millis();
}

void loop(void)
{

  if (millis() - lastTempRequest >= delayInMillis) { // waited long enough to get a temperature read??
    tempC = sensors.getTempCByIndex(0);
    // immediately after fetching the temperature we request a new sample in async mode
    sensors.requestTemperatures();
    if (tempC != DEVICE_DISCONNECTED_C) { // if the read worked
      Serial.print(" Temperature: ");
      Serial.println(tempC, resolution - 8); // display with variable number of decimal digits based on resolution


      if (tempC <= (targetTemp - .2)) {
        digitalWrite(heaterPin, HIGH);
        chronoMS = millis(); // note the current time
      } else if (tempC > targetTemp) {
        digitalWrite(heaterPin, LOW);
        totalTimeMS += millis() - chronoMS;
        Serial.print("Minutes out of 3060 used is ");
        Serial.println(totalTimeMS / (60000ul)); // 60000 ms in 1 minute
        Serial.print("Room Temp Is ");
        Serial.println((tempC * 9.0 / 5 + 32)); // why do you read the temp in °C if you are used to °F ?
      }
    }
    lastTempRequest += delayInMillis;
  }

  // here you can do other stuff


}

In this code I dropped the use of the Chrono class you had to just use the plain millis() function. I note the time when you turn on the furnace and then when the furnace is turned off, I calculate the difference between the time it is and when you activated it last and add that into a total time variable. This is a running count of the number of ms your furnace was ON.

As it seems you think in terms of °F instead of °C, you could use the function getTempFByIndex() to directly get the temperature in Fahrenheit and of course adjust targetTemp accordingly