Seite 2 von 2

Re: Präsenzsimulation im Urlaub

Verfasst: 8. Jun 2024 17:18
von udo1toni
Ja, da fehlt ein Import... Da es nur einmal verwendet wird...

Code: Alles auswählen

// Globale Variablen vor der ersten Rule definieren!
var Timer tRandomLights = null                                                                     // Handle für Urlaubslicht
val java.util.Random random = new java.util.Random()                                               // Zufall
var Integer iRandom = null

// ab hier kommen die Rules

rule "Präsenz Simulation"
when
    Item Urlaub changed or                                                                         // Schalter umgelegt
    Time is midnight or                                                                            // oder neuer Tag
    Time cron "0 45 23 * * ?" or                                                                   // täglich um 23:45 Uhr
    Channel 'astro:sun:local:nauticDawn#event' triggered END                                       // nautischer Sonnenaufgang
then
    tRandomLights?.cancel                                                                          // bestehenden Timer abbrechen
    if(Urlaub.state != ON)                                                                         // Falls kein Urlaub
        return;                                                                                    // Ende
    Urlaubslichter.members.filter[i | i.getStateAs(OnOffType) != OFF].forEach[Light | Light.sendCommand(OFF)] // alle nicht ausgeschalteten Lichter ausschalten

    val dtDawn = (LokaleSonnendaten_NauticDawn_Start.state as DateTimeType).getZonedDateTime                              // Sonnenaufgang (nautisch)
    val dtDusk = (LokaleSonnendaten_NauticDusk_Start.state as DateTimeType).getZonedDateTime                              // Sonnenuntergang (nautisch)
    var nextStart = now                                                                            // jetzt
    if(nextStart.getHour < 5) nextStart = nextStart.with(LocalTime.MIDNIGHT).plusHours(5)          // falls vor 5 Uhr, setze 5 Uhr
    if(nextStart.isAfter(dtDawn) && nextStart.isBefore(dtDusk)) nextStart = dtDusk                 // falls nach dtDawn und vor dtDusk, setze dtDusk
    if(nextStart.get(java.time.temporal.ChronoField.MINUTE_OF_DAY) > 1424)                                            // falls nach 23:45
        return;                                                                                    // heute kein Timer mehr
    iRandom = random.nextInt(240)                                                                  // generiere Zufallswert
    tRandomLights = createTimer(nextStart.plusSeconds(iRandom),[|                                  // Timer für nächsten Timerstart
        var randomItem = Urlaubslichter.members.get(random.nextInt(Urlaubslichter.members.size))                         // suche ein Item aus
        randomItem.sendCommand(if(randomItem.getStateAs(OnOffType) != OFF) OFF else ON)            // und schalte es um
        iRandom = random.nextInt(240)                                                              // generiere Zufallswert
        tRandomLights.reschedule(now.plusMinutes(5).plusSeconds(iRandom))                          // Plane Timer erneut nach mindestens 5 Minuten
    ])
end

Re: Präsenzsimulation im Urlaub

Verfasst: 8. Jun 2024 21:29
von fred07
habe es auf CivilDusk angepasst und auch die Laufzeit etwas verkürzt, läuft.

Code: Alles auswählen

// Globale Variablen vor der ersten Rule definieren!
var Timer tRandomLights = null                                                                     // Handle für Urlaubslicht
val java.util.Random random = new java.util.Random()                                               // Zufall
var Integer iRandom = null

// ab hier kommen die Rules

rule "Präsenz Simulation"
when
    Item Urlaub changed or                                                                         // Schalter umgelegt
    Time is midnight or                                                                            // oder neuer Tag
    Time cron "0 5 23 * * ?" or                                                                   // täglich um 23:05 Uhr
    Channel 'astro:sun:local:civilDawn#event' triggered END                                       // ziviler Sonnenaufgang
