OH3 Widget: Building a camera widget

That has been what I have been aiming towards for many months, however for a standard camera view it is better to use a URL, because many people will want to use Blue Iris, Motion, or any other number of software to process the camera with and not the binding. When it comes to PTZ or a history of recent recordings, then that is different and the binding has been written to leverage things that hopefully will come together over time.

Here’s another piece of code that is probably the closet I have come to what I want. It requires a hard coded widget for each camera on top of this. Still playing to see what the best method will be.

uid: ModalCamera
timestamp: Dec 13, 2020, 11:05:28 PM
component: f7-card
config:
  class:
    - oh-cell
slots:
  default:
    - component: oh-button
      config:
        action: popup
        actionModal: widget:SingleCamera
        style:
          color: transparent
          padding: 75px
          background-image: url(http://192.168.1.2:54321/autofps.mjpeg)
          background-size: cover
          background-repeat: no-repeat
          background-position: center
1 Like

Cool, but you have the oh-image-card for that, it’s true that you don’t have a cell widget for images.
On a layout click Add Block, Add Row, Add Column, and then add an “Image Card” widget. Configure the item for it, if it’s an Image item it will display the image, if it’s a String it will assume it to be the URL
(you can also configure a fixed URL).

Below you have the “Action” settings, you can set it to “Open photo browser”:
The other settings are [object Object] in the screenshot below because I configured them with YAML (actionPhotos is an array and actionPhotoBrowserConfig an object):

component: oh-image-card
config:
  item: WebcamSalon_MJPEGURL
  action: photos
  actionPhotos:
    - item: WebcamSalon_MJPEGURL
  actionPhotoBrowserConfig:
    theme: dark

image

If you specify multiple items in actionPhotos you’ll have a carousel and can swipe from one to the other (or use the arrows), and add captions if you like:

component: oh-image-card
config:
  item: WebcamSalon_MJPEGURL
  action: photos
  actionPhotos:
    - item: WebcamSalon_MJPEGURL
      caption: Camera 1
    - url: https://source.unsplash.com/random
      caption: Random image
  actionPhotoBrowserConfig:
    theme: dark
1 Like

@ysc
Thanks for the pointers, I had a few things go click in my head after seeing that. However I have 1 thing which I would like your advice on if it is a bug, code on the todo list, or a limitation on the way I am doing it…

The below widget fails if I try to use =props.streamURL but if I hardcode an URL in there in the format http://192.168.1.2:54321/snapshots.mjpeg it then works great. The thumbnailURL works as a props, so it is only the location of trying to use it inside the actionPhotos (array?).

uid: ClickableCamera
props:
  parameters:
    - description: "example: http://192.168.1.2:54321/autofps.mjpeg"
      label: Thumbnail URL
      name: thumbnailURL
      required: true
      type: TEXT
    - description: "example: http://192.168.1.2:54321/snapshots.mjpeg"
      label: Stream URL
      name: streamURL
      required: true
      type: TEXT
timestamp: Dec 14, 2020, 7:04:31 PM
component: oh-image-card
config:
  class:
    - oh-cell
    - no-margin
  style:
    - border-radius: 6px
    - width: 100%
    - height: auto
  url: =props.thumbnailURL
  action: photos
  actionPhotos: 
    - url: =props.streamURL
  actionPhotoBrowserConfig:
    theme: dark
    type: popup

Yes you can’t use expressions inside array members, but you can use an expression to build the array itself. So instead of:

actionPhotos:
  - url: =props.streamURL

do:

actionPhotos: =[props.streamURL]
1 Like

Thanks, that works perfect.

I actually tried many combos that were close and all failed before I posted as I didn’t know the right syntax…

actionPhotos: [=props.streamURL]
actionPhotos: [’=props.streamURL’]

Multiple Cameras can be done like this and with - html: You should be able to play back mp4 recordings, or possibly HLS video streams.

uid: cameraAll
timestamp: Dec 14, 2020, 10:59:55 PM
component: oh-image-card
config:
  class:
    - oh-cell
    - no-margin
  style:
    - border-radius: 6px
    - width: 100%
    - height: auto
  url: https://source.unsplash.com/category/technology
  action: photos
  actionPhotos:
    - html: <video loop autoplay src="https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/720/Big_Buck_Bunny_720_10s_1MB.mp4"></video>
      caption: BunnyCamera
    - url: https://source.unsplash.com/category/nature
      caption: Camera2
    - url: https://source.unsplash.com/category/street-photography
      caption: Camera3
    - url: https://source.unsplash.com/category/interiors
      caption: Camera4
  actionPhotoBrowserConfig:
    theme: dark
    type: popup

Single Camera that can have the URLs configured.

uid: ClickableCamera
props:
  parameters:
    - description: "example: http://192.168.1.2:54321/autofps.mjpeg"
      label: Thumbnail URL
      name: thumbnailURL
      required: true
      type: TEXT
    - description: "example: http://192.168.1.2:54321/snapshots.mjpeg"
      label: Stream URL
      name: streamURL
      required: true
      type: TEXT
timestamp: Dec 14, 2020, 9:59:29 PM
component: oh-image-card
config:
  class:
    - oh-cell
    - no-margin
  style:
    - border-radius: 6px
    - width: 100%
    - height: auto
  url: =props.thumbnailURL
  action: photos
  actionPhotos: =[props.streamURL]
  actionPhotoBrowserConfig:
    theme: dark
    type: popup
4 Likes

This might even be a good candidate for a oh-swiper-card with several oh-image-card as slides.
It’s better to have all images of the same dimensions in this case, or it will look weird.

component: oh-swiper-card
config:
  pagination: true
  navigation: true
  params:
    slidesPerView: 1.5
slots:
  default:
    - component: oh-image-card
      config:
        url: https://source.unsplash.com/800x600/?frontdoor
        action: photos
        actionPhotos:
          - https://source.unsplash.com/800x600/?frontdoor
    - component: oh-image-card
      config:
        url: https://source.unsplash.com/800x600/?garage
    - component: oh-image-card
      config:
        url: https://source.unsplash.com/800x600/?garden

You can also have some fun with the SwiperJS parameters like the coverflow effect -(https://swiperjs.com/api/#coverflow-effect):

component: oh-swiper-card
config:
  pagination: true
  navigation: true
  params:
    effect: coverflow
    coverFlowEffect:
      rotate: 30
      slideShadows: false

coverflow

or the cube:

component: oh-swiper-card
config:
  pagination: true
  navigation: true
  params:
    effect: cube
    cubeEffect:
      shadow: false

cube

2 Likes

Nice Effects. Is there any way to remove the frame of the image (the space between wrapper and container I guess) ?

I have not tried but my guess is it should be possible if you use CSS to change the background color. To do this see the examples above at how CSS is used after style:
If the background color matches then you don’t see it.

Right and add noBorder & noShadow too (properties of all cards).

config:
  noBorder: true
  noShadow: true
  style:
    --f7-card-bg-color: transparent

Trying to get mjpeg video streams from cameras working in Main UI…

In OH2 sitemap I used:

Video url="http://user:pwd@192.168.0.15:80/video2.mjpg" encoding="mjpeg"

I can’t get it working in Main UI.
Error message: No compatible source was found for this media.

I tried the Video card as follows…

URL:
http://user:pwd@192.168.0.15:80/video2.mjpg

Type:
mjpg mjpeg video/mjpeg video/mjpg (none of these options worked)

Is there a way to get mjpeg stream working in Main UI?

I had luck using the “Image” card with a motion jpeg.

Which video settings does your motion jpeg stream have?

  • resolution
  • frames per second

Yes if you use the ipcamera binding and the widget in this post it should work. I can only guess that there may be an issue with embedded credentials not being supported. It was removed from the http spec due to security concerns and more and more software is removing it so hence the binding is needed.

Now it works for me too with the Image card - I had to go with the IPcamera binding though.

Updated the first post to have an improved widget that displays better across devices and now can switch an item or bring up all the controls for the camera with overlaid buttons.

1 Like

A few things.

  • Once you click to open the video, there doesn’t seem to be any way to close it on a PC. On my phone I found swiping away makes it cose. But on the PC there is no way to close the pop-up video I can see.
  • There are URL fields but no way to use an IP Camera Binding channel? Or am I missing something?

Click anywhere outside the pop up window and it will return back to your UI page.

Yes done deliberately so people who don’t want to use the binding can use it as well. It could also be static pictures and not even a camera. If you don’t want URLs you can use the PTZ version and modify it to your needs as that one does not use the URLs.

Code updated in the first post:

Now it has:

  • A small ear icon that appear when the camera hears noise.
  • A small eye icon when the camera sees movement.

For these to work you need to select the equipment that has been auto created from the thing with the motion and audio alarm channels ticked.