Get image data from image item in script

I have an image item that gets an image from MQTT. I can see the image in the model. I’m trying to get this image data or image file in a rule ECMAScript-2021 script.

var item = item || items.getItem('MQTTEventItem_Image')
console.log(`Image: ${item.state}.`)

// Image: raw type (image/jpeg): 10458 bytes.

It is aware of certain things (mime type, image size), but I can’t figure out how to get them. I’ve tried the getMimeType() and toFullString() as documented here but they result in method not found errors.

How can I get the file or the binary contents so I can script further behavior?

(By the way, btoa() and atob() seem to be unavailable in openhab-js. This will probably be my next problem.)

Reviewing the JS Scripting reference docs shows that Item.state returns a String. You want the Item.rawState to access the original Java State Object. JavaScript Scripting - Automation | openHAB

You may have to import and use the Java Classes to do this.

1 Like

How could I have missed this? Awesome, thank you! :+1:

Can I send this binary data using HTTP.sendHttpPostRequest?

I’m trying to send the image data to Matrix/Synapse. I’m using the following command, and as long as the payload is an ASCII string, the upload itself works fine and the base64 string arrives at the server.

var headers = new Map()
headers.set('Content-Length', String(payload.length))

var result = HTTP.sendHttpPostRequest(apiUrl, mimeType, payload, headers, 3000)
console.log(result)

However, Synapse doesn’t recognize base64 encoded data. It wants binary data. How can I send binary data? I have tried the following:

  • Sending item.rawState.getBytes() as payload directly, both as is and escape()ed.

  • Getting the payload from the base64 string as below, sending it both directly and escape()ed:

var dataStr = item.rawState.toFullString().replace('data:image/jpeg;base64,', '')
var Base64 = Java.type('java.util.Base64')
var dec64 = Base64.getDecoder()
var payload = dec64.decode(dataStr)

I have created the following workaround. Not pretty, but sharing since I know of no native way and it may be useful to others.

var result = actions.Exec.executeCommandLine(
  Duration.ofSeconds(3), 
  '/bin/sh', '-c', 
  `echo "${dataStr}" | base64 -d | curl -s -H "Content-Type: ${mimeType}" -H "Content-Length: ${dataLen}" --data-binary @- "${apiUrl}"`)

I used a slightly different set of command line tools, but back when I was saving off images to file, I used executeCommandLine too to convert the Base64 to a binary png file.

I am trying to send an image received by mqtt via executeCommandLine script as attachment for a signal message (signal-cli) which needs the image converted to a string.
the “direct conversion” in a dsl rule from item to string seems to be very difficult
could you give me further information how you converted base64 to binary png. This might be the first step (first saving, then sending)
best regards

Well, @Redsandro showed how he did it above.

There are a number of other posts with solutions of various formats on the forum. Here’s one: Save image item's image to disk - #2 by albauer. Here’s another: OpenWeatherMap Icon - use as image in rule? - #2 by rlkoshak

According to the signal binding docs it seems to be possible to send base64 encoded pictures ( I believe in the background they are anyway converted to base64 ).
So something like:

rule "SendImageViaSignal"
when
        Item  MQTTImage changed
then
        var dataStr = MQTTImage.toFullString
        val signalAction = getActions("signal", "signal:signallinkedbridge:<youruidhere>")
        signalAction.sendSignalImage("+33123456789", dataStr)
end

should work.

thanks for your help
I use a script with signal-cli and the image is an item
the following rule works fine:

rule "snapshot"
when
	Item nvrAlarm changed
then
	if (newState == ON) {
		executeCommandLine("/etc/openhab/scripts/signal.sh", nvrSnapshot.state.toFullString)
	}
end