openhab / openhab-core

Core framework of openHAB
https://www.openhab.org/
Eclipse Public License 2.0
923 stars 424 forks source link

Cannot send Commands to Image item #2578

Open NickWaterton opened 2 years ago

NickWaterton commented 2 years ago

OH 3.2 (all versions)

Commands are unsupported for Items of Image type. Only State updates and Refresh commands are allowed.

This means that sendCommand(ImageItem, RawType), or in fact any Type fails.

This is a problem where a binding is being developed that takes images of RawType and sends them to a display Device.

Workaround is to use a String Item, convert the RawType to a String using RawType.toFullString() and detect in the binding that the string startsWith("data:image"), then convert back to RawType using Rawtype.valueOf().

There is no reason that I can see for this limitation.

Expected result: sendCommand(ImageItem, RawType) binding channel connected to item receives command of type RawType

Actual result: Error:

Cannot convert 'data:image/png;base64,iVBORw0KGgoAAAAAElFTkSuQmCC' to a command type which item 'TV_ArtImage' accepts: [RefreshType].
kaikreuzer commented 2 years ago

An image is not a command, how should it be interpreted? The current behavior is absolutely correct.

What you want to have is an item, where the state is not managed by your physical device (the display), but by openHAB (or some other device that updates the state of the openHAB item). You therefore have the "follow" case, where the direction is inverted and hence you should apply the follow profile to your link. When this is done, any state update is sent to the handleCommand() method of your thing hander. See also https://github.com/openhab/openhab-core/pull/1669.

NickWaterton commented 2 years ago

An image is not a command, how should it be interpreted?

The same way a String is when sent to a String Item.

If an Image is not a command, then neither is a String. This is logically inconsistent.

In this case an image sent to an Image Item would be interpreted as an Image, either StringType or RawType.

The binding would then handle the received image - or reject it as not an image. It could interpret it as a URL (String), or an Image (RawType) - it would be up to the binding to decide.

You can postUpdate to an Image Item, as a String, which updates the displayed image - but you can’t sendCommand as a String.

So how is postUpdate(String) valid but sendCommand(String) isn’t?

Right now, the only way to send an Image to my binding is to send a base64 encoded jpg to a String Item. If you think that makes more sense than sending a jpg as a RawType to an Image item, well Ok, but it doesn’t seem correct to me.

I have an Image item that shows what is currently on my TV (controlled by my binding). The hope was that sending a jpg/png to the Image Item would be able to update the TV screen. Seeing as that isn’t supported, I have to have another String item and channel to send images to.

I’ll try the follow profile, see if that works on an Image channel.

Thanks for the quick response.

NickWaterton commented 2 years ago

I tried the "follow" profile, when I postUpdate the channel I get the this error:

2021-11-26 09:34:33.913 [DEBUG] [.openhab.core.io.rest.SseBroadcaster] - Sending event to sink failed
org.eclipse.jetty.io.EofException: Closed
        at org.eclipse.jetty.server.HttpOutput.checkWritable(HttpOutput.java:768) ~[bundleFile:9.4.40.v20210413]
        at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:792) ~[bundleFile:9.4.40.v20210413]
        at java.io.OutputStream.write(OutputStream.java:122) ~[?:?]
        at org.apache.cxf.jaxrs.sse.OutboundSseEventBodyWriter.writeTo(OutboundSseEventBodyWriter.java:113) ~[bundleFile:3.4.3]
        at org.apache.cxf.jaxrs.sse.OutboundSseEventBodyWriter.writeTo(OutboundSseEventBodyWriter.java:40) ~[bundleFile:3.4.3]
        at org.apache.cxf.jaxrs.sse.SseEventSinkImpl.dequeue(SseEventSinkImpl.java:238) ~[bundleFile:3.4.3]
        at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1520) [bundleFile:9.4.40.v20210413]
        at org.eclipse.jetty.server.AsyncContextState$1.run(AsyncContextState.java:153) [bundleFile:9.4.40.v20210413]
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:882) [bundleFile:9.4.40.v20210413]
        at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1036) [bundleFile:9.4.40.v20210413]
        at java.lang.Thread.run(Thread.java:829) [?:?]

So it seems there is no way to get a command sent to an Image channel.

Rossko57 commented 2 years ago

Comment: Contact type Items also accept no commands. It's regarded as a sensor, not an actuator.

You should be able to send the special REFRESH command, even to an Image Item, but that's no help here.

Further comment; The KNX binding for an example, has xxx-control type channels, these "listen" for the linked Item to update and act on that to transmit externally (including Contact types). Just what you want. I just had a quick look, and that is achieved by using the system follow profile as already suggested. Maybe that needs enhancing to deal with Image type states.

J-N-K commented 2 years ago

@kaikreuzer Using the system follow profile is not working for RawType, because RawType does not implement Command and the code in the SystemFollowProfile is

    @Override
    public void onStateUpdateFromItem(State state) {
        if (!(state instanceof Command)) {
            logger.debug("The given state {} could not be transformed to a command", state);
            return;
        }
        Command command = (Command) state;
        callback.handleCommand(command);
    }

Therefore it is not possible ATM to output RawType to an external system via a thing.

Rossko57 commented 2 years ago

because RawType does not implement Command

Does that imply that command REFRESH would not work for this Item type, either? That sounds like a useful future enhancement.

dalgwen commented 1 year ago

Hello,

I'd like to back this request. I made a Signal binding, and it can work with an item : when it receives a command, it sends the text as a message to a phone.

I can also send image with an action (btw, telegram is doing the same). But I would like to add an image channel on the same principle as the text one.

It could be used with the follow profile, as suggested. Workflow example :

So, is it as simple as implementing the Command interface into RawType ? Will we have unwanted side effect, with a structural modification like this ? I can test and make a PR, but I'd like to check with you if this is OK before.