Camera: Live MJPEG view with a MP4 Recording History

This widget allows you to view your live camera with the more compatible MJPEG format for the live stream, and when a MP4 recording is made via the ipCamera binding, it will allow the folder icon to be clicked to show the recordings to be reviewed. Useful to show the number of people that have rung your doorbell, or driven up your driveway allowing a quick review of the recordings.

MJPEG has low latency and good compatibility with browsers.
There is a HLS version of this widget that will give higher resolution at the expense of latency and less compatible.

Once you have seen all the recordings, you can click on the “X” button to clear the counter which will NOT delete the recordings. The X just resets the number of how many recordings that have been made since you last reviewed and cleared the counter. The video camera icon returns you to the live view. You can enter full screen mode if the recording contains something of interest.

widget

Setup

To get this widget working you MUST name your items with the default naming that occurs when you use the OH3 feature “Add equipment to model” from the things channel page (found at very bottom of page). If you manually create items, then the following items will need to be named as follows and linked to the channels of the same name:

EquipmentName (this is the item you select in the widget’s setup)
EquipmentName_MP4_History
EquipmentName_MP4_History_Length

The Base Url config needs to be set to use your openHAB IP address and also be updated to include the cameras unique ID. This will look like this and will end with a /

http://192.168.1.2:8080/ipcamera/doorbell/

Resources

uid: CameraMjpegHistory
tags: []
props:
  parameters:
    - context: item
      label: Select the Camera (Equipment)
      name: camera
      required: true
      type: TEXT
    - description: "example: http://192.168.1.2:8080/ipcamera/CameraUniqueID/"
      label: Base URL
      name: cameraBaseURL
      required: true
      type: TEXT
    - description: "ON will use the lower bandwidth autofps.mjpeg stream otherwise ipcamera.mjpeg"
      label: Use Lower Bandwidth Stream
      name: lowerBandwidth
      required: true
      type: BOOLEAN
component: f7-card
config:
  key: "=(vars.selected === undefined) ? Math.random() : Math.random() + vars.selected"
  style:
    --f7-card-margin-horizontal: 0px
    --f7-card-margin-vertical: 0px
    border-radius: 6px
    height: 9.4rem
    width: 15.2rem
slots:
  default:
    - component: oh-video-card
      config:
        hideControls: false
        startManually: false
        url: =props.cameraBaseURL + items[props.camera + '_MP4_History'].state.split(",")[vars.selected] +".mp4"
        visible: =vars.archive == 2
    - component: oh-image-card
      config:
        style:
          border-radius: 6px
          height: auto
          margin: 0px
          width: 100%
        url: "=props.lowerBandwidth === true ? (props.cameraBaseURL + 'autofps.mjpeg') : (props.cameraBaseURL + 'ipcamera.mjpeg')"
        visible: =vars.archive != 2
    - component: f7-row
      config:
        class: no-gap
        style:
          position: absolute
          top: 0px
          width: 99%
          z-index: 2
      slots:
        default:
          - component: oh-button
            config:
              action: variable
              actionVariable: archive
              actionVariableValue: 2
              iconColor: white
              iconF7: folder
              iconSize: 28
              style:
                margin: -2px
              visible: "=(items[props.camera + '_MP4_History'].state !== NULL ? vars.archive !== 2 : false)"
              z-index: 2
          - component: Label
            config:
              style:
                color: white
                font-size: 9px
                left: 18px
                position: absolute
                top: 12px
                z-index: -1
              text: =items[props.camera+'_MP4_History_Length'].state
              visible: =vars.archive != 2 && items[props.camera+'_MP4_History_Length'].state > 0
          - component: Label
            config:
              style:
                color: white
                font-size: 9px
                left: 12px
                position: absolute
                top: 9px
                z-index: -1
              text: =(vars.selected+1)
              visible: =vars.archive == 2
          - component: oh-button
            config:
              action: variable
              actionVariable: archive
              actionVariableValue: 1
              iconColor: white
              iconF7: videocam
              iconSize: 28
              style:
                margin: -2px
              visible: =(vars.archive == 2)
          - component: oh-button
            config:
              action: variable
              actionVariable: selected
              actionVariableValue: =(items[props.camera +'_MP4_History_Length'].state-1)
              iconColor: white
              iconF7: backward_end
              iconSize: 28
              style:
                margin: -2px
              visible: =vars.archive == 2 && items[props.camera+'_MP4_History_Length'].state > 0
          - component: oh-button
            config:
              action: variable
              actionVariable: selected
              actionVariableValue: =(vars.selected+1 < items[props.camera +'_MP4_History_Length'].state)?(vars.selected+1):(items[props.camera +'_MP4_History_Length'].state-1)
              iconColor: white
              iconF7: arrowtriangle_left
              iconSize: 28
              style:
                margin: -2px
              visible: =vars.archive == 2 && items[props.camera+'_MP4_History_Length'].state > 0
          - component: oh-button
            config:
              action: variable
              actionVariable: selected
              actionVariableValue: =(vars.selected != 0)?(vars.selected-1):(0)
              iconColor: white
              iconF7: arrowtriangle_right
              iconSize: 28
              style:
                margin: -2px
              visible: =vars.archive == 2 && items[props.camera+'_MP4_History_Length'].state > 0
          - component: oh-button
            config:
              action: variable
              actionVariable: selected
              actionVariableValue: 0
              iconColor: white
              iconF7: forward_end
              iconSize: 28
              style:
                margin: -2px
              visible: =vars.archive == 2 && items[props.camera+'_MP4_History_Length'].state > 0
          - component: oh-button
            config:
              action: toggle
              actionCommand: "0"
              actionItem: =props.camera+'_MP4_History_Length'
              iconColor: white
              iconF7: clear
              iconSize: 28
              style:
                margin: -2px
              tooltip: Clear cameras mp4 history
              visible: =vars.archive == 2 && items[props.camera+'_MP4_History_Length'].state > 0
1 Like

Just updated the widget to work with the newer item naming structure as follows when you create equipment from a thing.
Items names need to be like this…
EquipmentName (this is the item you select in the widget’s setup)
EquipmentName_MP4_History
EquipmentName_MP4_History_Length