Camera: Clickable thumbnail opens to a larger stream

Works for me here on the Android app on a Samsung tablet.

@matt1 are you just using the clickable widget on a page? its works fine in the browser but in the android app it just shows a grey box and no snapshot.

Thanks

Yes a layout page with the widget is workig for me. If may be a browser support issue, I donā€™t know that area and how the apps work.

I have the same issue with web frames not working in the app. Everything is ok in a browser but in the app the page inside the frame doesnā€™t load which s annoying as i want to run a web based keypad for my intruder alarm in this.

Existing issue:
Video not played if HTTP URL is used for video and HTTPS is used to connect to server

Videos on the local "https:// localserver:8443 do not work. If this is changed to http:// localserver:8080, it works.

Added more features to the widget in the first post and added it to the marketplace.

1 Like

Hi all,
It work for me:

        - component: widget:ClickableCameraImage
          config:
            streamURL: http://192.168.1.50:8048/snapshots.mjpeg
            showSettings: true
            showAlarms: true
            thumbnailURL: http://192.168.1.50:8048/ipcamera.jpg
            camera: FoscamCamera
            switchItem: FoscamCamera_EnableMotionAlarm

But if i use the android app on the local LAN, when I try the OH3 UI android app, I dinĀ“t get any video.

On the other hand, if I try the old Basic UI, with the same URL on the sitemap scrip, IĀ“m able to get the video:

	    Text label="Camaras" icon="camera"
	    {
            Video url="http://192.168.1.50:8048/snapshots.mjpeg" encoding="mjpeg"
            //Image icon="camera" item=FoscamCamera_ImageURL url="http://192.168.1.50:8048/ipcamera.jpg" refresh=5000
            Default	item=FoscamCamera_EnableMotionAlarm	label="Habilitacion Alarma Deteccion Movimiento" 	valuecolor=[ON="red",OFF="green"]
    	    Default	item=FoscamCamera_MotionAlarm 		label="Deteccion Movimiento"	valuecolor=[ON="red",OFF="green"]
	        Switch 	item=FoscamCamera_AutoLED 	        label="AutoControl Infrared LED"
		    Switch 	item=FoscamCamera_LEDControls	    label="Habilitacion Infrared LED"  
        }

any thougths?

See the above posts which are all similar to yours, it works on my Samsung tablet with the app so it is probably a browser issue needing something updated or installed. Best to raise an issue on github against the app since it appears that web frames are also doing the same thing reported above.

@matt1
I just started with the MainUI as a means to power my wall tablets, so sorry for the very basic question:
I do only want to display camera snapshots, no videos. How can I increase the size of the snapshot image that is displayed with the widget? thanks.

Edit the widget code using the developers tools when logged in as a admin. Change the height and width settings which is just css code which you can use screen size in % or pixels as per here

Hello everybody :slight_smile:
I wonder if anyone has already managed to enable this widget with zoneminder bindign?
I will be very happy for any hint :slight_smile:

It should work just fine if you supply it with URLS from zoneminder. However be aware of this issue that may be causing headachesā€¦

Display streams and snapshots from ipcamera binding in oh-image - Add-ons / UIs - openHAB Community

In openhab.log iā€™m getting this warning all the time I view the widget:

[e.internal.SseItemStatesEventBuilder] - Attempting to send a state update of an item which doesn't exist: MyCam_AudioAlarm

I didnā€™t configure an item for the audio alarm, because the camera is outside and with wind it doesnā€™t have any use. How can I disable this message without adding an AudioAlarm item?

uninstall and re add the widget as I just updated it to have show and hide of both the alarms separately. If you dont have the item created, just donā€™t tick the show alarm box and the message in the logs now wont appear.

Modified the widget for my doorphone. The first widget is for static image or moving MJEPG image. Second widget popups screenwide and can handle HLS stream for better quality.

uid: ClickablePTZCamera
tags:
  - video
props:
  parameters:
    - context: item
      label: Camera image URL
      name: camerajpeg
      required: true
      type: TEXT
    - context: item
      label: Camera stream URL
      name: camerahls
      required: false
      type: TEXT
    - context: item
      label: Motion item
      name: motionItem
      required: false
      type: TEXT
    - context: item
      label: Item for the door lock
      name: lockItem
      required: false
      type: TEXT
    - context: item
      label: Item for door state
      name: doorItem
      required: false
      type: TEXT
timestamp: Jul 30, 2022, 12:05:43 AM
component: f7-card
config:
  style:
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 10px 1px var(--f7-bars-bg-color)
    color: var(--f7-text-color)
    max-height: 150px
    font-size: medium
    font-weight: 500
    noShadow: false
slots:
  default:
    - component: oh-image
      config:
        action: popover
        actionModal: widget:Video
        actionModalConfig:
          camerahls: =props.camerahls
          motionItem: =props.motionItem
          lockItem: =props.lockItem
          doorItem: =props.doorItem
        item: =[props.camerajpeg]
        lazy: false
        style:
          border-radius: var(--f7-card-expandable-border-radius)
          margin: 0px
          padding: 0px
          height: 150px
          width: 100%
          z-index: -2
    - component: f7-row
      config:
        style:
          position: absolute
          top: 2px
          width: 99%
          z-index: 30
      slots:
        default:
          - component: oh-icon
            config:
              icon: "=(items[props.doorItem].state === 'ON') ? 'door-closed' : 'door'"
              style:
                color: "=(items[props.doorItem].state === 'ON') ? 'cyan' : 'red'"
                z-index: 99
              visible: =props.doorItem !== undefined
              width: 22
          - component: oh-button
            config:
              action: command
              actionCommand: ON
              actionItem: =props.lockItem
              class: card-prevent-open
              iconF7: "=(items[props.lockItem].state === 'ON') ? 'lock_open' : 'lock'"
              style:
                margin-left: auto
                margin-right: auto
                color: "=(items[props.lockItem].state === 'ON') ? 'cyan' : 'var(--f7-card-header-text-color)'"
                z-index: 99
              visible: =props.lockItem !== undefined
              iconSize: 23
          - component: oh-icon
            config:
              icon: "=(items[props.motionItem].state === 'ON') ? 'mymotion-on' : 'mymotion-off'"
              style:
                z-index: 99
              visible: =props.motionItem !== undefined
              width: 23

uid: Video
tags:
  - video
props:
  parameters:
    - context: item
      label: Camera stream URL
      name: camerahls
      required: false
      type: TEXT
    - context: item
      label: Motion item
      name: motionItem
      required: false
      type: TEXT
    - context: item
      label: Item for the door lock
      name: lockItem
      required: false
      type: TEXT
    - context: item
      label: Item for door state
      name: doorItem
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Jul 30, 2022, 12:07:00 AM
component: f7-card
config:
  class: no-margin
  style:
    --f7-card-margin-horizontal: 0px
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 10px 1px var(--f7-bars-bg-color)
    color: var(--f7-text-color)
    font-size: medium
    font-weight: 500
    height: 100%
    margin: 5
    noShadow: false
    padding: 0
    text-shadow: 1px 0px 2px var(--f7-bars-bg-color), -1px 0px 2px var(--f7-bars-bg-color), 0px 0px 2px var(--f7-bars-bg-color), 0px 0px 3px var(--f7-bars-bg-color)
    width: 100%
