Thermostat in function node

Hello,

Let me start with informing that i am a supernoob in programming JSON.

I am trying to setup a thermostat function in node-red.
The idea is to control my heatpump´s temperature, and fanspeed settings based on a temperature sensor on my knx system.

I have managed to write a code for this that kind of work.

Does anyone have a better solution?, please share :slight_smile:

var setpoint = flow.get("setpoint");
var current = msg.payload;
var h1 = 0.1
var h2 = 0.2
var h3 = 0.3
var h4 = 0.4
var h5 = 0.5
var h6 = 0.6
var h7 = 0.7

//Actual temperature under setpoint
if (current === (0)) {
    msg.payload = "nothing";
} else if(current == (setpoint - h1)) {
    msg.payload = "low";    
} else if(current == (setpoint - h2)) {
    msg.payload = "medium";
} else if(current == (setpoint - h3)) {
    msg.payload = "medium";
} else if(current == (setpoint - h4)) {
    msg.payload = "medium_high";
} else if(current == (setpoint - h5)) {
    msg.payload = "medium_high";
} else if(current == (setpoint - h6)) {
    msg.payload = "medium_high";
} else if(current <= (setpoint - h7)) {
    msg.payload = "high";

    
// actual temperature same as setpoint
} else if(current == (setpoint)) {
    msg.payload = "low"; 

    
// actual temperature over setpoint
} else if(current == (setpoint + h1)) {
    msg.payload = "low";
} else if(current == (setpoint + h2)) {
    msg.payload = "low";
} else if(current == (setpoint + h3)) {
    msg.payload = "low";
} else if(current == (setpoint + h4)) {
    msg.payload = "low";
} else if(current == (setpoint + h5)) {
    msg.payload = "low";
} else if(current >= (setpoint + h6)) {
    msg.payload = "off";
    
} else {
    msg.payload = "nothing";
}

return msg;

Welcome to the forum Kim.
Have you looked at the existing contrib nodes for controlling temperature (thermostats)?
Some of them are quite advanced, and include 'hysteresis' and 'rate of change' adjustments, which may increase efficiency.
Just a thought...

PS, it's javascript - not JSON :wink:

Thanks,
I will check it out :slight_smile:

Also check node-red-contrib-pid (node) - Node-RED
It's a bit more difficult to setup, but I'm sure you'd get some help here if you ran into problems.

However, looking at your function, what would happen if the value were 0.15 below setpoint, so none of your tests will be true.

What type of control do you have over the heat pump?

I have the heatpump setup with sensibo and home assistant

What I meant is what extent of control do you have? Is it continuous or are there just a few settings as in the code you posted (low, medium, etc)?

Also what end result are you trying to achieve? Do you want the software to automatically adjust the heatpump so that the temperature converges onto the setpoint?

Aha :slight_smile:
I only need the settings in the code (low, medium, medium, high and off).
I only want the fan speed, not the temperature setpoint on the heatpump to adjust.

I meant what is the purpose of adjusting the fan speed?

You said at the start

I still haven't really got a grasp of what you are trying to do. What is the temperature you are measuring and comparing against the setpoint? What is the purpose of the fan? Is it warming up a room, for example, and the setpoint is the temperature at which you are trying to control the room? But you mention the 'setpoint on the heatpump', so is that the same setpoint you are comparing against or some parameter of the heatpump itself. As I said I am a bit lost about what the purpose is.

Once I understand the system then hopefully I can help to find the best way to control it.

I am sorry for the bad description.

I have a heatpump that i use to warm up a room.
I want to compare the temperature on a sensor in my knx system with a setpoint on my home assistant system and control the fan speed settings with this.
I dont want to use the heatpumps internal sensors.

Thanks.

OK, understood.

If you do it the way you have suggested (but with code that works, obviously) then the temperature will generally settle out below the setpoint, unless only low speed is required. For example, if it actually required medium_high then it would settle out anything up to 0.7 low, which is not ideal, you will find yourselves tweaking the setpoint dependant on the weather. Better would be to use node-red-contrib-pid which will bring you close to the setpoint whatever fan speed is required. However, it is probably best to get the simple technique working first before moving on to a more sophisticated method. In fact the simple one might be good enough.

So looking at the code you posted the first question is why is there a test of current === 0? Is the measured temperature sometimes zero for some reason. Ignoring that question for the moment I suggest starting with an array of objects, something like this

const thresholds = [
  {delta: -0.7, output: "high"},
  {delta: -0.6, output: "medium_high"},
  {delta: -0.5, output: "medium_high"},
  {delta: -0.4, output: "medium_high"},
  {delta: -0.3, output: "medium"},
  {delta: -0.2, output: "medium"},
  {delta: 0, , output: "low"},
  {delta: 0.1, output: "low"},
  {delta: 0.2, output: "low"},
  {delta: 0.3, output: "low"},
  {delta: 0.4, output: "low"},
  {delta: 0.5, output: "low"},
  {delta: 0.6, output: "low"},
  {delta: 0.7, output: "off"}
}

Then you can get the output using something like

const error = current - setpoint   // -ve when current below sp
let i = 0
for (i=0; i<thresholds.length; i++) {
  if (thresholds[i].delta > error) break
}
if (i > thresholds.length) {
  // error > last delta in array so we want the last one
  i = thresholds.length
}
msg.payload = thresholds[i].output

I haven't been able to test that so it probably won't quite work as it is but it should be close. It is late now, if you look at it in the next few hours let us know how you get on and if necessary I will have a look in the morning.

If i restart home assistant, the temperature is 0 for a couple of seconds. Until the bus reports the temperature.

Thanks for the code, i will try it later today.

Is it a comma too mutch in this line?,
I get an error on "extra comma".

  {delta: 0, , output: "low"},

And what about the bracket at the end of the code? should it be an square bracket?

const thresholds = [
  {delta: -0.7, output: "high"},
  {delta: -0.6, output: "medium_high"},
  {delta: -0.5, output: "medium_high"},
  {delta: -0.4, output: "medium_high"},
  {delta: -0.3, output: "medium"},
  {delta: -0.2, output: "medium"},
  {delta: 0, , output: "low"},
  {delta: 0.1, output: "low"},
  {delta: 0.2, output: "low"},
  {delta: 0.3, output: "low"},
  {delta: 0.4, output: "low"},
  {delta: 0.5, output: "low"},
  {delta: 0.6, output: "low"},
  {delta: 0.7, output: "off"}
}

Yes to both. I said I hadn't tried it :slight_smile:

Should be

i = thresholds.length -1

Also no need for all the delta's, just the case edges are required
e.g.

const edges = 
  {"off":0.7,
  "low":0,
  "medium": -0.3,
  "medium_high": -0.6,
  "high": -0.7}

const error = Math.round((msg.current - msg.setpoint)*100)/100;  
let key, val;
for ([key,val] of Object.entries(edges)) {
  if (val <= error) break;
}
msg.payload = key
return msg;

[edit] to correct math as some results would be -0.60000000012

True, and also it should be
if (i >= thresholds.length) {

I thought about using a structure like you suggest, but decided it might be easier to tweak the values the way I suggested. Either way is fine though.

Thanks for the code.
This works perfectly for me :slight_smile: