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’stokenid
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:
- Base URL “https://flv.meshare.com/live”
- 7 URL parameters: devid, token, media_type, channel, aes_key, has_audio, cid
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