Writing to a text file

I would like to write the total energy produced by my PV inverter to a text file. I’m running OH3.2. I have looked at the discussion here. My script is following:

var String Usage = PV_total_energy.state.toString
logInfo("test1" , "PVYield " + Usage) 
executeCommandLine("echo "+ Usage + ( ">> /openHAB/html/totalyield.txt" ),5000)
logInfo(“TEST2”, executeCommandLine("echo "+ Usage + ( ">> /openHAB/html/totalyield.txt" ),5000))

The script fails when either of the two last lines are enabled. The log file just has the following lines:

2022-03-12 09:35:50.924 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'e68d4517a6' failed: var String Usage = PV_total_energy.state.toString
logInfo("test" , "PVYield " + PV_total_energy.state.toString) 
logInfo("test1" , "PVYield " + Usage) 
executeCommandLine("echo "+ Usage + ( ">> /openHAB/html/totalyield.txt" ),5000)
logInfo(“TEST2”, executeCommandLine("echo "+ Usage + ( ">> /openHAB/html/totalyield.txt" ),5000))

Any ideas?

1 Like

Syntax of executeCommandLine that you use if for OH2 not for OH3 see Actions | openHAB

Where did you put that, exactly? In a block expecting javascript, perhaps?

I’m running the DSL script in a rule.

Would you show the output from the [code] tab when viewing the rule in the GUI?

OK, here is the code:

configuration: {}
triggers:
  - id: "1"
    configuration:
      cronExpression: 0/15 * * * * ? *
    type: timer.GenericCronTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >-
        var String Usage = PV_total_energy.state.toString

        logInfo("test" , "PVYield " + PV_total_energy.state.toString) 

        logInfo("test1" , "PVYield " + Usage) 

        //executeCommandLine("echo "+ Usage + ( ">> /openHAB/html/totalyield.txt" ),5000)

        logInfo(“TEST2”, executeCommandLine("echo "+ Usage + ( ">> /openHAB/html/totalyield.txt" ),5000))
    type: script.ScriptAction

I haven’t had yet time to look at the OH3 syntax for executeCommandLine.

What seemed odd to me was the error message quoting the whole rule back to you. But you are definitely going to have to deal with the new syntax.

I had a look at the new syntax but I have no ideas how to change the OH2 syntax to OH3 in my case because I don’t fully understand the OH2 syntax either.

That’s not going to work. You are trying to use some io redirection which is only outbidded by a shell. When using executeCommandLine, you don’t have a shell so operations like | > >> don’t exist.

You either need to:

  • out that into a shell script and call that
  • write to the file some other way, such as using Java IO or in ways that don’t require shell io redirection
  • reconsider how to get to your end goal. This smells like an XY Problem. What is the purpose of writing this to a file line this? there is almost certainly another way.

My experience with executeCommandLine is zero. I found one post (which I linked) and I thought that might work but obviously it didn’t.

The reason why I want to write the total energy produced to a text file is that I want to pass the information to Homeseer. I could read two Modbus registers from my Fronius inverter with Homeseer but conversion from two 16 bit registers (float32) is rather tedious with VB scripting which would require quite lot of coding. So I thought that writing the energy value to a text file and reading this value with Homeseer would be lot easier.

I know nothing about Java. So are there any easy ways to write to a text file?

Can Homeseer speak MQTT or does it have a REST API? Having the two directly talk would be better. If Homeseer can read from a database supported by OH that could work too.

There really isn’t an easier way to write to a file. You’ll either need to move the io redirection to a shell script and then figure out the syntax for executeCommandLine (which isn’t hard, everywhere you see a space on the command line string you’d pass that string as a separate argument to executeCommandLine) or figure out the Java classes.

I had a quick look at Homeseer, and mqtt and rest api are supported through (payable) plugins so I’m not that interested in investing any more money on Homeseer which I’m running in parallel with OH only because of databases. Once I get influxDB and Grafana working with OH, then I’ll switch off Homeseer.

I’m somewhat surprised to hear that there is no easy solution to writing a single number to a text file. I could read two Modbus registers with Homeseer but I would need to do quite lot of coding to convert the contents of these registers to a single number and at the moment I don’t know the maths either.

Using executeCommandLine would be very appealing because you could in principle write a number only with a single command line.

I managed to circumvent the original problem so I can read registers 40101-40102 from Fronius with Homeseer. These two Modbus regs contain the info on total energy produced.

