Trouble with thermostat timing relay, temp and a set value

Hi,
Im having difficulty trying to write a code for my thermostat project using esp32 / wemos d32 pro.
I have a temperature reading using thermistor and a set value saved to eprom and all is well.
I want to control a relay relative to the set value and temerature, for specific times.

So,
If the temperature < 2 of the set value, turn relay on for 30 mins then 10 mins off.
Check the temperature again.
If the temperature is between <2 and <0.5 of set value, turn relay on for 15 mins then off for 10 mins.
Check the temperature again.
If the temperature is between <0.5 and >0.5 of set value, turn relay on for 10 mins then off for 10 mins.

I have been using millis for other timing in my current code but cant figure out how to write this.
Can someone help me write this piece of code?

Hello Jamhough22, Welcome to the forum.

In order to help you, you will need to provide a lot more information. Please read ‘how to use this forum - please read’, then provide the information requested.

You approach seems flawed. Why do you think this is a good idea:

If the temperature < 2 of the set value, turn relay on for 30 mins then 10 mins off.

?

Of course, we don’t know what you are heating as you’ve not told us, maybe that’s reasonable approach, impossible to be sure.

I have a heating controller I built for my home heating system, it checks the room temperatures in 4 different rooms about once per second and updates the heat output to each of 4 heating zones every second. If it only updated every 40 minutes I’d roast or freeze.

Thanks for the reply, Sorry about that, i did read that section before posting, if i have missed any information please point me in the right direction, i have tried to be clear and to the point.
It is a thermostat for the whole house, if the temperature is below 2 degrees of the set value it will take some time to come up to temperature hence 30 mins on time and 10 mins rest.
I live in the UK and my house is not terribly efficient, i can always tweak it if need be.
If you have a better or more efficient idea id be happy to give it a go.
Thanks,
James

Thanks for the reply, Sorry about that, i did read that section before posting, if i have missed any information please point me in the right direction, i have tried to be clear and to the point.

Errr… you code! You are asking us to comment on what you have tried without sharing it with us!

Anyway,
As I already indicated I think your approach is flawed (I was going to say ‘daft’, but that’s probably unfair if you are new to this :slight_smile: ).

Heating control can be done in (to my knowledge) 2 ways:

Simplest is on and off depending on the temperature. Temperature too low, turn it on, desired temperature reached, turn it off. You also need something called hystereses so that the heating isn’t being turned on and off every few seconds when the set temperature and the actual temperature are the same, so something like this:

float temperature_actual;
#define temperature_set 20        //The temperature setting you want
#define Hysteresis 1                  //This is so the on and off points are not exactly the same, otherwise the heating could end up being switched on and off every second or two

void setup() {
  // put your setup code here, to run once:
}

void loop() {
  read_temp_probes();
  heating_control(temperature_actual, temperature_setting);
}

void read_temp_probes() {
  //Some code that reads the probes and updates the values of temperature_actual;
}

void heating_control(float A, float S) {
  if ((A + Hysteresis) < S ) {
    //Whatever you need to do to turn the heating on;
  }
  else if (A >= S)  {
    //Whatever you need to do to turn the heating off;
  }
}

That’s simple and works but has some drawbacks, especially with a hot water heating system that takes considerable time to heat up and cool down. If the house is cold the heating comes on, the pipes and radiators get hot. Eventually the rooms get to the set temperature and the heating goes off. However the pipes and radiators are still hot so the rooms continue to heat up. Eventually the heating system cools down, followed by the rooms, until the heating turns back on. The system is now cold so it does not immediately heat the rooms, which continue to cool until such time as the heating system warms up.

The solution I used was pulse width modulation (PWM) with a period of 720 seconds. As the temperature of the room approaches the set temperature the heating turns on and off every few minutes, with the off to on ratio moving closer and closer to more off than on. At the set temperature the boiler might be on for 1 minute and off for 11. I usually get control to within 0.1 degree using this method, sometimes it only achieves 0.2 degrees.

I can post my code but it is rather large, im currently away from my pc and using my phone, my bad, i should have said!
I have a combi boiler, the water is always active and the heating comes on via a time clock and a thermostat, im building my own thermostat.
It has taken me a couple weeks to get to this stage, admittedly messy but i will post the code later.
The histeresis is what i was thinking initially but i do not want the boiler to be on and off every min and thought of the idea of longer on times the firther away the actual temprarure is.
Your idea of the pwm method seems like it could work for me as long as there was a minimum on/off time??

The hysteresis is what i was thinking initially but i do not want the boiler to be on and off every min and thought of the idea of longer on times the further away the actual temperature is.

The point of hysteresis is to make sure the heating is not being turned on and off every minute (or worse).

Your idea of the pwm method seems like it could work for me as long as there was a minimum on/off time??

You can use the method and include minimum on and off times. My boiler takes, from memory, about 25 seconds from being told to light to actually lighting. I think I built in a minimum on time of about 1 minute, not sure, ages since I wrote the code.

