Moin zusammen.
Ich suche schon etwas länger, aber irgendwie wurde ich nicht fündig.
Vielleicht hat auch einer einen Link, oder eine Vorlage für mein Vorhaben.
Es muss doch möglich sein, eine rule zu erstellen, womit man eine Position von einem Rollo, oder Motor bestimmen kann.
Ich denke dabei erstmal ganz einfach: Rollo fährt, rule zählt Zeit, rechnet % schreibt in Proxy Item.
Mir ist bekannt, das die Zeiten für hoch und runter Lauf nie 100% sind. Drum dachte ich weiter: bei Befehl in die Endlage:
Einfach Motor 10 Sekunden länger bestromen um neuen 0 Punkt zu generieren.
Und ein setpoint, könnte dann auch den Rollo in eine bestimmte Position fahren.
z.b. ist es bei lcn nicht so einfach eine % Steuerung zu realisieren, aber eventuell kann man hier eine rule Lösung anstreben.
Auch könnte man hier eventuell ein Relais Board verwenden, um die Motoren hoch und runter laufen zulassen.
Wisst ihr was ich meine? Jemand eine Idee, oder sogar schon um gesetzt?
Positions Bestimmung an Hand der Laufzeit rule
-
- Beiträge: 491
- Registriert: 6. Jan 2021 18:05
Positions Bestimmung an Hand der Laufzeit rule
Gruss mad-mike
openHABian 4.3.5 auf Raspberry Pi 4 Mod. b (8GB)
openHABian 4.3.5 auf Raspberry Pi 4 Mod. b (8GB)

- udo1toni
- Beiträge: 15249
- Registriert: 11. Apr 2018 18:05
- Wohnort: Darmstadt
Re: Positions Bestimmung an Hand der Laufzeit rule
Ich hatte so was mal vor Jahren im Einsatz. Das Ganze ist aber recht kritisch - Du darfst nie vergessen, dass openHAB kein Echtzeitsystem ist. Mehr noch, es ist asynchron designed. Das ist an mancher Stelle sehr praktisch, für diese Anwendung aber eher hinderlich, da man keine qualifizierten Aussagen über Laufzeiten machen kann.
Dennoch ein Beispielcode:
Sieht schlimm aus...
Erst mal die globalen Variablen und Konstanten:
lStart ist Zwischenspeicher für einen Unix Zeitstempel (Anzahl Millisekunden seit 1.1.1970,00:00:00.000 Uhr) Hier merkt sich die Rule, wann ein Befehl UP oder DOWN empfangen wurde
iRollCommand dient zum Merken der Fahrtrichtung
Die beiden Konstanten iUpTime und iDownTime geben die exakte Verfahrdauer von oben nach unten bzw. von unten nach oben an. Die beiden Zeiten weichen voneinander ab, weil der Motor beim Aufwickeln des Rollladens mehr Kraft benötigt.
Lokale Variablen und Konstanten:
iProzent: Die Position des Ladens
Laufzeit: Die Fahrtdauer in Millisekunden
iSoll: neue Sollposition
iMyTime: Errechnete Fahrzeit zum Erreichen der neuen Sollposition
Die Rule reagiert auf empfangene Befehle. Da die Position an verschiedenen Stellen gebraucht wird, wird zunächst die aktuell gespeicherte Position in iProzent gesichert.
Nun gibt es vier verschiedene Möglichkeiten:
1. Der Befehl lautete STOP
2. Der Befehl lautetet UP
3. der Befehl lautete DOWN
4. etwas Anderes
Im Fall 2 oder 3 müssen der aktuelle Zeitpunkt und die gewünschte Fahrtrichtung gesichert werden.
Im Fall 1 muss zunächst geprüft werden, ob es einen gültigen Wert in lStart gibt - falls nicht, muss die Rule abgebrochen werden. Ist dieser Test überstanden, können wir gefahrlos die Laufzeit bestimmen, indem wir lStart vom aktuellen Unix Zeitstempel abziehen.
Falls die Richtung aufwärts war, ergibt sich die neue Position aus der Differenz der alten Position minus der Laufzeit, geteilt durch die Gesamtlaufzeit * 100. Lief der Motor länger als nötig, um auf Position 0 zu kommen, ergibt sich dabei ein negativer Wert, den wir abfangen müssen, also falls iProzent kleiner 0, setze iProzent auf 0.
Das gleiche gilt sinngemäß für die Abwärtsbewegung, nur dass hier der prozentuale Anteil addiert wird und bei Überschreiten der 100 die 100 als Maximalwert gesetzt wird.
Der logInfo() Befehl sieht etwas komisch aus
ich wollte damit die Kommentar-Einrückungen etwas minimieren...
Für Fall 4, "etwas Anderes" bleibt eigentlich nur noch eine Zahl als Befehl übrig, denn andere Befehle kennt ein Rollershutter Item nicht.
Die Zahl ist also die neue Sollposition.
Nun müssen wir die benötigte Fahrdauer bestimmen. Diese ist natürlich abhängig von der Fahrtrichtung, die sich wiederum daraus ergibt, ob die neue Position kleiner oder größer als die aktuelle Position ist.
Dabei gilt, dass die Differenz aus den beiden Positionen den prozentualen Verfahrweg ergibt, also z.B. von 40 auf 50 wären 10. Das muss man dann durch 100 teilen und mit der Gesamtfahrzeit in Fahrtrichtung multiplizieren, um die nötige Fahrzeit zu ermitteln, natürlich wieder für beide Fahrtrichtungen getrennt
Ergibt sich eine Fahrtzeit über 0 (es könnte ja auch eine Positionsfahrt auf die aktuelle Position angefordert werden), so wird nun also der Timer für den Stop-Befehl gestartet und anschließend der Befehl UP bzw. DOWN gesendet (womit sich die Rule nun selbst triggert!)
Ich hoffe, dass die Theorie hinter der Rule klar wird
Ich hab bestimmt noch irgendwo Fehler drin
wie immer...
Nächstes Level ist dann, diese Rule so zu generalisieren, dass sie mit Gruppen funktioniert (wobei das bei Rollläden kritisch werden könnte - eine Rule kann seit 3.0 nur noch einmal zeitgleich ausgeführt werden, Rollläden werden aber gerne in Gruppen verfahren...)
Dennoch ein Beispielcode:
Code: Alles auswählen
var Long lStart = null // Speicher für Laufzeitmessung
var Integer iRollCommand = null // Zwischenspeicher für Befehl
val Integer iUpTime = 15000 // Gesamtlaufzeit von geschlossen nach offen
val Integer iDownTime = 13000 // Gesamtlaufzeit von offen nach geschlossen
rule "Rollo"
when
Item MyRollo received command // Befehl empfangen
then
var Integer iProzent = (MyRollo.state as Number).intValue // aktuelle gespeicherte Position
switch(receivedCommand) { // Welcher Befehl
case STOP : {
if(lStart === null) return; // falls was schief gegangen ist, raus
val Laufzeit = now.toInstant.toEpochMilli - lStart // Differenz Start zu Stopp in ms
if(iRollCommand == 1) { // Falls Richtung hoch war
iProzent = iProzent - (Laufzeit/iUpTime)*100 // ziehe Anteil der Laufzeit entsprechend von Prozent ab
if(iProzent < 0) iProzent = 0 // falls unter 0, setze 0
} else if(iRollCommand == -1) { // Falls Richtung runter war
iProzent = iProzent + (Laufzeit/iDownTime)*100 // addiere Anteil der Laufzeit
if(iProzent > 100) iProzent = 100 // Falls über 100, setze 100
}
logInfo("rollo",
"Rollo gestoppt. Laufzeit {} ms, neue Position {} %",
Laufzeit,iProzent)
MyRollo.postUpdate(iProzent) // melde neue Position
lStart = null // leeren!
}
case UP : {
lStart = now.toInstant.toEpochMilli // Setze Startzeit
iRollCommand = 1 // Setze Richtung
}
case DOWN : {
lStart = now.toInstant.toEpochMilli // Setze Startzeit
iRollCommand = -1 // Setze Richtung
}
default : { // Positionsfahrt
val Integer iSoll = (receivedCommand as Number).intValue // Setze Sollposition
val Integer iMyTime = 0 // Benötigte Fahrzeit
if(iSoll < iProzent) { // Falls Fahrtrichtung hoch
iRollCommand = 1 // Setze Richtung
iMyTime = (iProzent-iSoll)/100*iUpTime // bestimme benötigte Zeit
}
if(iSoll > iProzent) { // Falls Fahrtrichtung runter
iRollCommand = -1 // Setze Richtung
iMyTime = (iSoll-iProzent)/100*iDownTime // bestimme benötigte Zeit
}
if(iMyTime > 0) { // Falls Fahrtzeit > 0
createTimer(now.plusNanos(1000000*iMyTime),[| // Erzeuge Timer (ohne Zugriff!)
MyRollo.sendCommand(STOP) // Sende Stop
])
MyRollo.sendCommand(if(iRollCommand == 1) UP else DOWN) // Sende Befehl UP oder DOWN
}
}
}
end
Erst mal die globalen Variablen und Konstanten:
lStart ist Zwischenspeicher für einen Unix Zeitstempel (Anzahl Millisekunden seit 1.1.1970,00:00:00.000 Uhr) Hier merkt sich die Rule, wann ein Befehl UP oder DOWN empfangen wurde
iRollCommand dient zum Merken der Fahrtrichtung
Die beiden Konstanten iUpTime und iDownTime geben die exakte Verfahrdauer von oben nach unten bzw. von unten nach oben an. Die beiden Zeiten weichen voneinander ab, weil der Motor beim Aufwickeln des Rollladens mehr Kraft benötigt.
Lokale Variablen und Konstanten:
iProzent: Die Position des Ladens
Laufzeit: Die Fahrtdauer in Millisekunden
iSoll: neue Sollposition
iMyTime: Errechnete Fahrzeit zum Erreichen der neuen Sollposition
Die Rule reagiert auf empfangene Befehle. Da die Position an verschiedenen Stellen gebraucht wird, wird zunächst die aktuell gespeicherte Position in iProzent gesichert.
Nun gibt es vier verschiedene Möglichkeiten:
1. Der Befehl lautete STOP
2. Der Befehl lautetet UP
3. der Befehl lautete DOWN
4. etwas Anderes

Im Fall 2 oder 3 müssen der aktuelle Zeitpunkt und die gewünschte Fahrtrichtung gesichert werden.
Im Fall 1 muss zunächst geprüft werden, ob es einen gültigen Wert in lStart gibt - falls nicht, muss die Rule abgebrochen werden. Ist dieser Test überstanden, können wir gefahrlos die Laufzeit bestimmen, indem wir lStart vom aktuellen Unix Zeitstempel abziehen.
Falls die Richtung aufwärts war, ergibt sich die neue Position aus der Differenz der alten Position minus der Laufzeit, geteilt durch die Gesamtlaufzeit * 100. Lief der Motor länger als nötig, um auf Position 0 zu kommen, ergibt sich dabei ein negativer Wert, den wir abfangen müssen, also falls iProzent kleiner 0, setze iProzent auf 0.
Das gleiche gilt sinngemäß für die Abwärtsbewegung, nur dass hier der prozentuale Anteil addiert wird und bei Überschreiten der 100 die 100 als Maximalwert gesetzt wird.
Der logInfo() Befehl sieht etwas komisch aus

Für Fall 4, "etwas Anderes" bleibt eigentlich nur noch eine Zahl als Befehl übrig, denn andere Befehle kennt ein Rollershutter Item nicht.
Die Zahl ist also die neue Sollposition.
Nun müssen wir die benötigte Fahrdauer bestimmen. Diese ist natürlich abhängig von der Fahrtrichtung, die sich wiederum daraus ergibt, ob die neue Position kleiner oder größer als die aktuelle Position ist.
Dabei gilt, dass die Differenz aus den beiden Positionen den prozentualen Verfahrweg ergibt, also z.B. von 40 auf 50 wären 10. Das muss man dann durch 100 teilen und mit der Gesamtfahrzeit in Fahrtrichtung multiplizieren, um die nötige Fahrzeit zu ermitteln, natürlich wieder für beide Fahrtrichtungen getrennt

Ergibt sich eine Fahrtzeit über 0 (es könnte ja auch eine Positionsfahrt auf die aktuelle Position angefordert werden), so wird nun also der Timer für den Stop-Befehl gestartet und anschließend der Befehl UP bzw. DOWN gesendet (womit sich die Rule nun selbst triggert!)
Ich hoffe, dass die Theorie hinter der Rule klar wird

Ich hab bestimmt noch irgendwo Fehler drin

Nächstes Level ist dann, diese Rule so zu generalisieren, dass sie mit Gruppen funktioniert (wobei das bei Rollläden kritisch werden könnte - eine Rule kann seit 3.0 nur noch einmal zeitgleich ausgeführt werden, Rollläden werden aber gerne in Gruppen verfahren...)
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet
-
- Beiträge: 491
- Registriert: 6. Jan 2021 18:05
Re: Positions Bestimmung an Hand der Laufzeit rule
Danke dafür.
Ich habe dies mal einfach versucht und ein Proxy Item "MyRollo" erstellt... (rollershutter)
Nch dem Speichern der Rule:
Info:
und beim ausführen des Rollo schalters:
Im Log sehe ich, das der Rollo wechselt von 0 - direkt auf 100 und umgedreht von 100 - 0.
ich kann ihn auch setzen mit dem
Das Log aus der Rule wird nicht angezeigt...
Und die Fehlermeldung wird immer beim befehl ""Stop"" ausgeführt.
Ich habe dies mal einfach versucht und ein Proxy Item "MyRollo" erstellt... (rollershutter)
Nch dem Speichern der Rule:
Info:
Code: Alles auswählen
2023-02-15 19:47:31.243 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'rollo.rules', using it anyway:
Assignment to final variable
Assignment to final variable
Constant condition is always false.
und beim ausführen des Rollo schalters:
Code: Alles auswählen
2023-02-15 19:41:13.584 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'rollo-1' failed: An error occurred during the script execution: Could not invoke method: org.eclipse.xtext.xbase.lib.IntegerExtensions.operator_lessThan(int,int) on instance: null in rollo
ich kann ihn auch setzen mit dem
Das Log aus der Rule wird nicht angezeigt...
Und die Fehlermeldung wird immer beim befehl ""Stop"" ausgeführt.
Gruss mad-mike
openHABian 4.3.5 auf Raspberry Pi 4 Mod. b (8GB)
openHABian 4.3.5 auf Raspberry Pi 4 Mod. b (8GB)
