Migrate from http binding js-transform to js-script - how to do this? ICAL interpreter for events per day

I use a transform from the germany openhab forum to read a ICAL calender from internet or locally and extract events.

String GlobalHolidayICAL              {http="<[https://www.schulferien.org/media/ical/deutschland/ferien_bayern_%1$tY.ics?k=yRn5ZxhHnEGLS-Q5moUjssrrewdJotK0vjDSiUqnIO0Ld_cm5-wcNJkUNXBBMtWB5j6Van10h4KxggpP2xQPcAGDYJkKP25S6zec7oXmtg:7200000:JS(ical_holiday.js)]"}
String TrashBiomuellICAL              {http="<[http://localhost:8080/static/Abfallkalender-Lindenstr-50-xxx_%1$tY.ics:7200000:JS(ical_biomuell.js)]"}

It is working perfect. I just have to manually download a ICAL-File once a year or use the direct link to the file at the internet. Both are in the example. A js-transform-script picks out the ICAL entry of the current day, if there is one.

But the ICAL file does not change over the year and it is enough to start the item calculation once a day to get the needed informations. Yes, I know, i can use the interval and set it to 1 day. But I cannot control at what time the item will updated thsi is why I use 2h at the moment (7200000)

Is there a way to do it a little bit different? To migrate this to a js-script which works with the ICAL-file instead of use it inside of the http-transform?

It will be enough to start the ical_biomuell.js with the ICAL-file as parameter. Similiar to the holiday.js from the forum here. But I’m not so familiar with js-coding and as I understand I must move the script from transform folder to scripts folder and have to change a lot inside of the file. Puh, will be a lot of work.

And a second thing I want to do is to send more parameters to the js-script. In the ICAL-File there are more calenders, for paper trash, plastic trash and so on. At the moment I use different js-transform file to pick out the right value. Will be more flexible to use parameters.

Any hints are welcome.

Current js-transform skeleton is

(function(i)
{

... code
icalParser.parseIcal(input);
... code

})(input);

I think I must do something to get the parameter (input) in another way and get more then one parameter to work with.
my idea is something like:

rule "somehting"
when
   Time cron "0 0 1 * * ?"
then
   callScript("ical_biomuell", "path to ICAL", "other parameters")
end

Is this possible, I do not find a good documenation for the script part of OH.

Can someone lead me to some js-script examples which work in OH, maybe I can learn from them and solve this problem by myself.

So I think you are mixing up a few concepts. It is understandable because OH has a bad habit of reusing common words in a very specific way.

For openHAB, a Script is a small piece of Rules Domain Specific code that can be called from your Rules. But there are some very significant limitations of what you can do in a Script (you can’t pass in command line arguments, you can’t get a return value) so almost no one uses them. This is what is supposed to go in openHAB’s script folder. You cannot use callScript to execute a JavaScript. You need to use executeCommandLine for something like that.

This will require a complete rewrite of your JavaScript function into a complete JavaScript program which will indeed be a lot of work if you don’t know JavaScript. And then you have to do some more work to get the results of the JavaScript into OH.

I think it will be much easier to keep using the JS transform. You can make some changes though:

  • Use the HTTP caching config to pull the ICAL file down once per year and store the full ICAL file in a String Item. Make sure you have restoreOnStartup on these Items.
  • Use a cron triggered Rule so you can control when the next day’s entries are processed (one second after midnight perhaps). In this Rule use transform("JS", "ical_biomuell.js", TashBiomuellICAL.state.toString).
  • You can’t pass extra arguments to the transform and it isn’t clear what needs to be done differently for each ICAL file. Assuming that all it is doing is extracting the entries for the current day you shouldn’t need a different one for each calendar and can call the same one over and over. That could let you do something like gCalendars.members.forEach[ cal | transform("JS", "ical.js", cal.state.toString) ] to extract the current day’s entries for all your calendars.

All of the above you should be able to do with what you already know I think.

Hi Rich,

thanks for your reply. I found one of your post afterwards.

But in this post and here:
https://docs.openhab.org/configuration/rules-dsl.html#transformations

The argument is an input not an output.

Your Rule
transform(“JS”, “ical_biomuell.js”, TrashBiomuellICAL.state.toString)
will need TrashBiomuellICAL.state.toString as input.

I need this as output. Something like this:
TrashBiomuellICAL.state.toString = transform(“JS”, “ical_biomuell.js”, PathToCacheICALFile)

Or do you mean, that I should use HTTP-binding without transform? Then I have the full file content in the String variable.

String TrashBiomuellICALBuffer              {http="<[http://localhost:8080/static/Abfallkalender-Lindenstr-50-xxx_%1$tY.ics:7200000]"}

TrashBiomuellICAL = transform("JS", "ical_biomuell.js", TrashBiomuellICALBuffer.state.toString)

Can persistance handle that big String datas? My String TrashBiomuellICALBuffer will be 16294 Byte.

Yes

Shouldn’t be a problem. That’s easy enough to test.16KB really isn’t that big in the grand scheme of things. I’d be more surprised if MapDB or InfluxDB or whatever you are using (note rrd4j cannot store Strings) can’t handle something that size. A quick search on InfluxDB implies a max String size of 64k and MapDB has a maximum record size of 32k. So even with MapDB your ICAL file can be twice as big as you mention without a problem. That should be enough of a buffer.

But if size does become a problem, you can go the file route and use:

val icalStr = executeCommandLine("cat /full/path/to/ical/file", 5000)
TrashBiomuellICAL.postUpdate(transform, "JS", "ical_biomuell.js", icalStr)