I am building a rule which needs to calculate the time between now (which will always be before 16:00) and 16:00.
rule "Grid-charge if required"
when
// s m h D M DoW Y
Time cron "0 1/5 13-15 * * ? *"
// here: every 30 minutes during the hours of 13-15; use http://www.cronmaker.com/
then
if (spm_Battery_SoC.state < 100)
{
logInfo(logPrefix + "02.01", "SoC < 100..........: {}", spm_Battery_SoC.state)
// what charge is missing: batt capacity - (batt capacity * current SoC / 100)
val Number missing_charge = 20000 - (20000 * ((spm_Battery_SoC.state as DecimalType).intValue / 100))
logInfo(logPrefix + "02.02", "missing_charge.....: {}", missing_charge)
// Can we reach a SoC of 100 if we continue charging at this rate?
// calculate time between now and max charge time = 16:00
//
val deltaMillis = now.millis - (spm_LastUpdate.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli
logInfo(logPrefix + "02.03", "time diff..........: {}", deltaMillis)
}
end
The calculation is working with spm_LastUpdate, but, converting a time string to epoch requires a format like so: “yyyy-MM-dd’T’HH:mm:ss.SSSZ”… which would be static and not 1600 as per the actual day.
However, things still don’t work as intended… using this will result in a conversation error:
//val arvo = now.with(LocalTime.MIDNIGHT).plusHours(16)
val max_charge_time = (now.withTimeAtStartOfDay.plusHours(16) as DateTimeType).zonedDateTime.toInstant.toEpochMilli
logInfo(logPrefix + "02.04", "max_charge_time....: {}", max_charge_time)
val time_to_charge = (max_charge_time - now.millis) / 1000
logInfo(logPrefix + "02.05", "arvo...............: {}", time_to_charge)
2022-10-03 14:13:33.797 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'sppro_modbus.rules', using it anyway:
Cannot cast from DateTime to DateTimeType
2022-10-03 14:13:33.804 [INFO ] [el.core.internal.ModelRepositoryImpl] - Loading model 'sppro_modbus.rules'
2022-10-03 14:14:35.592 [INFO ] [.smarthome.model.script.Modbus.00.00] - System start or rule file reload for Modbus.
2022-10-03 14:16:00.027 [INFO ] [.smarthome.model.script.Modbus.02.01] - SoC < 100..........: 100.0
2022-10-03 14:16:00.044 [INFO ] [.smarthome.model.script.Modbus.02.02] - missing_charge.....: 0
2022-10-03 14:16:00.057 [INFO ] [.smarthome.model.script.Modbus.02.03] - time diff..........: 523598
2022-10-03 14:16:00.068 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'Grid-charge if required': Could not cast 2022-10-03T16:00:00.000+10:00 to org.eclipse.smarthome.core.library.types.DateTimeType; line 96, column 27, length 54
Well… lots of trial and error… and got it…
// 16:00 today as epoch
val max_charge_time = now.withTimeAtStartOfDay.plusHours(16).millis
logInfo(logPrefix + "02.03", "max_chrg_t (epoch).: {}", max_charge_time)
// subtract now from 16:00 = millis; stored as minutes
val time_left_to_charge = (max_charge_time - now.millis) / 1000 / 60
logInfo(logPrefix + "02.04", "time_left_to_charge: {} minutes", time_left_to_charge)
I would use the org.joda.time.Duration class and avoid messing with epoch and all that stuff. Also, the withTimeAtStartOfDay.plusHours() approach will fail when DST changes. One day a year only has 23 hours, the other has 25 hours so + 16 will be an hour off on those days.
val max_charge_time = now.withTime(16, 0, 0, 0)
val time_left_to_charge = new org.joda.time.Duration(now, max_charge_time).getStandardMinutes()
Note that in OH 3 Joda is dropped for the standard Java time library. I think the calls are the same though so the only difference would be replacing org.joda.time with java.time.