[Solved] OH2 previousState.state errors

I am trying to set a timer for a PIR sensor.
This has been tried and tested many times; however, I want to catch when the PIR comes on, which causes errors on rule reload.

This rule w/o the catch “ON” works, but errors on reload.

rule "Shed_NLO_PIR debounce"
    when
        Item Shed_NLO_PIR received update ON
    then
        if (Shed_NLO_PIR_debounceTimer === null || Shed_NLO_PIR_debounceTimer.hasTerminated())
        {
            Shed_NLO_PIR_debounceTimer = createTimer(now.plusMinutes(5), [|
                logInfo("Sonoff.2.03", "Shed_NLO_PIR.............: OFF")
                Shed_NLO_PIR_LUP.postUpdate(new DateTimeType())
                Shed_NLO_PIR.sendCommand(OFF)
                Shed_NLO_PIR_debounceTimer = null
            ])
        }
        else
        {
            Shed_NLO_PIR_debounceTimer.reschedule(now.plusMinutes(5))
        }
end

The error on rule reload when the timer is active is:

2020-11-07 11:41:45.596 [INFO ] [e.smarthome.model.script.Sonoff.2.03] - Shed_NLO_PIR.............: OFF
2020-11-07 11:41:45.599 [ERROR] [org.quartz.core.JobRunShell         ] - Job DEFAULT.Timer 82 2020-11-07T11:39:38.209+10:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {
  logInfo(<XStringLiteralImpl>,<XStringLiteralImpl>)
  <XFeatureCallImplCustom>.postUpdate(<XConstructorCallImplCustom>)
  <XFeatureCallImplCustom>.sendCommand(<XFeatureCallImplCustom>)
  <null>.Shed_NLO_PIR_debounceTimer = <XNullLiteralImplCustom>
} ] threw an unhandled Exception: 
java.lang.NullPointerException: null

Adding any one of these three statements to catch the PIR ON state…

        logInfo("Sonoff.2.01", "Shed_NLO_PIR historic....: {}", Shed_NLO_PIR.historicState(now.minusSeconds(61),"rrd4j").state)
        logInfo("Sonoff.2.01", "Shed_NLO_PIR.prev state..: {}", Shed_NLO_PIR.previousState.state)
        if (Shed_NLO_PIR.previousState.state === null || Shed_NLO_PIR.previousState.state == OFF)
        {
            logInfo("Sonoff.2.02", "Shed_NLO_PIR.............: ON")
        }

creates this error:

2020-11-07 10:55:43.103 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Shed_NLO_PIR debounce': cannot invoke method public abstract org.eclipse.smarthome.core.types.State org.eclipse.smarthome.core.persistence.HistoricItem.getState() on null

To complete the config:

var Timer Shed_NLO_PIR_debounceTimer = null

rule "Sonoff rules started"
    when
        System started
    then
		logInfo("sonoff.0.0", "System start or rule file reload for Sonoff rules")

        if (Shed_NLO_PIR.state == NULL || Shed_NLO_PIR.state == ON)
        {
            Shed_NLO_PIR.postUpdate(OFF)
        }
end

(another rule identifying the PIR postUpdates the item:)
            switch PIR_id
            {
                case "54978":
                {
                    Shed_NLO_PIR.postUpdate(ON)
                }
            }

Persistence is on as question in this post and here.

Is there a way to:
a) deal cleanly with timers?
b) test for the previousState.state on reload?

[edit 1] to my query a) I read Rossko’s post, regarding running timers on reload. Sorted! by design.

I was going to suggest “orphaned Timer” if you had been rules editing, but you’ve arrived there already. It’s more limitation than “by design”, but it’s just a nuisance.

I think you’d better spell out what you mean here.

1 Like

Thanks :slight_smile:I am working on this and now have a rule that works, and no longer requires the previous state.

The issue was: I have a PIR that does only send an 433MHz signal (Sonoff DW2) when triggered. A rule extracts an id for the sensor, which I use as an ON trigger.

My previousState.state was returning always ON, because no OFF is received or created by a timer.

I eventually used a proxy, which I think is, given the current rule, not even necessary.

The current, working rule:

rule "Shed_NLO_PIR debounce"
    when
        Item Shed_NLO_PIR_pxy received update ON
    then
        val PIR_timeout = (Shed_NLO_PIR_Timeout.state as DecimalType).intValue
        //logInfo("Sonoff.2.01", "Shed_NLO_PIR previous state...: {}", Shed_NLO_PIR.previousState.state)

        if (Shed_NLO_PIR_Timer === null || Shed_NLO_PIR_Timer.hasTerminated())
        {
            Shed_NLO_PIR.postUpdate(ON)
            logInfo("Sonoff.2.02", "Shed_NLO_PIR..................: ON for {} minutes", PIR_timeout)
            Shed_NLO_PIR_LUP.postUpdate(new DateTimeType())

            Shed_NLO_PIR_Timer = createTimer(now.plusMinutes(PIR_timeout), [|
                logInfo("Sonoff.2.03", "Shed_NLO_PIR..................: OFF")
                Shed_NLO_PIR_LUP.postUpdate(new DateTimeType())
                Shed_NLO_PIR.postUpdate(OFF)
                Shed_NLO_PIR_pxy.postUpdate(OFF)
                Shed_NLO_PIR_Timer = null
            ])
        }
        else
        {
            logInfo("Sonoff.2.04", "Shed_NLO_PIR rescheduled......: yes")
            Shed_NLO_PIR_Timer.reschedule(now.plusMinutes(PIR_timeout))
            Shed_NLO_PIR_LUP.postUpdate(new DateTimeType())
        }
end

Result:

2020-11-07 20:50:21.788 [INFO ] [e.smarthome.model.script.Sonoff.2.02] - Shed_NLO_PIR..................: ON for 1 minutes
2020-11-07 20:51:21.815 [INFO ] [e.smarthome.model.script.Sonoff.2.03] - Shed_NLO_PIR..................: OFF
2020-11-07 21:24:37.966 [INFO ] [e.smarthome.model.script.Sonoff.2.02] - Shed_NLO_PIR..................: ON for 1 minutes
2020-11-07 21:24:44.771 [INFO ] [e.smarthome.model.script.Sonoff.2.04] - Shed_NLO_PIR rescheduled......: yes
2020-11-07 21:24:52.687 [INFO ] [e.smarthome.model.script.Sonoff.2.04] - Shed_NLO_PIR rescheduled......: yes
2020-11-07 21:25:52.699 [INFO ] [e.smarthome.model.script.Sonoff.2.03] - Shed_NLO_PIR..................: OFF