OH2 rule to calculate time difference between 16:00 and now()

  • Platform information:
    • Hardware: Raspberry Pi 3 Model B Rev 1.2_
    • Host: rpi3ohv2 Kernel: 5.4.51-v7+ armv7l bits: 32 Console: tty 2
    • Distro: Raspbian GNU/Linux 10 (buster)
    • OpenJDK Runtime Environment (Zulu 8.31.1.122-linux_aarch32hf) (build 1.8.0_181-b122)
  • Version: 2.5.11 (Build) (apt-get), text-based config
    • binding = astro, exec, logreader, network, ntp, systeminfo, fritzboxtr0641, expire1, mqtt1, weather1
    • ui = paper, basic, classic, restdocs
    • persistence = rrd4j, mapdb
    • action = mail, mqtt
    • transformation = map, javascript, xslt, scale, jsonpath

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.

Any hits appreciated.

Found a way to get the 16:00 :slight_smile:

	val arvo = now.withTimeAtStartOfDay.plusHours(16)
	logInfo(logPrefix + "02.04", "arvo...............: {}", arvo)

Inspired by Set future time for DateTime item with rule (text or blockly) - #3 by Udo_Hartmann

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)

this works. :slight_smile:

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.

1 Like