then
    tRandomLights?.cancel                                                                          // bestehenden Timer abbrechen
    if(Urlaub.state != ON)                                                                         // Falls kein Urlaub
        return;                                                                                    // Ende
    Urlaubslichter.members.filter[i | i.getStateAs(OnOffType) != OFF].forEach[Light | Light.sendCommand(OFF)] // alle nicht ausgeschalteten Lichter ausschalten

    val dtDawn = (LokaleSonnendaten_CivilDawn_Start.state as DateTimeType).getZonedDateTime                              // Sonnenaufgang (zivil)
    val dtDusk = (LokaleSonnendaten_CivilDusk_Start.state as DateTimeType).getZonedDateTime                              // Sonnenuntergang (zivil)
    var nextStart = now                                                                            // jetzt
    if(nextStart.getHour < 5) nextStart = nextStart.with(LocalTime.MIDNIGHT).plusHours(5)          // falls vor 5 Uhr, setze 5 Uhr
    if(nextStart.isAfter(dtDawn) && nextStart.isBefore(dtDusk)) nextStart = dtDusk                 // falls nach dtDawn und vor dtDusk, setze dtDusk
    if(nextStart.get(java.time.temporal.ChronoField.MINUTE_OF_DAY) > 1384)                                            // falls nach 23:05
        return;                                                                                    // heute kein Timer mehr
    iRandom = random.nextInt(240)                                                                  // generiere Zufallswert
    tRandomLights = createTimer(nextStart.plusSeconds(iRandom),[|                                  // Timer für nächsten Timerstart
        var randomItem = Urlaubslichter.members.get(random.nextInt(Urlaubslichter.members.size))                         // suche ein Item aus
        randomItem.sendCommand(if(randomItem.getStateAs(OnOffType) != OFF) OFF else ON)            // und schalte es um
        iRandom = random.nextInt(240)                                                              // generiere Zufallswert
        tRandomLights.reschedule(now.plusMinutes(5).plusSeconds(iRandom))                          // Plane Timer erneut nach mindestens 5 Minuten
    ])
end
Es kam aber dann beim zweiten Licht der folgende Fehler und es ging dann gleich aus:

Code: Alles auswählen

2024-06-08 21:18:34.008 [WARN ] [ore.internal.scheduler.SchedulerImpl] - Scheduled job '<unknown>' failed and stopped
java.lang.reflect.UndeclaredThrowableException: null
	at jdk.proxy3346.$Proxy16209.apply(Unknown Source) ~[?:?]
	at org.openhab.core.internal.scheduler.SchedulerImpl.lambda$12(SchedulerImpl.java:189) ~[?:?]
	at org.openhab.core.internal.scheduler.SchedulerImpl.lambda$1(SchedulerImpl.java:88) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) [?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) [?:?]
	at java.lang.Thread.run(Thread.java:840) [?:?]
Caused by: org.openhab.core.model.script.engine.ScriptExecutionException: The name '<unkown>' cannot be resolved to an item or type; line 0, column 0
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:141) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:1008) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:971) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:247) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:227) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:874) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:243) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:227) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:1222) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1152) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:1098) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:878) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:243) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:227) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:933) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:287) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:227) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:475) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:251) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:227) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:213) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:47) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:30) ~[?:?]
	... 9 more
Was mir noch nicht klar ist, wie lange läuft es morgens?

Unter OH2 hatte ich es so, dass um 8.00 morgens die Rule aufhört zu arbeiten, bis sie bei Dusk wieder anfängt. Mangels Kenntnis kann ich das aus dem Code nicht ableiten.

Re: Präsenzsimulation im Urlaub

Verfasst: 9. Jun 2024 22:06
von udo1toni
Es läuft morgens bis civilDawn erreicht wurde (also bis zum bürgerlichen Sonnenaufgang). Wenn Du die Uhrzeit auf 8 Uhr begrenzen willst, wäre vermutlich zusätzlich diese Zeile zielführend:

Code: Alles auswählen

    val dtEight = now.with(LocalTime.MIDNIGHT).plusDays(1).minusHours(16) // <--- zusätzliche lokale Konstante...
    if(nextStart.getHour < 5) nextStart = nextStart.with(LocalTime.MIDNIGHT).plusHours(5)          // falls vor 5 Uhr, setze 5 Uhr
    if(nextStart.isAfter(dtDawn) && nextStart.isBefore(dtDusk)) nextStart = dtDusk                 // falls nach dtDawn und vor dtDusk, setze dtDusk
    if(nextStart.isAfter(dtEight) && nextStart.isBefore(dtDusk)) nextStart = dtDusk                 // falls nach 8 Uhr und vor dtDusk, setze dtDusk
Die beiden mittleren Zeilen stehen schon im Code, die beiden äußeren Zeilen müssen dazu, damit um 8 Uhr bis Sonnenuntergang "Schicht" ist.
Die Idee der ersten Zeile (sieht ja auf den ersten Blick unnötig kompliziert aus...): Mitternacht könnte vor der Zeitumstellung sein, Mitternacht nach dem aktuellen Tag ist aber nach einer Zeitumstellung, minus 16 Stunden ist dann 8 Uhr (egal, ob nun Zeitumstellung Sommer->Winter, Winter->Sommer oder auch keine Umstellung)

Die Fehlermeldung ist unschön...
Idee: Evtl. muss diese Zeile angepasst werden:

Code: Alles auswählen

        var randomItem = Urlaubslichter.members.get(random.nextInt(Urlaubslichter.members.size))                         // suche ein Item aus
und zwar so:

Code: Alles auswählen

        var randomItem = Urlaubslichter.members.get(random.nextInt(Urlaubslichter.members.size -0.5))                         // suche ein Item aus
members.size liefert die Anzahl der Items, der Index ist aber 0-basiert, geht also von 0 bis n-1 (wobei n die Anzahl der Member ist). Ich bin mir allerdings nicht sicher, ob damit die Untergrenze von 0 potenziell unterschritten wird...
Um absolut sicherzustellen, dass der Index immer korrekt ist, wäre die Zeile so zu ersetzen:

Code: Alles auswählen

        var randomIndex = random.nextInt(Urlaubslichter.members.size - 0.5)                        // bestimme nächstes zufälliges Licht
        if(randomIndex < 0)                                                                        // falls unter 0
            randomIndex = 0                                                                        // setze 0
        else if(randomIndex > Urlaubslichter.members.size - 1)                                     // falls über Obergrenze
            randomIndex = Urlaubslichter.members.size - 1                                          // setze Obergrenze
        var randomItem = Urlaubslichter.members.get(randomIndex)                                   // Wähle Item
Siehe Kommentar...

Ob dies allerdings die "richtige Stelle" im Code ist, kann ich nicht mit letzter Sicherheit sagen, sie ist lediglich ein heißer Kandidat.

Re: Präsenzsimulation im Urlaub

Verfasst: 10. Jun 2024 21:17
von fred07
Danke für Deine Mühe!

Leider ist irgendwo noch ein Fehler.

Die Rule sieht jetzt so aus:

Code: Alles auswählen

// Globale Variablen vor der ersten Rule definieren!
var Timer tRandomLights = null                                                                     // Handle für Urlaubslicht
val java.util.Random random = new java.util.Random()                                               // Zufall
var Integer iRandom = null

// ab hier kommen die Rules

rule "Präsenz Simulation"
when
    Item Urlaub changed or                                                                         // Schalter umgelegt
    Time is midnight or                                                                            // oder neuer Tag
    Time cron "0 5 23 * * ?" or                                                                   // täglich um 23:05 Uhr
    Channel 'astro:sun:local:civilDawn#event' triggered END                                       // ziviler Sonnenaufgang
