OH Image Item Saving to a file location

Does anybody have code to save an OH Image Item [raw type (image/jpeg)] to the file system?

The image is viewable via the OH GUI interface at the item level.

I’m trying to send images either via sendmail or pushover but it needs paths vs. an item that is an image.

Best, Jay

Notification supports sending an image from an item

actions.notificationBuilder("Image“)
    .withMediaAttachmentUrl('item:ImageItem')
    .send();

In case your image comes from a camera in the first place and you need to save it on your server I would run executeCommand and wget (or curl).

Thanks! but I’m using pure DSL, not JavaScript. Any help in that would be great!

Best, Jay

rule "Speichere Kamerabild auf Filesystem"
when
    Item Camera_Image changed
then
    if (openHABServer_Item_wetter_Image.state === NULL) {
        logWarn("image", "Kein Bild im Item")
        return
    }

    val raw = openHABServer_Item_wetter_Image.state as org.openhab.core.library.types.RawType
    val bytes = raw.getBytes()

    val path = "/etc/openhab/rules/camera_latest.jpg"

    java.nio.file.Files::write(
        java.nio.file.Paths::get(path),
        bytes
    )

    logInfo("image", "Bild gespeichert: {}", path)
end

Thank you @Bloodboy! I took your example and blew it out a bit and used GROK to help me. This is a working example of it taking an array of cameras with pushover.

rule "Take RING Pictures of All Cameras"
	when 
		Item RING_Picture_Switch changed to ON
	then

		if (systemStarted.state != ON && OH_Uptime_HumanReadable.state != NULL && OH_Uptime_HumanReadable.state != UNDEF) {

			var PushOverBinding = getThingStatusInfo(zPushOverBinding)
			val pushOverActions = getActions("pushover",zPushOverBinding) 
			val PushOverTitle   = "Ring Cameras"
			val PushOverMessage = "Snapshot attached (one notification per camera)"	
			var ring_images = null

			if (RingDoorbellSnapShot.state == NULL || RingDoorbellSnapShot.state == UNDEF) {
			
				ring_images = newArrayList("RingPatioDoorbellSnapShot", "RingGarageDoorbellSnapShot")
			}
			
			if (RingPatioDoorbellSnapShot.state == NULL || RingPatioDoorbellSnapShot.state == UNDEF) {
			
				ring_images = newArrayList("RingDoorbellSnapShot", "RingGarageDoorbellSnapShot")
			}
			
			if (RingGarageDoorbellSnapShot.state == NULL || RingGarageDoorbellSnapShot.state == UNDEF) {
			
				ring_images = newArrayList("RingDoorbellSnapShot", "RingPatioDoorbellSnapShot")
			}			
			
			if (RingDoorbellSnapShot.state != NULL && RingDoorbellSnapShot.state != UNDEF && RingGarageDoorbellSnapShot.state != NULL && RingGarageDoorbellSnapShot.state != UNDEF && RingPatioDoorbellSnapShot.state != NULL && RingPatioDoorbellSnapShot.state != UNDEF) {
			
				ring_images = newArrayList("RingDoorbellSnapShot", "RingPatioDoorbellSnapShot", "RingGarageDoorbellSnapShot")
			}				
			
			RING_Picture_Switch.postUpdate(OFF)
			
			if (ring_images === null) {
			
				logInfo("PUSHOVER","NO Ring Snapshots across all cameras are available to use.")
				return;
			}
					
			if ((PushOverBinding !== null) && (PushOverBinding.getStatus().toString() == 'ONLINE')) {

				ring_images.forEach[ GenericItem itemName |

					val item = org.openhab.core.model.script.ScriptServiceUtil.getItemRegistry.getItem(itemName)
					
					if (item === null) {
					
						logError("PUSHOVER","Ring Snapshot Item '" + itemName + "' not found - skipping")
						return;
					}

					val state = item.state
					if (state === NULL || state === UNDEF) {
					
						logWarn("PUSHOVER", "Item " + itemName + " has no valid state - skipping")
						return;
					}

					if (!(state instanceof org.openhab.core.library.types.RawType)) {
					
						logError("PUSHOVER", "Ring Snapshot Item " + itemName + " is not an Image/RawType item (state type: " + state.getClass.getSimpleName + ") - skipping")
						return;
					}

					val raw = state as org.openhab.core.library.types.RawType
					val bytes = raw.bytes 

					val path = "/var/lib/openhab/pics/" + itemName + ".jpg"

					try {
							java.nio.file.Files::write(java.nio.file.Paths::get(path), bytes)
							logInfo("PUSHOVER", "Ring Snapshot Wrote snapshot: " + path)
							
						} catch (Exception e) {
							
							logInfo("LINE","-----------------------------------------------------------------------------")
							logError("ERROR","Ring Snapshot File write failed for " + itemName + ": " + e.getMessage)
							logInfo("LINE","-----------------------------------------------------------------------------")
							return;
						}
					
						Thread::sleep(500)

					pushOverActions.sendAttachmentMessage(PushOverMessage, PushOverTitle, path, PushOverMIME)
					logInfo("PUSHOVER", PushOverMessage)

						Thread::sleep(1500)
				]			
			}			
		}
end

Best, Jay

As this is openHAB 5.1 a new immutable ArrayList/List can be constructed with #["RingPatioDoorbellSnapShot", "RingGarageDoorbellSnapShot"] instead of newArrayList("RingPatioDoorbellSnapShot", "RingGarageDoorbellSnapShot").

In any case the items in the ring_images list are of type String, so in ring_images.forEach[ GenericItem itemName | instead of GenericItem should be used String. Skipping the type might also work. ItemRegistry.getItem(item) also accepts as parameter a String, not GenericItem.

Finally you can skip get and use small letter afterwards in e.getMessagee.message; ScriptServiceUtil.getItemRegistryScriptServiceUtil.itemRegistry; PushOverBinding.getStatus().toString()PushOverBinding.status.toString .

1 Like