[SOLVED] Zoneminder Camera doesn't display picture in UI, Sensor shows correct data

I’ve got HA and Zoneminder talking to each other successfully, but I can’t see any camera images. In Zoneminder, I have a single camera called “dome”. In HA, I see the following entities:

  • Binary sensor for Zoneminder
  • camera.dome
  • sensor.dome_events
  • sensor.dome_status

Both dome_events and dome_status have correct values, so I know I’m getting good data from Zoneminder, but all the various Picture cards in the HA UI that I’ve attached to the camera.dome entity just show a broken image and the text “Preview of the dome camera.”

I don’t see any errors in either the HA or Zoneminder logs, just success/status messages.

Should I be using a different kind of UI card to view the camera entity, or should this be working?

Config:

zoneminder:
  - host: 192.168.9.26
    path: /zm/
    path_zms: /zm/cgi-bin/nph-zms
    ssl: false
    username: <username>
    password: <password>

camera:
  - platform: zoneminder
  
sensor:
  - platform: zoneminder
    include_archived: false

Entries from Zoneminder’s access.log (these repeat every 30 seconds or so):

192.168.9.29 - 192.168.9.26 [22/Sep/2020:18:21:56 -0500] "GET /zm/api/monitors/1.json?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJab25lTWluZGVyIiwiaWF0IjoxNjAwODEyMDg3LCJleHAiOjE2MDA4MTkyODcsInVzZXIiOiJhZG1pbiIsInR5cGUiOiJhY2Nlc3MifQ.I801mAvxeS0TC52VKtwL1hTn_CQo17Ufv8tPsPUD-3o HTTP/1.1" 200 2331 "-" "python-requests/2.24.0" "-"rt=0.027 ut=0.027 cs=-
192.168.9.29 - 192.168.9.26 [22/Sep/2020:18:21:56 -0500] "GET /zm/api/monitors/alarm/id:1/command:status.json?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJab25lTWluZGVyIiwiaWF0IjoxNjAwODEyMDg3LCJleHAiOjE2MDA4MTkyODcsInVzZXIiOiJhZG1pbiIsInR5cGUiOiJhY2Nlc3MifQ.I801mAvxeS0TC52VKtwL1hTn_CQo17Ufv8tPsPUD-3o HTTP/1.1" 200 14 "-" "python-requests/2.24.0" "-"rt=0.333 ut=0.333 cs=-
192.168.9.29 - 192.168.9.26 [22/Sep/2020:18:21:56 -0500] "GET /zm/api/host/daemonCheck.json?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJab25lTWluZGVyIiwiaWF0IjoxNjAwODEyMDg3LCJleHAiOjE2MDA4MTkyODcsInVzZXIiOiJhZG1pbiIsInR5cGUiOiJhY2Nlc3MifQ.I801mAvxeS0TC52VKtwL1hTn_CQo17Ufv8tPsPUD-3o HTTP/1.1" 200 12 "-" "python-requests/2.24.0" "-"rt=0.459 ut=0.459 cs=-
192.168.9.29 - 192.168.9.26 [22/Sep/2020:18:21:56 -0500] "GET /zm/api/monitors/daemonStatus/id:1/daemon:zmc.json?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJab25lTWluZGVyIiwiaWF0IjoxNjAwODEyMDg3LCJleHAiOjE2MDA4MTkyODcsInVzZXIiOiJhZG1pbiIsInR5cGUiOiJhY2Nlc3MifQ.I801mAvxeS0TC52VKtwL1hTn_CQo17Ufv8tPsPUD-3o HTTP/1.1" 200 87 "-" "python-requests/2.24.0" "-"rt=0.468 ut=0.468 cs=-
192.168.9.29 - 192.168.9.26 [22/Sep/2020:18:21:56 -0500] "GET /zm/api/events/consoleEvents/100%20year/Archived=:0.json?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJab25lTWluZGVyIiwiaWF0IjoxNjAwODEyMDg3LCJleHAiOjE2MDA4MTkyODcsInVzZXIiOiJhZG1pbiIsInR5cGUiOiJhY2Nlc3MifQ.I801mAvxeS0TC52VKtwL1hTn_CQo17Ufv8tPsPUD-3o HTTP/1.1" 200 23 "-" "python-requests/2.24.0" "-"rt=0.020 ut=0.020 cs=-
192.168.9.29 - 192.168.9.26 [22/Sep/2020:18:21:56 -0500] "GET /zm/api/states.json?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJab25lTWluZGVyIiwiaWF0IjoxNjAwODEyMDg3LCJleHAiOjE2MDA4MTkyODcsInVzZXIiOiJhZG1pbiIsInR5cGUiOiJhY2Nlc3MifQ.I801mAvxeS0TC52VKtwL1hTn_CQo17Ufv8tPsPUD-3o HTTP/1.1" 200 81 "-" "python-requests/2.24.0" "-"rt=0.015 ut=0.015 cs=-
192.168.9.29 - 192.168.9.26 [22/Sep/2020:18:21:56 -0500] "GET /zm/api/states.json?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJab25lTWluZGVyIiwiaWF0IjoxNjAwODEyMDg3LCJleHAiOjE2MDA4MTkyODcsInVzZXIiOiJhZG1pbiIsInR5cGUiOiJhY2Nlc3MifQ.I801mAvxeS0TC52VKtwL1hTn_CQo17Ufv8tPsPUD-3o HTTP/1.1" 200 81 "-" "python-requests/2.24.0" "-"rt=0.016 ut=0.016 cs=-
192.168.9.29 - 192.168.9.26 [22/Sep/2020:18:21:56 -0500] "GET /zm/api/monitors/daemonStatus/id:1/daemon:zmc.json?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJab25lTWluZGVyIiwiaWF0IjoxNjAwODEyMDg3LCJleHAiOjE2MDA4MTkyODcsInVzZXIiOiJhZG1pbiIsInR5cGUiOiJhY2Nlc3MifQ.I801mAvxeS0TC52VKtwL1hTn_CQo17Ufv8tPsPUD-3o HTTP/1.1" 200 87 "-" "python-requests/2.24.0" "-"rt=0.472 ut=0.472 cs=-
192.168.9.29 - 192.168.9.26 [22/Sep/2020:18:21:57 -0500] "GET /zm/api/host/daemonCheck.json?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJab25lTWluZGVyIiwiaWF0IjoxNjAwODEyMDg3LCJleHAiOjE2MDA4MTkyODcsInVzZXIiOiJhZG1pbiIsInR5cGUiOiJhY2Nlc3MifQ.I801mAvxeS0TC52VKtwL1hTn_CQo17Ufv8tPsPUD-3o HTTP/1.1" 200 12 "-" "python-requests/2.24.0" "-"rt=0.444 ut=0.444 cs=-

I have the: path: /zm/ omitted in my config.
No sure why, but it works.

ZM’s api setup correctly?
There is a detailed page on testing ZM’s api.
https://zmninja.readthedocs.io/en/latest/guides/validating-api.html#make-sure-zm-apis-are-working

That page has some tips if needed and zm’s forums as well.

Hope it helps.

Thanks for the suggestions. I tried removing the “path” variable, but that doesn’t seem to have had any effect.

The page you listed was a great resource. Unfortunately, it looks like my APIs are already set up correctly. HA is even getting proper event counts for the camera from the Zoneminder APIs… just not the picture for some reason.

In case it helps, here’s my monitors.json response from ZoneMinder. Maybe you’re using a different type of stream or something, and I could change mine to something supported by HA?

{
   "monitors":[
      {
         "Monitor":{
            "Id":"1",
            "Name":"dome",
            "Notes":"",
            "ServerId":"0",
            "StorageId":"2",
            "Type":"Ffmpeg",
            "Function":"Modect",
            "Enabled":"1",
            "LinkedMonitors":null,
            "Triggers":"",
            "Device":"",
            "Channel":"0",
            "Format":"0",
            "V4LMultiBuffer":null,
            "V4LCapturesPerFrame":"1",
            "Protocol":"rtsp",
            "Method":"rtpRtsp",
            "Host":"rtmp:\/\/192.168.9.9\/bcs\/channel0_main.bcs?token=254&channel=0&str",
            "Port":"554",
            "SubPath":"",
            "Path":"rtmp:\/\/192.168.9.9\/bcs\/channel0_main.bcs?token=254&channel=0&stream=0&user=REDACTED&password=REDACTED",
            "Options":null,
            "User":null,
            "Pass":null,
            "Width":"2560",
            "Height":"1920",
            "Colours":"4",
            "Palette":"0",
            "Orientation":"ROTATE_0",
            "Deinterlacing":"0",
            "DecoderHWAccelName":null,
            "DecoderHWAccelDevice":null,
            "SaveJPEGs":"3",
            "VideoWriter":"2",
            "OutputCodec":null,
            "OutputContainer":null,
            "EncoderParameters":"# Lines beginning with # are a comment \r\n# For changing quality, use the crf option\r\n# 1 is best, 51 is worst quality\r\n#crf=23",
            "RecordAudio":"1",
            "RTSPDescribe":false,
            "Brightness":"-1",
            "Contrast":"-1",
            "Hue":"-1",
            "Colour":"-1",
            "EventPrefix":"Event-",
            "LabelFormat":"%N - %d\/%m\/%y %H:%M:%S",
            "LabelX":"0",
            "LabelY":"0",
            "LabelSize":"1",
            "ImageBufferCount":"100",
            "WarmupCount":"0",
            "PreEventCount":"5",
            "PostEventCount":"5",
            "StreamReplayBuffer":"0",
            "AlarmFrameCount":"1",
            "SectionLength":"600",
            "MinSectionLength":"10",
            "FrameSkip":"0",
            "MotionFrameSkip":"0",
            "AnalysisFPSLimit":null,
            "AnalysisUpdateDelay":"0",
            "MaxFPS":null,
            "AlarmMaxFPS":null,
            "FPSReportInterval":"100",
            "RefBlendPerc":"6",
            "AlarmRefBlendPerc":"6",
            "Controllable":"0",
            "ControlId":null,
            "ControlDevice":null,
            "ControlAddress":null,
            "AutoStopTimeout":null,
            "TrackMotion":"0",
            "TrackDelay":null,
            "ReturnLocation":"-1",
            "ReturnDelay":null,
            "DefaultRate":"100",
            "DefaultScale":"100",
            "DefaultCodec":"auto",
            "SignalCheckPoints":"0",
            "SignalCheckColour":"#0000be",
            "WebColour":"#74b4f4",
            "Exif":false,
            "Sequence":"1",
            "TotalEvents":"461",
            "TotalEventDiskSpace":"19328404487",
            "HourEvents":"1",
            "HourEventDiskSpace":"38394504",
            "DayEvents":"54",
            "DayEventDiskSpace":"1995424403",
            "WeekEvents":"281",
            "WeekEventDiskSpace":"11444889383",
            "MonthEvents":"461",
            "MonthEventDiskSpace":"19328404487",
            "ArchivedEvents":null,
            "ArchivedEventDiskSpace":null,
            "ZoneCount":"3",
            "Refresh":null
         },
         "Monitor_Status":{
            "MonitorId":"1",
            "Status":"Connected",
            "CaptureFPS":"12.50",
            "AnalysisFPS":"11.11",
            "CaptureBandwidth":"325752"
         }
      }
   ]
}

Any errors in HA’s logs?

I use the picture-entity card for my views. Example:

aspect_ratio: 75%
camera_image: camera.grarge_roof
camera_view: live
entity: camera.grarge_roof
type: picture-entity

If it helps.

Just curious. When you log in to ZM with a browser does the url path look like http://192.168.9.26/zm/index.php ?

Or does it differ. If it differs then change the path: /zm/ in the config to match the url.

That’s all I got after sleeping on it.

Yep, http://192.168.9.26/zm/index.php is the URL.

I didn’t have aspect_ratio or camera_view set. I set those, and now it… seems to have split into two separate entities on the UI?

Here’s what it looked like before: https://drive.google.com/file/d/1J2t246O5_d6LXpDQS3fJqWDF-91mMQ1x/view?usp=sharing

… and here’s what it looked like after: https://drive.google.com/file/d/1Swd7vWY0bwcFlsUI1YO8llVBy_xcNwSy/view?usp=sharing

That may be a necessary improvement in the long run, so that’s a good tip to know in the future.

Unfortunately, I now get errors. HA shows errors like these, every 2 hours like clockwork (as in, within about 15 seconds of exactly 2 hours apart).

2020-09-23 00:41:14 ERROR (MainThread) [homeassistant.helpers.entity] Update for camera.dome fails
Traceback (most recent call last):
  File "/usr/local/share/homeassistant/lib/python3.7/site-packages/homeassistant/helpers/entity.py", line 263, in async_update_ha_state
    await self.async_device_update()
  File "/usr/local/share/homeassistant/lib/python3.7/site-packages/homeassistant/helpers/entity.py", line 457, in async_device_update
    self.update  # type: ignore
  File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/share/homeassistant/lib/python3.7/site-packages/homeassistant/components/zoneminder/camera.py", line 57, in update
    self._is_recording = self._monitor.is_recording
  File "/usr/local/share/homeassistant/lib/python3.7/site-packages/zoneminder/monitor.py", line 140, in is_recording
    return int(status) == STATE_ALARM
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'

ZoneMinder now shows the following errors at the same time I get these errors:

2020-09-23 20:41:23	web_php		48667	ERR	Unable to authenticate user. error decoding JWT token:Expired token	includes/auth.php	120

I’ve removed the “camera_view: live” entry, and I’ll see if the errors go away or not.

After all that, I was randomly poking around in the Chrome dev tools in Zoneminder.

Turns out path_zms should be set to “/cgi-bin/nph-zms” instead of “/zm/cgi-bin/nph-zms”.

Thanks for the great tip about aspect ratio and live camera feed, Akriss, it looks great now!

Hi,

Sorry for jumping on this but I just wondered if you still get the HA & ZoneMinder errors every 2hrs ?

My config works fine, I can watch my cameras, but I do also have these errors every 2hrs and I’m curious if it’s just me…

Thanks!

did you manage to fix it? I have got the same issue. thanks.

No, still got the same issue. As everything appears to work haven’t investigated too much.

Sorry for the necro post. Arrived at this post looking for the answer to a different problem.

EvlLprchan - The “errors every 2 hours like clockwork” are likely caused by the default timeout for JWT tokens. This timeout value is configurable in Options for Zoneminder. It appears the integration does not renew the tokens until after they timeout.

For me this:
path_zms should be set to /cgi-bin/nph-zms instead of /zm/cgi-bin/nph-zms
Was also the solution. I don’t understand why yet. Especially because /etc/apache2/vhosts.d/zm.conf lists:

    ScriptAlias /zm/cgi-bin/ "/usr/lib/zoneminder/cgi-bin"
    ScriptAlias /cgi-bin "/usr/lib/zoneminder/cgi-bin"

So both should work, although the inner workings of zoneminder could very well be past my knowledge.

The page of the integration (ZoneMinder - Home Assistant) has a default of /zm/cgi-bin/nph-zms, but it also notes " This should match PATH_ZMS in ZM’s “Paths” settings." Turns out that the PATH_ZMS settings has disappeared from ZM’s settings window since version 1.32.0 and now in zmcustom.conf typically found under /etc/zm/conf.d. Not in my case though, the /etc/zm folder doen’t even exist. /etc/zm.conf also doesn’t list the PATH_ZMS setting, so I had to find the suggestion here to have the camera’s working.

For me this : sudo a2nmod apache2-cgi

I came by this topic trying to resolve the same issue. I am on RHEL9 with zoneminder-httpd-1.37.63-1.74.20240816gitg09f5e6df7.el9.x86_64 RPM installed and have the following entry in the Apache config:

[root@zm ~]# grep ScriptAlias /etc/zm/www/zoneminder.httpd.conf
ScriptAlias /cgi-bin-zm "/usr/libexec/zoneminder/cgi-bin"
[root@zm ~]# ls -l "/usr/libexec/zoneminder/cgi-bin"
total 2668
lrwxrwxrwx 1 root root       3 Aug 16 06:54 nph-zms -> zms
-rwxr-xr-x 1 root root 2730872 Aug 16 06:54 zms
[root@zm ~]#

Had to add the following line to configuration.yaml to get it properly working:

    path_zms: /cgi-bin-zm/nph-zms