Wie einen Node-BLUE Flow generalisieren?

Hallo,
ich möchte ein paar alte MAX! Basic Thermostate zur Steuerung einer Fußbodenheizung einsetzen. Das funktioniert rein technisch nur über den BOOST Modus der Thermostate, da sich nur hier die Ventilöffnung steuern läßt.
Die im Thermostat eingebaute Regelung in Abhängigkeit der Temperatur muss natürlich ausgeschaltet werden, da die im Heizraum gemessene Temperatur (da sitzen die Ventile) nichts mit der Raumthemperatur zu tun hat.
Wochenprogramm dito.
Die aktuelle Raumtemperatur wird über Wandthermostate erfasst. Die Soll Temperatur wird ebenfalls am Wandthermostaten eingestellt.
Mit Hilfe dieser 2 Eingabewerte soll ein PID Regler (HVAC heating in node-BLUE) angesteuert werden. Dieser ermittelt dann die notwendige Ventilöffnung, welche man nur noch ausgeben muss.


Boost-Mode.zip (905 Bytes)

Das funktioniert im Testbetrieb auch wie gewünscht.
Muss man den Flow jetzt für alle Thermostate kopieren und an allen Stellen in jedem Flow die peerID anpassen? Das wären ja bei 4 Stellen in einem Flow und 10 Thermostaten insgesamt 36 Änderungern. Wenn man dann mal den Flow anpassen will wirds lustig …

Oder geht das irgendwie eleganter mit einem generalisierten Flow? Schließlich unterscheiden sich die Flows nur in der peerID’s. Die sind in meinem Beispiel aber immer fest einem Flow zugeordnet. Nix dynamisch :frowning:

Nein, leider nicht. Das geht nur, wenn du einen function-node im Subflow einsetzt, der dann über getValue/setValue im php die entsprechende Logik herstellt. (Wahrscheinlich geht python/javascript analog, habe ich aber nie benutzt.)

@job
Erst mal vielen Dank für die Antwort.
Ich habe mich ja erst ein paar Stunden mit Node-BLUE beschäftigt. Und meine Programmier-Kenntnisse sind Mainframe spezifisch eher auf Cobol und ein paar Zeilen C ausgerichtet.
PHP, Python, Java, und das ganze andere objektorientierte Zeugs ist alles Teufelswerk für mich :wink:

Vielleicht kannst du ja noch etwas Anschubhilfe geben…
Wenn ich z.B. den “HomeGear Event” Knoten nehme und dort auf Gerätevariablen filtern stelle. Dann bekomme ich alle Messages, in denen für mich relevante Daten stehen.
Hier ein Beispiel beim Ändern der Solltemperatur an einem Wandthermostaten.

Jetzt müsste ich ja die PayLoad untersuchen um zunächst einmal bestimmen zu können, ob sie für mich relevant ist. Im Beispiel würde ich also die PayLoad mit RSSI_DEVICE verwerfen. Gibt es irgendwo ein Beispiel in dem auch für Noobs verständlich beschrieben steht, wie man die gewünschten Elemente aus der Msg Struktur herauszieht.
Wenn ich das richtig verstehe ist “data” ein array, das aus 6 Elementen besteht.
Woher weiß ich jetzt, das in Elemtent 1 (immer?) die peerID steht und in Element 2 der Channel?
Vielleicht könntest du ja einem Unwissenden etwas Erleuchtung verschaffen …

Ich antworte mir mal wieder selbst. Um dann gleich eine neue Frage zu stellen …

Ich glaube inzwischen verstanden zu haben, das die PayLoad immer den gleichen Aufbau hat. Es ist mir gelungen im “function-node” eine Nachricht einzulesen etwas herauszufiltern, Daten in ein neues Array zu schaufeln und dieses dann auszugeben.
Bedenke: Dies sind meine ersten Gehversuche in PHP !

// Array definieren, in dem Werte ausgegeben werden sollen
$outmsg = array();

