Jython: Rule to run when script file is loaded

Hi,

I want to run a rule that will check if items are intialized (not NULL). If item is not set, I set a default value (those items are stored in mapdb so the next time they will be loaded).

In DSL, i used an item that after some delay (enough for the system to start) was triggered and rules used this trigger to run the initialization code. Here is an example:

rule "Siren init"
when
  Item Openhab_Init received command OFF
then
  if (Siren_Enable.state == NULL) Siren_Enable.postUpdate(ON)
  if (Siren_Sound.state == NULL) Siren_Sound.postUpdate("burglar")
end

The problem is that I need to make sure that the trigger will be send after the scripts are loaded and the only way that I know (for now) is to have a long delay for the trigger (as the org.eclipse.smarthome.automation.module.script.rulesupport is running with start-level 90).

Thx

I have over 1000 Items and this script has always worked. Actually, I’m pretty sure Items load before ruleSupport. Are you familiar with this repo?

I’ve added tags to your post… helps to get more attention to your post because people subscribe to them.

1 Like

@5iver

Thx for your reply

Yes, I saw the repo although as I am in the early stage of trying to understand how to write scripts with Jython, I am not sure I understand everything here …

Is this script a replacement for the start-level 90?

How do you initialize NULL items? As I am developing my scripts, from time to time, I delete the mapdb content and the cache to check that the system can restart from clean env and this is why I need the ability to initialize NULL items.

Is there a priority between the community / core / personal folders or the scripts will run based on the index (no matter which folder they are)?

I don’t change the start-levels, as it is strongly suggested not to change them. So, I guess it would be. I do not have startup issues, but I also do not have any DSL rules that need validation and could slow down the startup.

I don’t… persistence does this for me. I’m not sure why you would be testing this, couldn’t you just remove mapdb and restart OH? After the test, install mapdb again. You could also just add a NULL check into each of your rules. Hopefully this works for you!

In my testing, directories are not considered… just file names (last sentence here). Based on earlier versions of the documentation, I believe this may have behaved differently in older versions of ESH.

If I add a NULL check I need to add it to any rule that use the item. This is why I run a script before to make sure that items, that should have value, will have it.

For me it is simpler just to delete the db file of mapdb. I am doing it just to make sure that I can always run OH from clean deployment. I also make sure to have everything from configuration files, I don;t use PaperUI for configuration at all.

I am moving from DSL to Jython. It will take time until I will move all scripts, so I need some patch for now.

Did the startup delay script help at all?

I am not sure. If I clean cache and remove db seems not, if just restart than yes, but again, not sure at all.

I hope this doesn’t come across as harsh… I’m just trying to understand better so that I can help! I still don’t understand the purpose of your test. Your db will not be wiped after a clean deployment, unless you are migrating to different hardware… but then wouldn’t you migrate/restore the db too? A clean deployment without a persistence db and restoreOnStartup will bring the system up with all Items having a state of NULL. I guess if this is what you want to do, then you need to find a way to restore all of the Item states, which means storing a default state for all of the Items, and then updating the Items with that state before any other rule runs. I just don’t see the point of writing a rule for this, when that’s exactly what restoreOnStartup does for you. :man_shrugging:

@5iver

Migrating to different deployment, which can be cause of current hardware failure or moving to new hardware.

Yes, I can backup the persistence db and restore it on the new platform, but I personally prefer to have a rule that will make sure that any value that should not be null will have a default value before rules run.

I do use restoreOnStartup, and usually the init rules doesn’t do anything as the items gets the values from the db (mapdb).

One other reason that I am doing that is because I want to have few layers of backup. If for some unknown reason, there is a failure with the db, I still want to have functional system (as much as possible). I can check each item for NULL but as I wrote, it will require to do so on any rule, using the init rule, I just do it in one place.

I guess you’re set on going down this path then. :slightly_smiling_face:

To clarify then, you want a script that starts before all others, iterates through all of your Items, and sets a default state for any that are NULL?

I will define it more general: I was looking for a way to have a script that run before all rules but after items are loaded. In my case I will initialize items that should have value (not all my items, mainly items which are categorised as setting items), e.g., the siren value and the siren sound name (and others).

BTW, I suggest in other thread in the past to have the ability to define default values for items in the item files so the system can set the value when the item is being created (even before the item is loaded from persistence). From my POV this is the right way, same as the ability to define variables in code (global / local) with initial value.

This may work for you. You could put it at the end of the startup delay script, or in another script that is named sequentially right after it… like 001_initialize_items.py.

from core.log import logging, LOG_PREFIX

default_values = {
    "Item_1": "ON",
    "Item_2": "ON",
    "Item_3": "ON"
}

for item in default_values.keys():
    if items[item] == UnDefType.NULL:
        logging.getLogger(LOG_PREFIX + ".Initialize Items").info("Initialized [{}]".format(item))
        events.sendCommand(item, default_values[item])

If you wanted to get fancy with it, you could add the default value to the item’s metadata, and read it in this script, instead of using the dictionary.

@5iver

Thx, I will probably go with the Metadata. This way I can define the default value in the item configuration and have one place to initialize the items. I haven’t used the metadata so far and I am trying to understand how to define metadata.

Q: Do you know if the script will run after persistent is loaded (from mapdb) or before? I will of course check if the item is NULL before setting but just curious

Thx

@5iver

Based on yur suggestion I have wrote the following script (001_initialize_items.py) Comments are more than welcome:

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Init items
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

from personal.metadata import Metadata

from core.log import logging, LOG_PREFIX

# Module logger
log = logging.getLogger(LOG_PREFIX + ".init_items")

log.info("Initialize items default value")

for item in ir.getItems():
  '''
  Iterate all items and initialize item which:
    - Is NULL
    -  Has metatdata { default="default" [value=<value>] }
  '''
  if item.state == UnDefType.NULL:
    m = Metadata(item.name, "default")
    if m.is_namespace_exist() != None:
      value = m.get_configuration_value_for_key("value")
      if value != None:
        events.sendCommand(item.name, value)

log.info("Completed")

Metadata class is based on this

Scripts run after Items are loaded and persistence data is restored, if you are using the startup delay script. Your solution looks good! It would be a nice addition if you were to add it as a community or example script to the openhab2-jython repo.

I will wait until the merge with Metadata class pull request will complete