Startseite » Heizkörperthermostate mit Raumthermostaten in OpenHAB koppeln

Heizkörperthermostate mit Raumthermostaten in OpenHAB koppeln

Du bist hier gelandet, weil du dir wahrscheinlich eine der folgenden Fragen stellst:

  • Wie kann ich Heizkörperthermostate mit einem Raumthermostat in openHAB koppeln?
  • Wie steuere ich mehrere Thermostate zentral über openHAB?
  • Wie sorge ich dafür, dass die Heizkörper auf die Raumtemperatur eines bestimmten Sensors reagieren?
  • Was ist der Unterschied zwischen Heizkörperthermostat und Raumthermostat?
  • Wie setze ich Regel-Logik in openHAB für meine Heizung um?
  • Wie konfiguriere ich mein Smart Home so, dass die Heizkörper effizient geregelt werden?
  • Wie verbinde ich einen Homematic-Wandthermostat mit Heizkörperreglern in openHAB?

Kernidee

Das Prinzip ist einfach: Wir vergleichen das Raumthermostat mit dem Heizkörperthermostat und geben Letzterem über den Kalibrierungs-Wert dynamisch die Differenz mit. So weiß das Heizkörperthermostat immer, wie sehr sein Wert aktuell von der Wahrheit abweicht und kann seine übrige Funktion voll zur Verfügung stellen.

minimale Struktur

du brauchst dafür wenigstens folgende Struktur. Außerdem einen funktionierenden Persistenz-Service (z.B. rrd4j oder influxdb).

  • eine Gruppe, die den Raum repräsentiert und mit sg (semantic group) beginnt
  • jeweils eine Gruppe, die den Gegenstand (Thermostate) repräsentiert und mit ig (item group) beginnt
    • eine gemeinsame Gruppe für die Number-Items funktioniert auch
  • ein Item vom Typ „Number:Temperature“, die den Temperatursensor für den Raum repräsentiert, wird mit den Tags [„Measurement“,“Temperature“] markiert
  • ein Item vom Typ „Number:Temperature“, die den Calibrierungs-Wert am Heizkörperthermostat repräsentiert, wird mit den Tags [„Setpoint“,“Calibration“] markiert
  • ein Item vom Typ „Number:Temperature“, die denTemperatur-Messwert am Heizkörperthermostat repräsentiert, wird mit den Tags [„Measurement“,“TempThermostat“] markiert
Group 					sgBedroom 							(sgGroundFloor)

Group					igArduino51							(sgBedroom)
Number:Temperature		Arduino51_680Temp					(igArduino51)["Measurement","Temperature"]	{ channel="..." }

Group					igThermostatSchlafzimmer			(sgBedroom)["RadiatorControl"]
Number:Temperature		ThermostatSchlafzimmer1_Calibration	(igThermostatSchlafzimmer)["Setpoint","Calibration"]  { channel="..." }
Number:Temperature		ThermostatSchlafzimmer1_Temperature	(igThermostatSchlafzimmer)["Measurement","TempThermostat"]	{ channel="..." }

auto_calibration.rule

Das Prinzip ist relativ einfach: alle 12 Minuten werden alle Raum-Sensoren geprüft, über ihre Raum-Zuordnung die im selben Raum befindlichen Heizkörperthermostate gesucht und anhand des Unterschieds der Temperatur-Werte wird der Calibrierungs-Wert gesetzt.

Dabei kann einiges schiefgehen. Notwendige Items können nicht existieren, die Werte zu alt sein (weil ein Sensor vielleicht gerade nicht funktioniert) oder im Persistenz-Speicher keine Werte vorhanden sein. Das wird hier berücksichtigt.

rule "set thermostat temperature_calibration based on room thermostat"
when
	Time cron "0 0/12 * ? * * *" 
