-
-
Save Noschvie/239cfa9c463f940ff0bd7a9bdc1bdebe to your computer and use it in GitHub Desktop.
//https://forum.iobroker.net/post/133815 | |
//VL, outgoing temperature | |
const idTempVL = 'sonoff.0.HWR.DS18B20-2_Temperature'; | |
const iddTVL = '0_userdata.0.WWZirkulationspumpe.dTVL'; | |
const swOn = 0.7; // Grenzwert in K/min | |
var speedVL | |
var speedVLold = 0; | |
//RL, return temperature | |
const idTempRL = 'sonoff.0.HWR.DS18B20-1_Temperature'; | |
const iddTRL = '0_userdata.0.WWZirkulationspumpe.dTRL'; | |
const swOff = 0.3; // Grenzwert in K/min | |
var speedRL | |
var speedRLold = 0; | |
var timer = null; | |
const minTime = 60000 // Minimum Zeit in Millisekunden, welche die Pumpe laufen soll, bevor abgeschalten werden kann (TRL ist noch unter swOff) | |
const minTemp = 36 // Minimum Temperatur, bevor die Pumpe wieder läuft | |
var check = false; // Check für minTime | |
var check2 = 1; // Check für minimalen speedVL für Ausschalten, sonst wird zu früh abgeschalten | |
var h1, h2 | |
const idAktor = 'sonoff.0.HWR.POWER2'; | |
var aktor = getState(idAktor).val; | |
on({id: idAktor, ack: true}, function(dp) {aktor = dp.state.val;}); | |
////////////////////////////////////////////////////////// | |
/* Einschalten bei steigender Vorlauftemperatur */ | |
on(idTempVL, function(dp) { // Triggern bei Wertänderung | |
h1 = 60000 * (dp.state.val - dp.oldState.val) / (dp.state.lc - dp.oldState.lc); // K/min | |
speedVL = (h1 + speedVLold)/2; | |
//console.debug(([Math.round(speedVL*100)/100,' speedVL = (',Math.round(h1*100)/100,' + ',Math.round(speedVLold*100)/100,')/2 K/min'].join(''))); | |
speedVLold = h1; | |
if (speedVL < -5 || speedVL > 5) {return;} | |
//console.debug((['state - oldState: ',dp.state.val,' - ',dp.oldState.val,' = ',Math.round((dp.state.val - dp.oldState.val)*100)/100].join(''))); | |
//console.debug((['TDiff: ',(dp.state.lc - dp.oldState.lc),'ms'].join(''))); | |
//console.debug(([speed,' K/min.'].join(''))); | |
setState(iddTVL, Math.round(speedVL*1000)/1000, true); | |
if (speedVL >= swOn && !aktor && getState(idTempVL).val <= minTemp) { | |
setState(idAktor,true); | |
var messageText =['Zirkulationspumpe an. (*dTVL: ',Math.round(speedVL*1000)/1000,', dTRL: ',Math.round(speedRL*1000)/1000,')'].join(''); | |
//sendTo("telegram", "send", { text: messageText }); | |
console.log((messageText)); | |
/* Prüfung mit Alarm */ | |
if (!getState("0_userdata.0.Anwesenheit.Status.anyonePresent").val) { | |
var messageText =['Zirkulationspumpe an, obwohl niemand da ist!\r\n(*dTVL: ',Math.round(speedVL*1000)/1000,', dTRL: ',Math.round(speedRL*1000)/1000,')'].join(''); | |
sendTo("telegram", "send", { text: messageText }); | |
console.error((messageText)); | |
} | |
//console.debug(([Math.round(speed*100)/100,' K/min'].join(''))); | |
//console.debug((['Temperatur ist um mehr als ',gw,' K/min gestiegen.'].join(''))); | |
//clearTimeout(timer); | |
timer = setTimeout(function() { | |
//if(aktor) setState(idAktor, false); | |
check = true | |
}, minTime); | |
} | |
}); | |
/* Ausschalten bei fallender Rücklauftemperatur, nach minimaler Zeit, bei stagnierender Vorlauftemperatur */ | |
on(idTempRL, function(dp) { // Triggern bei Wertänderung | |
h2 = 60000 * (dp.state.val - dp.oldState.val) / (dp.state.lc - dp.oldState.lc); // K/min | |
speedRL = (h2 + speedRLold)/2; | |
//console.debug(([Math.round(speedRL*100)/100,' speedRL = (',Math.round(h2*100)/100,' + ',Math.round(speedRLold*100)/100,')/2 K/min'].join(''))); | |
speedRLold = h2; | |
if (speedRL < -5 || speedRL > 5) {return;} | |
setState(iddTRL, Math.round(speedRL*1000)/1000, true); | |
if(speedRL <= swOff && speedRL > 0 && aktor && check && speedVL <= check2) { | |
clearTimeout(timer); | |
check = false | |
setState(idAktor,false); | |
var messageText =['Zirkulationspumpe aus. (dTVL: ',Math.round(speedVL*1000)/1000,', *dTRL: ',Math.round(speedRL*1000)/1000,')'].join(''); | |
//sendTo("telegram", "send", { text: messageText }); | |
console.log((messageText)); | |
} | |
}); | |
//Debug | |
/* | |
on({id: new RegExp(idTempVL + "$|" + idTempRL + "$"), change: "ne"}, async function (obj) { | |
console.debug((['(dTVL: ',Math.round(speedVL*1000)/1000,', dTRL: ',Math.round(speedRL*1000)/1000,', aktor: ',aktor,', timeout: ',check,')'].join(''))); | |
}); | |
*/ |
Hier ist der JavaScript-Code, der für Tasmota in die Regel-Engine umgewandelt wurde. Tasmota verwendet eine spezielle Syntax für Regeln, die in einer Konfiguration definiert wird. Beachte, dass Tasmota-Regeln eine vereinfachte Syntax haben und nicht alle JavaScript-Funktionen direkt übersetzbar sind. Die grundlegende Logik sollte jedoch beibehalten werden.
Konvertierter Tasmota-Regel-Code
// Definiere Variablen
Var1 0 // h1
Var2 0 // speedVL
Var3 0 // speedVLold
Var4 0 // minTemp
Var5 0 // swOn
Var6 0 // timer
Var7 0 // check
Var8 0 // dTRL (dTVL)
Rule1 ON Temperature#State DO
// Berechne Temperaturänderungsrate in K/min
Var1 (60000 * (Temperature#State - Temperature#Previous) / (Time#State - Time#Previous))
Var2 (Var1 + Var3) / 2 // speedVL
Backlog Var3 Var1; Var8 %Var2% // Speichere aktuelle Werte
IF (Var2 < -5) OR (Var2 > 5)
THEN
// Werte liegen außerhalb der akzeptablen Grenzen
RETURN
ENDIF
// Setze den geglätteten Wert in den Statuspunkt
Publish stat/tasmota/iddTVL %Var2%
// Bedingungen für das Einschalten der Pumpe
IF (Var2 >= Var5) AND (Power1 == OFF) AND (Temperature#State <= Var4)
THEN
Power1 ON
// Log-Nachricht
Publish stat/tasmota/LOG "Zirkulationspumpe an. (*dTVL: %Var2%, dTRL: %Var8%)"
// Prüfe Anwesenheit
IF (Status#Anwesenheit == 0)
THEN
// Sende Alarmnachricht
Publish stat/tasmota/ALARM "Zirkulationspumpe an, obwohl niemand da ist! (*dTVL: %Var2%, dTRL: %Var8%)"
ENDIF
// Setze Timer
Timer1 60
ENDIF
ENDON
Rule2 ON Timer1#State DO
// Überprüfe und setze den Status
Power1 OFF
Publish stat/tasmota/LOG "Zirkulationspumpe aus. (*dTVL: %Var2%, dTRL: %Var8%)"
ENDON
// Regeln aktivieren
Rule1 1
Rule2 1
Erläuterungen:
-
Variablen-Initialisierung:
- Die Variablen
Var1
bisVar8
werden für die Berechnungen und Zustände verwendet. Var1
wird verwendet, um die Änderungsrate der Temperatur (h1
) zu speichern.Var2
speichert die geglättete Geschwindigkeit (speedVL
).Var3
speichert den alten Wert (speedVLold
).Var4
,Var5
,Var6
,Var7
undVar8
entsprechen den Schwellenwerten und Statusvariablen.
- Die Variablen
-
Berechnung der Temperaturänderungsrate:
- Die Änderungsrate wird berechnet und geglättet (
Var2
).
- Die Änderungsrate wird berechnet und geglättet (
-
Bedingungen für das Einschalten der Pumpe:
- Die Pumpe wird eingeschaltet, wenn die Geschwindigkeit den Schwellenwert (
Var5
) überschreitet und die Vorlauftemperatur unterVar4
liegt.
- Die Pumpe wird eingeschaltet, wenn die Geschwindigkeit den Schwellenwert (
-
Timer für das Ausschalten der Pumpe:
- Ein Timer wird gesetzt, der nach einer bestimmten Zeit (
60 Sekunden
) die Pumpe ausschaltet.
- Ein Timer wird gesetzt, der nach einer bestimmten Zeit (
-
Log-Nachrichten und Alarm:
- Nachrichten werden veröffentlicht, um die Aktionen der Pumpe zu protokollieren, und es wird ein Alarm gesendet, wenn niemand zu Hause ist.
Berry Beispiel
Für Berry, das eine vereinfachte JavaScript-ähnliche Syntax verwendet, könnte der Code so aussehen:
// Initialisiere Variablen
let speedVLold = 0;
let timer;
let check = false;
// Funktion für Temperaturänderung
function onTemperatureChange(dp) {
let h1 = 60000 * (dp.state.val - dp.oldState.val) / (dp.state.lc - dp.oldState.lc); // K/min
let speedVL = (h1 + speedVLold) / 2;
speedVLold = h1;
if (speedVL < -5 || speedVL > 5) return;
setState(iddTVL, Math.round(speedVL * 1000) / 1000, true);
if (speedVL >= swOn && !aktor && getState(idTempVL).val <= minTemp) {
setState(idAktor, true);
let messageText = `Zirkulationspumpe an. (*dTVL: ${Math.round(speedVL * 1000) / 1000}, dTRL: ${Math.round(speedRL * 1000) / 1000})`;
console.log(messageText);
if (!getState("0_userdata.0.Anwesenheit.Status.anyonePresent").val) {
let alarmMessage = `Zirkulationspumpe an, obwohl niemand da ist! (*dTVL: ${Math.round(speedVL * 1000) / 1000}, dTRL: ${Math.round(speedRL * 1000) / 1000})`;
sendTo("telegram", "send", { text: alarmMessage });
console.error(alarmMessage);
}
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
check = true;
}, minTime);
}
}
// Setze die Event-Handler
on(idTempVL, onTemperatureChange);
Anmerkungen:
- Tasmota-Regeln: Die Syntax für Tasmota-Regeln unterscheidet sich erheblich von JavaScript und erfordert die Nutzung von
Publish
undTimer
. - Berry: Die Syntax ist näher an JavaScript, aber es gibt Einschränkungen bei der Funktionalität im Vergleich zu vollständigem JavaScript.
In Berry für Tasmota kannst du Klassen erstellen, die ähnlich wie in JavaScript oder Python funktionieren. Um eine Klasse zu erstellen, die die aktuelle Temperatur, den aktuellen Timestamp sowie die vorherige Temperatur und den vorherigen Timestamp speichert, kannst du die folgende Struktur verwenden.
Beispiel: Erstellen einer Klasse in Berry
Hier ist ein Beispiel für eine Klasse, die die Temperatur- und Zeitstempel-Daten speichert:
class TemperatureTracker {
var currentTemp
var previousTemp
var currentTimestamp
var previousTimestamp
// Konstruktor zum Initialisieren der Werte
construct() {
this.currentTemp = 0
this.previousTemp = 0
this.currentTimestamp = 0
this.previousTimestamp = 0
}
// Funktion zum Aktualisieren der Temperatur und des Timestamps
update(temp, timestamp) {
this.previousTemp = this.currentTemp
this.previousTimestamp = this.currentTimestamp
this.currentTemp = temp
this.currentTimestamp = timestamp
}
// Funktion zum Anzeigen der aktuellen und vorherigen Werte
display() {
print("Aktuelle Temperatur: " + this.currentTemp + "°C")
print("Aktueller Timestamp: " + this.currentTimestamp)
print("Vorherige Temperatur: " + this.previousTemp + "°C")
print("Vorheriger Timestamp: " + this.previousTimestamp)
}
}
// Beispiel für die Verwendung der Klasse
let tracker = TemperatureTracker()
// Beispielwerte aktualisieren (aktuelle Temperatur und Timestamp)
tracker.update(22.5, system_time()) // system_time() gibt den aktuellen Timestamp zurück
// Werte anzeigen
tracker.display()
// Neue Werte aktualisieren
tracker.update(23.0, system_time())
// Erneut anzeigen
tracker.display()
Erläuterung:
- Konstruktor: Die Methode
construct()
wird beim Erstellen einer Instanz der Klasse aufgerufen. Hier werden die Werte für Temperatur und Timestamp initialisiert. update()
-Methode: Diese Methode wird verwendet, um die aktuellen Werte der Temperatur und des Zeitstempels zu aktualisieren. Die vorherigen Werte werden ebenfalls gespeichert.display()
-Methode: Diese Methode zeigt die aktuellen und vorherigen Temperaturen sowie die zugehörigen Zeitstempel an.
Funktionsweise:
- Wenn die
update()
-Methode aufgerufen wird, speichert sie die aktuellen Werte in den "vorherigen" Variablen und setzt die neuen Werte als "aktuelle". - Mit der
display()
-Methode kannst du die aktuellen und vorherigen Temperaturen und Zeitstempel in der Konsole anzeigen.
In deinem spezifischen Fall, wenn du mit Tasmota arbeitest, kannst du die system_time()
-Funktion verwenden, um den aktuellen Timestamp zu erhalten. Die Temperatur kann beispielsweise von einem Sensor gelesen werden, indem du eine passende Funktion dafür aufrufst.
Um den JavaScript-Code für Tasmota und Berry zu konvertieren, müssen wir einige Anpassungen vornehmen. Tasmota verwendet eine spezifische Syntax für seine Regel-Engine und für die Steuerung von Geräten, die sich von allgemeinem JavaScript unterscheidet. Berry ist ein JavaScript-Interpreter für Mikrocontroller, der eine reduzierte Funktionalität bietet, aber in vielen Fällen ähnliche Konzepte verwendet.
Hier ist eine konvertierte Version des Codes für Tasmota und Berry:
Tasmota Regeln
In Tasmota werden Regeln verwendet, um Ereignisse zu verarbeiten. Hier ist ein Beispiel, wie der Code in Tasmota-Regeln umgesetzt werden könnte:
Berry Beispiel
Berry verwendet eine vereinfachte JavaScript-ähnliche Syntax. Hier ist eine Beispielkonvertierung für Berry:
Anmerkungen: