[JSR223]failure to import

Loosely following @rlkoshak’s Journey to Jython #1, I keep failing to get ‘basic’ functions to work in Jython such as to send a mail and notify myself via Telegram.
I followed the install instructions for the helper libraries.
Basic .py script execution works but I have the vague feeling I missed something essential during setup because both issues seem to be related to library location, scoping or similar.
(Mail and telegram binding both are installed in OH2.5)

Mail problem:
from core.actions import Mail
already chokes at the beginning:

2019-12-16 20:57:17.042 [ERROR] [ipt.internal.ScriptEngineManagerImpl] - Error during evaluation of script 'file:/etc/openhab2/automation/jsr223/python/personal/battery.py': ImportError: cannot import name Mail in <script> at line number 5

Telegram problem:

telegram = actions.get("telegram", "telegram:telegramBot:nnnnnnnnn")
telegram.sendTelegram("Hello *World* " +  u"\U0001F44D")

results in

2019-12-16 20:43:23.004 [ERROR] [jython.battery monitor              ] - 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 50, in battery_check
AttributeError: 'NoneType' object has no attribute 'sendTelegram'

2019-12-16 20:43:23.025 [ERROR] [e.automation.internal.RuleEngineImpl] - Failed to execute rule '2b49105b-692b-427c-90f4-ecfb34c446f6':

It also does not make a difference to have this at the beginning (from someone this code works for)

from core.jsr223 import scope
from core.jsr223.scope import actions

Any ideas? I start feeling silly.

PS: stumbling across this and browsing the docs as a normal user, I came across several binding docs pages with examples. But they’re all in rules DSL.
I think we would need to complement all of them with Python equivalent ? (JS or Groovy I think is not so important as it isn’t all too much used)

1.x Mail Action or the newer 2.5 Mail binding? Here is working code I have that uses the new 2.x Mail binding.

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

def send_info(message, logger):
    """
    Sends an info level message by sending an email and logging the message
    at the info level.

    Arguments:
        - message: The String to deliver and log out at the info level.
        - logger: The logger used to log out the info level alert.
    """
    out = str(message)
    logger.info("[INFO ALERT] {}".format(message))
    NotificationAction.sendNotification(admin_email, out)
    (actions.get("mail", "mail:smtp:gmail")
        .sendMail(admin_email,  "openHAB Info", out))

Note that this is in a library module, not a script. You do not need to import actions when using a script, it’s already a part of the context, like items and ir and events.

The above though shows both a call to an old OH 1.x style Action (NotificationAction) which does always require the import and the newer 2.x style Actions that get embedded inside bindings.

IIRC I had a challenge getting the old Mail Action to work, was informed about the new Mail binding, and I just switched to that. I honestly don’t remember if it is the same problem you are seeing or not. I don’t use Telegram so can’t speak to how the 1.x version of the Action works, or doesn’t, in Python rules.

For the Telegram example, are you using the 1.x Action or the 2.x binding? Unlike the mail example which uses the 1.x Actions style, this one is using the 2.x style.

It might be useful to post your original Rules DSL version.

So that is only required for a module (i.e. code you put in automation/lib/python/personal). For scripts (automation/jsr223/python/personal) that is imported for you.

To summarize, since both Mail and Telegram have both a 1.x style Action and a 2.x binding, confirm which version you have installed and configured and compare it to what version you are using in your Rule.

1.x Mail Action example:

from core.actions import Mail
Mail.sendMail("someone@example.com", "This is the subject", "This is the message")

2.x Mail Binding example:

actions.get("mail", "mail:smtp:gmail").sendMail(admin_email,  "openHAB Info", out)

1.x Telegram example"

from core.actions import Telegram
Telegram.sendTelegram("MyBot", "Test")

2.x Telegram example

actions.get("telegram","telegram:telegramBot:<uid>").sendTelegram("Hello world!")

For both of the 2.x examples above, you only need to import actions if the file lives in the lib/personal folder.

Hopefully this is the problem. If not we have some digging to do.

That is definitely high up on the list of to dos and I know, at least for the main docs, that @Confectrician is very diligent about making sure we have examples for both on anything newly added (see the Ephemeris docs). The binding readmes are easier to miss though. I’ve also been going to all the design patterns and my more popular tutorials and posting a Python equivalent where applicable. Updating the binding docs is indeed going to be necessary but it’s also going to be a pretty big effort. But I suspect/hope that if Python becomes the default in OH 3, as was mentioned in Kai’s blog post, that there will be a big “Change all your examples to Python” issue in the add ons repos. If not, I bet we as a community can do a scrub and create the issues/PRs for them.

In the mean time, the Helper Library docs are your best bet for information like this right now. Especially the “But how do I…” page.

Also, I hope you are keeping a list of lessons learned. It will help us create/improve the docs that will go with a lot of this. The unicode observation is an important one already.

1 Like

To clarify this a bit:
We started that with a big enthusiasm, but i have slowed down my plans.

Here’s why:
@5iver is mentionig everywhere, that the helper libraries will be a temporary solution and (hopefully) move to the core/addons/project in some kind of depth.

So i simply didn’t see the benefit in starting with adding those examples, when they need to change again definetely.
Adding the native examples, would be more complicated than before.

I am open for good ideas where and how to start with parallel examples in a long term stable way.
I had none so far.

Indeed the helper library will change significantly and he is very close to having the ability to install Jython with the helper libraries as an add-on to have it merged. So the way it all gets installed and the locations of files will change. Ultimately, how you write the Rules will change too (i.e. written through them UI for most users). But, for example, what you need to do to import the Telegram action to a custom Script Action will remain the same.

So, for example, if I create a Rule in PaperUI right now with a custom Script that needs to do some stuff and then send a Telegram using the Telegram 2.x binding’s Action it would look like:

image

The contents of the Script is:

# do some stuff

actions.get("telegram", "telegram:telegramBot:nnnnnnnnn").sendTelegram("Hello *World* " +  u"\U0001F44D")

# do some more stuff

Notice it’s pretty much exactly like Marcus’ example above. How someone would use these Actions from inside a Script is unlikely to change much if at all. So unless @5iver knows something I don’t, it’s likely safe to add examples to the bindings that use Actions.

However, what is likely to change drastically about NGRE are:

  • the UI
  • how to install one of the supported languages
  • how to write a Rule not using the UI
  • locations of the files
  • perhaps minor changes to some of the libraries
  • how to find, install, and use community libraries and rules

Given that this covers almost all of the user facing aspects of the NGRE it is indeed a bit premature to create a full set of docs like we have for Rules DSL. But I don’t see what we are discussing right now changing that much if at all so it’s probably safe to include.

However, what we have now is not complete, so maybe it is worth holding off so we can update everything all at once. For example, instead of writing code, if you have a simple Rule where you just want to send a telegram, you can just select it as the Action of the Rule.

The problem is that there is no way right now to provide the actual value (e.g. I can’t actually supply the subject and body of a Text Mail). Besides that, the UIs will be changing anyway. But it seems prudent to include the UI as well as the code in the examples.

I do regret that I didn’t provide mainly Python versions of the Actions for Ephemeris when I wrote it, but I felt that were I to do that I’d need to update the whole page to show the Python version first and then include the “if you are using Rules DSL, do this instead.”

I’m aware of both, the Mail and Telegram bindings to replace 1.x actions.
So I’m using the new 2.5 bindings in both cases.

Ok, it does not so I removed the imports.

Using

actions.get("mail", "mail:smtp:gmx").sendMail(admin_email, "openHAB Info", "contents")

with mail:smtp:gmx being the name of the SMTP server Thing, I get an error message saying
Trying to send mail but exception occured: Sending the email to the following server failed : mail.gmx.net:25
Changing SMTP parameters on the Thing doesn’t help. I also don’t get it to send clear text SMTP?
Strange. Ok so no success but ok, at least the right code is called in Python.


On Telegram, no idea.
Seems the actions.get fails?
The code seems correct. It’s the same you propose and others to claim it’s working.

2019-12-16 22:16:33.724 [ERROR] [jython.battery monitor ] - Traceback (most recent call
last):
File “/etc/openhab2/automation/lib/python/core/log.py”, line 51, in wrapper
return fn(*args, **kwargs)
File “”, line 50, in battery_check
AttributeError: ‘NoneType’ object has no attribute ‘sendTelegram’

OK, well that’s progress. Perhaps you can put the binding into debug logging and see the exact cause of the exception if it’s not apparent from the exception that hopefully was printed to the logs. I’d guess that there is some configuration problem with the server Thing. It took me a bit to get it to work with gmail.

I’ve no direct experience with Telegram so I’m just guessing, but NoneType is like null so my guess is that it’s failing to find an Action named “telegram” or it can’t find the Thing “telegram:telegramBot:nnnnnnnnnnn”. The best I can offer is double check the Thing ID is right (note the warning in the docs, the nnnnnnnnnnnnn part is the Thing UID, not the chat ID. Make sure the Thing shows as online. Test it with Rules DSL and see if it works there. Nothing you wouldn’t have already thought to try unfortunately.

Tried that of course but it does not show anything although
openhab> log:get|grep -i mail
javax.mail x ERROR
org.openhab.binding.mail x DEBUG

Either way, found the reason (I’ve set a source address to be incompatible with spam protection) so that works now.

On telegram yes the Thing is offline which is probably the explanation of that ‘NoneType’. Will do more conventional digging.
Seems both were not Python related.
Thanks for guiding me.

If your Telegram Thing is offline, that means your token is wrong

That ultimately was the problem.
So nothing was Python related as I thought at first sight. Sorry for bugging you with this.

In OH3, a Scripting API will be introduced that will provide all of the features of the core helper libraries (creating rules and triggers, logging, improved actions, global variables, metadata, date conversion, Items, Links, Things, OSGi services, etc.) Everything the core helper libraries do now, and more, will be in the Scripting API and available for all languages. After the Jython bundle is merged, automation will hopefully be moved to a separate repo. Then expect to see issues in GH for bits of functionality being moved into the Scripting API

I have a PR for a bundle that provides Jython and the helper libraries. I’m considering splitting the libraries into a separate bundle… I think I will look into that tonight.

Thing actions are probably pretty safe, but they were very quickly implemented and may be revised. Everything in automation is in a state of flux in preparation for OH3. I’m considering trying an experiment with a design specification document, but I’m not sure how well that would go within an OSS project.

@mstormi, it would be great if you could provide the commands you used for each of these actions, and tips for troubleshooting… like the errors received when certain things were configured incorrectly. If you’d like to submit this as a PR to the helper library docs, that would be great too, otherwise I can easily throw it in. Glad you got them working!

Just one simple question regarding this: if I start rewriting my rules to Jython soon, will it be usable in later versions of OH? So basically, is it worth starting this now, or at a later time? I mean it is not a problem if not all new functions is present yet, if I can rewrite my existing rules, but I hope that I will not have to rewrite them completely again in the upcoming releases.

Sure but in the end it was misconfiguration of the things in both cases so that would need to go in the binding docs for those, right ?

actions.get("mail", "<mail thing>").sendMail(admin_email, u"subject", unicode(msg))

and

telegram = actions.get("telegram", "<telegram bot thing>")
telegram.sendTelegram(unicode(msg))

Eventually the only Python related hint would be that a ‘NoneType’ is essentially NULL and means the previous command failed (i.e. the user needs to resort to “classic” debugging of the binding/things).
The 2nd, more verbose programming variant is probably better because in the compacted 1st version you would not get any as-meaningful error message.
The unicode() constructor and “u” before strings is not mandatory but required to have the output in UTF-8.

(I’m still playing with that, will get back to this post if there’s more to report)

An unqualified and enthusiastic “yes”. You may need to move them around folder wise or make other tweaks to them as things change, but that’s true of Rules DSL as well.

We are heading towards a goal where users don’t have to “write code” to create their Rules, but those who want or need to will be able to.

Obviously I thought it was worth starting now. But I think the answer for you depends. Do you want to keep your Rules as “code” or would you be more interested in defining your Rules through the UI in the future? If you would be more comfortable having more between you and the code I would say wait for the UI to mature a bit and then migrate using that. If you are happy getting your hands dirty or want to learn you some Python (or JavaScript or Groovy) than now is a great time to get started.

From a purely selfish perspective, the more users we have migrating the more helpers we have on the forum who can get others migrating too. :slight_smile:

Believe it or not, the ability to write Python Rules has existed in openHAB almost forever. What is changing is doing so is becoming easier and easier. If you start now, you probably will not to do much to your Rules ever again, or at least no more than you have had to do with Rules DSL over the years. There are always breaking changes that you must adapt to over time.

But, as the stuff that Scott is working on matures, the overall approach to writing Rules may change. It won’t break your existing rules, but it may present a better way for you to write them.

And since the end goal is to make Rules something you find and use rather than something you write (unless you like writing Rules or you have a very specific use case, but given you don’t want to have to touch your Rules again that probably isn’t you, developers rarely can leave well enough alone :wink: ) maybe someone will write them for you. :smiley:

Personally, I wouldn’t wait. I’d go for it. It will not be wasted effort and there are some pretty cool features in NGRE that will open lots of new opportunities for you.

null not NULL. NULL is a special state that an Item can have that indicates it has not been initialized since the Item was loaded/openHAB started. null is a programming concept that indicates that a variable has been uninitialized, there is no result, or something is not found. Many programming languages use null but NoneType is what Python decided to call it.

The only reason I stress this is because you will still see NULL in Python Rules. But you won’t see null and instead you will see NoneType.

I have never been a fan of the change from UNINITIALIZED to NULL when we went from OH 1.x to 2.x. I think calling it NULL, while something that the developers are more familiar with, is confusing to the users. UNINITIALIZED is much more informative to users even if it’s longer to type.

Yes of course, sorry. Pardon my origins in C programming.

This is an important point… I hope to keep backwards compatibility while the Scripting API is being implemented, so that the helper libraries will stay functional.

One major benefit to the Scripting API is that it buffers us from changes to the rule engine. What previously was a breaking change that had to wait for a major release can now be implemented in a minor release.

I like writing my own rules and I think I have some really specific rules which is not that common. Thats why I don’t want to rewrite them multiple times because it is sooo much (over 150 rules), which can be reduced by using Python :slight_smile:
However I don’t get how these pre-defined rules will work, mainly because I think I haven’t looked into its development that much. You just have to call a function for example? If something like this, how you will fine-tune this for your system? I mean most of the rules interact with items, but the names of the items won’t appear there magically. So you will just pass everything when calling that function? Or you just “fill-out” a config file with the needed info?
This looks great and really good who don’t want to ever learn programming, but I can see that if something (some parameter) will be hardcoded in these rules, the first complaint will be to make it “user-configurable”.
This was just an example, I hope you get what I wanted to ask…

Yes. For example, I’ve submitted an implementation of the Gatekeeper design pattern. You just instantiate a class and call a function and it does the rest.

I’ve also submitted a version of the Time of Day design pattern. You just need to tell it what Items to use and it does the rest. My generic presence detection tutorial? There a reusable rule. Just point it at the Items you want to use and the code just runs.

Scott has a submission that complies the 3 day forecast from open weather map. It even creates the items for you.

You never have to look at the code. Just create a little bit of configuration and it does the rest. Right now the configuration goes in a library file named configuration.py. in the future there will be a web UI form to fill out.

So even if you do have some very specific rules, there is likely already or soon to be something you can build upon that will greatly simplify your rules.

I’ve so far tried to focus on creating building blocks rather than fully fledged capabilities, though I’ve submitted a few of those too. For example:

  • Gatekeeper: enforces a delay between commands, can also be used to implement the cascading timers dp. Can be used to keep from overloading a USB dongle with too many commands too fast or to schedule a series of things to happen in sequence with different times between them.

  • hysteresis: centralizes a common conditional

  • Timer Manager: implements the common case where you have to maintain a separate timer per item. Just make one function call and it tests for and creates the timer.

  • Countdown timer: creates a timer and updates a number item to show how many seconds are left in the timer once a second.

  • Rate limit: kind of like Gatekeeper except it ignores commands if they come too fast. Can be used to, for example, only get an alert once a day for that battery being low.

  • Deferred actions: kind of a quick a dirty timer that lets you define the delay using “2m5s” role notation.

  • Item init: a rule that boot straps the state of an item based on it’s metadata.

I have more in the queue to implement and submit. These are common things people need to do in all sorts of rules. Only rather than copy/paste and edit to customize to your needs, you just import them and use them. You never even need to open the files.

That’s what the configuration of for. Take the Time of Day submission. Define a set of groups and items for reach group (e.g. a get for weekend, another for weekdays, another for holidays, etc.) Based on the states of the Items and the Ephemeris configuration it will drive a time of day item’s state. So you can have any number if different time of day periods for as many different types of days as you want. All you have to do is define the Items and groups.

There are all sorts of ways to do configuration. Item metadata, Groups and Items membership, configuration.py, configuration files, arguments and lambdas passed to functions, arguments passed to class contractors, etc.

Almost none of these are available for Rules DSL. But with careful coding, we can make a library almost infinitely configurable without changing any code.

That’s part of the configuration. You can tell it about the Items in configuration.py, group membership, metadata, etc. You don’t have to know the names of the item to write the logic. You can let the user provide the names as part of the configuration.

Sometimes.

Sometimes.

And there are other options too.

So that user should file an issue and who ever wrote the the library will make it configurable. But most developers will try to make as much configurable as feasible.

Thanks for your detailed answer! This really looks promising. I mean I don’t mind writing my own code, but if there is a solution already for something, why ‘reinvent the wheel’…
I have already started migrating my rules (starting with the simplest ones) to Python and it looks really good, I like it much better than the DSL, it simplifies (or it can if you just don’t “translate” your DSL rules 1:1 to Python) the whole codebase…