I don’t know if there is any other demand for this but I’ve struggled to use the limited information from the two other examples on the community for Dahua IP camera integration. It would be great if someone was able to develop / further develop these so there could be a Dahua camera component (API/MQTT events seem to be viable). These are great fully featured cameras for a reasonable price and good quality. I use the mini PTZ zoom dome and I thought they were popular. I can integrate the images no problem but the integration for motion detection (both video and IVS) and PTZ is a minefield.
Got this working in the end- a sensor that tracks movement and an automation that picks up on these, seems to be working fine for movement and tripwire on the Dahua IP Dome camera
Can you please share your setup and config. I havent got tripwire to work iam also using MQTT IPC component.
I’m running Pi3 with HA in VEnv and MQTT server. Back everything up on image, mine was OK but you never know. Dahua SD1A203T Dome Camera.
I have an input Boolean to turn the HA sensor (script) on/off;
input_boolean:
cam_movement_sensor_on_off:
name: Cam Movement Sensor On Off
initial: off
Have a binary MQTT sensor detecting via script from the Dahua camera detection;
binary_sensor:
- platform: mqtt
state_topic: "home-assistant-1/cameras/motion"
name: "Cam Movement Sensor"
I have this script in a ‘scripts’ folder in same folder as the .yaml’s, named dahua.py
(will need to input your Dahua camaera IP and MQTT information into this and save this script);
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import logging
import socket
import pycurl
import time
import shlex
import subprocess
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish
ALARM_DELAY = 2
#PLAY_TEMPLATE = "gst-launch-1.0 playbin uri=\"rtsp://{user}:{pass}@{host}:554/cam/realmonitor?channel=1&subtype=2\" latency=300000000 audio-sink=\"autoaudiosink sync=false\""
URL_TEMPLATE = "http://{host}:{port}/cgi-bin/eventManager.cgi?action=attach&codes=%5B{events}%5D"
CAMERAS = [
{
"host": "your IP cam IP address here",
"port": your IP cam Port here,
"user": "your username",
"pass": "your password",
"events": "VideoMotion"
},
{
"host": "your IP cam IP address here",
"port": your IP cam Port here,
"user": "your username",
"pass": "your password",
"events": "CrossLineDetection"
}
]
class DahuaCamera():
def __init__(self, master, index, camera):
self.Master = master
self.Index = index
self.Camera = camera
self.CurlObj = None
self.Connected = None
self.Reconnect = None
self.Alarm = dict({
"Active": None,
"Last": None
})
#self.Player = None
#def StartPlayer(self):
# if self.Player:
# return
# print("[{0}] StartPlayer()".format(self.Index))
# self.Master.OnStartPlayer()
# Command = PLAY_TEMPLATE.format(**self.Camera)
# Args = shlex.split(Command)
# self.Player = subprocess.Popen(Args,
# stdin = subprocess.DEVNULL,
# stdout = subprocess.DEVNULL,
# stderr = subprocess.DEVNULL)
#def StopPlayer(self):
# if not self.Player:
# return
# print("[{0}] StopPlayer()".format(self.Index))
# self.Player.kill()
# self.Player.wait()
# self.Player = None
# self.Master.OnStopPlayer()
def SensorOn(self):
client = mqtt.Client
client.connect("your MQTT IP address, mine same as HA",1883,60)
client.publish("home-assistant-1/cameras/motion", "ON");
client.disconnect();
def SensorOff(self)
client = mqtt.Client
client.connect("your MQTT IP address, mine same as HA",1883,60)
client.publish("home-assistant-1/cameras/motion", "OFF");
client.disconnect();
def OnAlarm(self, State):
#print("[{0}] Alarm triggered! -> {1}".format(self.Index, "ON" if State else "OFF"))
if State:
self.SensorOn()
print("Motion Detected")
else:
self.SensorOff()
print("Motion Stopped")
def OnConnect(self):
print("[{0}] OnConnect()".format(self.Index))
self.Connected = True
def OnDisconnect(self, reason):
print("[{0}] OnDisconnect({1})".format(self.Index, reason))
self.Connected = False
# self.StopPlayer()
def OnTimer(self):
#if self.Player:
# self.Player.poll()
# if self.Player.returncode != None:
# self.StopPlayer()
if self.Alarm["Active"] == False and time.time() - self.Alarm["Last"] > ALARM_DELAY:
self.Alarm["Active"] = None
self.Alarm["Last"] = None
self.OnAlarm(False)
def OnReceive(self, data):
Data = data.decode("utf-8", errors="ignore")
#print("[{0}]: {1}".format(self.Index, Data))
for Line in Data.split("\r\n"):
if Line == "HTTP/1.1 200 OK":
self.OnConnect()
if not Line.startswith("Code="):
continue
Alarm = dict()
for KeyValue in Line.split(';'):
Key, Value = KeyValue.split('=')
Alarm[Key] = Value
self.ParseAlarm(Alarm)
def ParseAlarm(self, Alarm):
print("[{0}] ParseAlarm({1})".format(self.Index, Alarm))
if Alarm["Code"] not in self.Camera["events"].split(','):
return
if Alarm["action"] == "Start":
if self.Alarm["Active"] == None:
self.OnAlarm(True)
self.Alarm["Active"] = True
elif Alarm["action"] == "Stop":
self.Alarm["Active"] = False
self.Alarm["Last"] = time.time()
class DahuaMaster():
def __init__(self):
self.Cameras = []
self.NumActivePlayers = 0
self.CurlMultiObj = pycurl.CurlMulti()
self.NumCurlObjs = 0
for Index, Camera in enumerate(CAMERAS):
DahuaCam = DahuaCamera(self, Index, Camera)
self.Cameras.append(DahuaCam)
Url = URL_TEMPLATE.format(**Camera)
CurlObj = pycurl.Curl()
DahuaCam.CurlObj = CurlObj
CurlObj.setopt(pycurl.URL, Url)
CurlObj.setopt(pycurl.CONNECTTIMEOUT, 30)
CurlObj.setopt(pycurl.TCP_KEEPALIVE, 1)
CurlObj.setopt(pycurl.TCP_KEEPIDLE, 30)
CurlObj.setopt(pycurl.TCP_KEEPINTVL, 15)
CurlObj.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_DIGEST)
CurlObj.setopt(pycurl.USERPWD, "%s:%s" % (Camera["user"], Camera["pass"]))
CurlObj.setopt(pycurl.WRITEFUNCTION, DahuaCam.OnReceive)
self.CurlMultiObj.add_handle(CurlObj)
self.NumCurlObjs += 1
#def OnStartPlayer(self):
# self.NumActivePlayers += 1
# if self.NumActivePlayers == 1:
# subprocess.run(["xset", "dpms", "force", "on"])
#def OnStopPlayer(self):
# self.NumActivePlayers -= 1
# if self.NumActivePlayers == 0:
# subprocess.run(["xset", "dpms", "force", "off"])
def OnTimer(self):
for Camera in self.Cameras:
Camera.OnTimer()
def Run(self, timeout = 1.0):
while 1:
Ret, NumHandles = self.CurlMultiObj.perform()
if Ret != pycurl.E_CALL_MULTI_PERFORM:
break
while 1:
Ret = self.CurlMultiObj.select(timeout)
if Ret == -1:
self.OnTimer()
continue
while 1:
Ret, NumHandles = self.CurlMultiObj.perform()
if NumHandles != self.NumCurlObjs:
_, Success, Error = self.CurlMultiObj.info_read()
for CurlObj in Success:
Camera = next(filter(lambda x: x.CurlObj == CurlObj, self.Cameras))
if Camera.Reconnect:
continue
Camera.OnDisconnect("Success")
Camera.Reconnect = time.time() + 5
for CurlObj, ErrorNo, ErrorStr in Error:
Camera = next(filter(lambda x: x.CurlObj == CurlObj, self.Cameras))
if Camera.Reconnect:
continue
Camera.OnDisconnect("{0} ({1})".format(ErrorStr, ErrorNo))
Camera.Reconnect = time.time() + 5
for Camera in self.Cameras:
if Camera.Reconnect and Camera.Reconnect < time.time():
self.CurlMultiObj.remove_handle(Camera.CurlObj)
self.CurlMultiObj.add_handle(Camera.CurlObj)
Camera.Reconnect = None
if Ret != pycurl.E_CALL_MULTI_PERFORM:
break
self.OnTimer()
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
Master = DahuaMaster()
Master.Run()
I have this automation to turn the sensor script on and off from the input boolean;
#dahua cam movement
- alias: cam movement on
initial_state: true
trigger:
entity_id: input_boolean.cam_movement_sensor_on_off
platform: state
to: 'on'
#condition: []
action:
- service: shell_command.cam_motion_on
- alias: cam movement off
initial_state: true
trigger:
entity_id: input_boolean.cam_movement_sensor_on_off
platform: state
to: 'off'
#condition: []
action:
- service: shell_command.cam_motion_off
- delay: 00:00:02
- service: mqtt.publish
data_template:
payload: 'OFF'
topic: 'home-assistant-1/cameras/motion'
I have this in my shell scripts to turn the camera movement detection script on and off from the automation;
shell_command:
cam_motion_on: 'python3 /home/homeassistant/.homeassistant/scripts/dahua.py'
cam_motion_off: 'pkill -f /home/homeassistant/.homeassistant/scripts/dahua.py'
I have this automation for the alarm trigger and to send me the pictures, now I’ve been using a while I find this as good if not better then the Dahua one as I can integrate other things, you can still adjust sensitivity and detection areas on the camera and you can still control if motion is on from the camera, a shortened version is below as mine emails pictures, pushbullets, reads it out from TTS on another HA hub, turns light on and so on (I have the camera as an entity via url stream so am able to camera.snapshot
;
#cam alarm
- alias: Cam Movement
initial_state: false
trigger:
entity_id: binary_sensor.cam_movement_sensor
platform: state
to: 'on'
#condition: []
action:
- service: camera.snapshot
data:
entity_id: camera.cam
filename: /home/homeassistant/.homeassistant/tmp/campic.jpg
#- delay: 00:00:02
- delay: 00:00:01
- service: notify.email_notification
data:
message: movement
title: Movement
data:
#html: <h4>Movement in Dining Room</h4>
images:
- /home/homeassistant/.homeassistant/tmp/campic.jpg
If needed;
I also had to install/update python components, also sudo apt-get update
and sudo apt get-upgrade
, can’t recall exactly which ones but think it was;
pip3 install paho-mqtt
install pycurl info I found http://pycurl.io/docs/latest/install.html
There were some libraries to update and elements when these were installed but was informed on installs, I’m pretty sure I had to install/update setuptools.
The various folders may need the correct permissions 0755 (I just use WinSCP and right click properties on files/folders). I have the group/owner of dahua.py as homeassistant
As I’m VEnv I installed any updates/upgrades through VEnv and normal.
The camera is still pretty sensitive however you get movement alarms. I turned sensitivity and thresholds down and still get false alarms with rain/pigeons and spiders! Cross line detection is better but I wanted both.
Thank you for the info. Did you get other events then motion to work?