Need a little help transforming DSL Rules to the new JSScript

Hi Everyone,
just as side note, my production system runs oh 2.5 pretty stable for two years now and i am setting everything up from scratch as I am switching to oh 3.2. So at some point i got confused and sure enough I try to do things better and “the right way”. So in oh2.5 I have everything set up in files. Now I try to hang on to the UI witch gets frustrating some times. But so what. Now all my rules I migrated from DSL to JSScript (5.1) until I just fell over one of the articles saying that it is basically deprecated. So now I am transformig from 5.1 to JSScript 11. I do have one of my scripts done now and would appreciate if someone with experience could take a look if things are good or if something can be done better. The script in fact works. So please give me your thoughts on my solution.

if (items.getItem("V_Alarm_Internal").state == 'ON' || items.getItem('V_Alarm_External').state == 'ON'){ 
  var pushover = actions.get("pushover", "pushover:pushover-account:xxxxxxxxx");
  var exec = actions.Exec;
  var time = Math.round(Date.now()/1000);
  var itemName = triggeringItem.label
  var picturesDirectory = "/usr/share/openhab/pictures/";
  var destination = "";
  var source = "";
  
  if (items.getItem("V_Alarm_Internal").state == 'ON'){
    pushover.sendPriorityMessage(itemName + " wurde geöffnet", "ACHTUNG, (STILLER) ALARM!!!", 1);
  } else if (items.getItem('V_Alarm_External').state == 'ON'){
    pushover.sendPriorityMessage(itemName + " wurde geöffnet", "ACHTUNG, ALARM!!!", 2);
    var cameraIDList = ['id1', 'id2', 'id3', 'id4', 'id5'];
    var cameraNameList = ['Ostseite', 'Haupteingang', 'Westseite', 'Terrasse', 'Garage'];
  
    java.lang.Thread.sleep(3000);
    for(var i = 0; i < cameraIDList.length; i++){
      source = "http://xxxxxxxxxx:8080/xxxxxx/jpeg/xxxxxxxx/" + cameraIDList[i] + "/s.jpg";
      destination = picturesDirectory + cameraNameList[i] + "." + time + ".jpg";
      exec.executeCommandLine("wget", source, "-O", destination);
    }
  
    java.lang.Thread.sleep(500);
    for(var i = 0; i < cameraIDList.length; i++){
      destination = picturesDirectory + cameraNameList[i] + "." + time + ".jpg";
      pushover.sendAttachmentMessage(cameraNameList[i], cameraNameList[i], destination, null);
    }
  }
    exec.executeCommandLine("find", picturesDirectory, "-name", "*.jpg", "-type", "f", "-mtime", "+10", "-delete");
}

Thanks,
Dan

It might be better to use time.ZonedDateTime and time.Duration for time stuff.

This will not work in JSScripting and will generate an exception. For the time being you’ll have to use a Timer.

A dict might work better here. You can use the Camera name as the key and the id as the value

But over all the rule looks reasonable.

1 Like

Is there a convinient way to save global constants in one script and use them in all rules? For example the IP address of my CCTV instance. I need that in multiple rules. So I would like to prefer one place to define that.

You mean like a HashMap in Java? I am actually a Java developer and not verry familiar with Javascript.

Yes.

Is there a solution?

Only with JS Scripting where there is a cache Map Object that is shared across all rules.

In all other cases if you are writing in text files instead of the UI you can define “global” variables at the top of the file which is shared between all the rules in that file. In UI rules you are currently out of luck.

Ok, thank you! Worked fine with global variables in the cache. I am starting a script at system startup witch sets all the needed variables in the cache.

I hear a lot of talk about the need for ‘global variables’ in various different languages used in openHAB and always wonder why an unbound item isn’t a good solution?

i hate to ping people but Rich @rlkoshak could you answer this?

You can’t put a Timer into an Item. You can’t instantiate an Object from a library like my TimerMgr or LoopingTimer or the like in an item.

Am Item or great to hold a value, but not sufficient of you need to hold an Object like a Timer.

I do encourage the use of Items, tags, and metadata or sharing values between rules, even complicated data structures. But if you need to call a function like timer.reschedule() an Item simply can’t do the job.

ok, well of course not but for example

would be perfectly adequate right?

Yes, I would put that into an item if it were needed across multiple rules or hard code it f needed by only one rule.

Ok, I thought about that too. But I cannot find any place (in the UI) where to store additional information. If I could create some type of custom field where I could store that kind of information it would be great. I tried it with Metadata (Custom Namespace) but it didn’t work for me. For some reason my custom Metadata doesn’t appear in the Metadata list. Defining the item as String doesn’t really make it either because I cannot set a fixed value.

Not claiming that it is a perfect solution, but I use datetime items for this. Any rule can change a datetime item. I have a rule that triggers if the datetime item is changed. The rule itself just starts or reschedules a timer to the current value of the datetime item. As an extra benefit, this means that your timers will ‘survive’ a restart of openhab. Of course in that case you need some logic to make sure that the value of the datetime item is in the future.

1 Like

It is a limitation of the MainUI at the moment: custom metadata is not viewable in the UI: [MainUI] See and edit Item metadata on the Item page · Issue #397 · openhab/openhab-webui · GitHub

That doesn’t mean it’s not there. Because of limitations the UI can currently only show will known metadata, not custom metadata, in that list.

I’ve published a rule template that does this.

It’s a good approach too unless the timer needs additional information from the rule that triggered it.

I hope you don’t mind me writing your rule in JRuby

Things to note:

  • This is a fully file based rule, not GUI, so it includes the trigger and rule definition, not just the rule ‘body’
  • Don’t need to download the image as a file, then later on delete them (unless you want to keep the images?). Pushover lets you send the raw image (in memory)
  • Not using sleep. Instead we use a timer for fetching the snapshot from each camera, so the fetching runs in parallel
  • I haven’t tested this, so there may be some minor errors. I’d be happy to help further.
require 'openhab'
require 'net/http'

CAMERAS = { 
  id1: 'Ostseite',
  id2: 'Haupteingang',
  id3: 'Westseite',
  id4: 'Terrasse',
  id5: 'Garage'
}

rule 'Internal Alarm' do
  changed V_Alarm_Internal, to: ON
  triggered do |item|  
    pushover.sendPriorityMessage("#{item.id} wurde geöffnet", "ACHTUNG, (STILLER) ALARM!!!", 1)
  end
end

rule 'External Alarm' do
  changed V_Alarm_External, to: ON
  triggered do |item|
    pushover.sendPriorityMessage("#{item.id} wurde geöffnet", "ACHTUNG, ALARM!!!", 2)

    CAMERAS.each do |id, name|
      after(3.seconds) do
        source = "http://xxxxxxxxxx:8080/xxxxxx/jpeg/xxxxxxxx/#{id}/s.jpg"
        image = Net::HTTP.get(URI(source))
        pushover.sendAttachmentMessage(name, name, image, nil)
      end
    end
  end
end

def pushover 
  things['pushover:pushover-account:xxxxxxxxx']
end

wow. thank you for all the great ideas. I still have alot other rules that need to be transfered into this new enviornment.