// Namen des Devices ermitteln
// Name immer in Element 0 speichern
$outmsg[0] = $message['payload']['data'][5]['name'];

// Prüfen ob das aktuelle device zu bearbeiten ist.
// WandThermostate beginnen bei mir immer mit WT ...
// Ansonsten Verarbeitung hier beenden
if (substr_compare($outmsg[0], "WT", 0, 2) != 0) {
    return;
}

// Die hier zu verarbeiten Infos kommen immer auf Kanal 1
// Bearbeitung beenden, wenn Channel != 1
if ($message['payload']['data'][2] == 1) {
    // peerID immer in Element 1 speichern
    $outmsg[1] = $message['payload']['data'][1];
    
    // Channel immer in Element 2 speichern
    $outmsg[2] = $message['payload']['data'][2];
} else {
    return;
}

// Typ immer in Element 3 speichern
$outmsg[3][] = $message['payload']['data'][3][0];

// Zugehörigen Wert immer in Element 4 speichern
$outmsg[4][] = $message['payload']['data'][4][0];

$msg['payload'] = $outmsg;
return $msg;

Unklar ist mir bislang aber wie ich die gesamte PayLoad nach einem Filter Vorgang unverändert an einen weiteren Konten durchreichen kann, damit dieser auf Basis der Original PayLoad weitere Verarbeitungen machen kann.

// Namen des Devices ermitteln
$name = $message['payload']['data'][5]['name'];

// Prüfen ob das aktuelle device zu bearbeiten ist.
// WandThermostate beginnen bei mir immer mit WT ...
// Ansonsten Verarbeitung hier beenden
if (substr_compare($name, "WT", 0, 2) != 0) {
    return;
}

// Die hier zu verarbeiten Infos kommen immer auf Kanal 1
// Bearbeitung beenden, wenn Channel != 1
if ($message['payload']['data'][2] != 1) {
    return;
}

// Jetzt Input Payload ausgeben
return ????????????????;

Entweder

return $msg;

oder

output(0,$msg);
return;

Man kann das $msg (oder $message, weiß ich aus dem Kopf nicht mehr) Objekt einfach wieder rausgeben.

Das ist tatsächlich etwas tricky. Zumindest, wenn man mehr als einen Ausgang benutzen möchte…

So funktioniert es wie gewünscht:

$buffer = "bla";

// Wenn die Original Message, egal auf welchem Ausgang wieder
// ausgegeben werden soll, so muss das immer zuerst passieren.
// Ansonsten wird $message durch $msg überschrieben, und diese 
// mehrfach ausgegeben
output(0, $message);

// Danach andere Daten - hier den kompletten Buffer - ausgeben
$msg['payload'] = $buffer;
output(1, $msg);

Das hier funktioniert wegen der Reihenfolge aber nicht:

$buffer = "bla";

$msg['payload'] = $buffer;
output(1, $msg);

output(0, $message);

Nächste Falle …

Die Verarbeitung innerhalb eines “function nodes” verläuft nur scheinbar sequentiell.
Nehmen wir folgendes Beispiel:

$buffer = "bla";
$msg['payload'] = $buffer;
output(1, $msg);

$buffer = "blubb";
$msg['payload'] = $buffer;
output(0, $msg);

Das führt zumindest bei bir dazu, das nur an Ausgang 0 eine Message erscheint.
Nimmt man jedoch unterschiedliche Namen für die Variablen erscheint an beiden Ausgängen die gewünschte Message.

$buffer = "bla";
$msg_out1['payload'] = $buffer;
output(1, $msg_out1);

$buffer = "blubb";
$msg_out2['payload'] = $buffer;
output(0, $msg_out2);

Offensichtlich ist es so, daß Funktionsaufrufen wie “setFlowData” oder “output” ein Pointer auf den Speicherbereich in dem die auszugebenden Daten stehen mitgegeben wird. Die Funktion wird aber scheinbar nicht direkt ausgeführt sondern irgendwann, etwas später. Wenn dann aber Speicherbereich von der eigenen Programmlogik überschrieben wurde, dann wird nur die Letzte output Anweisung ausgeführt. Jedenfalls erscheint dann im Debug-Node nichts …
Verwendet man unterschiedliche Variablen-Namen gibt es hingegen keine Probleme.