then {
	// Alle Items holen
    val room_thermostate_items = ScriptServiceUtil.getItemRegistry.getItems().filter[ item | item.hasTag("Measurement") && item.hasTag("Temperature") ]

	//Durchlaufe alle Raum-Thermostate		
	room_thermostate_items.forEach[ room_thermostate_item |
		//detect itemGroup (ig) of the item
		val igName = room_thermostate_item.getGroupNames.findFirst[ String groupName | groupName.startsWith("ig") ]
		val GroupItem igRoomThermostat = ScriptServiceUtil.getItemRegistry.getItem(igName) as GroupItem
		
		val bool room_changed = room_thermostate_item.changedSince(now.minusMinutes(15))
		
		//detect semanticGroup of the itemGroup
		val String sgName = igRoomThermostat.getGroupNames.findFirst[ String groupName | groupName.startsWith("sg") ]
		val roomList = newArrayList(sgName)
		
		roomList.forEach[ String sgName |
			val GroupItem room = ScriptServiceUtil.getItemRegistry.getItem(sgName) as GroupItem
			val radiatorControls = room.members.filter[ GroupItem igItem | igItem.hasTag("RadiatorControl")]
			
			radiatorControls.forEach[ GroupItem radiatorControl |
				val NumberItem radiatorSensor 			= radiatorControl.members.findFirst[ NumberItem item | item.hasTag("Measurement") && item.hasTag("TempThermostat") ]
				val NumberItem currentCalibrationItem   = radiatorControl.members.findFirst[ NumberItem item | item.hasTag("Setpoint") && item.hasTag("Calibration") ]
				
				//Aktuelle Temperaturwerte an den Heizungen checken
				if(radiatorSensor !== null && currentCalibrationItem !== null){
					val QuantityType<Temperature> room_temp_value 			 = room_thermostate_item.state as QuantityType<Temperature>
					val QuantityType<Temperature> radiator_temp_value 		 = radiatorSensor.state as QuantityType<Temperature>
					val QuantityType<Temperature> current_calibration_value  = currentCalibrationItem.state as QuantityType<Temperature>
					
					val QuantityType<Temperature> radiator_measurement		 = radiator_temp_value - current_calibration_value
					val QuantityType<Temperature> target_calibration_value 	 = room_temp_value - radiator_measurement
					val QuantityType<Temperature> calibration_difference 	 = current_calibration_value - target_calibration_value
					val QuantityType<Temperature> abs_calibration_difference = if(calibration_difference < 0|°C) calibration_difference.negate() else calibration_difference
					
					
					//ist der Wert des Raum-Thermostats noch aktuell  &&  Hat sich der calibration_value um mehr als 1°C geändert?
					if( room_changed ){
						if(abs_calibration_difference > 1|°C){
							//neuen Wert setzen
							logInfo("Test", "{}: {} -> {} (depending on {})", currentCalibrationItem.name, current_calibration_value.intValue, target_calibration_value, room_thermostate_item)
							currentCalibrationItem.sendCommand(target_calibration_value.intValue)
						}
					}
					else{
						//versuche Mittelwert aus den letzten Stunden zu setzen
						var QuantityType<Temperature> avg_calibration_value = currentCalibrationItem.averageSince(now.minusHours(48))
						if(!avg_calibration_value){ //maybe there is no data for 48h yet
							avg_calibration_value = currentCalibrationItem.averageSince(now.minusHours(24))
						}
						if(!avg_calibration_value){
							avg_calibration_value = currentCalibrationItem.averageSince(now.minusHours(6))
						}
						else{
							avg_calibration_value = 0|°C
						}
						
						val QuantityType<Temperature> avg_calibration_difference 	 = current_calibration_value - avg_calibration_value
						val QuantityType<Temperature> abs_avg_calibration_difference = if(avg_calibration_difference < 0|°C) avg_calibration_difference.negate() else avg_calibration_difference
						if( abs_avg_calibration_difference > 1|°C ){
							//Mittelwert setzen
							logInfo("Test", "room_thermostate left. fallback target_calibration_value: {}, item: {}", avg_calibration_value.intValue, currentCalibrationItem.name)
							currentCalibrationItem.sendCommand(avg_calibration_value.intValue)
						}
					}
				}
				else{
					logInfo("Test", "Calibration Item oder Radiator Sensor Item existiert nicht für: {}", radiatorControl.name)
				}
			]
		]
    ]
}
end

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Seite verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden..

Translate »