OH3: rule script execution error (input string)

  • openhabian 3.3.0 on rPi4

I seem to hit a snag here and there during my migration from v2 to v3.

I have this rule:

        if (spm_Message.state.toString.contains("|ERROR|"))
        {
            val String ERROR_MESSAGE = ZonedDateTime.now().toString + " " + spm_Message.state.toString.replace('|', '_')
            val String CLI_RETURN_CODE = executeCommandLine(Duration.ofSeconds(3), "/bin/sh", "-c", "echo " + ERROR_MESSAGE + " >> /etc/openhab/html/Modbus.txt; echo $?")
            logInfo(LOG_PREFIX + "01.05","Modbus error logged to file: {}", spm_Message.state.toString.split("\\|").get(2))

            // this is printed despite being 0
            if (CLI_RETURN_CODE != 0)
            {
                logInfo(LOG_PREFIX + "01.07","Return code: {}", CLI_RETURN_CODE)
            }

            /*
                // next creates an error: 2022-11-11 16:27:56.331 [ERROR] [internal.handler.ScriptActionHandler] -
                // Script execution of rule with UID 'sppro_modbus-2' failed: For input string: "0" in sppro_modbus
                // worked in OH2

                if (Integer::parseInt(CLI_RETURN_CODE) != 0)
                {
                    logInfo(LOG_PREFIX + "01.07","Return code: {}", CLI_RETURN_CODE)
                }
            */
            logInfo(LOG_PREFIX + "01.08","into if")
            if (Integer::parseInt(CLI_RETURN_CODE) != 0)
            {
                logInfo(LOG_PREFIX + "01.08","Return code: {}", CLI_RETURN_CODE)
            }
        }

Which creates this error:

2022-11-12 14:13:44.379 [INFO ] [enhab.core.model.script.Modbus.01.05] - Modbus error logged to file: Invalid CRC at 8051
2022-11-12 14:13:44.381 [INFO ] [enhab.core.model.script.Modbus.01.07] - Return code: 0

2022-11-12 14:13:44.383 [INFO ] [enhab.core.model.script.Modbus.01.08] - into if
2022-11-12 14:13:44.386 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'sppro_modbus-1' failed: For input string: "0" in sppro_modbus

Where I see the return code of 0 in the log, the intent is not not to print this message. It seems to be zero but isn’t for this if statement (CLI_RETURN_CODE != 0)

Assuming the CLI_RETURN_CODE is a string type as defined further up, the comparison should be CLI_RETURN_CODE != "0", but this also leads to the same script error.

Any hints appreciated.

Okay, that’s a string.

A string will never be equal to numeric 0, not even if it is string “0”
You can do string comparisons, of course
if (CLI_RETURN_CODE != "0")

I’m not sure why that doesn’t work, something about imports and context I expect. Is this a file based rule, do you have imports carried over from older OH and perhaps no longer required?

Yes, it is a string; compared against string, which should work.
No imports were used in OH2, nor in here in OH3.

While I have things and items in the UI, rules are in files.
I am migrating from v2 to v3, and only adjust rules as required to make them work.
The plan for later is to rewrite them in JS.

I don’t see anywhere that you are doing that?

This is not a string comparison; 0 is a numeric

Correct, why I wrote:

            logInfo(LOG_PREFIX + "01.08","into if")
            if (Integer::parseInt(CLI_RETURN_CODE) != "0")
            {
                logInfo(LOG_PREFIX + "01.08","Return code: {}", CLI_RETURN_CODE)
            }
2022-11-12 19:52:35.353 [INFO ] [enhab.core.model.script.Modbus.01.08] - into if
2022-11-12 19:52:35.355 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'sppro_modbus-1' failed: For input string: "0" in sppro_modbus

I didn’t update what I had originally, but added the string comparison while writing it ensure the error occurs, and it is not working.

That’s not a string comparison either. By its very purpose, parseInt will return a numeric. A numeric will never be equal to a string like “0”.

I agree.

Of course it might not do what you expect if the variable is actually something like "0<newline>". Maybe count characters and see if there is more to it than you thought
Log out CLI_RETURN_CODE.length

With the rest of the rule hidden from us, have you considered the error may come from later on?

1 Like

There could be something going on here caused by Rules DSL’s “flexibility” (to put it kindly) in managing type. Even if you declare the variable as a String, if you assign an Number to it later, it’ll often accept that and just change the type to a Number.

I don’t think that’s happening here because executeCommandLine returns a String.

But @Max_G, it isn’t the return code that all Linux programs return when they exit, as is implied here by this code. It returns the output of the script on stdout and stderr. So it’s always going to be a String and, unless your command outputs “0"” when you run it it’'ll almost never just be a String representation of a number like that.

Looking at the command that is run, if I remember my bash syntax correctly, CLI_RETURN_CODE should be the same as ERROR_MESSAGE (I’m assuming that’s what that last echo $? does). Unless I’m wrong and somehow that’s causing it to output the return code from the previous command, in which case, that’s pretty clever.

It will also almost certainly include a newline like @rossko57 pointed out. If you don’t use echo -n you will get a newline in the output. I think that was one of the breaking changes as at some point in the past executeCommandLine automatically removed that newline and now it doesn’t.

But everything else @rossko57 mentioned is right on. CLI_RETURN_CODE is a String. 0 is a Number. "0" != 0. They are different types.

1 Like

No :slight_smile:

I am listing what I have got right now here (which includes your suggestion to log out CLI_RETURN_CODE):

rule "Modbus: Last Reboot"
    when
        Item spm_Message received update
    then
        if (spm_Message.state.toString.contains("|ERROR|"))
        {
            val String ERROR_MESSAGE = ZonedDateTime.now().toString + " " + spm_Message.state.toString.replace('|', '_')
            val String CLI_RETURN_CODE = executeCommandLine(Duration.ofSeconds(3), "/bin/sh", "-c", "echo " + ERROR_MESSAGE + " >> /etc/openhab/html/Modbus.txt; echo $?")
            logInfo(LOG_PREFIX + "01.05","Modbus error logged to file: {}", spm_Message.state.toString.split("\\|").get(2))

            logInfo(LOG_PREFIX + "01.05b","logging out length of CLI_RETURN_CODE: {}", CLI_RETURN_CODE)

            // this is printed despite being 0
            if (CLI_RETURN_CODE != 0)
            {
                logInfo(LOG_PREFIX + "01.07a","Return code: {}", CLI_RETURN_CODE)
            }

            if (CLI_RETURN_CODE != "0")
            {
                logInfo(LOG_PREFIX + "01.07b","Return code: {}", CLI_RETURN_CODE)
            }

            logInfo(LOG_PREFIX + "01.08","into if")
            if (Integer::parseInt(CLI_RETURN_CODE) != "0")
            {
                logInfo(LOG_PREFIX + "01.08","Return code: {}", CLI_RETURN_CODE)
            }

            logInfo(LOG_PREFIX + "01.09","into if")
            if (Integer::parseInt(CLI_RETURN_CODE) != 0)
            {
                logInfo(LOG_PREFIX + "01.09","Return code: {}", CLI_RETURN_CODE)
            }
        }
end

You are both on the right right track; and I realise now I did not pay enough attention!

image

As we can see, there is a newline in the return string; silly me; chose to ‘reformat’ it. I do apologise for misleading my fellow collaborators.

Logging out the length shows CLI_RETURN_CODE is two characters.

2022-11-13 09:02:35.672 [INFO ] [nhab.core.model.script.Modbus.01.05b] - logging out length of CLI_RETURN_CODE: 2

I assume the -n correction needs to go in like this:

 executeCommandLine(Duration.ofSeconds(3), "/bin/sh", "-c", "echo", "-n" + ERROR_MESSAGE + " >> /etc/openhab/html/Modbus.txt; echo $?")

That’s what I have in the rule now, let’s wait for the next Modbus error message.

1 Like

Probably echo -n $? is where it needs to go. That’s where the return code is being printed I think. You probably want the newline in the first echo since that’s adding lines to a file.

2 Likes

Thank you; done.
… and it works.

This is what was tested:

        if (spm_Message.state.toString.contains("|ERROR|"))
        {
            val String ERROR_MESSAGE = ZonedDateTime.now().toString + " " + spm_Message.state.toString.replace('|', '_')
            val String CLI_RETURN_CODE = executeCommandLine(Duration.ofSeconds(3), "/bin/sh", "-c", "echo " + ERROR_MESSAGE + " >> /etc/openhab/html/Modbus.txt; echo -n $?")
            logInfo(LOG_PREFIX + "01.05","Modbus error logged to file: {}", spm_Message.state.toString.split("\\|").get(2))

            logInfo(LOG_PREFIX + "01.05b","logging out length of CLI_RETURN_CODE: {}", CLI_RETURN_CODE.length)
            logInfo(LOG_PREFIX + "01.05c","logging out CLI_RETURN_CODE: {}", CLI_RETURN_CODE)

            if (CLI_RETURN_CODE != 0)
            {
                logInfo(LOG_PREFIX + "01.07a","Return code: {}", CLI_RETURN_CODE)
            }

            if (CLI_RETURN_CODE != "0")
            {
                logInfo(LOG_PREFIX + "01.07b","Return code: {}", CLI_RETURN_CODE)
            }

            logInfo(LOG_PREFIX + "01.08","into if")
            if (Integer::parseInt(CLI_RETURN_CODE) != 0)
            {
                logInfo(LOG_PREFIX + "01.08","Return code: {}", CLI_RETURN_CODE)
            }

            logInfo(LOG_PREFIX + "01.09","into if")
            if (Integer::parseInt(CLI_RETURN_CODE) != "0")
            {
                logInfo(LOG_PREFIX + "01.09","Return code: {}", CLI_RETURN_CODE)
            }
        }

This is the outcome:

2022-11-13 18:40:36.841 [INFO ] [enhab.core.model.script.Modbus.01.05] - Modbus error logged to file: Invalid CRC at 8051
2022-11-13 18:40:36.844 [INFO ] [nhab.core.model.script.Modbus.01.05b] - logging out length of CLI_RETURN_CODE: 1
2022-11-13 18:40:36.845 [INFO ] [nhab.core.model.script.Modbus.01.05c] - logging out CLI_RETURN_CODE: 0
2022-11-13 18:40:36.850 [INFO ] [nhab.core.model.script.Modbus.01.07a] - Return code: 0
2022-11-13 18:40:36.851 [INFO ] [enhab.core.model.script.Modbus.01.08] - into if
2022-11-13 18:40:36.853 [INFO ] [enhab.core.model.script.Modbus.01.09] - into if
2022-11-13 18:40:36.854 [INFO ] [enhab.core.model.script.Modbus.01.09] - Return code: 0

Thank you Rich and Rossko