hmm.
I edited many things. I implemented Hashtables like you said.
Unfortunately, i get “null” errors, for example here:
try {
mylock.lock()
if (timers.get(Raum_Name) !== null){
timers.get(Raum_Name).cancel()
timers.put(Raum_Name, null)
}
}
catch(Throwable t) {
logError("Error", "Keine Ahnung was passiert ist..." + t.toString)
timers.put(Raum_Name, null)
}
finally {
mylock.unlock()
}
Error:
17:58:19.613 [ERROR] [untime.internal.engine.RuleEngineImpl] - Rule ‘Motion’: null
It doesnt matter if I have locks or not, it was just a try.
Any ideas?
import java.util.Hashtable
import org.eclipse.smarthome.model.script.ScriptServiceUtil
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
////GLOBALE PARAMETER/////
val String[] Raumliste = newArrayList('Flur','Kueche','Bett')
val Log_An = true
//Textbausteine(Prefix + Raumname + Suffix)
val Light_Prefix = "gMotion_"
val Light_Suffix_Brightness = "_Licht_Helligkeit"
val Light_Suffix_Temperature = "_Licht_Farbtemperatur"
val Motion_Sensor_Prefix = "gMotion_"
val Motion_Sensor_Suffix = "_Sensor_Bewegung"
val Lux_Sensor_Prefix = "gMotion_"
val Lux_Sensor_Suffix = "_Sensor_Lux"
////GLOBALE PARAMETER/////
//intern
val Hashtable<String, Timer> timers = new Hashtable<String, Timer>()
val Hashtable<String, DateTime> last_Update_Time = new Hashtable<String, DateTime>()
val Hashtable<String, String> last_Update_Type = new Hashtable<String, String>()
val Hashtable<String, Number> last_Update_Brightness = new Hashtable<String, Number>()
val Hashtable<String, Number> last_Update_Temperature = new Hashtable<String, Number>()
var Lock mylock = new ReentrantLock()
rule "Motion"
when
Member of gMotion_Sensor_Bewegung changed //Bewegungsmelder
or Member of gMotion_Sensor_Lux received update //Helligkeit
then
///////Zeiten////////
val Zeit_Morgens = now.withTimeAtStartOfDay.plusDays(1).minusHours(24-10) //10 Uhr
val Zeit_Mittags = now.withTimeAtStartOfDay.plusDays(1).minusHours(24-13) //13 Uhr
val Zeit_Nachmittags = now.withTimeAtStartOfDay.plusDays(1).minusHours(24-16) //16 Uhr
val Zeit_Nachts = now.withTimeAtStartOfDay.plusDays(1).minusHours(24-22) //22 Uhr
var Tageszeit = "UNBEKANNT"
switch now {
case now.isAfter(Zeit_Morgens) && now.isBefore(Zeit_Mittags): Tageszeit = "MORGENS"
case now.isAfter(Zeit_Mittags) && now.isBefore(Zeit_Nachmittags): Tageszeit = "MITTAGS"
case now.isAfter(Zeit_Nachmittags) && now.isBefore(Zeit_Nachts): Tageszeit = "NACHMITTAG"
default: Tageszeit = "NACHTS"
}
///////Zeiten////////
///////RAUM bestimmen/////
var Trigger_Name = triggeringItem.name
var Raum_Name = ""
//Raum bestimmen
val i = Raumliste.iterator
while (i.hasNext){
val str = i.next
if (Trigger_Name.contains(str)){
Raum_Name = str
}
}
if (Raum_Name == "") {return;} //Raum nicht in der Raumliste
///////RAUM bestimmen/////
if (Log_An) {logWarn("MOTION", Raum_Name)}
///////PARAMETER//////////
//Standardwerte
var Par_Lux_Threshold = 5.0 //lx
var Par_SP_Brightness = 70.0 //%
var Par_SP_Temperature = 70.0 //%
var Par_Timeout_Seconds = 30 //s
var Par_Deadtime_Manual_Seconds = 20 //Totzeit für Bewegungsmelder nach man. Bedienung
//Individuelle Werte
switch (Raum_Name){
case "Flur":{
Par_Lux_Threshold = 40.0
Par_Timeout_Seconds = 10
switch(Tageszeit){
case "MORGENS",
case "NACHTS":{
Par_SP_Brightness = 30.0
Par_SP_Temperature = 80.0
}
case "NACHMITTAG":{
Par_SP_Brightness = 100.0
Par_SP_Temperature = 60.0
}
default:{
Par_SP_Brightness = 0.0
Par_SP_Temperature = 60.0
}
}
}
////Küche
case "Kueche": {
Par_Lux_Threshold = 180.0
Par_Timeout_Seconds = 60
switch(Tageszeit){
case "MORGENS",
case "NACHTS":{
Par_SP_Brightness = 50.0
Par_SP_Temperature = 80.0
}
case "NACHMITTAG":{
Par_SP_Brightness = 100.0
Par_SP_Temperature = 60.0
}
default:{
Par_SP_Brightness = 100.0
Par_SP_Temperature = 40.0
}
}
}
////Küche
case "Bett": {
Par_Lux_Threshold = 300.0
Par_Timeout_Seconds = 0
Par_Deadtime_Manual_Seconds = 0
switch(Tageszeit){
case "MORGENS",
case "NACHTS":{
Par_SP_Brightness = 20.0
Par_SP_Temperature = 100.0
}
case "NACHMITTAG":{
Par_SP_Brightness = 100.0
Par_SP_Temperature = 60.0
}
default:{
Par_SP_Brightness = 100.0
Par_SP_Temperature = 50.0
}
}
}
}
///////PARAMETER//////////
if (Log_An) {logWarn("MOTION", "Parameter bestimmt")}
///////Items bestimmen////
val GenericItem Motion_Sensor = ScriptServiceUtil.getItemRegistry?.getItem(Motion_Sensor_Prefix + Raum_Name + Motion_Sensor_Suffix) as GenericItem
val GenericItem Lux_Sensor = ScriptServiceUtil.getItemRegistry?.getItem(Lux_Sensor_Prefix + Raum_Name + Lux_Sensor_Suffix) as GenericItem
val GenericItem Light_Brightness = ScriptServiceUtil.getItemRegistry?.getItem(Light_Prefix + Raum_Name + Light_Suffix_Brightness) as GenericItem
///////Items bestimmen////
if (Log_An) {logWarn("MOTION", "Items bestimmt")}
///////MOTION AN//////////
if (Motion_Sensor.state == ON){
if (Log_An) {logWarn("MOTION", "Sensor Aktiv")}
//Timer canceln, wenn bereits aktiv,da wieder Bewegung
try {
mylock.lock()
if (timers.get(Raum_Name) !== null){
timers.get(Raum_Name).cancel()
timers.put(Raum_Name, null)
}
}
catch(Throwable t) {
logError("Error", "Keine Ahnung was passiert ist..." + t.toString)
timers.put(Raum_Name, null)
}
finally {
mylock.unlock()
}
if (Log_An) {logWarn("MOTION", "Timer gecancelt")}
///////BEDINGUNGEN ZUM ANSCHALTEN////
//nur wenn Lampen aus
if (Light_Brightness.state >= 1.0) {
if (Log_An) {logWarn("MOTION", "BEDINGUNG Licht an nicht OK")}
return;
}
if (Log_An) {logWarn("MOTION", "BEDINGUNG Licht aus OK")}
//wenn letzter Befehl von Automatik, dann nur wenn letzter Befehl älter als X Sekunden (Da der Sensor bis zu 15 Sekunden lang noch AN senden kann)
//verhindert, dass das Licht nach dem Ausschalten direkt wieder an geht
if (last_Update_Type.get(Raum_Name) === null || last_Update_Type.get(Raum_Name).contains("MANU")){
if (last_Update_Time.get(Raum_Name) !== null && now.minusSeconds(Par_Deadtime_Manual_Seconds).isBefore(last_Update_Time.get(Raum_Name))) {
if (Log_An) {logWarn("MOTION","BEDINGUNG Totzeit nach manuell aus nicht OK")}
return;
}
}
if (Log_An) {logWarn("MOTION","BEDINGUNG Totzeit nach manuell aus OK")}
//Helligkeitswert gering genug, um zu aktivieren?
var Cur_Lux = (Lux_Sensor.state as DecimalType).floatValue
if (Cur_Lux == UNDEF){ Cur_Lux = (1000.0).floatValue }
if ((Cur_Lux > Par_Lux_Threshold)) {
if (Log_An) {logWarn("MOTION","BEDINGUNG Helligkeit nicht OK")}
return; //nichts tun.
}
if (Log_An) {logWarn("MOTION","BEDINGUNG Helligkeit OK")}
//Wenn Sollhelligkeit quasi 0 ist, ist der Bewegungsmelder auch nicht aktiv.
if (Par_SP_Brightness <= 0.1){
if (Log_An) {logWarn("MOTION","BEDINGUNG Sensor Sollhelligkeit >0 nicht OK")}
return;
}
if (Log_An) {logWarn("MOTION","BEDINGUNG Sensor Sollhelligkeit >0 OK")}
///////BEDINGUNGEN ZUM ANSCHALTEN////
///////AKTION AN//////
//Rücksetzen der Befehle durch Automatik verhindern
last_Update_Time.put(Raum_Name,now)
last_Update_Type.put(Raum_Name,"AUTO")
Thread::sleep(100)
//Ausführen der jeweiligen Aktion
//Aktion an
sendCommand(Light_Prefix+Raum_Name+Light_Suffix_Brightness,Par_SP_Brightness.toString())
createTimer(now.plusMillis(300), [ | sendCommand(Light_Prefix+Raum_Name+Light_Suffix_Temperature,Par_SP_Temperature.toString())])
createTimer(now.plusMillis(600), [ | sendCommand(Light_Prefix+Raum_Name+Light_Suffix_Brightness,Par_SP_Brightness.toString())])
createTimer(now.plusMillis(900), [ | sendCommand(Light_Prefix+Raum_Name+Light_Suffix_Temperature,Par_SP_Temperature.toString())])
if (Log_An) {logWarn("MOTION","AKTION AN")}
///////AKTION AN//////
}
///////MOTION AN//////
///////MOTION AUS//////////
else {
if (Log_An) {logWarn("MOTION", "Sensor Inaktiv")}
///////BEDINGUNGEN ZUM AUSCHALTEN/////
//nur wenn letzte Aktion nicht Manuell war
if (last_Update_Type.get(Raum_Name) === null || last_Update_Type.get(Raum_Name).contains("MANU")){
if (Log_An) {logWarn("MOTION","BEDINGUNG letzte Aktion Automatik nicht OK")}
return;
}
if (Log_An) {logWarn("MOTION","BEDINGUNG letzte Aktion Automatik OK")}
//nur wenn Timer nicht vorhanden
if (timers.get(Raum_Name) !== null) {
if (Log_An) {logWarn("MOTION","BEDINGUNG Timer noch nicht vorhanden nicht OK")}
return;
}
if (Log_An) {logWarn("MOTION","BEDINGUNG Timer noch nicht vorhanden OK")}
///////BEDINGUNGEN ZUM AUSCHALTEN/////
///////AKTION AUS//////
////Aktion aus
if (Log_An) {logWarn("MOTION","AKTION AUS TIMER AKTIVIERT")}
timers.put(Raum_Name, createTimer(now.plusSeconds(Par_Timeout_Seconds), [|
last_Update_Time.put(Raum_Name,now)
last_Update_Type.put(Raum_Name,"AUTO")
sendCommand(Light_Prefix+Raum_Name+Light_Suffix_Brightness,0.toString())
if (Log_An) {logWarn("MOTION","AKTION AUS")}
]))
///////AKTION AUS//////
}
///////MOTION AUS//////////
end
rule "Motion Cancel" //bei manuellem Eingriff
when
Member of gMotion_Licht_Helligkeit changed
or Member of gMotion_Licht_Farbtemperatur changed
then
///////RAUM bestimmen/////
var Trigger_Name = triggeringItem.name
var Raum_Name = ""
//Raum bestimmen
val i = Raumliste.iterator
while (i.hasNext){
val str = i.next
if (Trigger_Name.contains(str)){
Raum_Name = str
}
}
if (Raum_Name == "") {return;} //Raum nicht in der Raumliste
///////RAUM bestimmen/////
if (Log_An) {logWarn("MOTIONCANCEL", Raum_Name)}
///////BEDINGUNG ABBRUCH///////
//Bedingung Mindeständerung für Abbruch oder Lampen aus
if (triggeringItem.state == UNDEF ||triggeringItem.state == NULL ){
return;
}
val Current_Value = (triggeringItem.state as DecimalType).floatValue
if (triggeringItem.name.contains(Light_Suffix_Brightness)){
if (last_Update_Brightness.get(Raum_Name) === null){
last_Update_Brightness.put(Raum_Name,Current_Value)
}
if (Current_Value+0.1 <= last_Update_Brightness.get(Raum_Name)
|| Current_Value-0.1 >= last_Update_Brightness.get(Raum_Name)
|| Current_Value <=0.1){
last_Update_Brightness.put(Raum_Name,Current_Value)
}
else{
if (Log_An) {logWarn("MOTIONCANCEL","BEDINGUNG Mindestaenderung Helligkeit nicht OK")}
return;
}
if (Log_An) {logWarn("MOTIONCANCEL","BEDINGUNG Mindestaenderung Helligkeit OK")}
}
else{
if (last_Update_Temperature.get(Raum_Name) === null){
last_Update_Temperature.put(Raum_Name,Current_Value)
}
if (Current_Value+0.1 <= last_Update_Temperature.get(Raum_Name)
|| Current_Value-0.1 >= last_Update_Temperature.get(Raum_Name)
|| Current_Value <=0.1){
last_Update_Temperature.put(Raum_Name,Current_Value)
}
else{
if (Log_An) {logWarn("MOTIONCANCEL","BEDINGUNG Mindestaenderung Farbtemp nicht OK")}
return;
}
if (Log_An) {logWarn("MOTIONCANCEL","BEDINGUNG Mindestaenderung Farbtemp OK")}
}
//nur wenn letzter Befehl von Automatik
if (last_Update_Type.get(Raum_Name) === null || last_Update_Type.get(Raum_Name).contains("MANU")){
if (Log_An) {logWarn("MOTIONCANCEL","BEDINGUNG Timer von Automatik nicht OK")}
return;
}
if (Log_An) {logWarn("MOTIONCANCEL","BEDINGUNG Timer von Automatik OK")}
//nur wenn letzter Befehl älter als 5 Sekunden
if (last_Update_Time.get(Raum_Name) !== null && now.minusSeconds(5).isBefore(last_Update_Time.get(Raum_Name))) {
if (Log_An) {logWarn("MOTIONCANCEL","BEDINGUNG letzter Befehl alt genug nicht OK")}
return;
}
if (Log_An) {logWarn("MOTIONCANCEL","BEDINGUNG letzter Befehl alt genug OK")}
///////BEDINGUNG ABBRUCH///////
///////AKTION ABBRUCH///////
//Timer stoppen, wenn aktiv
if (timers.get(Raum_Name) !== null){
timers.get(Raum_Name)?.cancel()
timers.put(Raum_Name, null)
}
last_Update_Time.put(Raum_Name,now)
last_Update_Type.put(Raum_Name,"MANU")
if (Log_An) {logWarn("MOTIONCANCEL","MOTION UNTERBROCHEN")}
///////AKTION ABBRUCH///////
end