JS Transformation in rule does not appear to run

  • Platform information:
    • Hardware: i7/250Gb SSD/16Gb RAM
    • OS: Ubuntu 19.10
    • Java Runtime Environment: OpenJDK Version 1.8.0_252
    • openHAB version: 2.5.7-1
  • Issue of the topic: JS Transformation in rule does not appear to run

default.items:

String      ZM_Camera2               "Camera-2 Front House [%s]"    { channel="mqtt:topic:mc:zoneminder:Cam2"}

mqtt.things:

Thing topic zoneminder "Zoneminder" @ "MQTT" {
            Channels:
            Type string : Cam2      "Camera-2"          [ stateTopic="zoneminder/2"]
        } // end of thing

zoneminder.rules:

    rule "zm_Front of house alarmed"
    when
        Item ZM_Camera2 received update
    then
    if (ZM_Camera2.state == NULL)
        {
            logInfo("zoneminder.rules", "Camera2 Item is null, cancelling...")
        return;
        }
        var payload = ZM_Camera2.state.toString
        logInfo("zoneminder.rules", "Incoming payload: " + payload)
        var eventtype = transform("JSONPATH", "$.eventtype", payload)
        logInfo("zoneminder.rules", "Event Type: " + eventtype)
        var eventid = transform("JSONPATH","$.eventid", payload)
        if (eventtype=="event_start"){
          // Check that this is triggered by the FrontGatePerson zone
          var zone = transform("JS", "esmotiontrigger.js", payload)
          logInfo("zoneminder.rules", "Zone triggered: " + zone)       
          // If this is the FrontGatePerson zone //
          if (zone=="FrontGatePerson")
          {
            // Lets check if a person was the trigger of this zone
            var wasperson = transform("JS", "esnotificationperson.js", payload)
            if (wasperson==true)
            {
                logInfo("zoneminder.rules", "Person has been detected in the FrontGatePerson zone. Event ID:" + eventid)
            }
          }
          // Add other zones here
          if (zone=="Driveway")
          {
            // Lets check if a person was the trigger of this zone
            var wasperson = transform("JS", "esnotificationperson.js", payload)
            if (wasperson==true)
            {
                logInfo("zoneminder.rules", "Person has been detected in the Driveway zone. Event ID:" + eventid)
            }
            // Lets check if a car was the trigger of this zone
            var wascar = transform("JS", "esnotificationcar.js", payload)
            if (wascar==true)
            {
                logInfo("zoneminder.rules", "Car has been detected in the Driveway zone. Event ID:" + eventid)
            }
          }         
         } // end of event_Start eventtype
    end

esmotiontrigger.js:

    (function(i) {
      var data = JSON.parse(i);
      var result = "";
      var namesummary = data.name;
      const regex = /(?<=Motion\s).\w+/gm;
    result = regex.exec(namesummary);
    return result[0];
      })(input)

Sample of JSON that comes in to item ZM_Camera2:

{"hookvalue":"0","monitor":"2","detection":[{"confidence":"97.32%","type":"object","box":[315,288,595,674],"label":"car"},{"label":"person","confidence":"54.27%","box":[320,608,442,674],"type":"object"}],"eventtype":"event_start","name":"Front_House:(3482) [a] detected:person:54%  Motion Driveway","state":"alarm","eventid":"3482"}

Logged data

2020-09-02 17:07:12.748 [INFO ] [rthome.model.script.zoneminder.rules] - Incoming payload: {"hookvalue":"0","monitor":"2","detection":[{"confidence":"97.32%","type":"object","box":[315,288,595,674],"label":"car"},{"label":"person","confidence":"54.27%","box":[320,608,442,674],"type":"object"}],"eventtype":"event_start","name":"Front_House:(3482) [a] detected:person:54%  Motion Driveway","state":"alarm","eventid":"3482"}

2020-09-02 17:07:12.749 [INFO ] [rthome.model.script.zoneminder.rules] - Event Type: event_start

2020-09-02 17:07:12.752 [INFO ] [rthome.model.script.zoneminder.rules] - Zone triggered: {"hookvalue":"0","monitor":"2","detection":[{"confidence":"97.32%","type":"object","box":[315,288,595,674],"label":"car"},{"label":"person","confidence":"54.27%","box":[320,608,442,674],"type":"object"}],"eventtype":"event_start","name":"Front_House:(3482) [a] detected:person:54%  Motion Driveway","state":"alarm","eventid":"3482"}

Problem
Testing the esmotiontrigger.js code seems to result in the correct value (in this case: “Driveway”) to be returned from the function.

When it is in the rule as shown this should result in the variable “zone” in the rules file to have the value “Driveway”, however when it is run, it simply results in the payload being reported back, as if it does not process the JS at all. Consequently the rest of the rule fails.

I have modified esmotiontrigger.js to return “Test” and this does not change the variable “zone” when logging this - which seems to indicate to me that it is not executing the transform.

In PaperUI, under Add-Ons -> Transformations I have enabled "Javascript Transformation - transformation-javascript-2.5.8

I am unsure why this is not executing the transform. Have I called it incorrectly in the rule to be able to have it process the transformation?

I know I can also do some stuff with JSONPATH, however I would like to be able to expand on this script in future to detect and report on multiple events, which is easier in JS to write and return value to OpenHAB.

Please How to use code fences.

When a JS transform encounters an error or returns null the transform will return the whole string I think so there is likely something different about the string being passed to the transform or something different about how it’s processing it that is causing it to fail.

I’m not actually sure how that would be the case given that the JS Transform can only return one String value.

I’ve tried my best to re-format the info above with code fences - maybe it is my browser but it doesn’t seem to like formatting it with the button in the editor, so I have put them in the “< code >” brackets to try and fix that.

I have done a capture of the data that is being sent to the MQTT broker, and this seems to correlate with the payload that is being received:

{“eventid”:“2202”,“name”:“Front_House:(2202) [a] detected:person:99% Motion FrontGatePerson”,“monitor”:“2”,“detection”:[{“box”:[576,234,644,422],“confidence”:“99.34%”,“label”:“person”,“type”:“object”},{“type”:“object”,“label”:“car”,“confidence”:“94.36%”,“box”:[323,288,607,678]}],“state”:“alarm”,“hookvalue”:“0”,“eventtype”:“event_start”}

This is being captured in the rules file in the lines:
var payload = ZM_Camera2.state.toString
logInfo(“zoneminder.rules”, "Incoming payload: " + payload)

After checking the JSON in JSONLint, this is valid JSON.

In an experiment I have created a simple function that just returns text, and this works fine, so it has to be something in the function that encounters an error - and that would be what is causing the whole string being returned. I wasn’t sure if this was expected behavior for it to return the whole string on error and glad to have that confirmed.

In regards to JSONPATH I was just simply going to try and look for the $.detection.label and pick up on the label “person” but that would only return one event/value, so I am looking to use JS to be able to do a simple count of times this has shown in the JSON presented and then return the number.

Jumping in the deep end and using JS first - I figured I would have to do this anyway for the end goal so I should try and do this for something that is easier!

Testing the JS on online editors results in the right value being returned, so this is a bit puzzling at the moment. When I work this out I will definitely report back and advise what it was so it can save someone else from frustration!

```

Sandwich your code between three back ticks

```

1 Like

Okay, after a lot of testing, it appears that the JS that is used in OpenHAB doesn’t seem to like the positive lookbehind that I was using in my regex.
var patt= /(?<=Motion\s).\w+/

So I have revised the function to be the following:

(function(i) {
  var data = JSON.parse(i);
  var result = "";
  var namesummary = data.name;
  var patt = /Motion\s(.*\w+)/;
  
  result = namesummary.match(patt);
  return result[1];
  })(input)

and this seems to have fixed the issue, with the data that I am looking for returned successfully.

1 Like