I found out that BitConverter.ToSingle method solves the conversion from float32 to decimal. But it would be still interesting to know how to write to a text file in OH3.2.

As @rlkoshak stated

you may do something like:

executeCommandLine(Duration.ofSeconds(2), "/path/to/your_script.sh", "YourParameter")

your_script.sh then may look like:

#!/bin/bash
echo "$1" > /tmp/YourFile.txt

to see the latest output only or something like

#!/bin/bash
echo `date` : "$1" >> /tmp/YourFile.txt

to collect datetime and argument that was submitted.

Wolfgang_S. Great, many thanks for your help. I’ll try this later.

OK, I tried with following rule:

configuration: {}
triggers:
  - id: "1"
    configuration:
      cronExpression: 0/15 * * * * ? *
    type: timer.GenericCronTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >-
        var String Usage = PV_total_energy.state.toString

        logInfo("test1" , "PVYield " + Usage) 

        executeCommandLine(Duration.ofSeconds(2), "/runtime/bin/totalyield_script.sh", "Usage")

        logInfo("TEST2", executeCommandLine(Duration.ofSeconds(2), "/runtime/bin/totalyield_script.sh", "Usage"))
    type: script.ScriptAction

totalyield_script.sh is:

echo "$1" > /html/totalyield.txt

And logfile shows following error:

2022-03-15 15:01:00.899 [ERROR] [e.automation.internal.RuleEngineImpl] - Failed to execute rule 'cae33edaee': Fail to execute action: 2
2022-03-15 15:01:11.016 [INFO ] [org.openhab.core.model.script.test1 ] - PVYield 15043.201000
2022-03-15 15:01:11.018 [WARN ] [rg.openhab.core.io.net.exec.ExecUtil] - Failed to execute commandLine '[/runtime/bin/totalyield_script.sh, ]'
2022-03-15 15:01:11.018 [WARN ] [rg.openhab.core.io.net.exec.ExecUtil] - Failed to execute commandLine '[/runtime/bin/totalyield_script.sh, totalyield.txt]'
2022-03-15 15:01:11.019 [INFO ] [org.openhab.core.model.script.TEST2 ] - null

So I’m still missing something.

  • user openhab has read and execute permission for /runtime/bin/totalyield_script.sh ?
  • runtime exists under / ?
  • add #!/bin/bash or #!/bin/sh in the very first line of your script to let the system know which shell interpreter to use

Here’s how to do it using jruby:

configuration: {}
triggers:
  - id: "1"
    configuration:
      cronExpression: 0/15 * * * * ? *
    type: timer.GenericCronTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/x-ruby
      script: >-
        require 'openhab' # not needed on openhab 3.3+
        logger.info("PVYield #{PV_total_energy)") 
        File.write('/openHAB/html/totalyield.txt', "#{PV_total_energy}\n", mode: 'a')
    type: script.ScriptAction

Note: you’d need to install the jrubyscripting automation and configure it to load the openhab-scripting library.

If you want to prepend each line with a timestamp:

require 'openhab' # not needed on openhab 3.3+

logger.info("PVYield #{PV_total_energy)") 
time_stamp = Time.now.strftime('%F %T')
File.write('/openHAB/html/totalyield.txt', "#{time_stamp} #{PV_total_energy}\n", mode: 'a')

The question is, what are you trying to achieve? There may be a better way, for example, writing this data to influxdb instead of a text file, so you can plot the data, or analyse it in some other ways. You would also be able to calculate, say energy usage between two points in time.

Hi guys,

For some reason I couldn’t get Wolfgang_S’s method working but jruby method seems to work. One issue with jruby, though. Mode ‘a’ seems to append new data at the end of the file but I want the script just the replace the previous value. I couldn’t find the right mode for this.

I agree that e.g. influxDB would be much better solution. The reason why I want to write data to a text file is that I’m running Homeseer in parallel and I have database under Homeseer. I can setup Homeseer to read the values from this text file and save them into the database. This is just a temporary solution because I haven’t had yet time to setup the influxDB under OH. I still have a pulse counter (using RS232) under Homeseer but will replace this with a Modbus TCP pulse counter. I am saving the pulse data from energy meters into the database under Homeseer.

Thanks a lot for your help.

If you want the file to have just one line without past values, just remove mode completely. Just call File.write with two arguments.

An alternative is to publish this value via mqtt and have your other system listen on mqtt, so no file.

In jruby:

things['mqtt:broker:yourbrokername'].publishMQTT('topic', PV_total_energy.to_s)