HM-CC-RT-DN und VALVE_STATE setzen

Hallo,

ich habe eine Fußbodenheizung und wollte diese gerne mit dem HM-CC-RT-DN steuern.
Direkte Verbindung zu einem HM-TC-IT-WM-W-EU Wandthermostat wäre zwar denkbar, aber ist ja vom Hersteller nicht empfohlen, da ganz andere Heizkurve. Daher würde ich das gerne selber steuern. Da es die HM-CC-VD ja nicht mehr gibt, dachte ich, man könnte auch die HM-CC-RT-DN nehmen.

Ich habe hier eine openHAB Installation und homegear auf einem Raspberry sowie den HM-CFG-LAN für die Übertragung. Das funktioniert im Grunde auch alles und ich bekomme die Daten vom Wandthermostat und von dem eigentlichen auch angezeigt. Ich hatte allerdings gehofft, direkt das Ventil steuern zu können. Laut: homegear.eu/index.php/HM-CC-RT-DN_Reference kann man den Parameter VALVE_STATE setzen. Wenn ich das versuche, bekomme ich immer nur zurück, dass der Parameter read only ist. Liegt das an mir, am HM-CFG-LAN oder an etwas anderem?

Viele Grüße
Matthias

Hallo Matthias,

bei deinem Vorhaben treten gleich mehrere Schwierigkeiten auf:

  1. Selbst wenn du noch ein HM-CC-VD hättest, wäre in Verbindung mit dem HM-CFG-LAN das Timing nicht genau genug, um das Ventil steuern zu können. Siehe auch https://www.homegear.eu/index.php/HM-CFG-LAN .

  2. Der Datenpunkt VALVE_STATE des HM-CC-RT-DN ist laut eq3-Dokumentation und xml-Datei nicht schreibbar.

  3. Soweit ich weiß, regelt das HM-CC-RT-DN in jedem Betriebsmodus eigenständig die Ventilstellung. Mir ist keine Möglichkeit bekannt, dies zu unterbinden.

Es gibt aber dennoch eine Möglichkeit.

Hierzu muss das HM-CC-RT-DN ständig mit so hoher Solltemperatur betrieben werden, dass das Ventil von der internen Regelung weit geöffnet wird.
In diesem Betriebszustand lässt sich dann die Ventilstellung über den schreibbaren Parameter VALVE_MAXIMUM_POSITION von 0 - 100 % kontrollieren. Da sich über den HM-CFG-LAN auch andere Parameter schreiben lassen, vermute ich, dass es hierbei nicht zu Timingproblemen kommen wird.

Um die Ventilstellung über openHab kontrollieren zu können muss man:

  1. Eine Systemvariable in Homegear anlegen, die den Wert der Ventilstellung repräsentiert. Hierzu folgendes Script in /var/lib/homegear/scripts anlegen, gegebenenfalls anpassen und ausführen.

[code]#!/usr/bin/env php

<?php include_once("Connect.php"); $Client->send("setSystemVariable",array("maxVentilstellungKueche",0)); //hg_set_system("maxVentilstellungKueche",0); ?>

[/code]

  1. Ein Event definieren, dass bei Veränderung der eben erstellten Systemvariablen ein Script aufruft.

[code]#!/usr/bin/env php

<?php include_once("Connect.php"); print_r($Client->send("addEvent", array( "TYPE" => 0, "ID" => "setValveMaxPosKueche", "VARIABLE" => "maxVentilstellungKueche", "TRIGGER" => 2, "EVENTMETHOD" => "runScript", "EVENTMETHODPARAMS" => Array("setValveMaxPos.php")) )); // "PEERID" => 0, // "PEERCHANNEL" => -1, ?>

[/code]
3. Das Script setValveMaxPos.php erstellen, dass den Wert der Systemvariablen auf den Parameter VALVE_MAXIMUM_POSITION überträgt.

[code]#!/usr/bin/env php

<?php include_once("Connect.php"); $maxValvePos = $Client->send("getSystemVariable",array("maxVentilstellungKueche")); $Client->send("putParamset", array([ID DES HM-CC-RT-DN],-1,"MASTER",array("VALVE_MAXIMUM_POSITION"=>$maxValvePos))); ?>

[/code]
4. In openHab ein Item anlegen, über welches auf die Systemvariable zugegriffen werden kann.

Fertig.

Nun kann man über einen selbst erstellten Regelalgorithmus das Ventil ansteuern.

Bei mir funktioniert das wie beschrieben. Eine Haftung für eventuelle Schäden wie hohe Heizkosten, verbrannte Fußsohlen, etc. übernehme ich natürlich nicht. Ich gehe davon aus, dass in der Heizungsanlage Sicherheitseinrichtungen vorhanden sind, die eine zu hohe Temperatur der Fußbodenheizung verhindern. Ohne zusätzliche Sicherheitseinrichtungen würde ich eine solche Steuerung nicht aufbauen.

Gruß
Ralf

Hallo Ralf,

vielen Dank für die ausführliche Antwort. Das klingt doch nach einer guten Lösung. Ich hatte schon mit dem Burst Modus experimentiert, da man da ja auch die Stellung angeben kann, aber die Antworten bringen einen da nicht wirklich weiter. Die Lösung scheint aber einfach umzusetzen zu sein, werde ich am Wochenende mal ausprobieren.

Viele Grüße
MAtthias

Hallo zusammen,

ich schließe mich hier mal an, da es auch mein Ziel ist die Ventilstellung selbst zu steuern. Ich verzweifele inzwischen, da ich es nicht schaffe der “intelligenten” Steuerung der Thermostate das Schwingen abzugewöhnen, aber das ist ein anderes Thema.

Hat sich hier evtl. etwas getan, dass man den Wert nicht mehr über diesen Umweg setzen muss. Was genau unterscheidet VALVE_MAXIMUM_POSITION denn von z.B. SET_TEMPERATURE? Letzteres kann ich ja direkt aus openhab 2 setzen.

Für Hilfe wäre ich sehr dankbar.

Hallo,

die Ventilstellung des HM-CC-RT-DN lässt sich nicht setzen - das ist leider nicht vorgesehen. Aktuell testen wir gerade EnOcean-Stellantriebe. Damit lässt sich die Ventilstellung und Zykluszeit vorgeben. Somit kann man mit diesen eigene Regelalgorithmen implementieren und hat auch den Batterieverbrauch selbst in der Hand.

“SET_TEMPERATURE” setzt die Solltemperatur und mit “VALVE_MAXIMUM_POSITION” kannst du die Ventilöffnung begrenzen.

Viele Grüße

Sathya

Wofür die sind, ist mir schon klar :wink: Ich wollte wissen warum die unterschiedlich zu setzen sind. Bzw. warum ich von openHAB SET_TEMPERATURE direkt lesen und setzen kann, VALVE_MAXIMUM_POSITION aber nicht.

Ich habe mir nun mit einem kleinen Script beholfen, sodass ich die Ventilstellung beliebig steuern kann. Ich setze außerdem die Solltemperatur im Thermostat einfach 1° höher als gewünscht, sodass das Ventil eigentlich immer auf 100% gehen will und begrenze dann mit VALVE_MAXIMUM_POSITION. Das funktioniert wunderbar. Die Thermostate lassen sich also bestens als “dumme” Ventile nutzen, denen ich die Ventilöffnung vorgebe.

Seitdem habe ich nur noch geschätzte 10% der Ventilbewegungen gegenüber der Standardregelung bei viel genauerer Einhaltung der gewünschten Temperatur. Wirft echt kein gutes Licht auf die Thermostate, dass ich mit ca. 15 Zeilen Code und einer Woche rumoptimieren eine in jeder Hinsicht weitaus bessere Regelung hinbekomme.

Hey @dasc,

da hast du vielleicht sogar recht. Du musst aber überlegen wofür eq-3 die Thermostatet entwickelt hat.
Grundliegend sollen sie ja nur mit den vorgesehenen Steuerungen eingesetzt werden und müssen dann eben auch von (z.B.) meiner Oma bedienbar sein und dabei noch möglichst alle möglichen Heizumstände, Wärmeverlust des Raumes, etc. mit einbeziehen.
Den meisten Leuten ist es sicher zu kompliziert eine eigene Heizungsregelung zu programmieren :wink:

Aus “unserer” Perspektive wäre es natürlich wünschenswert das alles zu parametrieren…

so long,
p

Achso :blush: … “VALVE_MAXIMUM_POSITION” ist ein Konfigurationsparameter (also eine Variable, welche sich nach Konfiguration gar nicht oder nur selten ändert). Daher lässt er sich nicht über “setValue” setzen.

Schöner Trick ;-).

Ja, die Regelung ist nicht die beste… Immerhin schon besser als bei den alten Stellantrieben. Auch teure Systeme bekommen die Regelung nicht unbedingt gut hin. Ich habe bei mir zu Hause jetzt Busch PriOn (KNX) in Verbindung mit einer Fußbodenheizung im Einsatz - grauenvolle Regelung.

Viele Grüße

Sathya

Hi dasc,

würdest du mir den Quellcode des Scriptes zur Verfügung stellen?

Viele Grüße
Spunky

Das Ganze ist inzwischen deutlich umfangreicher geworden. Aber im Prinzip ist das ein einfacher KI-Regler. “calculateHeatingPercentage” wird für jeden Raum alle fünf Minuten aufgerufen und das Ergebnis in “setValveState” reingesteckt (siehe im Code ganz unten). Die notwendigen Items usw. sollten größtenteils selbsterklärend sein. Falls noch Fragen da sind, ruhig her damit.

Ich würde es ja liebend gerne besser kapseln, aber mit dem Krüppel-“Java” für die rules ist das leider nicht wirklich möglich…

Ich bin höchst zufrieden mit meiner Regelung, die inzwischen seit gut einem Jahr läuft. Die Abweichung zwischen Ist- und Solltemperatur ist im Rahmen der Messauflösung, sprich die Raumtemperatur weicht im Normalbetrieb nie mehr als 0,1°C von der gewünschten Temperatur ab. Besser geht’s also nicht.

/*
 * calculateHeatingPercentage
 */
val org.eclipse.xtext.xbase.lib.Functions$Function4<String, Double, Double, Double, Double> calculateHeatingPercentage = [
	String roomName,
	double kp,
	double kpPow,
	double constKi |

	var double ki = constKi

	var double minutesSinceLastRun = 5 // TODO
	var double pidIFallbackValue = 30


	var itemIValue = All.members.findFirst[name.equals("Pid" + roomName + "IValue")]
	var itemTemperature = All.members.findFirst[name.equals("Temperature" + roomName)]
	var itemSetpoint = All.members.findFirst[name.equals("Setpoint" + roomName)]
	var itemHeatingPercentage = All.members.findFirst[name.equals("HeatingPercentage" + roomName)]
	var itemHeatingPercentageBounded = All.members.findFirst[name.equals("HeatingPercentageBounded" + roomName)]

	ki = ki * minutesSinceLastRun // Zeitkorrektur ki * Minuten seit letztem Durchlauf

	var double iValue
	if(itemIValue.state == NULL) {
		logWarn("heizungssteuerung " + roomName,"Missing itemIValue. Set to fallback value " + pidIFallbackValue)
		iValue = pidIFallbackValue
	} else {
		iValue = (itemIValue.state as DecimalType).doubleValue
	}

	var double result
	var double ist = (itemTemperature.state as DecimalType).doubleValue
	var double soll = (itemSetpoint.state as DecimalType).doubleValue
	var double diff = soll - ist

//	logInfo("heizungssteuerung " + roomName,"soll: " + soll)
//	logInfo("heizungssteuerung " + roomName,"ist:  " + ist)
//	logInfo("heizungssteuerung " + roomName,"diff: " + diff)

	var double pValue = kp * Math.pow(Math.abs(diff), kpPow)
	if(diff < 0) pValue = pValue * -1

//	logInfo("heizungssteuerung " + roomName,"pValue: " + pValue)
//	logInfo("heizungssteuerung " + roomName,"iValue current: " + iValue)
	
	result = pValue + iValue

	// I berechnen mit Anti Windup
	if(result > 0 && result < 100) {
		iValue += ki * diff
		postUpdate(itemIValue, iValue)		
	}

//	logInfo("heizungssteuerung " + roomName,"iValue new: " + iValue)

	result = pValue + iValue
//	logInfo("heizungssteuerung " + roomName,"result: " + result)
	postUpdate(itemHeatingPercentage, result)

	if(result <= 0) postUpdate(itemHeatingPercentageBounded, 0)
	if(result >= 100) postUpdate(itemHeatingPercentageBounded, 100)
	if(result > 0 && result < 100) postUpdate(itemHeatingPercentageBounded, result)

	result
]

/*
 * setValveState
 */
val org.eclipse.xtext.xbase.lib.Functions$Function2<String, Double, Void> setValveState = [
	String heaterName,
	double heatingPercentage |

	var double valveMin = ((All.members.findFirst[name.equals("ValveMin" + heaterName)]).state as DecimalType).doubleValue
	var double valveMax = ((All.members.findFirst[name.equals("ValveMax" + heaterName)]).state as DecimalType).doubleValue
	var double valveOff = ((All.members.findFirst[name.equals("ValveOff" + heaterName)]).state as DecimalType).doubleValue

	var itemValveStateMax = All.members.findFirst[name.equals("ValveStateMax" + heaterName)]

	// quadratisches Verhalten der Ventilöffnung einberechnen
	var double resultSquared = (100 * Math.pow(heatingPercentage / 100, 2))
	if(heatingPercentage < 0) resultSquared = resultSquared * -1
//	logInfo("setValveState " + heaterName,"result squared: " + resultSquared)

	// FIXME Momentan können auch Ventilöffnungen > ValveMax entstehen wenn resultSquared größer 100 ist
	
	// Wirkbereich des Ventils berücksichtigen
	var int targetValvePosition = Math::round(valveMin + (valveMax - valveMin) / 100 * resultSquared).intValue

	// wenn aus dann auf Ruheposition fahren
	if (heatingPercentage <= 0) targetValvePosition = valveOff.intValue

	// Begrenzen auf 0 bis 100 Prozent
	if(targetValvePosition < 0) targetValvePosition = 0
	if(targetValvePosition > 100) targetValvePosition = 100
		
//	logInfo("setValveState " + heaterName, "heatingPercentage: {}", heatingPercentage)
//	logInfo("setValveState " + heaterName, "targetValvePosition cur: {}", itemValveStateMax.state)
//	logInfo("setValveState " + heaterName, "targetValvePosition new: {}", targetValvePosition)

	// Änderung der Ventilstellung nur sinnvoll wenn Heizung an
	if(BoilerEnabled.state == ON)
		// neue Ventilstellung setzen falls abweichend
		if(itemValveStateMax.state == NULL || (itemValveStateMax.state as DecimalType).intValue != targetValvePosition)
			sendCommand(itemValveStateMax, targetValvePosition)
	
	return null
]

rule "Besprechung PID"
when
	Time cron "40 1/5 * * * ?"
then
	if(checkAutomode.apply(AutomodePidadaption)) {
		var double result = calculateHeatingPercentage.apply("Besprechung", 50.0, 1.5, 0.2)
	
		setValveState.apply("Besprechung", result)
	}
end
3 Likes

Ups, wir sind hier ja im homegear Forum ^^ Außerdem fehlt ja noch der Code auf homegear-Seite :sweat_smile: Und der kommt hier.

Feedback ausdrücklich erwünscht!

createMaxValveLogic.php:

<?php

$hg = new \Homegear\Homegear();

// TODO alle hm-cc-rt-dn holen und Variablen basierend auf dem Namen erstellen
//$devices = $hg->listDevices();


foreach(array(7 => "Kueche", 9 => "Buero", 10 => "Lounge", 12 => "Besprechung", 14 => "Bad") as $id => $room) {

    print_r($hg->deleteSystemVariable("maxValveState" . $room));

    print_r($hg->setSystemVariable("maxValveState" . $room, 23));

    print_r($hg->getAllSystemVariables());
    

    try {
        print_r($hg->removeEvent("setMaxValveState" . $room));
    } catch (Exception $e) {
        print("no event to remove for room " . $room);
    }
    
    print_r($hg->addEvent(
        array(
            "TYPE" => 0,
            "ID" => "setMaxValveState" . $room,
            "VARIABLE" => "maxValveState" . $room,
            "TRIGGER" => 2,

            "EVENTMETHOD" => "runScript",
            "EVENTMETHODPARAMS" => Array("setMaxValveState.php", $id . " " . $room),
        )
    ));

    print_r($hg->listEvents());
}

setMaxValveState.php:

<?php

// 1. Argument: ID des Geraets in homegear
// 2. Argument: Name des Raums
$deviceId = intval($argv[1]);
$deviceName = $argv[2];

/**** Use built-in script engine ****/
$hg = new \Homegear\Homegear();

$percentage = $hg->getSystemVariable("maxValveState" . $deviceName);

if($percentage >= 0 && $percentage <= 100) {
    $hg->putParamset(
        $deviceId, -1, "MASTER", array("VALVE_MAXIMUM_POSITION" => $percentage)
    );
}
3 Likes

Find ich knaller, was du machst.

Kannst du schon eine Aussage treffen wie lange die Batterien halten bei der Nutzung als “dummen” Stellmotor?

Danke für die Blumen :wink:

Wie lange halten die Batterien denn üblicherweise? Meine Steuerung läuft inzwischen seit gut einem Jahr (seit Anfang Dezember 2016) und bisher musste ich noch keine Batterien wechseln und ich habe auch noch keinerlei Anzeichen, dass das bald der Fall sein wird.

Bei meinen Thermostaten wo ich öfter mal Boost nutze, halten sie etwas länger als ein Jahr. Also ist das nicht sooo schlim. :+1:

Danke für den Super Code. Werde ich wahrscheinlich bis zur nächsten Heizperiode auch implementieren.

Kleiner Tipp: Wenn homegear mit MQTT an openhab angebunden ist, kann man mit dem MQTT Action Add-In den Max-Valve-State auch so setzen:

publish("mosquitto","homegear/xxxx-xxxx-xxxx/config/1/0/MASTER","{\"VALVE_MAXIMUM_POSITION\":100}")

(Hier im Beispiel Device Nr. 1, Wert 100)

Dann braucht man keinen Code in homegear (Geschmackssache).

2 Likes

Jungs mal ne Frage:

Warum geht ihr überhaupt den Umweg über OpenHAB? Wenn ich mir das Ganze anschaue, sollte sich das doch auch sauber mit PHP in Homegear realisieren lassen. Dadurch würde die Regelung auch bei einem OpenHAB-Ausfall, bzw. dem Ausfall der Kommunikation zw. Homegear und OpenHAB weiter funktionieren. Und ich habe auch den Eindruck, das Homegear-PHP auch noch deutlich Ressourcen-schonender ist als OpenHAB-Xtend. Und wenn einmal der Code gebaut ist, können auch Nicht-OpenHAB-Nutzer mit Homegear die Regelung verwenden.

Ich habe im Büro einen großen Raum mit 12 (!!!) Heizkörpern, alle mit HM-CC-RT-DN. Aktuell hängen 8 Stück an einem HM-TC-IT-WM-W-EU und die restlichen 4 regeln autark (der HM-TC-IT-WM-W-EU kann nur mit 8 HM-CC-RT-DN pairen). Ich will schon länger auf eine eigene Regelung mit „VALVE_MAXIMUM_POSITION-Trick“ umsteigen, was bisher immer am Zeitfaktor gescheitert ist. Aber ich würde das gerne vor der nächsten Heizperiode angehen (verrückt darüber nachzudenken wo wir letzte Woche gerade 37°C im Schatten hatten…).

Wie sieht es denn mit der Funkkanal-Auslastung mit dem „VALVE_MAXIMUM_POSITION-Trick“ aus. Ich habe keine Lust mir mit den 12 Stellantrieben mein Gateway regelmäßig an die 1% Grenze zu treiben. Notfalls würde ich für die Stellantriebe ein extra Gateway installieren.

Gruß Andreas

1 Like

Oder eben node-blue :wink:

Node-Blue wäre eine Option, aber auch wenn Node-Blue in Homegear in Form eines Add-Ons integriert ist, möchchte ich ungern eine weitere Stelle aufreißen an der ich Teile meiner Automation abwickle.

Ich ziehe aktuell nach und nach alle möglichen Skripte von OpenHAB zu Homegear um. Mit Ausnahme der Skripte in denen Komponenten beteiligt sind, die noch nicht in Homegear angebunden sind. Im Büro (HG 0.7.x Stable) habe ich das Node-Blue-AddOn noch nicht mal installiert. In meiner Heim-Installation (HG 0.8.x Nightly) habe ich schon damit gespielt, aber das ist einfach nicht meine Wellenlänge. Mir ist da richtiger Code lieber. Da bin ich vielleicht bisschen Oldschool. Mag aber auch meinem Werdegang geschuldet sein (Studium im Embedded-Bereich (C, C++, verschiedene Assember) und Job in der IT - Networking und Datacenter Automation (Powershell, Shell-Scripting, C#.Net, wenn sich nicht vermeiden lässt Java)). Ich bin zwar bei Weitem kein Software-Entwickler, aber eine gewisse Code-Affinität kann ich nicht abstreiten…

Aber wenn wer die Regelung in Node-Blue umsetzt, ist das sicher eine feine Sache! Und das zu Teilen, würde sicherlich vielen helfen, die keine Code-Tick haben. Interessieren würde es mich auf jeden Fall auch. Gibt es bei Node-Blue irgendeine Import-Export-Funktion?

1 Like

Ja, du kannst die Flows ähnlich wie in node-red per JSON-String teilen. Die function-nodes in node-blue beherbergen übrigens PHP. Schaus dir - trotz codeafinität - mal an.

Ich mach aktuell noch alles über node-red mit mqtt und habe leider noch gar nichts in node-blue umgesetzt. Gegenüber node-red hat es aber den Vorteil, dass es auch SPS-artike Logikbausteine gibt.

https://allgeek.de/2017/07/09/homematic-mit-node-red-ueber-homegear/

Wie gesagt, daheim habe ich damit schon bisschen gespielt. Werde ich aber auch wohl nochmal intensiver machen müssen, da hast du wohl nicht ganz unrecht!

P.S.Da es in Node-Blue bereits einen PID-Heating-Controller gibt, ist das ja in Sekunden zusammengeklickt:

Nur wie/oder ob ich den MASTER-Parameter VALVE_MAXIMUM_POSITION direkt in Node-Blue setzen kann, habe ich noch nicht herausgefunden!

1 Like