I’m running openHAB 2.5.10 on docker. Host system is an Ubuntu 18.04.5 LTS.
I’ve noticed for quite some time, I guess starting with openHAB 2.5.0 that at the startup of openHAB the rules scripts doesn’t load and start correctly. There are two issues that I’ve noticed:
- Types declared in import statements or using of implicit types of the rules produce warnings/errors in the log. I’ve attached examples of these logs below.
- Init rules are not executed. I have to touch the files manually after openHAB startup to get the init rules working.
Here is an example of the warnings/errors concerning import statements:
2020-11-23 14:40:05.700 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'wind.rules', using it anyway:
The field Tmp_windRules.convertToCentiGrade refers to the missing type Angle
The field Tmp_windRules.convertToCentiGrade refers to the missing type Angle
The code producing this log is as follows:
val convertToCentiGrade = [ QuantityType<Angle> angle |
if (angle !== NULL) {
angle.multiply(100|°).divide(360|°)
} else {
0|°
}
]
rule "Init"
when
System started
then
Zentralfunktion_Windrichtung_Proxy.state = convertToCentiGrade.apply(Zentralfunktion_Windrichtung.state)
end
rule "Wind direction changes"
when
Item Zentralfunktion_Windrichtung changed
then
Zentralfunktion_Windrichtung_Proxy.state = convertToCentiGrade.apply(newState as QuantityType<Angle>)
end
It seems that upon parsing/compiling the rule file the quantity types (here Angle, type in the default scope) is not yet loaded and therefore declared as missing. This case is only a minor issue, because as the logs states, the missing type is ignored and the rule is used anyway.
I have a more complex rule that implements a scheduling service for my heating actors. It uses imports that are not in the default scope:
import java.util.ArrayList
import java.util.stream.Collectors
import java.util.HashMap
import java.util.List
import java.util.Map
import org.eclipse.xtext.util.Triple
import org.eclipse.xtext.util.Tuples
val loggerName = "Zeitschaltuhr"
val List<String> keys = newArrayList("vacation", "holiday", "weekend", "workday")
val Map<String, List<Triple<LocalTime, String, List<GenericItem>>>> schedules = new HashMap
val List<Timer> timers = new ArrayList
val scheduleTimers = [ String loggerName, List<String> keys, Map<String, List<Triple<LocalTime, String, List<GenericItem>>>> schedules, List<Timer> timers, boolean onVacation |
// Reset scheduled timers for the current day
timers.forEach[ timer |
timer.cancel()
]
timers.clear()
// Select schedule key based on date and item state
val currentDate = LocalDate.now()
val selectedSchedule = switch (currentDate) {
case onVacation : keys.get(0)
case isBankHoliday() : keys.get(1)
case isWeekend () : keys.get(2)
default : keys.get(3)
}
logInfo(loggerName, "Schedule " + selectedSchedule + " selected")
val currentTime = DateTime.now()
schedules.get(selectedSchedule).forEach[triple |
val DateTime time = triple.getFirst().toDateTimeToday()
val String value = triple.getSecond()
val List<GenericItem> items = triple.getThird()
if (time.isBefore(currentTime)) {
items.forEach[ item |
item.sendCommand(value)
]
val String itemsString = items.stream().map([ item | item.name]).collect(Collectors.joining(", "))
logInfo(loggerName, String.format("HVAC Mode set to %s on %tR for items %s", value, time.toGregorianCalendar(), itemsString))
} else {
timers.add(
createTimer(
time, [ |
items.forEach[ item |
item.sendCommand(value)
]
val String itemsString = items.stream().map([ item | item.name]).collect(Collectors.joining(", "))
logInfo(loggerName, String.format("HVAC Mode set to %s on %tR for items %s", value, time.toGregorianCalendar(), itemsString))
]
)
)
}
]
]
rule "Init"
when
System started
then
// Clear schedules
schedules.clear()
// Add vacation schedule
schedules.put(keys.get(0), newArrayList(
Tuples.create(LocalTime.parse("00:00"), "Building Protection", newArrayList(Wohnzimmer_Klima_Betriebsart, Esszimmer_Klima_Betriebsart, Schlafzimmer_Klima_Betriebsart, Mariam_Klima_Betriebsart, Hannah_Klima_Betriebsart, Lounge_Klima_Betriebsart, Badezimmer_Klima_Betriebsart))
))
// Add holiday schedule
schedules.put(keys.get(1), newArrayList(
Tuples.create(LocalTime.parse("06:30"), "Comfort", newArrayList(Badezimmer_Klima_Betriebsart, Lounge_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("08:30"), "Comfort", newArrayList(Wohnzimmer_Klima_Betriebsart, Esszimmer_Klima_Betriebsart, Mariam_Klima_Betriebsart, Hannah_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("19:30"), "Comfort", newArrayList(Schlafzimmer_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("22:30"), "Economy", newArrayList(Wohnzimmer_Klima_Betriebsart, Esszimmer_Klima_Betriebsart, Schlafzimmer_Klima_Betriebsart, Mariam_Klima_Betriebsart, Hannah_Klima_Betriebsart, Lounge_Klima_Betriebsart, Badezimmer_Klima_Betriebsart))
))
// Add weekend schedule
schedules.put(keys.get(2), newArrayList(
Tuples.create(LocalTime.parse("06:30"), "Comfort", newArrayList(Badezimmer_Klima_Betriebsart, Lounge_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("08:30"), "Comfort", newArrayList(Wohnzimmer_Klima_Betriebsart, Esszimmer_Klima_Betriebsart, Mariam_Klima_Betriebsart, Hannah_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("19:30"), "Comfort", newArrayList(Schlafzimmer_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("22:30"), "Economy", newArrayList(Wohnzimmer_Klima_Betriebsart, Esszimmer_Klima_Betriebsart, Schlafzimmer_Klima_Betriebsart, Mariam_Klima_Betriebsart, Hannah_Klima_Betriebsart, Lounge_Klima_Betriebsart, Badezimmer_Klima_Betriebsart))
))
// Add workday schedule
schedules.put(keys.get(3), newArrayList(
Tuples.create(LocalTime.parse("05:30"), "Comfort", newArrayList(Badezimmer_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("06:30"), "Comfort", newArrayList(Wohnzimmer_Klima_Betriebsart, Esszimmer_Klima_Betriebsart, Mariam_Klima_Betriebsart, Hannah_Klima_Betriebsart, Lounge_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("08:30"), "Standby", newArrayList(Hannah_Klima_Betriebsart, Lounge_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("10:30"), "Standby", newArrayList(Wohnzimmer_Klima_Betriebsart, Esszimmer_Klima_Betriebsart, Mariam_Klima_Betriebsart, Badezimmer_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("16:00"), "Comfort", newArrayList(Wohnzimmer_Klima_Betriebsart, Esszimmer_Klima_Betriebsart, Mariam_Klima_Betriebsart, Hannah_Klima_Betriebsart, Lounge_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("19:30"), "Comfort", newArrayList(Schlafzimmer_Klima_Betriebsart, Badezimmer_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("21:30"), "Economy", newArrayList(Wohnzimmer_Klima_Betriebsart, Esszimmer_Klima_Betriebsart, Mariam_Klima_Betriebsart, Hannah_Klima_Betriebsart)),
Tuples.create(LocalTime.parse("22:30"), "Economy", newArrayList(Schlafzimmer_Klima_Betriebsart, Badezimmer_Klima_Betriebsart, Lounge_Klima_Betriebsart))
))
// create timers for current day
scheduleTimers.apply(loggerName, keys, schedules, timers, Zentralfunktion_Urlaub.state == ON)
logInfo(loggerName, "Initialization done")
end
rule "Vacation state changed"
when
Item Zentralfunktion_Urlaub changed
then
// create timers for current day due to vacation state change
scheduleTimers.apply(loggerName, keys, schedules, timers, newState == ON)
logInfo(loggerName, "Vacation state change to " + newState + " processed")
end
rule "Passed midnight"
when
Time is midnight
then
// create timers for current day due to date change
scheduleTimers.apply(loggerName, keys, schedules, timers, Zentralfunktion_Urlaub.state == ON)
logInfo(loggerName, "Passed midnight processed")
end
This rule is loaded/parsed/compiled with no error/warning to be seen in the logs, but the init rule that initializes the scheduling structures is not called. In order to get this work, I have to touch the file after openHAB is fully started. Then the rule is updated and the init rule is executed.