Before the heating season of 2016/17 I was faced with the task of adjusting the floor heating system, which was installed at the highest level of my house last year. It is built of 11 independent heating loops, a circulation pump, a 3-way valve, thermostatic head with a capillary. The hot water comes from the main heating circuit which powers also the heat exchangers in the basement and on the ground floor
I conducted the first test with a 24VDC actuators controlling each of the individual floor heating loops. I used some of the unused actuators I had from my existing installation and added a few Danfoss TWA-K units. I set the minim temperature at the mixing valve and programmed the individual actuators with the Fb_Weather function block from the building_commong.lib library.
Unfortunately, such a setting turned out to be insufficient. The floor heating repeatedly overheated the rooms by 1-1.5 degrees. It was, most probably, caused by a too high temperature flowing through the system. The thermostatic head was not able to limit the temperature. Maybe it was fault? I do not know. At the end - I do not have a PLC at home to miss such an occassion to automate something...
In the search of an actuator, which would control the 3-way mixer valve, I checked the original solutions of Viessman, but I turned down due to high prices and a lack of space in the cabinet. The actuators of ESBE required a replacement of the mixing valve, which was out of the question. Finally I found the actuators of Danfoss (AME 120NL), controlled by 0-10V, which can be used as a direct replacement of my existing thermostatic head, without the need of changing the layout of pipes or the valves. I bought the analog AO module 750-550 on ebay and started the tests.
Here is the solution, which I ended up with after a few attempts. The room temperatures are quite stable. The family is happy:
1. I test if it makes sense to power the actuators at all: is my Viessmann unit in the heating mode OR is the fireplace supplying heat to the system:
WINTER := ManualWinter OR (VitoMode = 2) OR (SensorReader.T_Fireplacek > 40);
2. I check if any of the actuators needs to be opened
Each of the actuators are controlled by the Fb_Weather function blocks. Those blocks on the input side need the current room temperature (in my case an average from two 1-wire sensor in each room), the target temperature and the target accepted deviation (the valve opens if the temprature in the room is lower than the target temperature minus the accepted deviation; the valve closes, when the temperature in the room is above the target temperature increased by the accepted deviation).
HEATER_2PP(iInput_Signal:=SensorReader.T_2_PP, iLimit1:=TEMP_H2PP); OUT131:=WINTER AND (NOT HEATER_2PP.xActorLimit1);
3. I check if the circulation pomp should be started. There is no sense for it working when all the loops are closed. I start the pump 1 minute after a first actuator is turned on.
TON_Podl_PUMP(PT := T#1m, IN := OUT131 OR OUT132 OR OUT133 OR OUT134 OR OUT135);
4. I calculate the target temperature to be fed into the floor heating system on the basis of a heating curve provided by the FbHeatingCharacteristics function block from the Building_HVAC_03.lib library. This block on the input side need the target room temperature, the outside temperature and the parameters of the curve: the gradient and curvature. It returns the needed target temperature.
VAR heatCurve : FbHeatingCharacteristics; END_VAR VAR RETAIN PERSISTENT cEnable : BOOL := TRUE; cTargetTemp : REAL := 21; cConfig : typConfigHeatingCharacteristics; END_VAR ----- heatCurve( xEnable := cEnable, rOutsideTemperature := FuAI_Temp(iTemp := A_IN8), rReferenceValueRoom := cTargetTemp, typConfigHeatingCharacteristics := cConfig );
5. I control the analog actuator on the mixer through an analog 0-10V output and a PID blocked provided by FbPIDController function block also from the Building_HVAC library. I am not an expert in the subject of PIDs, but for now I must say that using it was not at all that difficult.
VAR Mixer : FbPIDController; END_VAR VAR RETAIN PERSISTENT mixerConfig : typConfigPIDController; mEnable : BOOL := TRUE; maunalAction : BOOL := FALSE; manualTemp : REAL := 30; END_VAR ---- Mixer( xEnable := mEnable OR PLC_PRG.TON_Podl_PUMP.Q, rReferenceValue := heatCurve.rReferenceSupplyTemperature, rActualValue := FuAI_Temp(iTemp := A_IN1), xManualOperation := maunalAction, rManualValue := manualTemp, typConfigPIDController := mixerConfig ) A_OUT1 := Mixer.wY;
To sum up: when the temperature in room falls below the target (for example 20 degrees), decreased by the accepted deviation (for example 0.2), I check if there is a source of heating (the Viessman or the fireplace) and if so, I power the actuators. In minute later the circulation pump turns on, the target heating water temperature is being calculated. At the default settings of 0.8 and 1.1 (suggested in the library description), the suggested heating water temperature is for example 30 degrees. The PID controller smoothly adjusts the valve on the mixer to make the temperature reach that level.
Here are the visualizations I use to configure the heating curve and the PID:
..and a few visualization examples from the on-line dashboard: