Floor Heating - Normally open thermoelectric actuators

Hi,

I manage my floor heating by using Openhab for more than a year. Now I plan to step for forward by managing each heating cycle separated. I bought Normally Open thermoelectric actuators. So in this case when a room has heating demand I have to close every heating cycle except the current one and all other whose have demand as well.

forEach loops a bit difficult to me, could you please help me to create the rule?

This is what I started to think about:

Items:

Number living_heating_temp (heating_temps)
Number living_heating_setpoint (heating_setpoints)
Switch living_heating_demand (heating_demands)
Switch living_heating_valvePos (heating_valves)

Number kitchen_heating_temp (heating_temps)
Number kitchen_heating_setpoint (heating_setpoints)
Switch kitchen_heating_demand (heating_demands)
Switch kitchen_heating_valvePos (heating_valves)

Number bedroom1_heating_temp (heating_temps)
Number bedroom1_heating_setpoint (heating_setpoints)
Switch bedroom1_heating_demand (heating_demands)
Switch bedroom1_heating_valvePos (heating_valves)

Rule

when
    Item heating_setpoints received update
    or Item heating_temps received update
then
    heating_setpoints?.allMembers.forEach[sp|
        val String base_name = sp.name.substring(0, sp.name.indexOf("_setpoint"))
        val current_temp = heating_temps.allMembers.filter(m | m.name.equals(base_name+"_temp")).last.state as DecimalType
        val current_setpoint = heating_setpoints.allMembers.filter(m | m.name.equals(base_name+"_setpoint")).last.state as DecimalType
        
        if (current_temp < (current_setpoint - hysteresis)) {
            postUpdate(heating_demands.allMembers.filter(m | m.name.equals(base_name+"_demand")).last,ON)
            
            //This is what I dont know how to handle. At this point I have to turn on every valve except related to current cycle and which currently has heating demand.
        
        } else if (current_temp >= current_setpoint) {
            postUpdate(heating_demands.allMembers.filter(m | m.name.equals(base_name+"_demand")).last,OFF)
            
            //If there is any other active cycle current valve has to turned on. If no valve has to remain off
        
        }
    ]
end
val otherValves = heating_valves.members.filter[v|!v.name.startsWith(base_name)]
otherValves.members.forEach[v|
    val String vNameBase = v.name.split("_").get[0]
    val SwitchItem demand = heating_demands.members.filter[d|d.name.startsWith(vNameBase)
    if(demand.state == ON) v.sendCommand(ON)
]

This is looking very complicated. I would try to attack the problem from a different angle.

What I don’t understand is why do you need to go through all of this looping?

You rule triggers for any update and it runs the same loop through everything on every update. Won’t the “have to turn on every valve which has heating demand” happen anyway?

Assuming you implemented it as your comment suggests, your rule would;

  1. Set the demand for the first item
  2. Turn on all valves except for the current one to ON do not have demand
  3. Set the demand for the second item
  4. Turn on all valves except for the current one to ON that do not have demand (note, if the first one didn’t have demand it will now turn OFF)
  5. Se the demand for the third item
  6. turn on all valves except for the current one to ON that do not have demand (note, if the second one had demand it will now turn OFF)

Note, if the third valve had demand it would not turn OFF until the next time the rule triggers. Also, if the first Item had demand it would be turned OFF twice.

This can’t possibly be how you want it to really work. It makes no sense.

Why not split the problem. First figure out which ones have demand and then set the valves accordingly:

heating_setpoints.allMembers.forEach[sp|
    val baseName = sp.name.split("_").get(0)
    val current_temp = heating_temps.allMembers.filter[m|m.name.startsWith(baseName)].last.state as DecimalType
    val current_setpoint = sp.state as DecimalPoint
    val demand = heating_demands.members.filter[d|d.name.startsWith(baseName)].last

    val newDemand = OFF
    if(current_temp < (current_setpoint - hysteresis)) newDemand = ON

    demand.postUpdate(newDemand)
]

Thread::sleep(100) // give the postUpdate a chance to work through the bus, may not be necessary or could be shorter

// At this point all of the valves that have demand are known. 
// Now set the valves based on demand. If I understand correctly, all valves which do
// not have demand should be ON, the rest should be OFF
heating_demands.members.forEach[d |
    val baseName = d.split("_").get(0)
    val valve = heating_valves.members.filter[v|v.name.startsWith(baseName)].last

    if(d.state == ON) valve.sendCommand(OFF)
    else valve.sendCommand(ON)
]
1 Like

Dear Rich,

Thank you for your help. Your suggestion works nice. I should modify your code some point but the logic is better than mine. I am not a developer hence my code sometimes requires some improvements.

Thanks.