Exec Transformation in Item

Does anyone have an example of doing an Exec transformation in an item definition?

I have a value in bytes that I would like to convert to human readable format. The numfmt command looks like it would perform the transformation with the appropriate arguments.
numfmt --to=iec-i --suffix=B --padding=7

I see plenty of examples of using JSON, XML or JS transformations. However, I can’t find a single example of an exec transformation being done in an item definition. I have attempted a few different permutations but I still have not been successful invoking the exec transformation for an item.

https://docs.openhab.org/addons/bindings/exec/readme.html#channels
I think that is not possible.

Thanks. That is the exec binding. The exec transformation service is documented here: https://docs.openhab.org/addons/transformations/exec/readme.html

However, it doesn’t appear to be documented with any uses cases in item transformation.

I am not sure what you want to do is possible. Maybe an example would help. Where does the bit value come from? How is it stored? Etc. Maybe we could suggest a solution.
As your question raises the need of more information I will post some information.

What i know of the regex-transformation-service is that:

I only used exec-retransformation to set the output argument to the command line to execute. Have a look in the example.
https://community.openhab.org/t/1-openhab-433mhz-radio-transmitter-tutorial-exec-binding-explained-in-detail/34977/20

Using transformation in the exec thing for example has the drawback that the result will always be a string.

You may use a rule to make the transformation as shown here.

Maybe with this information you could solve your problem or formulate example or question which explains what you try to do explicitly.

If the EXEC-Transformation sould be for the binding of a item see https://github.com/openhab/openhab1-addons/wiki/Transformations
But I think you want to use it for the label-status of a item.
You can transfer in a rule and show in a second Item.

Thanks @hr3 and @Josar

You are correct I do want to do this transformation within a label. I didn’t see anything that indicated Exec was limited to only to bindings. I thought all transformations were available for labels (map, scale, etc). But that would explain why I couldn’t get it to work.

Thanks!

Be aware that label are static and can not be change after they are set. So they can not be change in rules.
see here.

Still missing exactly what you want to achieve, maybe anexample would help us get you a good solution.

Sure… I am getting a set of memory usage values using the HTTP binding and the data comes back in bytes. I wanted to transform that to human readable format. I could do it in a rule, I supposed, but I was hoping to do it in a label so I didn’t need to make additional items, etc.

searching a bit, i think it schould work.

Number YourNumber "Memory [%.1f]"  { http="<[http://example.com/var/value:60000:EXEC(/absolute/path/to/my/program %s)]" }

something like that.

But i had no time to test it. Is is documented in the openhab1 wiki

Not easy to understand what you want, without a example. Is it this:

numfmt --to=iec-i --suffix=B --padding=7 1234567
 1.2MiB

or want you to convert a byte in a binary format e.g. 0b00010101 or 00010101

@josar -
Thanks for the idea of doing it in the binding. Unfortunately, I want to persist the raw number not the converted number.

@hr3 -
Yes exactly, I am looking to convert byte values to human readable so bytes to MB, GB, TB, etc. Just like you get with a standard ‘-h’ flag on a lot of unix commands.

Have you considered using the JS Transform for this? I don’t know how easy it will be but it should be possible to use something like:

(function(i) {
    if(isNaN(i)) return "NA" // avoids errors when Item is NULL
    var bytes = parseInt(i, 2)
    return Math.round(bytes/1048576) + "MB"
})(input)

@broconne

best i can do is using a rule and two items one for the value and one for the human readabel text.

rule "Convert byte to Readabel"
  when
    Item binaryBytes changed
then
    var formatted = transform("EXEC","numfmt --to=iec-i --suffix=B --padding=7 %s", binaryBytes.state.toString )
    deximalBytes.sendCommand(formatted.toString ) 
end

I tried it in the item definition and got this so far, using the exec transform with the value in the exec call produces the right output

String deximalBytes "Memory  [EXEC(numfmt --to=iec-i --suffix=B --padding=7 10010100):%s]"

But I don’t know how to set the value of deximalBytes as argument for the transformation.

String deximalBytes "Memory  [EXEC(numfmt --to=iec-i --suffix=B --padding=7 %s):%s]"

It produces this errors

