OH3: update a datetime item with a ZonedDateTime

  • openhabian 3.3.0 on rPi4

I have a decimal time of say 6.75
Then turn this into hours and minutes.
Then update a DateTime item, which fails

        val time_to_charge = TeslaM3_time_to_full_charge.state as DecimalType
        logInfo(logPrefix + "02.01", "time_to_charge {}", time_to_charge)

        val hours = (Math::floor(time_to_charge.floatValue)).intValue
        logInfo(logPrefix + "02.02", "hours {}", hours)

        val minutes = Math::round((time_to_charge.floatValue - hours) * 60)
        logInfo(logPrefix + "02.03", "minutes {}", minutes)

        val charged_at_time = ZonedDateTime.now().plusHours(hours).plusMinutes(minutes)
        logInfo(logPrefix + "02.04", "charged_at_time {}", charged_at_time)

        TeslaM3_time_charged.postUpdate(charged_at_time)
        logInfo(logPrefix + "02.05", "TeslaM3_time_charged {}", TeslaM3_time_charged.state)

This line fails:

        TeslaM3_time_charged.postUpdate(charged_at_time)

Here the log:

2022-11-10 22:01:00.484 [INFO ] [ab.core.model.script.testRules.02.01] - time_to_charge 6.75
2022-11-10 22:01:00.487 [INFO ] [ab.core.model.script.testRules.02.02] - hours 6
2022-11-10 22:01:00.490 [INFO ] [ab.core.model.script.testRules.02.03] - minutes 45
2022-11-10 22:01:00.493 [INFO ] [ab.core.model.script.testRules.02.04] - charged_at_time 2022-11-11T04:46:00.491425+10:00[Australia/Brisbane]
2022-11-10 22:01:00.496 [INFO ] [ab.core.model.script.testRules.02.05] - TeslaM3_time_charged 2022-11-11T04:45:30.491524+1000

Any hints appreciated.

I had a look at this:

But it does not sink in what type I have in charged_at_time.
I thought it was DateTime?!

Well, further reading and trial and error, this works:

TeslaM3_time_charged.postUpdate(DateTimeType.valueOf(charged_at_time.toLocalDateTime().toString()))
2022-11-10 22:15:30.879 [INFO ] [ab.core.model.script.testRules.02.02] - hours 6
2022-11-10 22:15:30.882 [INFO ] [ab.core.model.script.testRules.02.03] - minutes 30
2022-11-10 22:15:30.885 [INFO ] [ab.core.model.script.testRules.02.04] - charged_at_time 2022-11-11T04:45:30.884094+10:00[Australia/Brisbane]
2022-11-10 22:15:30.889 [INFO ] [ab.core.model.script.testRules.02.05] - TeslaM3_time_charged 2022-11-11T04:45:00.880009+1000

Wouldn’t that be a duration, a period of time, not a datetime, a specific instant in the life of the world?

EDIT okay ignore that, you are trying to predict an instant I think.

I would have expected that to work on Rules DSL. What’s not clear here is how that line fails. There is no error in the log.

Right now you have a java.time.ZonedDateTime in changed_at_time. You started with a ZonedDateTime and manipulated it’s state but did change it’s type.

That’s a little overworked. This should work.

TeslaM3_time_charged.postUpdate(new DateTimeType(charged_at_time))

This should work too:

TeslaM3_time_charged.postUpdate(charged_at_time.toLocalDateTime().toString()))

But over all I would expect both of these to work too.

TeslaM3_time_charged.postUpdate(charged_at_time)
TeslaM3_time_charged.postUpdate(charged_at_time.toString())

Running with this, here is how it would be done with a Duration.

val myDur = Duration.ofHours(hours).plusMinutes(minutes)
val charged_at_time = now.plus(myDur)

There could be times where working with a duration might be easier, I’m not sure this is one of them.

But overall, I think it would make sense to just calculate the minutes and forget the hours. I think the following would work:

val time_to_charge = TeslaM3_time_to_full_charge.state as Number // It's better to cast to Number than DecimalType
val minutes = Math:round(time_to_charge * 60)
TeslaM3_time_charged.postUpdate(now.plusMinutes(minutes).toString())

Using a Duration gives you some convenience functions that might prove useful.

val time_to_charge = TeslaM3_time_to_full_charge.state as Number
val dur = Duration.ofMinutes(time_to_charge * 60)
// dur.toString() will print the duration in ISO8601 format, e.g. 6 hours 45 minutes would be PT6h45m
// dur.toHours() gives you just the hours
// dur.toMinutesPart() gives you the minutes after subtracting the hours
TeslaM3_time_charged.postUpdate(now.plus(dur).toString())
1 Like

What I had…

In OH2 I had:

        spm_LastUpdate.postUpdate(new DateTimeType())

So I thought I stick the time into the brackets and should be OK; but it threw an error I can no longer trace, as I tried a few iterations.

Anyway, I put your suggested:

        TeslaM3_time_charged.postUpdate(new DateTimeType(charged_at_time))

… into the rule, and indeed it works.

Again, thank you for your detailed explanation… always appreciate your’s too rossko57 :slight_smile:


The Tesla API returns “time_charged_to_set_level” as decimal number. I am too lazy calculating the end time in my head, as it will change based on solar PV power levels.

Right, but you can convert that number to just minutes and save a step calculating the hours. That’s the point of my reductions. now.plusHours(5).plusMinutes(10) is the same as now.plusMinutes(310).

1 Like