- Platform information:
- Hardware: Raspberry Pi 3 Model B Plus Rev 1.3
- OS: Linux openhabian 5.15.84-v7+ #1613 SMP Thu Jan 5 11:59:48 GMT 2023 armv7l
- Java Runtime Environment:
- openjdk version “11.0.16” 2022-07-19
- OpenJDK Runtime Environment (build 11.0.16+8-post-Raspbian-1deb11u1)
- OpenJDK Server VM (build 11.0.16+8-post-Raspbian-1deb11u1, mixed mode)
- openHAB version: openHAB 3.4.1 - Release Build
- Issue of the topic: I try to create a timer for each opened window sensor and delete it when it gets closed and it is not already expired. To reduce the lines of code I tried to manage the timers and configurations in hashmaps.
sensor.rules
import org.openhab.model.script.actions.*
import org.openhab.core.model.script.ScriptServiceUtil
import java.util.HashMap
// storage for timers
val HashMap<String, Timer> sensorTimers = newHashMap()
// echo devices to create generic items
val HashMap<String,String> Echo_Name = newHashMap(
"WZ" -> "Living_Room",
"BZ" -> "Bath_Room",
"KU" -> "Kitchen",
"FL" -> "Floor",
"AZ" -> "Office"
)
val HashMap<String,String> Fenster_Name = newHashMap(
"WZ" -> "Wohnzimmer",
"BZ" -> "Badezimmer",
"KU" -> "Kueche",
"KZ" -> "Kinderzimmer",
"SZ" -> "Schlafzimmer",
"AZ" -> "Arbeitszimmer"
)
// durations in minutes
val HashMap<String,Number> Fenster_Dauer = newHashMap(
"WZ" -> 10,
"BZ" -> 5,
"KU" -> 10,
"KZ" -> 5,
"SZ" -> 10,
"AZ" -> 5
)
val handleTimer = [ String State, String TimerName, String EchoName, long TimerDuration |
logInfo("Timer", "Triggered! " + State)
logInfo("Timer", "Triggered! " + sensorTimers.get(TimerName))
if(State == "ON") {
if(sensorTimers.get(TimerName) === null) {
logInfo("Timer", TimerName + " Timer created.")
sensorTimers.put(TimerName, createTimer(now.plusSeconds(TimerDuration), [|
speak_with_volume.apply("Living_Room", 20, TimerName + " Fenster geöffnet.")
sensorTimers.put(TimerName, null)
logInfo("Timer", TimerName + " Timer expired.")
]))
}
}
if(State == "OFF") {
if(sensorTimers.get(TimerName) !== null) {
sensorTimers.put(TimerName, null)
logInfo("Timer", TimerName + " Timer abgebrochen.")
}
}
]
// will create a rule for every sensor
rule "Dev_Manual_Sensor WZ"
when
Item Dev_Manual_Sensor changed
then
var Room = "WZ"
var EchoName = "WZ"
logInfo("Dev_Manual_Sensor", "new state --> " + newState.toString)
handleTimer.apply(newState.toString, Fenster_Name.get(Room), Echo_Name.get(EchoName), Long::parseLong(Fenster_Dauer.get(Room).toString))
end
When I manually change the item to trigger the rule I get the following error message:
[internal.handler.ScriptActionHandler] - Script execution of rule with UID 'sensor-1' failed: cannot invoke method public java.lang.Object java.util.HashMap.get(java.lang.Object) on
null in sensor
I think it’s because I try to access the hashmap inside the lambda, but is there an approach to use them as I tried?
I usually try to use item groups and use them as triggers, but with my sensors I only receive updates and no commands. This is why I don’t get the “triggeredItem” and I can not create a specifically named timer on my echo device.
This was my first approach, but here I won't know what item triggered the rule.
import org.openhab.model.script.actions.*
import org.openhab.core.model.script.ScriptServiceUtil
import java.util.HashMap
val HashMap<String, Timer> sensorTimers = newHashMap()
val speak_with_volume = [ String Echo_Location, Number Echo_Vol, String Message |
val Echo_TTS = ScriptServiceUtil.getItemRegistry.getItem("Echo_" + Echo_Location + "_TTS") as GenericItem
val Echo_TTS_Vol = ScriptServiceUtil.getItemRegistry.getItem("Echo_" + Echo_Location + "_TTS_Vol") as GenericItem
var previousVol = if (Echo_TTS_Vol.state === null) 30 else Echo_TTS_Vol.state as Number
Echo_TTS_Vol.sendCommand(Echo_Vol)
Echo_TTS.sendCommand("<speak>" + Message.toString + "</speak>")
Echo_TTS_Vol.sendCommand(previousVol)
]
rule "Sensor group rule"
when
Member of Fenster_Sensoren received update
then
Fenster_Sensoren.members.filter[ sensor | sensor.state !== sensor.previousState() && sensor.state !== null ].forEach[ sensor |
// Only create a Timer if there isn't one already
if(sensorTimers.get(sensor.name) === null) {
logInfo("timer", "timer created for " + sensor.name)
sensorTimers.put(sensor.name, createTimer(now.plusSeconds(10), [|
speak_with_volume.apply("Living_Room", 20, "Fenster geöffnet.")
sensorTimers.put(sensor.name, null) // remove the timer from the Hashmap
logInfo("timer", "removed timer for " + sensor.name)
]))
}
]
end