Zmodo Cloud (non-NVR)

I want to post my journey that I went through in order to get my Zmodo cameras working. I have two Zmodo SD-H2001 cameras and wanted to integrate them into Home Assistant (HA).

Logging in and cookies

The first step was to log into Zmodo’s web frontend. You have to input a username, password, and solve a 4 digit captcha. Once you log in, you receive a “cookie” that contains tokenid. This is what drives everything and is needed for every subsequent api call. It is in this format: tokenid=9887d3867411142bc34f510d2e76fd5c. On the webpage, once every 5 minutes, an ajax request is sent to the refresh api endpoint “https://user.zmodo.com/api/refresh” which needs two inputs in order to work:

  • The cookie you are using tokenid=9887d3867411142bc34f510d2e76fd5c
  • One URL parameter tokenid and you guessed it, is the same as the cookie’s tokenid value.

I created a simple bash script and use crontab to run it every 10 minutes:

#!/bin/bash
PATH=/bin:/usr/bin

# Cookie
COOKIE=9887d3867411142bc34f510d2e76fd5c
REFRESH="https://user.zmodo.com/api/refresh?tokenid=$COOKIE"
curl -X GET \
     -H "Content-Type: application/json" \
     -b "tokenid=$COOKIE" \
     $REFRESH > /dev/null 2>&1

exit 0

Device list

The next step was to get a list of my devices (because I have more than one). To find your devices, make a GET request to “https://user.zmodo.com/api/devices” making sure to pass in your same cookie header. From what I know, the relevant fields that you need are: physical_id, aes_key, name.

Messages or alerts

There is also an api endpoint for message and/or alerts which can be queried by making a GET request to “https://user.zmodo.com/api/messages” and once again passing in your cookie header.

Streaming video

This particular camera has two streaming modes: LD and HD. LD is low definition. HD is high definition. The URL two access the live stream has this format:

devid = device’s physical_id. token = cookie value. media_type: use 1 for LD and 2 for HD. channel: for me it was always 0, but for you it might be different. aes_key = device’s aes_key. has_audio = 1. cid = 0 (but I do not know what this is). The full URL should look something like “https://flv.meshare.com/live?devid=ZMD13BLXX######&token=9887d3867411142bc34f510d2e76fd5c&media_type=1&channel=0&aes_key=32CHARACTERDEVICESTRINGCAM1&has_audio=1&cid=0”.

This is the URL that you can use in HA once you have setup your cronjob so save it for later. NOTE: I tried to use this endpoint in VLC Player, but it wouldn’t work… so don’t go down that rabbit hole like I did.

Setting up the camera in HA

For some reason, in my current setup, when I add a “generic camera” entry, HA crashes. This is my problem to solve someday, but not right now. So, I had to manually add my two cameras into my configuration.yaml file like this:

camera:
  - platform: ffmpeg
    name: Zmodo Cam 1 HD
    input: "https://flv.meshare.com/live?devid=ZMD13BLXX######&token=9887d3867411142bc34f510d2e76fd5c&media_type=2&channel=0&aes_key=32CHARACTERDEVICESTRINGCAM1&has_audio=1&cid=0"
  - platform: ffmpeg
    name: Zmodo Cam 2 HD
    input: "https://flv.meshare.com/live?devid=ZMD13BLXX######&token=9887d3867411142bc34f510d2e76fd5c&media_type=2&channel=0&aes_key=32CHARACTERDEVICESTRINGCAM2&has_audio=1&cid=0"

Messages to be used in automations

This part is hard and it isn’t 100% working yet, but I want to include it for completeness sake and maybe someone can help me out?