Auch die Funktionen “setFlowData” ist mit Vorsicht zu genießen. Es steht zwar nirgends explizit, aber es ist so, das die Daten “nur” für den Flow als Ganzes gespeichert werden. Nicht jedoch für jeden Event der den Flow auslöst getrennt.

Das hat folgenden Effekt. Wenn man direkt am Anfang eines Flows die Funktion “setFlowData” aufruft und die so gespeicherten Daten am Ende eines Flows mit “getFlowDate” verarbeiten möchte. dann kann es sein, das inzwischen ein weiter Event einen weiteren parallel laufenden Flow auslöst. Wenn dieser jetzt ebenfalls das “setFlowData” aufruft, dann liest der erste Prozess die Daten des 2. Prozesses. :frowning:
Das Verhalten dürfte auch von der darunter liegenden Hardware abhängig sein.
Also schön aufpassen …

Es ist meines Erachtens in deinem Fall einfacher, die “Variable in”-Knoten zu verwenden, und so bereits fertige, passende Messages zu bekommen, und auch nur dann, wenn ich etwas geändert hat.
Angehängt mal meine aktuelle Konfiguration für einen Thermostaten mit Fenstersensor.
GetFlowData und GetNodeData sind meiner Erfahrung nach eine ziemlich Katastrophe und funktionieren nur nach Gutdünken. Was verlässlich läuft ist GetGlobalData. Daher speichere ich meine Handvoll Variablen immer unter Hinzunahme der PeerId Global.

Das hilft mir erst mal nicht so viel weiter…
Die “schwarzen Nodes” gibts bei mir gar nicht. Und was in den SubFlows passiert weiß ich ja auch nicht. Um den Flow zu verstehen wäre der kompletten Export inkl. der Subflows hilfreich.

Und “Variable-In” wollte ich ja gerade vermeiden, da ich dann für jeden meiner 14 Wandthermostate eine eigene Definition machen muss.
Und das Ganze muss dann auch noch 25 Heizkörperthemostate bedienen. Je eines für einen Kreislauf an der Fußbodenheizung. Und verlinken geht nicht, weil die Thermostate eigenständig in Abhängigkeit von der Temperatur steuern.
Und die erreicht im Winter im isolierten Verteiler auch schon mal 30°C, da die Vorlauftemperatur dann bei ca. 35-40°C liegt.
Bei 30°C als “current” Temperatur machen die Thermostate aber zu. Dabei sollen die evtl. gerade dann voll aufmachen…
Es kann bei einer Fußbodenheizung also nur über den Öffnungsgrad der Ventile funktionieren. Nicht über Temperatur …

Daher baue ich mir gerade einen Flow, der das alles für alle Ventile und alle Wandthemostate möglichst vollautomatisch machen soll :slight_smile:

Ja, eine universelle Lösung die ohne die ganzen Variable in/out Knoten läuft wäre schon gut. Aber da ich das ganze Node-Blue hauptsächlich mache um ein brauchbares UI zu bekommen (über die schwarzen Nodes) sehe ich da in meinem Fall keine andere Möglichkeit.
Ich kopiere immer ein ganzes Set, und passe dann nur noch die Variablen an, das geht pro Thermostat recht fix (wenige Minuten, mal 16 Thermostate bei mir), macht dann vielleicht eine Stunde oder etwas mehr.
Warum du die schwarzen UI-Nodes nicht hast ist mir ein Rätsel. Ich hab die stable Docker Version 0.7.x, die wohl schon lange nicht mehr angefasst wurde: Version 0.7.51-3497, UI-Version 0.2.0-1321-dev.

Ok. Ich habe hier eine nightly aus 2024 im Testbetrieb…