Skip to content

Instantly share code, notes, and snippets.

@Noschvie
Last active September 6, 2024 05:53
Show Gist options
  • Save Noschvie/239cfa9c463f940ff0bd7a9bdc1bdebe to your computer and use it in GitHub Desktop.
Save Noschvie/239cfa9c463f940ff0bd7a9bdc1bdebe to your computer and use it in GitHub Desktop.
"Circulating Hot Water Pump" Controller (https://forum.iobroker.net/post/133815)
//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('')));
});
*/
@Noschvie
Copy link
Author

Noschvie commented Sep 5, 2024

Dieser Code ist eine JavaScript-Funktion, die auf ein Ereignis reagiert, wenn sich ein bestimmter Datenpunkt (hier idTempVL) ändert. Es scheint sich um ein Heizungs- oder Pumpensystem zu handeln, bei dem die Vorlauftemperatur überwacht und basierend auf bestimmten Kriterien eine Zirkulationspumpe gesteuert wird. Hier ist eine detaillierte Erklärung der wichtigsten Teile des Codes:

1. Berechnung der Temperaturänderungsgeschwindigkeit:

h1 = 60000 * (dp.state.val - dp.oldState.val) / (dp.state.lc - dp.oldState.lc);  // K/min
  • dp.state.val: Der aktuelle Wert des Datenpunkts (vermutlich die aktuelle Vorlauftemperatur).
  • dp.oldState.val: Der vorherige Wert des Datenpunkts.
  • dp.state.lc und dp.oldState.lc: Zeitstempel (in Millisekunden) des aktuellen und vorherigen Zustands.
  • h1: Die Änderungsrate der Vorlauftemperatur in Kelvin pro Minute (K/min). Die Berechnung basiert auf der Differenz zwischen dem aktuellen und dem vorherigen Temperaturwert sowie der Zeitdifferenz.

2. Glättung der Geschwindigkeit:

speedVL = (h1 + speedVLold)/2;
  • Die berechnete Geschwindigkeit (h1) wird mit dem alten Wert (speedVLold) gemittelt, um Schwankungen zu glätten.
  • speedVL ist die geglättete Änderungsrate der Vorlauftemperatur.

3. Prüfen auf sinnvolle Werte:

if (speedVL < -5 || speedVL > 5) { return; }
  • Hier wird überprüft, ob die Änderungsrate der Vorlauftemperatur einen realistischen Bereich von ±5 K/min hat. Ist dies nicht der Fall, wird die Funktion beendet.

4. Speichern des neuen geglätteten Wertes:

setState(iddTVL, Math.round(speedVL*1000)/1000, true);
  • Der geglättete Wert der Temperaturänderungsgeschwindigkeit (speedVL) wird gerundet und in einem Datenpunkt (iddTVL) gespeichert.

5. Schalten der Zirkulationspumpe:

if (speedVL >= swOn && !aktor && getState(idTempVL).val <= minTemp) {
    setState(idAktor,true);
  • Wenn die Temperaturänderungsgeschwindigkeit (speedVL) größer oder gleich einem Schwellwert (swOn) ist, die Pumpe nicht bereits aktiv ist (!aktor) und die Vorlauftemperatur unterhalb einer minimalen Temperatur (minTemp) liegt, wird die Zirkulationspumpe aktiviert (setState(idAktor, true)).

6. Senden von Benachrichtigungen:

var messageText = ['Zirkulationspumpe an.  (*dTVL: ', Math.round(speedVL*1000)/1000, ', dTRL: ', Math.round(speedRL*1000)/1000, ')'].join('');
console.log(messageText);
  • Es wird eine Nachricht erzeugt und im Log ausgegeben, wenn die Pumpe aktiviert wird. Die Nachricht enthält die aktuellen Temperaturänderungswerte.

7. Überprüfung auf Anwesenheit:

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);
}
  • Wenn niemand zu Hause ist, wird eine Warnung per Telegram gesendet und ein Fehler im Log ausgegeben.

8. Timer für das Ausschalten der Pumpe:

timer = setTimeout(function() {
    check = true;
}, minTime);
  • Ein Timer wird gesetzt, der nach einer bestimmten Zeit (minTime) eine Aktion auslöst, möglicherweise zum Ausschalten der Pumpe.

Zusammenfassung:

Der Code überwacht die Vorlauftemperatur und berechnet die Änderungsrate. Wenn die Bedingungen erfüllt sind (z. B. hohe Temperaturänderung und niedrige Vorlauftemperatur), wird die Zirkulationspumpe eingeschaltet. Zusätzlich gibt es eine Benachrichtigung, falls die Pumpe eingeschaltet wird, obwohl niemand zu Hause ist.

@Noschvie
Copy link
Author

Noschvie commented Sep 5, 2024

Dieser Code überwacht die Rücklauftemperatur (idTempRL) WW Heizungsanlage. Er dient dazu, eine Zirkulationspumpe auszuschalten, wenn die Bedingungen erfüllt sind, etwa bei einer fallenden Rücklauftemperatur oder stagnierender Vorlauftemperatur, und nach einer minimalen Laufzeit.

Hier ist die Erklärung des Codes:

1. Berechnung der Rücklauftemperaturänderung:

h2 = 60000 * (dp.state.val - dp.oldState.val) / (dp.state.lc - dp.oldState.lc);  // K/min
  • dp.state.val: Der aktuelle Wert des Rücklauftemperatur-Datenpunkts.
  • dp.oldState.val: Der vorherige Wert des Rücklauftemperatur-Datenpunkts.
  • dp.state.lc und dp.oldState.lc: Zeitstempel (in Millisekunden) des aktuellen und vorherigen Zustands.
  • h2: Die Änderungsrate der Rücklauftemperatur in Kelvin pro Minute (K/min). Wie im vorherigen Code wird die Differenz zwischen den aktuellen und alten Temperaturwerten sowie der Zeitdifferenz genutzt, um die Änderungsrate zu berechnen.

2. Glättung der Rücklauftemperaturgeschwindigkeit:

speedRL = (h2 + speedRLold)/2;
  • Die Rücklauftemperaturänderungsgeschwindigkeit (h2) wird mit dem vorherigen Wert (speedRLold) gemittelt, um die Werte zu glätten.
  • speedRL ist die geglättete Änderungsrate der Rücklauftemperatur.

3. Prüfen auf sinnvolle Werte:

if (speedRL < -5 || speedRL > 5) { return; }
  • Die Rücklauftemperaturgeschwindigkeit muss im Bereich von ±5 K/min liegen. Ist die Änderungsrate zu groß oder zu klein, wird die Funktion abgebrochen.

4. Speichern des neuen Werts:

setState(iddTRL, Math.round(speedRL*1000)/1000, true);
  • Die geglättete Rücklauftemperaturgeschwindigkeit (speedRL) wird gerundet und in einem Datenpunkt (iddTRL) gespeichert.

5. Ausschalten der Zirkulationspumpe:

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('');
    console.log(messageText);
}
  • Bedingungen zum Ausschalten der Pumpe:

    • speedRL <= swOff: Die Rücklauftemperaturänderungsgeschwindigkeit ist kleiner oder gleich einem definierten Schwellwert (swOff). Dies könnte darauf hinweisen, dass die Rücklauftemperatur fällt oder stagniert.
    • speedRL > 0: Die Rücklauftemperatur darf nicht negativ sein.
    • aktor: Die Zirkulationspumpe ist aktuell eingeschaltet.
    • check: Eine Bedingung, die sicherstellt, dass die minimal erforderliche Zeit verstrichen ist, bevor die Pumpe ausgeschaltet werden darf.
    • speedVL <= check2: Die Vorlauftemperaturgeschwindigkeit (speedVL) muss unter einem bestimmten Schwellwert (check2) liegen, was auf eine stagnierende Vorlauftemperatur hinweist.
  • Wenn alle Bedingungen erfüllt sind:

    • Der Timer wird zurückgesetzt (clearTimeout(timer)).
    • Die Pumpe wird ausgeschaltet (setState(idAktor, false)).
    • Eine Nachricht wird im Log ausgegeben, um das Ausschalten der Pumpe zu protokollieren.

6. Nachrichtenausgabe:

var messageText = ['Zirkulationspumpe aus. (dTVL: ',Math.round(speedVL*1000)/1000,', *dTRL: ',Math.round(speedRL*1000)/1000,')'].join('');
console.log(messageText);
  • Es wird eine Nachricht erzeugt, die die aktuellen Vorlauf- und Rücklauftemperaturänderungswerte anzeigt. Diese Nachricht wird im Log ausgegeben, um das Ausschalten der Pumpe zu dokumentieren.

Zusammenfassung:

Dieser Code überwacht die Rücklauftemperatur und deren Änderungsrate. Wenn die Rücklauftemperatur sinkt und die Vorlauftemperatur stagniert, wird die Zirkulationspumpe nach einer bestimmten Zeit ausgeschaltet. Die Funktion stellt sicher, dass die Pumpe nur dann ausgeschaltet wird, wenn es sinnvoll ist, und gibt eine entsprechende Nachricht im Log aus.

@Noschvie
Copy link
Author

Noschvie commented Sep 5, 2024

In der Praxis wird häufig "Grad Celsius" verwendet, wenn es um Temperaturmessungen und -änderungen geht. Der Begriff "Kelvin pro Minute" könnte jedoch auch verwendet werden, insbesondere in wissenschaftlichen und technischen Kontexten, weil Kelvin und Celsius lineare Einheiten mit dem gleichen Intervall sind. Das bedeutet:

  1. Kelvin (K) ist äquivalent zu 1 Grad Celsius (°C) in Bezug auf die Temperaturdifferenz oder Änderungsrate. Es gibt keinen Unterschied in der Größe der Intervalle zwischen diesen beiden Einheiten; sie unterscheiden sich nur durch einen konstanten Offset (273,15 K = 0 °C).

Wenn der Code also "Kelvin pro Minute" verwendet, könnte es daran liegen, dass Kelvin in bestimmten wissenschaftlichen oder technischen Kontexten bevorzugt wird, oder es könnte einfach eine Konvention sein. Der genaue Wert der Änderungsrate würde sich in beiden Fällen nicht ändern, da die Einheiten linear äquivalent sind.

In der Regel ist es jedoch üblicher, in alltäglichen Anwendungen "Grad Celsius" zu verwenden, insbesondere wenn es um Heizungssysteme oder ähnliche Anwendungen geht, da dies für die meisten Menschen verständlicher ist. In deinem Fall könntest du die Einheiten auch in Grad Celsius angeben, wenn es für dich praktischer ist und keine weiteren wissenschaftlichen Anforderungen bestehen.

@Noschvie
Copy link
Author

Noschvie commented Sep 5, 2024

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:

// Definiere Variablen
Var1 0
Var2 0
Var3 0
Var4 0
Var5 0
Var6 0

// Regel für Temperaturänderung
Rule1 ON Temperature#State DO 
   // Berechne Temperaturänderungsrate in K/min
   Var1 %value%
   Var2 %prevvalue%
   Var3 %time% 
   Var4 (Var1 - Var2) / ((Var3 - Var5) / 60000) // h1
   Var6 (Var4 + Var2) / 2 // speedVL
   // Setze den geglätteten Wert
   Backlog Var5 %time%; Var2 %Var4%; Var6 %Var6%; 
   // Prüfe, ob der Wert innerhalb der akzeptablen Grenzen liegt
   IF (Var6 > -5) AND (Var6 < 5) 
   THEN 
      // Setze den geglätteten Wert in den Statuspunkt
      Power1 ON
   ENDIF
   // Prüfe Bedingungen für das Einschalten der Pumpe
   IF (Var6 >= swOn) AND (Power1 == OFF) AND (Temperature#State <= minTemp)
   THEN 
      // Schalte die Pumpe ein
      Power1 ON
      // Log-Nachricht
      Publish stat/tasmota/POWER "Zirkulationspumpe an.  (*dTVL: %Var6%, dTRL: %Var3%)"
      // Prüfe Anwesenheit
      IF (Status#Anwesenheit == 0)
      THEN 
         // Sende Alarmnachricht
         Publish stat/tasmota/ALARM "Zirkulationspumpe an, obwohl niemand da ist! (*dTVL: %Var6%, dTRL: %Var3%)"
      ENDIF
      // Setze einen Timer
      Timer1 60
   ENDIF
ENDON

// Regel für den Timer
Rule2 ON Timer1#State DO 
   // Überprüfe und setze den Status
   Power1 OFF
   // Log-Nachricht
   Publish stat/tasmota/POWER "Zirkulationspumpe aus. (*dTVL: %Var6%, dTRL: %Var3%)"
ENDON

// Aktiviere Regeln
Rule1 1
Rule2 1

Berry Beispiel

Berry verwendet eine vereinfachte JavaScript-ähnliche Syntax. Hier ist eine Beispielkonvertierung für Berry:

// 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:

  1. Tasmota-Regeln: In Tasmota müssen Regeln in einer speziellen Syntax definiert werden. Die Logik wird in einer Art „Backlog“-Befehlen organisiert.
  2. Berry: Berry ist oft weniger leistungsfähig als vollständige JavaScript-Engines, aber die grundlegenden Konzepte sind ähnlich.

@Noschvie
Copy link
Author

Noschvie commented Sep 5, 2024

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:

  1. Variablen-Initialisierung:

    • Die Variablen Var1 bis Var8 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 und Var8 entsprechen den Schwellenwerten und Statusvariablen.
  2. Berechnung der Temperaturänderungsrate:

    • Die Änderungsrate wird berechnet und geglättet (Var2).
  3. Bedingungen für das Einschalten der Pumpe:

    • Die Pumpe wird eingeschaltet, wenn die Geschwindigkeit den Schwellenwert (Var5) überschreitet und die Vorlauftemperatur unter Var4 liegt.
  4. Timer für das Ausschalten der Pumpe:

    • Ein Timer wird gesetzt, der nach einer bestimmten Zeit (60 Sekunden) die Pumpe ausschaltet.
  5. 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 und Timer.
  • Berry: Die Syntax ist näher an JavaScript, aber es gibt Einschränkungen bei der Funktionalität im Vergleich zu vollständigem JavaScript.

@Noschvie
Copy link
Author

Noschvie commented Sep 6, 2024

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:

  1. Konstruktor: Die Methode construct() wird beim Erstellen einer Instanz der Klasse aufgerufen. Hier werden die Werte für Temperatur und Timestamp initialisiert.
  2. update()-Methode: Diese Methode wird verwendet, um die aktuellen Werte der Temperatur und des Zeitstempels zu aktualisieren. Die vorherigen Werte werden ebenfalls gespeichert.
  3. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment