This widget allows you to view your live IP camera with JPG snapshots that refresh every second (configurable), then when clicked it will open up to a larger stream of the camera. When any MP4 recordings are made via the ipCamera binding, it will allow the folder icon to be clicked to show the recordings to be reviewed. 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. You need to be logged in as an administrator to see the X.
The video camera icon returns you to the live view. You can enter full screen mode if the live view or the recording contains something of interest.
To get this widget working you MUST name your items with the default naming that occurs when you use the 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_HLS_URL
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/19216813/
The better way is to use relative URLs so it works via http and https like…
/ipcamera/19216813/
Resources
uid: ClickableJpgWithHistory
props:
parameters:
- description: "example: http://192.168.1.2:8080/ipcamera/CameraUniqueID/"
label: Base URL /ipcamera/CameraUniqueID/
name: cameraBaseURL
required: true
type: TEXT
- description: /ipcamera/CameraUniqueID/ipcamera.mjpeg
label: Stream URL (Relative or Absolute)
name: streamURL
required: true
type: TEXT
- context: item
label: Select the Camera (Equipment)
name: camera
required: true
type: TEXT
- context: item
label: Item to Switch
name: switchItem
required: false
type: TEXT
advanced: true
- default: "1000"
description: The refresh rate of the thumbnail image
label: Refresh rate ms
name: refreshRate
required: false
type: INTEGER
min: 1000
max: 100000
advanced: true
- default: "true"
label: Show Equipment Controls
name: showSettings
required: false
type: BOOLEAN
advanced: true
- default: "false"
label: Show Audio Alarms
name: showAudioAlarms
required: false
type: BOOLEAN
advanced: true
- default: "true"
label: Show Motion Alarms
name: showMotionAlarms
required: false
type: BOOLEAN
advanced: true
- default: "true"
label: Show Recording Icon
name: showRecording
required: false
type: BOOLEAN
advanced: true
parameterGroups: []
timestamp: Mar 10, 2025, 4:55:42 PM
component: f7-card
config:
key: "=(vars.selected === undefined) ? Math.random() : Math.random() +
vars.selected"
style:
--f7-card-margin-horizontal: 0px
height: 9rem
width: 16rem
slots:
default:
- component: oh-video-card
config:
hideControls: false
startManually: false
url: =props.cameraBaseURL + items[props.camera +
'_MP4_History'].state.split(",")[(vars.selected || 0)] +".mp4"
visible: =vars.archive == 2
- component: oh-image-card
config:
action: photos
actionPhotoBrowserConfig:
lazy: true
theme: dark
type: popup
actionPhotos: =[props.streamURL]
refreshInterval: =props.refreshRate
style:
border-radius: 6px
height: 9rem
margin: 0px
width: 100%
url: =(props.cameraBaseURL + 'ipcamera.jpg')
- 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 &&
items[props.camera + '_MP4_History_Length'].state > 0 ?
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 || 0)+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 || 0)+1 < items[props.camera
+'_MP4_History_Length'].state)?((vars.selected ||
0)+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) != 0)?((vars.selected || 0)-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
visibleTo:
- role:administrator
- component: oh-link
config:
action: toggle
actionCommand: ON
actionCommandAlt: OFF
actionItem: =props.switchItem
iconF7: power
iconSize: 28
style:
color: "=(items[props.switchItem].state === 'ON') ? 'cyan' : 'white'"
opacity: "=(items[props.switchItem].state === 'ON') ? '0.8' : '0.7'"
visible: =props.switchItem !== undefined && vars.archive !== 2
- component: oh-link
config:
action: group
actionGroupPopupItem: =props.camera
iconF7: gear_alt
iconSize: 28
style:
color: white
opacity: 0.7
visible: =props.showSettings === true && vars.archive !== 2
visibleTo:
- role:administrator
- component: f7-row
config:
class: no-gap
style:
position: absolute
top: 7.7rem
width: 99%
z-index: 2
slots:
default:
- component: oh-link
config:
color: red
iconF7: videocam_circle
iconSize: 22
style:
left: 0.2rem
opacity: 0.7
position: absolute
visible: =props.showRecording === true && items[props.camera +
'_MP4_Recording'].state > 0 && vars.archive !== 2
- component: oh-link
config:
iconF7: eye
iconSize: 22
style:
color: white
opacity: "=(items[props.camera + '_Motion_Alarm'].state === 'ON') ? '0.7' : '0'"
position: absolute
right: 0.2rem
visible: =props.showMotionAlarms === true
- component: oh-link
config:
iconF7: ear
iconSize: 22
style:
color: white
left: 1.2rem
opacity: "=(items[props.camera + '_Audio_Alarm'].state === 'ON') ? '0.7' : '0'"
position: absolute
visible: =props.showAudioAlarms === true