[WARN ] [.ui.internal.items.ItemUIRegistryImpl] - Exception while formatting value '10010100' of item deximalBytes with format 'EXEC(numfmt --to=iec-i --suffix=B --padding=7 %s):%s': {}
java.util.MissingFormatArgumentException: Format specifier '%s'
        at java.util.Formatter.format(Formatter.java:2519) [?:?]
        at java.util.Formatter.format(Formatter.java:2455) [?:?]
        at java.lang.String.format(String.java:2940) [?:?]
        at org.eclipse.smarthome.core.library.types.StringType.format(StringType.java:55) [109:org.eclipse.smarthome.core:0.10.0.b1]
        at org.eclipse.smarthome.ui.internal.items.ItemUIRegistryImpl.getLabel(ItemUIRegistryImpl.java:372) [155:org.eclipse.smarthome.ui:0.10.0.b1]
        at org.eclipse.smarthome.ui.basic.internal.render.AbstractWidgetRenderer.preprocessSnippet(AbstractWidgetRenderer.java:118) [196:org.eclipse.smarthome.ui.basic:0.10.0.b1]
        at org.eclipse.smarthome.ui.basic.internal.render.TextRenderer.renderWidget(TextRenderer.java:42) [196:org.eclipse.smarthome.ui.basic:0.10.0.b1]
        at org.eclipse.smarthome.ui.basic.internal.render.PageRenderer.renderWidget(PageRenderer.java:172) [196:org.eclipse.smarthome.ui.basic:0.10.0.b1]
        at org.eclipse.smarthome.ui.basic.internal.render.PageRenderer.processChildren(PageRenderer.java:137) [196:org.eclipse.smarthome.ui.basic:0.10.0.b1]
        at org.eclipse.smarthome.ui.basic.internal.render.PageRenderer.processChildren(PageRenderer.java:158) [196:org.eclipse.smarthome.ui.basic:0.10.0.b1]
        at org.eclipse.smarthome.ui.basic.internal.render.PageRenderer.processPage(PageRenderer.java:100) [196:org.eclipse.smarthome.ui.basic:0.10.0.b1]
        at org.eclipse.smarthome.ui.basic.internal.servlet.WebAppServlet.service(WebAppServlet.java:159) [196:org.eclipse.smarthome.ui.basic:0.10.0.b1]
        at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:848) [88:org.eclipse.jetty.servlet:9.3.22.v20171030]
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:584) [88:org.eclipse.jetty.servlet:9.3.22.v20171030]
        at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) [191:org.ops4j.pax.web.pax-web-jetty:6.0.7]
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) [87:org.eclipse.jetty.server:9.3.22.v20171030]
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548) [85:org.eclipse.jetty.security:9.3.22.v20171030]
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226) [87:org.eclipse.jetty.server:9.3.22.v20171030]
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1180) [87:org.eclipse.jetty.server:9.3.22.v20171030]
        at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:284) [191:org.ops4j.pax.web.pax-web-jetty:6.0.7]
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:512) [88:org.eclipse.jetty.servlet:9.3.22.v20171030]
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185) [87:org.eclipse.jetty.server:9.3.22.v20171030]
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1112) [87:org.eclipse.jetty.server:9.3.22.v20171030]
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [87:org.eclipse.jetty.server:9.3.22.v20171030]
        at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80) [191:org.ops4j.pax.web.pax-web-jetty:6.0.7]
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134) [87:org.eclipse.jetty.server:9.3.22.v20171030]
        at org.eclipse.jetty.server.Server.handle(Server.java:534) [87:org.eclipse.jetty.server:9.3.22.v20171030]
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:333) [87:org.eclipse.jetty.server:9.3.22.v20171030]
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251) [87:org.eclipse.jetty.server:9.3.22.v20171030]
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:283) [79:org.eclipse.jetty.io:9.3.22.v20171030]
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:108) [79:org.eclipse.jetty.io:9.3.22.v20171030]
        at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93) [79:org.eclipse.jetty.io:9.3.22.v20171030]
        at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.executeProduceConsume(ExecuteProduceConsume.java:303) [90:org.eclipse.jetty.util:9.3.22.v20171030]
        at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:148) [90:org.eclipse.jetty.util:9.3.22.v20171030]
        at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:136) [90:org.eclipse.jetty.util:9.3.22.v20171030]
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:671) [90:org.eclipse.jetty.util:9.3.22.v20171030]
        at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:589) [90:org.eclipse.jetty.util:9.3.22.v20171030]
        at java.lang.Thread.run(Thread.java:745) [?:?]

Anyone an idea, @rlkoshak? As it is almost possible only getting the argument to the EXEC transformation is not working!

Thanks. I had considered using javascript if I can’t get exec to work. There are probably a lot of corner cases that make using a well tested util like numfmt advantageous. However, since I can’t seem to get that to work as a label transformation I may have to take the javascript approach.

@broconne and @rlkoshak

I got it working

String deximalBytes "Memory  [EXEC(numfmt --to=iec-i --suffix=B --padding=7 %s):]"

Honestly I’m pretty weak with the Exec binding and before this thread I never even realized there was such a thing as the Exec Transform. It seems very odd to me though that it works just fine in the Rule but the identical (functionally identical) config won’t work in the Item label. The only thing that I can think of off the top of my head is the transform is chocking on deximalBytes being NULL.

But the error seems to point to a problem with the format of the stuff in the parens. So I’m at a loss.

Fantastic! It makes no sense to me that it would work that way but I’m glad it worked. Would you be willing to write an issue and contribute it to the README for the Exec transform?

The README.md file is the one that needs to be updated I’m 99% certain.

A couple sentences of explanation that the example is using numfmt to parse a binary number and this example is probably all that would be needed. It would certainly be a huge improvement.

@rlkoshak https://github.com/eclipse/smarthome/pull/4896

1 Like

Correct syntax should be following.

String deximalBytes “Memory [EXEC(numfmt --to=iec-i --suffix=B --padding=7 %s):%s]”

If that doesn’t work, I think it’s a bug. Most probably reason is that %s have special meaning in both exec transformation and in the label.

Thanks for all the help. It is working perfectly using @Josar’s example above.