Journey to JSR223 Python 1 of 9

:+1: that was what I was looking for and yes I, too, missed that until now.

2 Likes

I’m not sure how to do that without completely transforming them into a straight up tutorial which will require a complete rewrite. If I’m going to do that I may as well just write the official docs. But they’re is too much changing right now to really get started with that too (confectarian got a good start but had to back off as well).

It’s not clear is yet with the effort to get started on such a guide given significant portions of it will look significantly different from what it does today. For example, we are one pr merge away from a wholly new set of instructions for installing Python.

All of these are good things that need to be included in the docs when they get written, but it’s not clear yet what issues we now face will still be there next week, next month, and beyond.

I’m getting a 500 error when I try to edit the op. I’ll have to make the fix later.

Lately I have been getting those 500 errors whenever I try & tag a thread too. I think the forum server has issues.

Hello to all,

I posted this here because it has to do with using a library function for sending info and unicode.
I am using the jython helpers library with the jython-standalone-2.7.2.jar and I trying to use a simplified util.py example from @rlkoshak:

from core.jsr223 import scope
from core.actions import NotificationAction
from configuration import admin_email

def send_info(message, logger):
    logger.info("[INFO ALERT] {}".format(message))

but when calling send_info in my test rule file specifying that the string has unicode with u"string":

from core.rules import rule
from core.triggers import when
import personal.util
reload(personal.util)
from personal.util import send_info

@rule("JythonInfoTest", description="Jython Info Test", tags=["info"])
@when("Item SwitchJythonInfoTest changed")
def jython_info_test_rule(event):
    if items.SwitchJythonInfoTest == ON:
        send_info(u"Máquina Lavar Roupa - Começou!", jython_info_test_rule.log)
    else:
        send_info(u"Máquina Lavar Roupa - Terminou!", jython_info_test_rule.log)

I have an error:

2020-07-31 10:01:11.090 [ERROR] [jsr223.jython.JythonInfoTest        ] - 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 25, in jython_info_test_rule
  File "/etc/openhab2/automation/lib/python/personal/util.py", line 6, in send_info
    out = str(message)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe1' in position 1: ordinal not in range(128)

2020-07-31 10:01:11.101 [ERROR] [e.automation.internal.RuleEngineImpl] - Failed to execute rule '458332f8-34da-4007-9ec7-9d1921b7a08e': Fail to execute action: 1

If I call it like this it works:

jython_test_rule.log.info(u"Máquina Lavar Roupa - Começou!")
jython_test_rule.log.info(u"Máquina Lavar Roupa - Terminou!")

but using the library function send_info it does not. I know this should be something simple for you guys but I did not manage to get it working.

Could you please give me hand on this one.

Thanks for your help.

@rjduraocosta, please post your issue in a new topic and I will help you there.

Hello @5iver,

Done.

Thanks again.

2 Likes

Hello, is this tutorial still valid with OH 3.0?

I’m using version 3.1.0M4 and apparently something must be modified, because for example even the simple line:

from core.jsr223 import scope

causes an error:

[ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'myscript' failed: ImportError: No module named core in <script> at line number 5

@Frank_Pepperyellow you should be able to use the code in this series with only minimal changes. The Python/Jython part of these tutorials did not change from OH2 to OH3, but parts for OH did so you may need to change things that interact with OH yo work in 3. Largely the only thing you need to change will be DateTime related. OH2 had Joda DateTime installed and it was encouraged to use that, OH3 does not have Joda so you must use Java’s ZonedDateTime instead (which is also available in OH2).

In regards to the error you saw:

```
Use code fences like this when posting logs or code. 
Enclosing the log or code in 3 ticks, like you see
above and below here, will make it look like this
block
```

And I’m guessing you have installed the original Helper Libraries and not my update version that supports OH3. You can find it here:

2 Likes

@CrazyIvan359 Thank you very much, following your instructions I was able to run my first Python script!

Actually, after my first Hello World example working fine, I’m experiencing some problems.

First of all, I’m writing my scripts in ‘Scripts’ page, is this the correct way to proceed? When I write a script there, I can see it there but it is also in some way replicated in ‘Rules’ page, where it says that the rule cannot be modified because it is has been provisioned from a file.

The problem is that I’m starting having a list of ‘zombie’ rules appearing in Rules page and I cannot remove them because I cannot find in which file they have been put (I wrote them in Scripts page). Each time I modify the original script it seems that it creates a new rule and these rules are never deleted.

What am I doing wrong? Thank you again for your help…

You should open a new thread if you have a question unrelated to the content of this thread.

Though to answer your question, you want to using rules not scripts.

Just to elaborate a little bit on this. If by “Scripts” page @Frank_Pepperyellow means in MainUI, those have nothing to do with this series of posts. In fact this series of posts cannot be implemented in MainUI. You must use text based rules to use these as written (even after the updates for OH 3 already mentioned).

In UI created rules much of the rule is defined outside the code. There is no @rule and there is no @when. In fact there isn’t even a def functionname(event):. All of that is handled for you. The only code you enter is in a Script Action or a Script Condition (which is a concept that only exits in UI rules).
In the UI there are three types of rules:

  1. Rules: regular old run-of-the-mill rules
  2. Schedule: a regular rule that has a time based trigger or condition (“But only if…”) and tagged with “Schedule”
  3. Script: a regular old rule that only consists of a Script Action and tagged with “Script”. That means no triggers and no conditions.

You cannot copy the above code into the UI and have it work. Anything that is outside the body of the function that makes up the body of the rule is invalid in a UI rule.

@rlkoshak thank you, your post has been very helpful in clarifying all these aspects of rules and script (in relation to Main UI) that I was not aware of before.

I’m trying to write a simple rule for sending emails using a python script, but with no success so far. This works fine:

from core.actions import NotificationAction

but if I try to import also Mail modifying the previous this with this:

from core.actions import NotificationAction, Mail

I get the following error:

2021-05-24 13:39:43.830 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'XYZ' failed: ImportError: cannot import name Mail in <script> at line number 2

Of course, I installed and configured Mail add-on and followed all the steps described by @CrazyIvan359 in his post of 7 days ago. Can you help me in understanding what I’m doing wrong? I’m using OH 3.1.0M4… Thanks!

Importing an Action like that is for OH 1.x style add-ons and are no longer valid for OH 2/3 add-ons. You need to do it just like the examples shown in the binding docs. The only difference is in the Python code you need to reference the actions object.

mailActions = actions.getActions("mail","mail:smtp:samplesmtp")
success = mailActions.sendMail("mail@example.com", "Test subject", "This is the mail content.")
success = mailActions.sendMail("mail1@example.com, mail2@example.com", "Test subject", "This is the mail content sent to multiple recipients.")

Still having problems… Here is the complete code of my (very simple) rule, which I wrote in the Rules page of the MainUI and is triggered by an Item that I switch on and off:

from core import actions
from core.actions import NotificationAction

msg = 'Hello!'

NotificationAction.sendBroadcastNotification(msg)
mailActions = actions.getActions("mail", "mail:smtp:EmailSMTPServer")
success = mailActions.sendMail("some_email@example.com", "openHAB Info", msg)

The notification is correctly sent and received by my mobile app, but the email is not sent and I see this in the log:

2021-05-24 19:17:43.801 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'XYZ' failed: AttributeError: 'module' object has no attribute 'getActions' in <script> at line number 7

So, it seems I’m still missing something… :frowning:

My mistake. It’s actions.get("mail", ...

Now it works, thank you very much!

You should never use from core import actions as that will overwrite the built in actions object that you use to get binding actions. You should only ever use from core.actions import xxx and that only applies to about half a dozen core OH actions.

After my first experiments, there are still (at least) a couple of things that I don’t know how to implement in python. I hope this is the right place where to post these questions…

Here they are:

  1. How can I get the time of the last change of an Item’s state?

  2. How can I get the previous state of an Item?

I need 1) because I’m implementing a switch in the sitemap that will send an email containing information regarding all my anti theft Items, for example the current state of the entrance door and windows. I was thinking of sending an email with an HTML table with all those Items, their current state and the moment when they changed state last time (i.e. when the entrance door lock 1 was closed or opened last time).

I need 2) for a rule that will send a notification each time the overall power consumption of my house is above the allowed limit (basically the rule will be the following: if current_power_consumption > allowed_value and previous_power_consumption <= allowed_value then send notification).

Other things that I would like to know are the following:

  1. I read in an old post that the only way for having static values shared among rules is to create an Item and have it implement this behavior. Is this still valid with OH 3? Is there a different (simpler) method, for example in the case where the value must not be shared among different rules but only owned by a single rule (but preserving its value between subsequent calls of that rule)?

  2. If the only method for implementing a static shared variable is by creating an Item, I guess you can only associate basic types (numbers, strings, …) with this Item and in case you need to store more complex types (lists, dictionaries, …) you need to encode these values in a string and parse this string afterwards. Is this correct?

Thank you again!