As my suggestions move you away from your original question your original code is less important. My controller is a complete controller, including varying temperature by time of day.

That sound about right what my boiler takes to fire up.
Do you think you could help with writing that piece of pwm code? I don’t need any varying temprarure by time of day etc, i just use the timeclock to turn the heating on/off at specific times, thats enough for what i need.
All i really could do with is the basics of how to implement it between the set temperature value, the actual temprature value and set an output/relay on or off.

Its just dificult for me to write it on my own, no matter how much i research. Haha
Thanks,
James.

Do you think you could help with writing that piece of pwm code?

Here's my dilemma, obviously I could give you some working code, but I don't want to do that, I want you to try yourself and learn from the experience. Happy to help but please try yourself and ask for help when you get stuck. I have given you an outline of what is needed.

Well i could use the map function, to map out the temprature range to the timing in minutes. Something like this i think :confused:....

float tempratureactual;

void setup() {}

void loop() {
  int val = tempratureactual;
  val = map(val, 0, 30, 10, 2); //lower bound 0*C, upper bound 30*C, to low 10mins, to upper 2mins.
  
}

Then of course try and intergrate the set temperature in as well.

I could use millis as it overflows at ~49 days as i only need minutes.
But im a bit confused as to how to use this towards a variable pwm function? is there a way to use the pwm functionality using the millis?

Here is some example code for slow pwm using a proportional band around setpoint. The 5 second period time scale is wrong for your application, but it may give you some ideas. It shows how to use millis() for "blink without delay" with different on/off times.

//all values *10 to work with one decimal point
//measured temperatures from sensor in tenths of degree
float tempSensorReading;
int workingTemperature = tempSensorReading *10;
int setPoint = 30.0 * 10;
int difference;
byte dutyCycle;
// four degree proportional band 100% to 0% duty cycle linear transition
//use even number for symmetry around setPoint
byte proportionalBand = 4 * 10; 

void setup()
{}
void loop()
{
  tempSensorReading = 30.0;//some temperature from sensor in tenths of degree
  workingTemperature = 10 * tempSensorReading;
  difference = setPoint - workingTemperature;
  difference = constrain(difference, -proportionalBand/2, proportionalBand/2);
  dutyCycle = map(difference, -proportionalBand/2, proportionalBand/2, 0, 100);

  //call slowPWM function with linear proportional dutyCycle
  slowPWM(dutyCycle, 5000); // %duty cycle, period milliseconds
}

void slowPWM(byte dutyCycle, unsigned long period)
{
  const byte outputPin = 13;//  LED pin for visualization
  pinMode(outputPin, OUTPUT);
  static byte outputState = LOW;
  static unsigned long lastSwitchTime = 0;

  unsigned long onTime = (dutyCycle * period) / 100;
  unsigned long offTime = period - onTime;

  unsigned long currentTime = millis();

  if (outputState == HIGH && (currentTime - lastSwitchTime >= onTime))
  {
    lastSwitchTime = currentTime;
    outputState = LOW;
  }
  if (outputState == LOW && (currentTime - lastSwitchTime >= offTime))
  {
    lastSwitchTime = currentTime;
    outputState = HIGH;
  }
  digitalWrite(outputPin, outputState);
}

Here's and outline of how my controller works:

  • I have a float which holds the current temperature, updated roughly once per second.

  • I have a float which holds the set temperature, which I can change in steps of 0.1 degree centigrade.

  • I have an integer which increments once per second up to 720, then resets to 0, which gives me my 12 minute period.

  • If the set temperature is more than 1 degree higher than the current temperature then the heating is on.

  • If the set temperature is between 1 degree higher then the current temperature and the current temperature then the PWM becomes active. From the difference between the two temperatures I calculate a number between 0 and 720, such that when the difference is 1 degree the number is 720 and when the difference is 0 the number is 0, with the values in between being linearly in proportion. This is re-calculated every second.

  • As the 0 to 720 counter increments (every second) it is compared to the number above, if the counter is less than the number then the heating is on, if the counter is more than or equal to the number then the heating is off.

That's the basics, there are a few refinements and it might not be exactly as described, but that's the basic idea.
Something you need to be aware of, my temperature sensors give me 8 bits of whole degrees and 5 bits of fractions of a degree, so 13 bits in total. You can't get that with a 10 bit A2D. My algorithm should work with less precision, but probably won't give the level of control I get (0.1 to 0.2 degrees). You MUST have some amount of fractions of a degree for it to work at all.

Thank you for the replies.
I have written some code on its own so i can understand it, based on what perrybebbington has described, it was a bug help and i was able to use this to write my own. I will have to change it slightly to fit in with my project code.

Once I've had a chance to check (and make sure it makes sense to me) what i have written i will post it up here and see what you all think.
Having issues logging into here on firefox on my pc though google account at the moment.