slots:
  default:
    - component: oh-video-card
      config:
        hideControls: false
        item: =props.camerahls
        startManually: false
        style:
          height: 90%
    - component: f7-row
      config:
        style:
          position: absolute
          top: 10px
          width: 99%
          z-index: 30
      slots:
        default:
          - component: oh-icon
            config:
              icon: "=(items[props.doorItem].state === 'ON') ? 'door-closed' : 'door'"
              style:
                color: "=(items[props.doorItem].state === 'ON') ? 'cyan' : 'red'"
                z-index: 99
              visible: =props.doorItem !== undefined
              width: 30
          - component: oh-button
            config:
              action: command
              actionCommand: ON
              actionItem: =props.lockItem
              class: card-prevent-open
              iconF7: "=(items[props.lockItem].state === 'ON') ? 'lock_open' : 'lock'"
              style:
                margin-left: auto
                margin-right: auto
                color: "=(items[props.lockItem].state === 'ON') ? 'cyan' : 'var(--f7-card-header-text-color)'"
                z-index: 99
              visible: =props.lockItem !== undefined
              iconSize: 30
          - component: oh-icon
            config:
              icon: "=(items[props.motionItem].state === 'ON') ? 'mymotion-on' : 'mymotion-off'"
              style:
                z-index: 99
              visible: =props.motionItem !== undefined
              width: 30

1 Like

If your using a static image, you can get it to auto refresh with thisā€¦
oh-image - Image | openHAB

Also your first widget requires the second one to be created before the first one will work. Thanks for sharing how to get HLS working.

Hope together we will come someday to an universal widget, opening all cameras possibilities.

I have to call @JustinG for some magic. Trying to get ipcamera video record history widget working and a bit tired to figure out rather simple logic, so rewind and forward buttons donā€™t work.
MP4 history length contains a number of yet unrecorded mp4 file like if Domofon1.mp4 is present MP4 history length will be = 2. What Iā€™m trying is to switch played file name, to enable widget user to browse through record history.

uid: videoArchive
tags:
  - videoArchive
props:
  parameters:
    - context: item
      description: Ipcamera MP4 history length item
      label: MP4 history length
      name: history
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Aug 9, 2022, 1:24:35 AM
component: f7-card
config:
  class: no-margin
  style:
    --f7-card-margin-horizontal: 0px
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 10px 1px var(--f7-bars-bg-color)
    color: var(--f7-text-color)
    font-size: medium
    font-weight: 500
    height: auto
    margin: 5
    noShadow: false
    padding: 0
    text-shadow: 1px 0px 2px var(--f7-bars-bg-color), -1px 0px 2px var(--f7-bars-bg-color), 0px 0px 2px var(--f7-bars-bg-color), 0px 0px 3px var(--f7-bars-bg-color)
    width: 100%
slots:
  default:
    - component: oh-video-card
      config:
        hideControls: false
        url: '= vars.rewind != NULL ? "http://192.168.2.9:8080/static/doorphone/Domofon" + vars.rewind + ".mp4" : "http://192.168.2.9:8080/static/doorphone/Domofon" + (items[props.history].state -1) + ".mp4"'
        type: video/mp4
        startManually: false
        style:
          height: auto
          width: auto
    - component: f7-row
      config:
        style:
          position: absolute
          top: 10px
          width: 99%
          z-index: 30
      slots:
        default:
          - component: oh-button
            config:
              action: variable
              actionVariable: rewind
              actionVariableValue: '=(vars.rewind > 1 || rewind == NULL) ? (items[props.history].state - 1) : 1'
              iconColor: white
              iconF7: backward_end
              iconSize: 30
          - component: oh-button
            config:
              action: variable
              actionVariable: rewind
              actionVariableValue: '=vars.rewind < (items[props.history].state -1) ? (items[props.history].state + 1) : (items[props.history].state + 1)'
              iconColor: white
              iconF7: forward_end
              iconSize: 30

And I cannot close this widget popovered by button

          - component: oh-button
            config:
              iconColor: white
              iconF7: clear
              iconSize: 30
              popoverClose: widget:Video

