Wie gesagt, die Umwandlung ist umständlich - zumindest aus openHAB Sicht. - Nun ja, auch in VB.NET nutzt man DateTime als Datentyp, heißt dort eventuell anders, und auch dort wird man bevorzugt Objekte verwenden, statt Primitives.
Vermutlich liefert schon die erste Zuweisung nicht die korrekten Daten, denn someString.split().get() liefert halt einen Teilstring und keine Zahl. Die Variable ist aber ein Primitive. Eventuell ist openHAB gnädig und castet nach int, verlassen würde ich mich nicht darauf.
Es kann also sehr gut sein, dass schon die Variable
jahr keine Zahl enthält, sondern
null.
Alle anderen nachfolgenden Variablen funktionieren dann ebensowenig.
Und das besagt die Fehlermeldung ja auch:
kdb hat geschrieben: ↑Gestern 14:52
Could not invoke method [...] operator_minus(int,int) on instance: null
"Konnte die Methode
Minus(int,int) nicht auf die Instanz
null anwenden".
Und die Aussage:
kdb hat geschrieben: ↑Gestern 14:52
ist vielleicht unkonventionell, aber für mich am einfachsten.
kann so ja nicht stimmen, schließlich suchst Du hier nach einer Lösung, das kann definitiv nicht der einfachste Weg sein.
Wenn es um Zeitpunkte geht, verwende bitte einfach die korrekten Methoden, dann wird das auch sehr einfach funktionieren.
Der große Aufwand besteht in dem Fall dann nur darin, zu lernen, wie das richtig geht, dafür funktioniert die Rule dann aber auch.
Logging ist übrigens in VB.NET ebenfalls die empfohlene Möglichkeit, während der Entwicklung Daten zur Laufzeit sehen. Ja, man kann auch mal auf die Schnelle ein Feld im Programm einbauen, sinnvoller ist aber die Ausgabe direkt als Text in eine Debug Konsole. Da es bei openHAB Rules keine Debug Konsole gibt, ist die einfachste Variante das Logging. Das kann man z.B. super auch über die Karaf Konsole live beobachten, und man hat nicht das Risiko, dass die Übernahme des Wertes ins Item schief geht.
Also so wie ich das sehe, ist z.B. das Deine Wunschausgabe:
kdbINFOxx 2024/10/24( 2024_10_24 ) // 12:34:56 ( 12_34 ) NOW 2024 10 26 00 56
Mit Deinem Code ginge es vermutlich so (ungetestet):
Code: Alles auswählen
val datum = httpBUSHzgSet_Datum.state.toString.split(' ').get(0)
val zeit = httpBUSHzgSet_Datum.state.toString.split(' ').get(1)
var Integer jahr = Integer.parseInt(datum.toString.split('/').get(0))
var Integer monat = Integer.parseInt(datum.toString.split('/').get(1))
var Integer tag = Integer.parseInt(datum.toString.split('/').get(2))
var Integer stunde = Integer.parseInt(zeit.toString.split(':').get(0))
var Integer minute = Integer.parseInt(zeit.toString.split(':').get(1))
var Integer jahr_akt = now.getYear()
var Integer monat_akt = now.getMonth.getValue()
var Integer tag_akt = now.getDayOfMonth()
var Integer stunde_akt = now.getHour()
var Integer minute_akt = now.getMinute()
var Integer delta_stunde = (jahr_akt - jahr) * 365 * 24
var Integer delta_stunde1 = delta_stunde + (monat_akt - monat) * 30 * 24
delta_stunde = delta_stunde + ( tag_akt - tag ) * 24
delta_stunde = delta_stunde + ( stunde_akt - stunde )
// Nur eine der nachfolgenden Zeilen darf aktiv sein...
// var curr = "kdbINFO " + jahr + " / monat " + monat + " / tag " + tag + " stunde " + stunde + " : " + minute + " NOW " + jahr_akt + " " + monat_akt + " " + tag_akt
var curr = "kdbINFOxx " + datum + "( " + jahr + "_" + monat +"_" + tag +" ) " + " // " + zeit + " ( " + stunde + "_" + minute + " ) NOW " + jahr_akt + " " + monat_akt + " " + tag_akt + " " + stunde_akt + " " + minute_akt
// var curr = "kdbINFOaa " + datum + " " + jahr + " " + delta_stunde.toString
kdbINFOxx.postUpdate(curr)
Das Datum wird in Teilstrings zerlegt, die anschließend nach Integer geparsed und in passende Objekte gespeichert werden.
Anschließend funktioniert die Berechnung (also abgesehen davon, dass diese fehlerhaft ist)
Beachte bitte auch, dass
sendCommand() in diesem Kontext schlecht ist.
Du möchtest den
Status des Items ändern, um diesen Status anzuzeigen.
sendCommand() ändert
nicht den Status, sondern sendet einen Befehl. Dass Du dennoch eine Ausgabe erhältst, ist nur dem Umstand zu verdanken, dass openHAB davon ausgeht, dass der Befehl zu einem identischen Zustand führen soll. Deshalb führt openHAB (default Verhalten) automatisch nach jedem sendCommand() auch ein postUpdate() aus.
Da Du mit dem Befehl nichts anstellen wirst, ist es also zielführender, direkt das
postUpdate() zu verwenden.
Hier eine Rule, wie ich sowas mache.
Da ich nicht weiß, wie der Status von
httpBUSHzgSet_Datum exakt aussieht, verwende ich Deine Ausgangslösung zumindest zum Teil.
Ich erstelle hier auch eine ähnliche Ausgabe wie in Deinem Code, leicht abgewandelt:
Code: Alles auswählen
rule "Test"
when
Item httpBUSHzgSet_Datum received update
then
val ZoneId zoneId = ZoneId.of(ZoneId.systemDefault) // Die Zeitzone
val dtfmFormatter = java.time.format.DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm')
val lsInput = httpBUSHzgSet_Datum.state.toString.split(' ')
val strLDT = lsInput.get(0).replace('/','-') + 'T' + lsInput.get(1) // Falls Zeit mit Sekunden ausgegeben wird
// val strDT = lsInput.get(0).replace('/','-') + 'T' + lsInput.get(1) // Alternativ, falls Zeit ohne Sekunden ausgegeben wird
val dtLTs = LocalDateTime.parse(strLDT) // Zeitstempel in LocalDateTime überführen
val dtTs = dtLTs.atZone(zoneId) // Zeitstempel in ZonedDateTime überführen
val Number iDelta_s = now.toEpochSecond - dtTs.toEpochSecond // Differenz in Sekunden
val Integer iDelta_h = (iDelta_s/3600).intValue // Different in ganzen Stunden (abgerundet)
var strCurr = "kdbINFO: " + dtTs.format(dtfmFormatter) +
" NOW: " + now.format(dtfmFormatter) +
" Delta: " + iDelta_h.toString + " Stunden"
kdbINFO.postUpdate(strCurr) // Ausgabe ins String Item
logInfo("test","Ergebnis: {}", strCurr) // Ausgabe ins Log
end
Im Unterschied zu Deinem Code berücksichtigt die Berechnung hier auch, dass manche Monate 31 Tage oder auch nur 28 Tage haben.
Eine weitere Fehlerquelle ist die Zeitumstellung, Das gilt allerdings genauso für Deinen Code, bei meinem Code ist es aber so offensichtlich, dass ich direkt daran denken musste. Deshalb wandle ich jetzt den Zeitstempel zunächst in LocalDateiTime um (da fehlt die Zeitzone) und "verschiebe" die Zeit anschließend in die korrekte Zeitzone (die vom System vorgegeben ist)
So sieht das im Log aus:
Code: Alles auswählen
02:32:27.926 [INFO ] [org.openhab.core.model.script.test ] - Ergebnis: kdbINFO: 2024-10-24 01:00 NOW: 2024-10-26 02:32 Delta: 49 Stunden
02:32:27.928 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'kdbINFO' changed from kdbINFO: 2024-10-24 01:00 NOW: 2024-10-26 02:11 Delta: 49 Stunden to kdbINFO: 2024-10-24 01:00 NOW: 2024-10-26 02:32 Delta: 49 Stunden
Die erste Zeile stammt vom
logInfo() Befehl, die zweite Zeile stammt vom changed Ereignis, welches durch eine Änderung des Items
kdbINFO ausgelöst wurde.
EDIT: Anpassung wegen der Zeitzone und Berücksichtigung von Sommer/Winterzeit
openHAB4.2.2 stable in einem Debian-Container (bookworm) (Proxmox 8.2.7, LXC), mit openHABian eingerichtet