Error when migrating Timer from DSL to Scripted Automation

  • Platform information:
    • Hardware: RasPi 3b 1Gb
    • OS: Raspbian GNU/Linux 10 (buster)
    • Java Version:
      openjdk version “1.8.0_222”
      OpenJDK Runtime Environment (Zulu8.40.0.178-CA-linux_aarch32hf) (build 1.8.0_222-b178)
      OpenJDK Client VM (Zulu8.40.0.178-CA-linux_aarch32hf) (build 25.222-b178, mixed mode, Evaluation)
    • openHAB version: openHAB 2.5.4-1 (Release Build) - Openhabian
  • Issue of the topic: JSR223 Timer Error

I’m on the way to migrate my DSL-Rules to SA, but now I’m struggling with the “createTimer”-Function(lambda)

I have the following items(for testing the channels are unlinked and manually switched):

Switch Sonoff_socket_03 "Steckdose RasPi 3b+ [MAP(de.map):%s]"   (gSystem)   // (EG_Buro,gPlugSwitch,gSonoff)   { channel="mqtt:topic:hans:s2003:power"}        
Switch RasPi_online     "Office Pi  [MAP(tech.map):%s]"          (gSystem)   // {channel="network:pingdevice:raspi_office:online"}

The Rule is .py:

from core.rules import rule
from core.triggers import when
from core.date import DateTime
#from core.actions import Transformation
from core.actions import ScriptExecution
T_OFFICEPI_STATUS = None

@rule("raspi_online_monitor_office", description="monitors Office Raspi and switch it off after shutdown", tags=["RasPi", "OfficePi"])
@when("Item RasPi_online changed from ON to OFF")

def office_pi_online(event):
    office_pi_online.log.info("Rule is running")
    if items["Sonoff_socket_03"] == OFF:
        office_pi_online.log.info("Steckdose ist bereits ausgeschaltet")
    else:
        global T_OFFICEPI_STATUS
        office_pi_online.log.info("RasPi Office wird in 3 Minuten ausgeschaltet ")
        if items["Sonoff_socket_03"] == ON:
            if T_OFFICEPI_STATUS is None or T_OFFICEPI_STATUS.hasTerminated():
                T_OFFICEPI_STATUS = ScriptExecution.createTimer(DateTime.now().plusMinutes(3), lambda: events.sendCommand(items["Sonoff_socket_03"], "OFF"))
                office_pi_online.log.info("Timer runs ")
        elif T_OFFICEPI_STATUS is not None and not T_OFFICEPI_STATUS.hasTerminated("TERMINATED"):
            T_OFFICEPI_STATUS.cancel()
            office_pi_online.log.info("Timer cancelled ")

but when the rule is triggered and the “else”-Condition is true, the following error is logged.

Log:

2020-04-20 14:08:56.224 [INFO ] [3.ohtest.raspi_online_monitor_office] - Rule is running
2020-04-20 14:08:56.237 [INFO ] [3.ohtest.raspi_online_monitor_office] - Steckdose ist bereits ausgeschaltet
2020-04-20 14:09:52.091 [INFO ] [3.ohtest.raspi_online_monitor_office] - Rule is running
2020-04-20 14:09:52.103 [INFO ] [3.ohtest.raspi_online_monitor_office] - RasPi Office wird in 3 Minuten ausgeschaltet 
2020-04-20 14:09:52.192 [INFO ] [3.ohtest.raspi_online_monitor_office] - Timer runs 
2020-04-20 14:12:52.116 [ERROR] [org.quartz.core.JobRunShell         ] - Job DEFAULT.Timer 1 2020-04-20T14:12:52.109+02:00: <function <lambda> at 0x3> threw an unhandled Exception: 
org.python.core.PyException: null
	at org.python.core.Py.TypeError(Py.java:259) ~[?:?]
	at org.python.core.PyReflectedFunction.throwError(PyReflectedFunction.java:209) ~[?:?]
	at org.python.core.PyReflectedFunction.throwBadArgError(PyReflectedFunction.java:312) ~[?:?]
	at org.python.core.PyReflectedFunction.throwError(PyReflectedFunction.java:321) ~[?:?]
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:167) ~[?:?]
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:204) ~[?:?]
	at org.python.core.PyObject.__call__(PyObject.java:496) ~[?:?]
	at org.python.core.PyObject.__call__(PyObject.java:500) ~[?:?]
	at org.python.core.PyMethod.__call__(PyMethod.java:156) ~[?:?]
	at org.python.pycode._pyx43.f$3(<script>:53) ~[?:?]
	at org.python.pycode._pyx43.call_function(<script>) ~[?:?]
	at org.python.core.PyTableCode.call(PyTableCode.java:167) ~[?:?]
	at org.python.core.PyBaseCode.call(PyBaseCode.java:124) ~[?:?]
	at org.python.core.PyFunction.__call__(PyFunction.java:403) ~[?:?]
	at org.python.core.PyFunction.__call__(PyFunction.java:398) ~[?:?]
	at org.python.core.PyFunction.invoke(PyFunction.java:533) ~[?:?]
	at com.sun.proxy.$Proxy207.apply(Unknown Source) ~[?:?]
	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:48) ~[?:?]
	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) [bundleFile:?]
	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [bundleFile:?]
2020-04-20 14:12:52.180 [ERROR] [org.quartz.core.ErrorLogger         ] - Job (DEFAULT.Timer 1 2020-04-20T14:12:52.109+02:00: <function <lambda> at 0x3> threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception.
	at org.quartz.core.JobRunShell.run(JobRunShell.java:213) [bundleFile:?]
	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [bundleFile:?]
Caused by: org.python.core.PyException
	at org.python.core.Py.TypeError(Py.java:259) ~[?:?]
	at org.python.core.PyReflectedFunction.throwError(PyReflectedFunction.java:209) ~[?:?]
	at org.python.core.PyReflectedFunction.throwBadArgError(PyReflectedFunction.java:312) ~[?:?]
	at org.python.core.PyReflectedFunction.throwError(PyReflectedFunction.java:321) ~[?:?]
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:167) ~[?:?]
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:204) ~[?:?]
	at org.python.core.PyObject.__call__(PyObject.java:496) ~[?:?]
	at org.python.core.PyObject.__call__(PyObject.java:500) ~[?:?]
	at org.python.core.PyMethod.__call__(PyMethod.java:156) ~[?:?]
	at org.python.pycode._pyx43.f$3(<script>:53) ~[?:?]
	at org.python.pycode._pyx43.call_function(<script>) ~[?:?]
	at org.python.core.PyTableCode.call(PyTableCode.java:167) ~[?:?]
	at org.python.core.PyBaseCode.call(PyBaseCode.java:124) ~[?:?]
	at org.python.core.PyFunction.__call__(PyFunction.java:403) ~[?:?]
	at org.python.core.PyFunction.__call__(PyFunction.java:398) ~[?:?]
	at org.python.core.PyFunction.invoke(PyFunction.java:533) ~[?:?]
	at com.sun.proxy.$Proxy207.apply(Unknown Source) ~[?:?]
	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:48) ~[?:?]
	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]
	... 1 more
2020-04-20 14:18:51.673 [INFO ] [jsr223.ohtest.Moon distance         ] -  Moondistance updated every 5 Minutes by "astro.things" 2020-04-20T14:18:51.558+0200 1 / 1 Log every 2 hours
20

If I understand correct, there is something wrong with the “lambda” but I don’t know what and why !!?? :thinking: :thinking:

I used an example from the Docs

'''
    global chargerTimer2
    if items["Outlet9"] == ON and event.itemState <= DecimalType(8) and event.oldItemState <= DecimalType(8):
        if chargerTimer2 is None or chargerTimer2.hasTerminated():
            chargerTimer2 = ScriptExecution.createTimer(DateTime.now().plusMinutes(5), lambda: events.sendCommand("Outlet9","OFF"))
            batteryChargingMonitor2.log.info("Battery charging monitor: Started battery charging turn off timer: Outlet9_Power=[{}], oldItemState=[{}]".format(event.itemState, event.oldItemState))
    elif chargerTimer2 is not None and not chargerTimer2.hasTerminated():
        chargerTimer2.cancel()
        batteryChargingMonitor2.log.info("Battery charging monitor: Cancelled battery charging turn off timer: Outlet9_Power=[{}], oldItemState=[{}]".format(event.itemState, event.oldItemState))
'''

but I do not see what’s the difference.

Any help for a fool ? :wink: :crazy_face:

#1not T_OFFICEPI_STATUS.hasTerminated

#2… both args need to be str., but what are you doing with the state here, where you need an item name? The items object provides a dictionary of states.

events.sendCommand("Sonoff_socket_03", "OFF")
1 Like

…mostly the failure sits in front of the screen :upside_down_face: and can’t copy/paste properly either :rofl:

One more question:
Is it possible to log an info when timer ends ?

Thx for your quick reply and help

cheers
Peter

If you execute a function in the lambda, then you can do more than one thing. Lambdas in Python can only be one liners.

1 Like