The sleeps and sendTelegram also stand out to me. It would only require two calls to sendTelegram to hang before you run out of cron threads and all your cron triggered Rules stop running.
As Scott suggests, add some logging to make sure that your Rule is running to completion each and every time it gets triggered.
See Design Pattern: Looping Timers for how to deal with the Thread::sleeps using Timers and see Design Pattern: How to Structure a Rule for how to reduce this Rule down to just a dozen or so lines of code. Shorter Rules are easier to read, usually easier to understand, and easier to maintain.
Other general advice, avoid converting Numbers to primitive ints and always call ItemName.sendCommand(cmd) instead of using the sendCommand Action if you know the Item to call up front.
I don’t speak German so it is hard to really figure out what is going on here so I may have something off. I’m just typing this in, there are likely bugs.
import org.eclipse.smarthome.model.script.ScriptServiceUtil // to access Items by name
// Define constants to make Rules more self explanatory
val KOMFORT = 1
val STANDBY = 2
val NACHT = 3
val FRONT = 4
var Timer heizungTimer = null
rule "Steuerung - prüfen"
when
Time cron "25 0 * ? * * *"
then
// 1. Always execute the Rule logic
// 2. Calculate what to do
val dayNum = now.getDayofWeek
val hourNum = now.getHourOfDay
var dayStr = ""
switch(dayNum) {
case 0: dayStr = "So"
case 1: dayStr = "Mo"
case 2: dayStr = "Di"
case 3: dayStr = "Mi"
case 4: dayStr = "Do"
case 5: dayStr = "Fr"
case 6: dayStr = "Sa"
}
// Get the Ein, Wiederin, and Aus Items for the current day
val ein = ScriptServiceUtil.getItemRegistry.getItem("HeitzEin"+dayStr).state as Number
val widererin = ScriptServiceUtil.getItemRegistry.getItem("HeitzWiederein"+dayStr).state as Number
val aus = ScriptServiceUtil.getItemRegistry.getItem("HeitzAus"+dayStr).state as number
var timeCondition = "Unknown"
if(hourNum == ein || hourNum == wiederein) timeCondition ="Ein or Wiederein"
else if(hourNum == aus) timeCondition = "Aus"
// Get the the values to send to
var valueOne = -1 // Heizung_KanalA_Betriebsart through Heizung_KanalD_Betriebsart
var valueTwo = -1 // Heizung_KanalE_Betriebsart through Heizung_KanalG_Betriebsart
if(timeCondition == "Ein or Wiederein"){
valueOne = KOMFORT
valueTwo = STANDBY
}
else if(timeCondition == "Aus") {
valueOne = NACHT
valueTwo = NACHT
}
// Determine the message
var msg = ""
if(valueOne == -1 || valueTwo == -1) msg = "Heizprogramm keine Übereinstimmung!"
else msg = "Heizung " + (if(timeCondition == "Ein or Wiederein") "eingeschaltet " else "augeschaltet (Nacht) ") + "über Heizprogramm!"
// 3. Do it
sendTelegram("johannes","Heizungprogramm Prüfung läuft")
logInfo("rules","Heizungprogramm Prüfung läuft")
// If we don't have valueOne or valueTwo log message and return
if(valueOne == -1 || valueTwo == -1) {
logInfo("rules", msg) // Error message?
return;
}
// Loop through A to G and send the appropriate command
var char kanal = 'A' // primitive char is a number
heizungTimer = createTimer(now, [ |
sendCommand("Heizung_Kanal"+kanal+"_Betriebsart", if(kanal < 'E') valueOne else valueTwo)
kanal = kanal + 1
// wait if we haven't reached the final letter and run the Timer again
if(kanal <= 'G') HeizungTimer.reschedule(now.plusMillis(500))
// We are done, send the telegram and log the message
else {
sendTelegram("johannes", msg)
logInfo("rules", msg)
}
])
end
The above is meant primarily for inspiration. I can’t guarantee it works or does what you want. It should do what your current Rule does however. I like to leave before and after like examples around the forum though to help encourage users to discover and find a way to avoid lots and lots of duplicate code.
We have gone from 354 lines of code down to 85 lines of code, over a 65% reduction.