First you need a HA authorization token. You can use an existing one or create a new one on the Security tab of your Profile (http://homeassistant.local:8123/profile/security).

Next, you need a working MQTT broker, but I won’t cover that here in this post.

Finally, create another bash script and call it every minute through crontab. NOTE: This script uses curl and jq so be sure those packages are installed before running the script!

#!/bin/bash
PATH=/bin:/usr/bin

### START CHANGE THIS SECTION ###
# Cookie
COOKIE=9887d3867411142bc34f510d2e76fd5c
# Home Assistant Base URL
HA_URL="http://homeassistant.local:8123"
# Home Assistant Token
HA_TOKEN="HONEESTLYWHYARETHESETHINGSSUPERDUPERLONGIMEANJUSTWHY"
# Query Time (AKA filter down the number of messages that have happened since now minus X seconds)
Q_TIME=70
### END CHANGE THIS SECTION ###

URL="https://user.zmodo.com/api/messages"
JSON_RAW=$(curl -X GET \
     -H "Content-Type: application/json" \
     -b "tokenid=$COOKIE" \
     $URL)
EPOCHNOW=$(date +%s)
EPOCH=$((EPOCHNOW-Q_TIME))
# Filter raw query down to only messages from the last hour
JSON_FILT_TIME=$(echo $JSON_RAW | jq -c --arg jtime $EPOCH '.data[] | select(.alarm_time > $jtime)')

if [[ "$JSON_FILT_TIME" == "" ]]
then
# You will have to change this line to match your camera(s)
JSON_FILT_TIME=$'{"device_name": "Cam 1", "alarm_time": "", "image": "", "video": ""}\n{"device_name": "Cam 2", "alarm_time": "", "image": "", "video": ""}'
fi

# For each message we find, post data to HA
echo "$JSON_FILT_TIME" | while IFS=$'\n' read item; do
  device=$(jq -r '.device_name' <<< "$item")
  echo $device
  alarm=$(jq -r '.alarm_time' <<< "$item")
  image=$(jq -r '.image' <<< "$item")
  video=$(jq -r '.video' <<< "$item")
  if [[ "$image" != "" ]]
  then
  curl -X POST -H "Content-Type: application/json" \
       -H "Authorization: Bearer $HA_TOKEN" \
       -d '{"payload": "'"$image"'", "topic": "homeassistant/sensor/'"$device"'/image", "retain": "True"}' \
       $HA_URL/api/services/mqtt/publish > /dev/null 2>&1
  fi
  if [[ "$video" != "" ]]
  then
  curl -X POST -H "Content-Type: application/json" \
       -H "Authorization: Bearer $HA_TOKEN" \
       -d '{"payload": "'"$video"'", "topic": "homeassistant/sensor/'"$device"'/video", "retain": "True"}' \
       $HA_URL/api/services/mqtt/publish > /dev/null 2>&1
  fi
  curl -X POST -H "Content-Type: application/json" \
       -H "Authorization: Bearer $HA_TOKEN" \
       -d '{"payload": "'"$alarm"'", "topic": "homeassistant/sensor/'"$device"'/motion", "retain": "True"}' \
       $HA_URL/api/services/mqtt/publish > /dev/null 2>&1
done
exit 0

Add the MQTT sensors

Again, for whatever reason my auto-discovery isn’t working and isn’t pulling my new entries into the MQTT integration automatically. I COULD USE SOME HELP HERE PLEASE.

I had to manually add three sensors for each device into my configuration.yaml file. I will only show the setup for one device.

mqtt:
  sensor:
    - name: Zmodo Cam 1 Last Motion
      state_topic: "homeassistant/sensor/Cam 1/motion"
      device_class: timestamp
      value_template: '{{ as_datetime(value) }}'
    - name: Zmodo Cam 1 Video
      state_topic: "homeassistant/sensor/Cam 1/video"
      value_template: '{{ value }}'
  image:
    - name: Zmodo Cam 1 Image
      url_topic: "homeassistant/sensor/Cam 1/image"

RESTART HOME ASSISTANT.

Add a card for the cameras

This is the same way how you configure all other camera devices. I elected to use a “Vertical Stack Card” and add my two cameras as “Picture glance” cards.

Yes, I did pixelate the image. No the quality of the camera is not bad and is quite good.

Automations

I created two automations one for each camera. Basically, send a notification to my iPhone with the image data.

alias: Zmodo Cam 1 Push Notify
description: Motion detected
triggers:
  - trigger: state
    entity_id:
      - sensor.zmodo_cam_1_last_motion
    from: unknown
conditions: []
actions:
  - action: notify.mobile_app_iamdoubz_iphone
    metadata: {}
    data:
      title: Living Room
      message: Motion detected!
      data:
        image: /api/image_proxy/image.zmodo_cam_1_image
mode: single

What doesn’t work

  • I cannot for the life of me get the message video to play
    • Meaning, the URL that Zmodo creates for the motion notification
    • You could easily just create a FFMPEG recording and use that data…
  • Message script is probably incomplete and prone to errors but I did my best

Future work

  • Dynamic adding through MQTT
  • Probably do a true integration OR
  • Create a manual integration most likely using golang
1 Like

See this post about getting video to work: