Help converting rule to jython

I want to convert this rule to jsr223

var Number mooncount=0

rule "moondistances"
    when
        Item Dummy4 changed to ON or
        
        Item Date_distance changed      // Item defined in astro.items  and changed every five minutes(300 sec.) by astro.things
    then
        Date_Kilometer_actual.postUpdate(Date_distance.state.format("%1$ta, %1$td.%1$tb. ") + " / " + Kilometer_distance.state.format("%,.0f km").toString)
        Date_Kilometer_perigee.postUpdate(Date_perigee.state.format("%1$ta, %1$td.%1$tb. ") + " / " + Kilometer_perigee.state.format("%,.0f km").toString)
        Date_Kilometer_apogee.postUpdate(Date_apogee.state.format("%1$ta, %1$td.%1$tb. ") + " / " + Kilometer_apogee.state.format("%,.0f km").toString)
        mooncount = mooncount + 1
        if (mooncount == 1 ) {   //Log every 2 hours - just to inform that rule is still alive
            logInfo("astro_test-rules" + '_99'," Moondistance updated every 5 Minutes by \"astro.things \" " + Date_distance.state + " / " + mooncount + " Log every 2 hours")
        }
        if (mooncount >= 24) {       //refresh counter
            mooncount = 0
       }
end

At the end of the rule is a logging-routine which shows every 2 hours that it’s still running. Therefore I declared a variable “mooncount” and initialized it with 0.

Now I try to convert it, but don’t know how to handle the routine.

At the moment the new rule looks like

from core.rules import rule
from core.triggers import when
from core.log import logging, LOG_PREFIX

@rule("Moon distance", description="Concatination of DateTime and Distance", tags=["Date", "Distance"])

@when("Item Dummy5 changed to ON")
@when("Item Date_distance changed")

def dist_concat(event):
    dist_concat.log = logging.getLogger("{}.Moon distance".format(LOG_PREFIX))

    events.postUpdate("Date_Kilometer_actual1", (ir.getItem("Date_distance").state.format("%1$ta, %1$td.%1$tb. ") + " / " + ir.getItem("Kilometer_distance").state.format("%,.0f km")))
    events.postUpdate("Date_Kilometer_perigee1", (ir.getItem("Date_perigee").state.format("%1$ta, %1$td.%1$tb. ") + " / " + ir.getItem("Kilometer_perigee").state.format("%,.0f km")))
    events.postUpdate("Date_Kilometer_apogee1", (ir.getItem("Date_apogee").state.format("%1$ta, %1$td.%1$tb. ") + " / " + ir.getItem("Kilometer_apogee").state.format("%,.0f km")))
    #events.postUpdate("Update_Time", str(DateTimeType())) # just for test to see the Triggertime
    #mooncount = 0
    #mooncount += 1
    dist_concat.log.info(" Moondistance updated every 5 Minutes by \"astro.things \" %s %s %s", event.itemState, event.itemName, mooncount)

Any hints for me to solve my problem ?

What exactly is achieved with the mooncount log message? It appears to me that it logs once a day, so why not just have a cron rule to log this info?

{BTW, I’ve made a request for a moderator to split this discussion into a new topic.]

Thx for reply.
First I thought to make a new topic, but then thought less posts, so I can append one.

As my Astro-Binding(Thing) looks every 5 Minutes(300 Sec) for new values, all items will be updated then.
Example:

Thing astro:sun:local     "Sonnen Daten"    [geolocation="48.xxxx,9.yyyy,502", interval=300]

That also means that my rule is triggered every 5 Minutes. The Log-Info at the end of the Rule is only to inform that the rule was triggered and still alive.

But there is no need to show me every 5 Minutes this information in the log. It is enough if I get every two or four hours an information that the rule is running.

So 24 doesn’t mean “once a day” it means 24 * 5 Minutes = 2 Hours. It’s just a counter that logs on “1” then only counts up to 24 and resets the counter again. I know this is amateurish, but this works for me in the past since I’m with OH :innocent:

So, it provides a log entry every 2 hours so that you know that the astro binding is functioning. There are several other ways to do this, but to get you working with what you know…

from core.rules import rule
from core.triggers import when

mooncount = 0

@rule("Moon distance", description="Concatination of DateTime and Distance", tags=["Date", "Distance"])
@when("Item Dummy5 changed to ON")
@when("Item Date_distance changed")
def dist_concat(event):
    events.postUpdate("Date_Kilometer_actual1", "{} / {}".format(items["Date_distance"].format("%1$ta, %1$td.%1$tb. "), items["Kilometer_distance"].format("%,.0f km")))
    events.postUpdate("Date_Kilometer_perigee1", "{} / {}".format(items["Date_perigee"].format("%1$ta, %1$td.%1$tb. "), items["Kilometer_perigee"].format("%,.0f km")))
    events.postUpdate("Date_Kilometer_apogee1", "{} / {}".format(items["Date_apogee"].format("%1$ta, %1$td.%1$tb. "), items["Kilometer_apogee"].format("%,.0f km")))
    #events.postUpdate("Update_Time", DateTimeType().toString()) # just for test to see the Triggertime
    global mooncount
    mooncount += 1

    if mooncount == 1:# Log every 2 hours - just to inform that rule is still alive
        dist_concat.log.info(" Moondistance updated every 5 Minutes by \"astro.things\" {} {}".format(items["Date_distance"], mooncount))
    elif mooncount >= 24:# refresh counter
        mooncount = 0
  • Note the use of global to use the mooncount global variable. Here is some documentation on the use of global variables in Python, but there are plenty of other sources for this information.
  • You do not need to create the log attribute for the rule function, since the rule decorator does this for you.
  • You do not need to go to the ItemRegistry to get an Item’s state, since they are provided in the items object. This is much easier and less typing.
  • I used the string format method instead of the string concatenation operator. This is extremely useful. I left the StringType formats, but these could also be done within str.format().
1 Like

Many thx for your help and the patience and the detailed explanations. Both rules (DSL and SA) are running now quite fine with the global variables-settings:

2020-03-30 11:24:56.393 [INFO ] [ome.model.script.astro_test-rules_99] -  Moondistance updated every 5 Minutes by "astro.things " 2020-03-30T11:24:56.269+0200 / 1 Log every 2 hours
2020-03-30 11:34:56.401 [INFO ] [jsr223.ohtest.Moon distance         ] -  Moondistance updated every 5 Minutes by "astro.things" 2020-03-30T11:34:56.269+0200 1
2020-03-30 13:24:56.418 [INFO ] [ome.model.script.astro_test-rules_99] -  Moondistance updated every 5 Minutes by "astro.things " 2020-03-30T13:24:56.257+0200 / 1 Log every 2 hours
2020-03-30 13:34:56.442 [INFO ] [jsr223.ohtest.Moon distance         ] -  Moondistance updated every 5 Minutes by "astro.things" 2020-03-30T13:34:56.258+0200 1
  • Using global.
    I’m a little ashamed, as I’m tinkering a bit with it some days ago as in the following code snippet
   LOG.info("====== List of Members - End ====== u-Umlaut: %s = o-Umlaut: %s = Item-Label m. Umlaut: %s = Item-Group: %s ===============\n",(u"ü"),(u"ö"),(ir.getItem("V10_1").label),(list(listOfMembers6)))

# global variables    
globVar1 = 0
globVar2 = 0
globVar3 = 0

def itemtests():
    '''
    Spielereien mit Items und globalen Variablen sowie mit Logging
    '''

    LOG.info("================================= Itemtests - Start ==========================================")

    item_all = ir.getItem("V10")
    LOG.info(item_all)
    # work with global variables in function, see logs at the end of the .py - file
    global globVar1
    global globVar2
    global globVar3
    globVar1 = item_all.label
    globVar2 = item_all.state
    globVar3 = item_all.name

    item_state = ir.getItem("V10").state
    LOG.info(item_state)
    item_name = ir.getItem("V10").name
    LOG.info(item_name)
    item_label = ir.getItem("V10").label
    LOG.info("----Name: %s-------Laenge: %s ",item_label, len(item_label))
    index = 5
    item_index = (ir.getItem("Forecast_Timestamp_{:02d}".format(3 * index)))
    LOG1.info("--%s--",item_index)
    item_state_hhmm = ir.getItem("Sunset_Time").state.format("%1$tR")
    LOG.info("Time is :%s", item_state_hhmm)
 
    LOG.info("================================= Itemtests - End ==========================================\n")

#membertests()
itemtests()
#several_features()

# output of global variables
LOG.info("work with global Variables ---- %s ----- %s -------- %s ", globVar1, globVar2, globVar3)
LOG.info("================================= END =====================================")
  • logging I changed it as you described. I wasn’t aware of this “easy” way.

  • items / format method When using as described

events.postUpdate("Date_Kilometer_actual1", "{} / {}".format(items["Date_distance"].format("%1$ta, %1$td.%1$tb. "), items["Kilometer_distance"].format("%,.0f km")))  

I got the following error:

2020-03-30 14:15:01.349 [ERROR] [jsr223.ohtest.Moon distance         ] - Traceback (most recent call last):
  File "/etc/openhab2/automation/lib/python/core/log.py", line 51, in wrapper
    return fn(*args, **kwargs)
  File "<script>", line 14, in dist_concat
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 8: ordinal not in range(128)
2020-03-30 14:15:01.356 [ERROR] [e.automation.internal.RuleEngineImpl] - Failed to execute rule '26c40ce4-12fe-4628-a7cc-97ed3f458d7d': Fail to execute action: 1

I didn’t found Unicode on Pos.8, only the curly braces, but not on Pos. 8.
I have no idea, as the curly braces (and items) works with the log-statement

dist_concat.log.info(" Moondistance updated every 5 Minutes by \"astro.things\" {} {}".format(items["Date_distance"], mooncount)) # Scott's Version

Any idea ?

My guess is that items["Date_distance"].format("%1$ta, %1$td.%1$tb. ") has an ä in the month or day of the week. If you run into unicode issues, then you should use unicode strings…

events.postUpdate("Date_Kilometer_actual1", u"{} / {}".format(items["Date_distance"].format("%1$ta, %1$td.%1$tb. "), items["Kilometer_distance"].format("%,.0f km")))  
1 Like

You are my hero :+1: :+1: :clap:. That’s it, as month “March” is german “März”.

1 Like