OH3 Widget: Move and see your PTZ camera feed on a page

Here is a widget for moving PTZ IP cameras that I am developing at the moment, if you can improve on it then please post your changes. It can move a camera that either supports ONVIF presets or ONVIF Relative movements. Continuous move could be handled in a number of ways but is out of scope of this post.

Steps to get this working:

  1. You need to either use one of these two features to auto create the items with the default naming.
    “Add Equipment to model”
    “Create Equipment from thing”
    If using textual config, you will need to either edit the widget or create your items to match the standard naming.
  2. Make sure when creating the Equipment you click ‘show advanced’ to see all the channels and tick the Pan, Tilt, Zoom, GoToPreset and MJPEG URL channels as a minimum.
  3. Select the Equipment/Item that is your desired camera in the setup of the widget.
  4. Optionally you can select an item you wish to switch on and off. Example the lights in the room that the camera is in. Alternatively it may be blinds or a motorized gate, the choice is yours and if you leave this blank the control disappears.
  5. If your camera does not support Relative movements, then you can hide those controls and just use Presets instead. If your camera supports it, you will see a named list of your presets appear that you can choose from that will take your camera directly to the selected preset location.

Setup

Widget Code to add via the Developer Tools menu:

uid: ClickablePTZCamera
props:
  parameters:
    - context: item
      label: Select the Camera to Control
      name: camera
      required: true
      type: TEXT
    - context: item
      label: Item for Switch
      name: switchItem
      required: false
      type: TEXT
    - label: Invert Tilt Controls
      name: invertTilt
      required: true
      type: BOOLEAN
    - label: Show Discrete Controls
      name: showControls
      required: true
      type: BOOLEAN
  parameterGroups: []
timestamp: Dec 29, 2020, 11:56:36 AM
component: f7-card
config:
  class: no-margin
  expandable: true
  style:
    border-radius: 6px
    --f7-card-margin-horizontal: 0px
    width: 16rem
    height: 9rem
slots:
  default:
    - component: f7-card-content
      config:
        class: card-opened-fade-out
        style:
          color: white
          background-image: ="url('"+items[props.camera + "_MJPEGURL"].state+"')"
          background-size: 17rem 10rem
          background-repeat: no-repeat
          border-radius: 6px
          z-index: -1
    - component: f7-card-content
      config:
        class: card-opened-fade-in
        style:
          color: white
          background-image: ="url('"+items[props.camera + "_MJPEGURL"].state+"')"
          background-size: 100% auto
          background-position: center
          background-repeat: no-repeat
          z-index: -1
    - component: oh-link
      config:
        class: card-prevent-open
        style:
          margin: 0em 0.2em
          color: "=(items[props.switchItem].state === 'ON') ? 'cyan' : 'white'"
          opacity: "=(items[props.switchItem].state === 'ON') ? '0.4' : '0.3'"
        visible: =props.switchItem !== undefined
        iconF7: power
        iconSize: 22
        action: toggle
        actionItem: =props.switchItem
        actionCommand: ON
        actionCommandAlt: OFF
    - component: oh-link
      config:
        class: card-prevent-open
        style:
          margin: 0 0.2em
          color: white
          opacity: 0.3
        visible: =props.showControls === true
        iconF7: arrow_left
        iconSize: 22
        action: command
        actionItem: =props.camera + "_Pan"
        actionCommand: INCREASE
    - component: oh-link
      config:
        class:
          - card-prevent-open
        style:
          margin: 0 0.2em
          color: white
          opacity: 0.3
        visible: =props.showControls === true
        iconF7: arrow_up
        iconSize: 22
        action: command
        actionItem: =props.camera + "_Tilt"
        actionCommand: "=(props.invertTilt) ? 'INCREASE' : 'DECREASE'"
    - component: oh-link
      config:
        class: card-prevent-open
        style:
          margin: 0 0.2em
          color: white
          opacity: 0.3
        visible: =props.showControls === true
        iconF7: arrow_down
        iconSize: 22
        action: command
        actionItem: =props.camera + "_Tilt"
        actionCommand: "=(props.invertTilt) ? 'DECREASE' : 'INCREASE'"
    - component: oh-link
      config:
        class: card-prevent-open
        style:
          margin: 0 0.2em
          color: white
          opacity: 0.3
        visible: =props.showControls === true
        iconF7: arrow_right
        iconSize: 22
        action: command
        actionItem: =props.camera + "_Pan"
        actionCommand: DECREASE
    - component: oh-link
      config:
        class: card-prevent-open
        style:
          margin: 0 0.2em
          color: white
          opacity: 0.3
        visible: =props.showControls === true
        iconF7: plus
        iconSize: 22
        action: command
        actionItem: =props.camera + "_Zoom"
        actionCommand: INCREASE
    - component: oh-link
      config:
        class:
          - card-prevent-open
        style:
          margin: 0 0.2em
          color: white
          opacity: 0.3
        visible: =props.showControls === true
        iconF7: minus
        iconSize: 22
        action: command
        actionItem: =props.camera + "_Zoom"
        actionCommand: DECREASE
    - component: oh-link
      config:
        class: card-prevent-open
        style:
          margin: 0 0.2em
          color: white
          opacity: 0.3
        iconF7: list_number
        iconSize: 22
        action: options
        actionItem: =props.camera + "_GoToPreset"
    - component: oh-link
      config:
        class: card-prevent-open
        style:
          margin: 0 0.2em
          color: white
          opacity: 0.3
        iconF7: gear_alt
        iconSize: 22
        action: group
        actionGroupPopupItem: =props.camera
    - component: oh-link
      config:
        style:
          position: absolute
          top: 7.8rem
          right: 0.2rem
          color: white
          opacity: "=(items[props.camera + '_MotionAlarm'].state === 'ON') ? '0.5' : '0'"
        iconF7: eye
        iconSize: 18
    - component: oh-link
      config:
        style:
          position: absolute
          top: 7.7rem
          left: 0rem
          color: white
          opacity: "=(items[props.camera + '_AudioAlarm'].state === 'ON') ? '0.5' : '0'"
        iconF7: ear
        iconSize: 18

YAML code if you wish to add it via yaml instead of graphically.

component: widget:ClickablePTZCamera
config:
  camera: BabyCam
  switchItem: Second_Bedroom_Lights
  showControls: true

9 Likes

Added new ability to click on a gear icon to open up all the camera controls so you have access to PTZ via ABSOLUTE controls on a slider and the ability to turn alarms on and off and far more.

1 Like

Added some changes to first post widget code that make the opened view look nicer and the controls also work now on expanded view.

1 Like

Improved the code in the first post again.

Controls now open up to a larger size so they are easier to press.
Works better across iPhone and android tablets.

Great widget, thanks.

On the light theme, the controls are not visible when opened, as they are placed on the white space above the image.

Changing the
color: white

for the controls to
color: var(--f7-card-header-text-color)
seem to fix this, or at least makes it better.

I’m sure there are other ways to do this, but I am just getting started with widgets…

1 Like

Hope this isnt a dumb question but the camera itself is this an assumption the IPcamera binding has been used to create the equipment?

Yes as how else can you move a camera if it is not with the ip camera binding? There is a similar widget that is for non movable cameras that are not using the binding as it takes URL for the config setup.

Feel free to use any of the widgets to create your own however your setup works.

Is there any way to pop-up this widget or the other one without PTZ, by switching virtual item?

1 Like