The widget itself disappears from the screen, but still remains somehow active and itā€™s path is still in the address field of browser, so iā€™m getting an error if I reload openhabā€™s page.
And maybe itā€™s better to use actionPhotos for history widget, but I canā€™t even imagine how to dynamically form inside a widget itā€™s array of video URLs to get

  actionPhotos:
    - html: <video src="http://192.168.2.9:8080/static/doorphone/Domofon" + (items[props.history].state -1) + ".mp4"></video>
    - html: <video src="http://192.168.2.9:8080/static/doorphone/Domofon" + (items[props.history].state -2) + ".mp4"></video>
    - html: <video src="http://192.168.2.9:8080/static/doorphone/Domofon" + (items[props.history].state -3) + ".mp4"></video>

I see a few things going on here:

In the javascript-like expressions in the widget you rarely have to explicitly test if a variable is empty or undefined because both of these states are interpreted as false values and any existing state is interpreted as a true value. Just in case you ever do come across one of the situations where it is better to explicitly test if something exists, in these expressions it would be

vars.rewind === undefined

Also, instead of duplicating all the url, you can put the ternary expression right in the middle where you need the change. So this line can work better and be simplified to:

url: = "http://192.168.2.9:8080/static/doorphone/Domofon" + ((vars.rewind)?(vars.rewind):(items[props.history].state -1)) + ".mp4"

But I would take it even one step further. Because of the way or expressions are evaluated, you can use an even more convenient shortcut for using a default value if a variable doesnā€™t exist. The or expression will fully evaluate the first condition and if that condition is true it will return that value, only if the first condition is false does it both to evaluate the second condition. If the second condition is true it returns the second conditions value. That gives us:

url: = "http://192.168.2.9:8080/static/doorphone/Domofon" + (vars.rewind || items[props.history].state -1) + ".mp4"

Some of the same issue here (plus you forgot the vars in front of the rewind in the second condition):

But, more than that, 1) you donā€™t want to change the variable to the item state minus 1, you want to decrement the variable itself and 2) while it is probably best practice to test if vars.rewind exists before checking if it is greater than one, itā€™s not really necessary; ( vars.rewind > 1) will still be false if vars.rewind doesnā€™t exist . So formally this could look like:

actionVariableValue: =( vars.rewind && vars.rewind > 1 )?(vars.rewind - 1):1

But you could also reduce it to this:

actionVariableValue: =( vars.rewind > 1 )?(vars.rewind - 1):1

The main problem here:

appears to be that you have the same value for both the true result and the false result. This stems from the same issue as above (most of the time you want the new variable value to be based old variable value).

actionVariableValue: =( vars.rewind < (items[props.history].state -1))?(vars.rewind + 1):(items[props.history].state - 1)

The popoverClose property comes directly from the f7 base component, not the OH features overlaid on top. This means that this property doesnā€™t understand OH specific things such as widget or page IDs. If you are going to use this property then you have to set the value to a css selector that uniquely identifies your popver. Most of the time I do this just by adding a non-standard class name to the widget:

component: f7-card
config:
  class:
    - no-margin
    - video_history_popup

Then the appropriate css selector would look like this:

popoverClose: .popover.video_history_popup

I have to agree that this is probably not feasible at the moment (wellā€¦sufficiently non-trivial to probably not be worth it).

1 Like

Thanks, this one: actionVariableValue: =( vars.rewind > 1 )?(vars.rewind - 1):1 is genius. And with much more clear brains today iā€™ve seen my mistakes. Almost did it, but a rather big issue still remains - the video is not loading when i popup the widget until two switches from live to archive. And used all kind of css sizes, but still canā€™t fit the entire video into page - a small part in bottom is hidden and shows up only in fullscreen mode.

uid: Video
tags:
  - video
props:
  parameters:
    - context: item
      label: Camera stream URL
      name: camerahls
      required: false
      type: TEXT
    - context: item
      label: Motion item
      name: motionItem
      required: false
      type: TEXT
    - context: item
      label: Item for the door lock
      name: lockItem
      required: false
      type: TEXT
    - context: item
      label: Item for door state
      name: doorItem
      required: false
      type: TEXT
    - context: item
      description: Ipcamera MP4 history length item
      label: MP4 history length
      name: history
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Aug 10, 2022, 2:56:17 AM
component: f7-card
config:
  class: videoPopover
  key: '=(vars.rewind === undefined) ? Math.random() : Math.random() + vars.rewind'
  style:
    --f7-card-margin-horizontal: 0px
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 10px 1px var(--f7-bars-bg-color)
    color: var(--f7-text-color)
    font-size: medium
    font-weight: 500
    height: auto
    margin: 5
    noShadow: false
    padding: 0
    text-shadow: 1px 0px 2px var(--f7-bars-bg-color), -1px 0px 2px var(--f7-bars-bg-color), 0px 0px 2px var(--f7-bars-bg-color), 0px 0px 3px var(--f7-bars-bg-color)
    width: 100%
slots:
  default:
    - component: oh-video-card
      config:
        hideControls: false
        startManually: false
        style:
          height: auto
          width: auto
        url: =items[props.camerahls].state
        visible: =vars.archive != 2
    - component: oh-video-card
      config:
        hideControls: false
        startManually: false
        style:
          height: auto
          width: auto
        url: ="http://192.168.2.9:8080/static/doorphone/Domofon" + (vars.rewind || items[props.history].state -1) + ".mp4"
        visible: =vars.archive == 2
    - component: f7-row
      config:
        style:
          position: absolute
          top: 10px
          width: 99%
          z-index: 30
      slots:
        default:
          - component: oh-button
            config:
              action: variable
              actionVariable: archive
              actionVariableValue: 2
              iconColor: white
              iconF7: folder
              iconSize: 30
              visible: =(vars.archive !== 2)
          - component: oh-button
            config:
              action: variable
              actionVariable: archive
              actionVariableValue: 1
              iconColor: white
              iconF7: videocam
              iconSize: 30
              visible: =(vars.archive == 2)
          - component: oh-button
            config:
              action: variable
              actionVariable: rewind
              actionVariableValue: =(vars.rewind != undefined)?(( vars.rewind > 1 )?(vars.rewind - 1):1):(items[props.history].state -2)
              iconColor: white
              iconF7: backward_end
              iconSize: 30
              visible: =(vars.archive == 2)
          - component: oh-icon
            config:
              icon: "=(items[props.doorItem].state === 'ON') ? 'door-closed' : 'door'"
              style:
                color: "=(items[props.doorItem].state === 'ON') ? 'cyan' : 'red'"
                z-index: 99
              visible: =((props.doorItem !== undefined) && (vars.archive !== 2))
              width: 30
          - component: oh-button
            config:
              action: command
              actionCommand: ON
              actionItem: =props.lockItem
              class: card-prevent-open
              iconF7: "=(items[props.lockItem].state === 'ON') ? 'lock_open' : 'lock'"
              iconSize: 30
              style:
                color: "=(items[props.lockItem].state === 'ON') ? 'cyan' : 'var(--f7-card-header-text-color)'"
                margin-left: auto
                margin-right: auto
                z-index: 99
              visible: =((props.lockItem !== undefined) && (vars.archive !== 2))
          - component: oh-icon
            config:
              icon: "=(items[props.motionItem].state === 'ON') ? 'mymotion-on' : 'mymotion-off'"
              style:
                z-index: 99
              visible: =((props.motionItem !== undefined) && (vars.archive !== 2))
              width: 30
          - component: oh-button
            config:
              action: variable
              actionVariable: rewind
              actionVariableValue: =( vars.rewind < items[props.history].state - 1)?(vars.rewind + 1):(items[props.history].state - 1)
              iconColor: white
              iconF7: forward_end
              iconSize: 30
              visible: =(vars.archive == 2)
          - component: oh-button
            config:
              iconColor: white
              iconF7: clear
              iconSize: 30
              popoverClose: .videoPopover
              style:
                z-index: 99
              tooltip: Š—Š°Šŗрыть