then
    tRandomLights?.cancel                                                                          // bestehenden Timer abbrechen
    if(Urlaub.state != ON)                                                                         // Falls kein Urlaub
        return;                                                                                    // Ende
    Urlaubslichter.members.filter[i | i.getStateAs(OnOffType) != OFF].forEach[Light | Light.sendCommand(OFF)] // alle nicht ausgeschalteten Lichter ausschalten

    val dtDawn = (LokaleSonnendaten_CivilDawn_Start.state as DateTimeType).getZonedDateTime                              // Sonnenaufgang (zivil)
    val dtDusk = (LokaleSonnendaten_CivilDusk_Start.state as DateTimeType).getZonedDateTime                              // Sonnenuntergang (zivil)
    var nextStart = now                                                                            // jetzt
    val dtEight = now.with(LocalTime.MIDNIGHT).plusDays(1).minusHours(16)                          // <--- zusätzliche lokale Konstante...
    if(nextStart.getHour < 5) nextStart = nextStart.with(LocalTime.MIDNIGHT).plusHours(5)          // falls vor 5 Uhr, setze 5 Uhr
    if(nextStart.isAfter(dtDawn) && nextStart.isBefore(dtDusk)) nextStart = dtDusk                 // falls nach dtDawn und vor dtDusk, setze dtDusk
    if(nextStart.isAfter(dtEight) && nextStart.isBefore(dtDusk)) nextStart = dtDusk                 // falls nach 8 Uhr und vor dtDusk, setze dtDusk
    if(nextStart.get(java.time.temporal.ChronoField.MINUTE_OF_DAY) > 1384)                                            // falls nach 23:05
        return;                                                                                    // heute kein Timer mehr
    iRandom = random.nextInt(240)                                                                  // generiere Zufallswert
    tRandomLights = createTimer(nextStart.plusSeconds(iRandom),[|                                  // Timer für nächsten Timerstart
         var randomIndex = random.nextInt(Urlaubslichter.members.size - 0.5)                        // bestimme nächstes zufälliges Licht
        if(randomIndex < 0)                                                                        // falls unter 0
            randomIndex = 0                                                                        // setze 0
        else if(randomIndex > Urlaubslichter.members.size - 1)                                     // falls über Obergrenze
            randomIndex = Urlaubslichter.members.size - 1                                          // setze Obergrenze
        var randomItem = Urlaubslichter.members.get(randomIndex)                                   // Wähle Item
        randomItem.sendCommand(if(randomItem.getStateAs(OnOffType) != OFF) OFF else ON)            // und schalte es um
        iRandom = random.nextInt(240)                                                              // generiere Zufallswert
        tRandomLights.reschedule(now.plusMinutes(5).plusSeconds(iRandom))                          // Plane Timer erneut nach mindestens 5 Minuten
    ])
end
Wenn ich "Urlaub" einschalte, gibt es keine Fehlermeldung.

Wenn aber CivilDusk beginnt, bricht die Rule sofort ab:

Code: Alles auswählen

2024-06-10 20:58:32.002 [WARN ] [ore.internal.scheduler.SchedulerImpl] - Scheduled job '<unknown>' failed and stopped
java.lang.IllegalStateException: Could not invoke method: java.util.Random.nextInt(int) on instance: java.util.Random@4c02cc14
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1209) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1167) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1153) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:1098) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:878) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:243) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:227) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:933) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:287) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:227) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:475) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:251) ~[?:?]
	at org.openhab.core.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:227) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:213) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:47) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:30) ~[?:?]
	at jdk.proxy3346.$Proxy16209.apply(Unknown Source) ~[?:?]
	at org.openhab.core.internal.scheduler.SchedulerImpl.lambda$12(SchedulerImpl.java:189) ~[?:?]
	at org.openhab.core.internal.scheduler.SchedulerImpl.lambda$1(SchedulerImpl.java:88) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) [?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) [?:?]
	at java.lang.Thread.run(Thread.java:840) [?:?]
Caused by: java.lang.IllegalArgumentException: argument type mismatch
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1192) ~[?:?]
	... 28 more
Habe ich etwas in der falschen Zeile eingefügt?

Re: Präsenzsimulation im Urlaub

Verfasst: 11. Jun 2024 21:32
von udo1toni
Type mismatch ist immer ein blöder Fehler...
Ich nehme aber an, dass man .random.nextInt() nicht mit einem Float Wert aufrufen darf. Dann also statt

Code: Alles auswählen

var randomIndex = random.nextInt(Urlaubslichter.members.size - 0.5)
besser so:

Code: Alles auswählen

var randomIndex = (random.nextInt(Urlaubslichter.members.size) - 0.5).intValue
Ansonsten müssten wir anfangen, die verschiedenen Werte ins Log zu schreiben, um zu sehen, was da passiert.

Re: Präsenzsimulation im Urlaub

Verfasst: 13. Jun 2024 10:31
von fred07
Das wars, läuft jetzt ohne Fehlermeldung und tut was es soll.

Vielen Dank für deine Mühe, udo1toni!

Re: Präsenzsimulation im Urlaub

Verfasst: 13. Jun 2024 16:48
von udo1toni
Prima :) und immer gerne!