The Dahua Home Assistant integration allows you to integrate your Dahua cameras, doorbells, NVRs, DVRs in Home Assistant. It's also confirmed to work with some Lorex cameras and Amcrest devices.
Supports motion events, alarm events (and others), enabling/disabling motion detection, switches for infrared, illuminator (white light), security lights (red/blue flashers), sirens, doorbell button press events, and more.
Also exposes several services to enable/disable motion detection or set the text overlay on the video.
NOTE: Using the switch to turn on/off the infrared light will disable the "auto" mode. Use the service to enable auto mode again (or the camera UI).
Why not use the Amcrest integration already provided by Home Assistant? The Amcrest integration is missing features that this integration provides and I want an integration that is branded as Dahua. Amcrest are rebranded Dahua cams. With this integration living outside of HA, it can be developed faster and released more often. HA has release schedules and rigerous review processes which I'm not ready for while developing this integration. Once this integration is mature I'd like to move it into HA directly.
- Act on what the camera sees. Motion, tripwire, intrusion, abandoned object, human and vehicle detection and the rest arrive on the event bus and as binary sensors, so an automation can notify you or turn on a light without polling anything.
- Answer the door. A doorbell press arrives as an
evententity for "somebody rang at 19:42" and as a binary sensor that holds for a few seconds for automations to wait on, and there is a button and a service to release the lock. - Sound the alarm. On devices with the hardware, the siren, the red and blue security light and a physical alarm output relay can all be switched from an automation.
- Use the camera's own lights. The white illuminator and the infrared light are
lightentities, so the camera can light the drive on an automation and be handed back to its own automatic mode afterwards. - Stop it watching while you are home. Motion detection, smart motion detection, recording mode, privacy masks and the motorised lens cover are all switchable, so presence can turn the cameras down rather than off.
- Open the gate for a car you know. On cameras with ANPR, the recognised plate is a sensor, and naming the plates you trust gives a binary sensor that turns on only for those.
- Write on the video. The channel title, the timestamp and free text overlays can be set from an automation, which is how a temperature or a zone name gets burned into the recording.
If you want live-streaming, make sure to add the following to your config.yaml:
ffmpeg:
Home Assistant 2026.8.0 or newer. HACS will not offer the integration on anything older, because a recorder's channels are stored as config subentries and that needs a recent Home Assistant.
To install with HACS:
- Click on HACS in the Home Assistant menu
- Click on
Integrations - Click the
EXPLORE & ADD REPOSITORIESbutton - Search for
Dahua - Click the
INSTALL THIS REPOSITORY IN HACSbutton - Restart Home Assistant
- Configure the camera by going to
Configurations->Integrations->ADD INTERATIONSbutton, search forDahuaand configure the camera.
Fixes land in a pre-release first, usually within a day, and are gathered into a stable release afterwards. Pre-releases are hidden unless you ask for them, so if you do nothing, nothing changes: you keep being offered stable releases only.
To opt in:
Settings->Devices & services->Integrationstab- Open
HACS - Find the
Dahuaintegration - Turn on the pre-release toggle
You will then be offered pre-releases as updates, the same way as stable ones. Turn it back off at any time and the next stable release brings you back to the stable line.
Worth knowing before you opt in:
- Pre-releases get less testing than stable, by definition. Do not run one on a camera you cannot afford to have misbehave for an afternoon.
- If you report a problem, say which version you are on. This matters more here than on stable.
- Finding things before they reach everyone is the whole point, so a report from a pre-release user is worth a great deal. If something breaks, please open an issue rather than quietly rolling back.
To manually install:
# Download a copy of this repository
$ wget https://github.com/rroller/dahua/archive/refs/heads/main.zip
# Unzip the archive
$ unzip main.zip
# Move the dahua directory into your custom_components directory in your Home Assistant install
$ mv dahua-main/custom_components/dahua <home-assistant-install-directory>/config/custom_components/
⚠️ After executing one of the above installation methods, restart Home Assistant. Also clear your browser cache before proceeding to the next step, as the integration may not be visible otherwise.
Home Assistant talks to the device directly over its local HTTP API. Six things are decided on the camera or recorder, not in Home Assistant, and each one has been the entire cause of a failed setup for somebody. If you are setting up a device for the first time, it is worth checking these before you begin rather than after.
Menu paths differ between firmware generations, so treat these as the setting to look for rather than an exact route.
-
The CGI service must be enabled.
System→Safety(orSecurity) →System Service→CGI Service. On some firmwares it is underLocal Settings→Security. How to tell: openhttp://<address>/cgi-bin/magicBox.cgi?action=getMachineNamein a browser. A 404 means CGI is off. A login prompt means it is on. -
Use an account on the device, not a cloud account. The Dahua, Imou or Amcrest app login is a cloud account and will not work here. You need a user created on the device itself, and it is usually
adminin lower case. Watch for a phone keyboard capitalising it. -
If you have never set a password, it is the safety code printed on the device's label. A device that has never been initialised has no account at all and has to be initialised first, through its own web interface or ConfigTool.
-
Authentication mode must be Compatible, not Safety.
Network→Basic Services→Authentication, or on recordersSecurity→System Service→Basic Services→Private Protocol Authentication Mode. Set it to Compatibility Mode. -
The digest algorithm must include MD5.
System→Security→Security Authentication. With MD5 disabled the device answers500to API calls. Selecting more than one algorithm for user authentication is also known to break RTSP streaming, so MD5 alone is the working combination people report. -
Decide about HTTPS deliberately. If HTTPS is enabled on the device, either turn it off, or tick Use HTTPS in Home Assistant and use port
443. An HTTPS device added over plain HTTP on port 80 will not connect, and this has caught people out after a firmware update switched it on by itself.
Two more that affect video rather than the connection: at least one sub-stream should be H.264 rather than H.265, because H.265 will not render in the browser, and the sub-stream you intend to use has to be enabled on the device.
⚠️ Repeated failed logins will lock you out. Dahua devices lock the source IP after a number of failed attempts. At least one recorder reports its own policy as 5 failures then a 300 second lock, and separately a device can refuse with "Exceeded maximum number of connections", which needs a reboot rather than a wait. If setup fails, fix the cause rather than retrying the same credentials.
- In the Home Assistant left menu, click Settings
- Click Devices & services
- Click ADD INTEGRATION
- Type
Dahuaand select it - Enter the details:
- Username: an account on the device, usually
admin(see above) - Password: that account's password
- Address: the device's IP address or hostname
- Port: the HTTP port.
80normally, or443for HTTPS - RTSP port:
554normally. Used to stream the camera in Home Assistant - Use HTTPS: tick this if the device serves HTTPS on the port above.
Left unticked, HTTPS is used only when the port is
443 - Channel: counted from 0. A single camera is
0. On a recorder this is one less than the number the recorder shows, so its channel 4 is3here. You only need the first one: the recorder's other channels are offered on the next screen, where they are listed by the number the recorder itself uses
- Username: an account on the device, usually
Only username, password, address and channel are asked at first. Port, RTSP port and Use HTTPS appear only if the connection fails, because their defaults are right on almost every device and a form that asks eight questions to add one camera is a form people get wrong. Which events become binary sensors is not asked here either: it is on the options screen, where it can be changed afterwards without removing the camera.
On a recorder, the next screen offers the other channels that have a live camera on them, and the one after that lets you file each of them in an area. Channels that are empty, switched off, or reached over ONVIF are not offered, because this integration cannot drive them.
The last screen asks for a name and shows a still from the channel you chose, so a channel number that is off by one is caught by looking rather than after the entry exists. A device that will not serve a snapshot simply shows no picture.
NOTE: An entity is added for every stream the device can serve, whether or not that stream is enabled on the device, because which ones exist cannot be known without asking and asking costs a request per channel. Only the main stream is enabled to begin with. The sub streams are listed but switched off, so if you want to point a card at one, enable it from the entity's own page. Nothing that already exists is affected by this: a sub stream camera you are already using stays exactly as it is.
Earlier versions added one config entry per channel, so a sixteen channel recorder appeared as sixteen separate integrations. From 1.0 a recorder is one entry with one subentry per channel, which is what lets the channels share a single login and a single event connection instead of opening sixteen of each.
The first start after upgrading merges them for you. Nothing needs to be re-added and entity ids are kept, so automations and dashboards continue to work.
A copy of the registries is saved first. Before anything is changed, these three files
are copied out of .storage:
core.config_entries
core.device_registry
core.entity_registry
into a new directory named for the time it ran:
/config/dahua-pre-merge-backup-20260930-142824
The path is written to the log as a warning, so searching the log for
dahua-pre-merge-backup will find it. If the backup cannot be written the merge is not
attempted, and the log says so.
To go back, stop Home Assistant, copy those three files back into /config/.storage, and
start it again. It has to be done with Home Assistant stopped, because it rewrites the
files on shutdown. The merge cannot be undone from inside Home Assistant, so keep the
directory until you are happy with the result.
The error on the form names the cause where it can. What each one means:
| What you see | What it usually is |
|---|---|
| The camera rejected that username and password | A genuine 401. Check it is a device account and not a cloud one, and that admin is lower case |
| That address is serving web pages, but not the Dahua API | The CGI service is switched off. Prerequisite 1 above |
| Nothing answered on that port, but the device is listening on 443 | It is serving HTTPS. Tick Use HTTPS and use port 443 |
| The device is answering Dahua's own protocol, but nothing is serving HTTP | The device is alive and its web service is off. Turn on HTTP and CGI in System Service |
| The secure connection failed | Either the device does not serve HTTPS on that port, or it does and it is on 443. Self-signed certificates are accepted and are not the problem |
| Nothing answered at that address and port | Nothing is listening. Check the address, and that Home Assistant can reach that subnet |
| The camera did not answer in time | Reachable but slow or busy. Check the port is the one it serves HTTP on |
Two cases the form cannot diagnose for you:
- Some devices have no local API at all. Cloud-only Imou and Lechange models, and
some doorbells whose firmware moved to the cloud app, serve no
/cgi-bin/API. There is nothing this integration can do for those; ONVIF or the vendor's cloud integration is the route. A downgrade to earlier firmware has restored the local API for some people. - Cameras behind a recorder's own PoE ports often sit on a private subnet, such
as
10.1.1.x, that Home Assistant cannot route to. Add them through the recorder's address and channel number instead of trying to reach them directly.
Every device page has Download diagnostics under the three dot menu. It is the most useful thing to attach to an issue, and it is worth looking at yourself first.
Credentials are removed before the file is written: the username, the password, the serial
number and the unique id are replaced with **REDACTED**, and any RTSP URL has its
credentials swapped for REDACTED rather than being included and hidden.
Three fields answer most "my sensors stopped working" questions, all under events:
| field | what it tells you |
|---|---|
configured |
the event codes this channel actually subscribed to. If the code you expect is missing, the device was never asked for it |
subscribed_as |
how the request went out: the list of codes, or ["All"] if the device refused a list (see below) |
arrived_with_no_listener |
events the device did send that nothing was listening for. A non-zero count here means the event is arriving and being dropped, which is a different problem from the device not sending it |
Together they separate the three possibilities: never subscribed, subscribed but the device sent nothing, or sent and dropped.
- In Settings > Devices & services, find Dahua
- Click the three dots beside the device and choose Delete
- Confirm
One device is one config entry. A recorder is also one entry, holding one subentry per channel, so deleting the entry removes the whole recorder and every channel with it. To remove a single channel of a recorder, delete that channel rather than the entry.
Nothing is left behind on the device. The integration only reads settings and holds an event connection, and deleting the entry ends both. Settings you changed from Home Assistant are the device's own settings and stay as you left them, so if you turned motion detection off, or left the illuminator on, put it back from the device's web UI or the Dahua app.
To remove the integration itself, delete it in HACS, or delete the
custom_components/dahua directory if you installed it by hand, and restart Home
Assistant.
This integration should word with most Dahua cameras and doorbells. It has been tested with very old and very new Dahua cameras.
Doorbells will have a binary sensor that captures the doorbell pressed event.
- Please let me know if you've tested with additional cameras
These devices are confirmed as working:
| Series | 2 Megapixels | 4 Megapixels | 5 Megapixels | 6 Megapixels | 8 Megapixels |
|---|---|---|---|---|---|
| Consumer Series | |||||
| A26 | |||||
| 1-Series | |||||
| HFW1230S | HFW1431S1-S4 | ||||
| HDBW1230E-S2 | HFW1435S-W | ||||
| HFW1435S-W-S2 | |||||
| HDBW1431EP-S-0360B | |||||
| 2-/3-Series | |||||
| HDW2831T-ZS-S2 | HDW2431TP-AS | HDW3549HP-AS-PV | HDW3849HP-AS-PV | ||
| HDBW2231FP-AS-0280B-S2 | HDBW2431R-ZS | HFW3549T1-AS-PV-0280B-S3 | |||
| HFW2449S-S-IL | |||||
| HFW3441E-AS-S2 | |||||
| 4-/5-Series | |||||
| HDW4231EM-ASE | HFW4433F-ZSA | HDW4631EM-ASE | HDW5831R-ZE | ||
| HDBW4231F-AS | HDBW5421E-Z | ||||
| HDW4233C-A | T5442T-ZE | ||||
| HDBW4239R-ASE | T5442TM-AS | ||||
| B5442E-Z4E | |||||
| B54IR-ASE | |||||
| HDBW4239RP-ASE | |||||
| PTZ Series | |||||
| SD1A203T-GN | |||||
| SD42212S-HN | |||||
| Thermal Series | |||||
| TPC-BF2221P-B3F4 | |||||
| 6-/7-Series | |||||
| HDPW7564N-SP | |||||
| Panoramic Series | |||||
| EW5531-AS |
| Brand | 2 Megapixels | 4 Megapixels | 5 Megapixels | 8 Megapixels |
|---|---|---|---|---|
| Amcrest | ||||
| Amcrest IP5M-T1179E | Amcrest IPC-Color4K-T | |||
| EmpireTech | ||||
| IPC-Color4M-TZ | PTZ3E10X-T180 † | |||
| IMOU | ||||
| IMOU IPC-A26Z / Ranger Pro Z | IMOU DB61i | |||
| IMOU IPC-C26E-V2 * | ||||
| IMOU IPC-K22A / Cube PoE-322A | ||||
| Lorex | ||||
| Lorex E891AB/E893DD | ||||
| Lorex LNB8005-C | ||||
| Lorex LNE8964AB |
* partial support
† dual-sensor camera with an 8 MP overview channel and a 4 MP PTZ channel
The tables above are devices someone has confirmed working. This is a different and weaker claim: these are model names the integration looks for by name when it cannot detect a siren or a white security light any other way. If your model is here, the control should appear even when the device does not report the capability.
| model | what it gets |
|---|---|
anything containing AS-PV |
siren and security light |
anything containing L46N |
siren |
anything containing TPC-BF1241 |
siren |
anything starting W452ASD |
siren |
AD410, DB61I |
security light |
anything starting IP8M-2796E |
security light |
anything starting IPC-COLOR4M-TZ |
security light |
anything starting PTZ3E10X-T180 |
security light |
Matching by model name is a fallback, not the first choice, and it is the wrong shape:
it fails on a device that has the hardware and is not on the list. If yours is missing,
say so on an issue and include the diagnostics download, which lists what was and was not
detected under supports_siren_sources and
supports_security_light_sources. The
manual_siren and manual_security_light options force the control on in the meantime.
| Brand | 2 Megapixels | 4 Megapixels | 5 Megapixels | 8 Megapixels |
|---|---|---|---|---|
| Amcrest | ||||
| Amcrest AD110 | Amcrest AD410 | |||
| Dahua | ||||
| DHI-VTO2202F-P | ||||
| DHI-VTO2211G-P | ||||
| DHI-VTO3311Q-WP | ||||
| DHI-VTO2211G-WP-S2 | ||||
| IMOU | ||||
| IMOU C26EP-V2 | IMOU IPC-K46 | IMOU DB61i |
| Model | Firmware |
|---|---|
| VTH2421F-P | 4.800.0000000.1.R |
Add an indoor monitor like any other device, by its address and an account on the monitor itself (usually the same as the VTO's). A VTH serves no CGI at all, so the integration identifies it over RPC2 and shows its real model and firmware.
What it gets:
- A Camera for <VTO> calls select for each VTO it knows: the camera its screen opens on
when that VTO calls.
noneis the VTO's own picture; the other options are the cameras in the monitor's own camera list (Monitor > IPC on its screen). The monitor's screen has no control for this on the measured firmware, though its manual describes it. - Reboot, firmware version and serial number.
A monitor that reports it has no camera of its own (SupportVideo false in its
RemoteDevice table, as on the VTH2421F-P) gets no camera entities, no camera event
sensors, no event stream, no motion detection switch, no Day/Night select, no Preset
Position, and no License Plate or Authorized Vehicle entities.
The serial number shown is generated from the address and login, as for every device whose CGI does not answer, so that it stays stable; it is not the serial printed on the monitor.
To ring a monitor, use dahua.vto_call on the VTO, not on the monitor.
What this integration cannot do, as distinct from the bugs and firmware quirks under Known Issues.
- Settings are polled, so a change made elsewhere is not instant. Turning a light on from the Dahua app appears in Home Assistant within one poll interval, 30 seconds by default and 10 at the fastest. Events are pushed and are not affected by this. See How data is updated.
- The infrared and illuminator lights have three states, and a light entity has
two. Switching either on takes the camera out of Auto, and while it is in Auto the
entity cannot report on or off because the camera does not say which it is. Use
dahua.set_infrared_modeordahua.set_illuminator_modeto hand Auto back. - A device with no local API cannot be used at all. Cloud only Imou and Lechange
models, and some doorbells whose firmware moved to the vendor's app, serve no
/cgi-bin/API. ONVIF or the vendor's own integration is the route for those. - Cameras on a recorder's own PoE ports are usually not reachable directly, because they sit on a private subnet Home Assistant cannot route to. Add them through the recorder's address and channel number instead.
- Channels a recorder reaches over ONVIF cannot be driven, and are not offered when adding one. This integration speaks Dahua's own API and an ONVIF channel does not answer it.
- Active deterrence through a recorder is undocumented and unreliable. Whether an NVR passes a siren or white light command through to the camera behind it varies by model, and on some it accepts the command and does nothing at all. That is why those entities are off by default rather than created automatically.
- A large configuration write can be refused on a recorder. RPC2 answers
Request length error!to a bigsetConfig, and a recorder's IVS rule table can be large enough to hit that, so an IVS rule switch may fail to toggle. Measured on one recorder, where writes from 9KB upwards were refused. A single camera's table is far smaller and is not affected. - No triggers or conditions are provided. Events reach the bus as
dahua_event_receivedand become binary sensors, and automations are written against those. There are no integration specific trigger or condition types. - The siren and the security light switch themselves off after 10 to 15 seconds. That is the device's own behaviour and cannot be extended from here.
- Recorders cap how many RTSP streams they serve at once, often quite low, so several cards watching several channels can fail where one channel works.
- Not every camera has every entity. The illuminator, the security light, the siren, smart motion detection, PTZ presets, ANPR and the motorised lens cover are each created only on devices that report them. If one is missing and you know the hardware is there, see the manual enable options under Channel options.
-
A camera that shows a still image but never a moving stream is usually sending H.265. Home Assistant handles H.264 reliably; an H.265 stream commonly gives a camera that is plainly online, with entities that populate and a picture that updates when you click it, and a live view that never plays. HomeKit will not play H.265 at all.
Fix it on the device, not in Home Assistant: in the camera or recorder's web UI, under Video > Encode, set the stream you use to H.264. If you want the low bandwidth path, set the sub stream to H.264 and point the card at the sub stream. Adding
ffmpeg:toconfiguration.yamldoes not change this, so having added it does not rule the codec out.Reported as #236, #244, #257, #262 and #272, among others.
If the stream error is
Operation timed outrather than a demuxing failure, that is a different problem: the device is not answering RTSP at all, which points at the RTSP port or at how many simultaneous streams it allows. Recorders in particular cap that quite low. -
Versions between 0.9.84 and 0.9.92 could leave the illuminator switched on in a profile you are not using. In that window the illuminator wrote to the wrong day/night profile on some cameras (#605, #582); which versions affected you depends on the camera, and 0.9.93 fixed the write for both kinds. It does not undo what the earlier versions wrote. If you turned the illuminator on during that window,
Lighting_V2[<channel>][0][0].Modemay still beManualon the Day profile.While the camera is in General mode this does nothing at all. But if the camera is ever switched to Day/Night profile management, the light comes on when that profile becomes active, looking as though it did so by itself. Home Assistant will report it as on and can turn it off — but only once you notice it.
The integration deliberately does not correct this for you, because doing so would mean writing to a profile you are not currently using, on every camera, unprompted. To check for it and clear it by hand, see Curl/HTTP commands.
Two separate things happen, on two separate schedules, and most confusion about this integration comes from reading one as the other.
Events are pushed, and arrive as soon as the device sends them. The integration holds a long lived connection to the device and the device writes to it when something happens. Motion, tripwire, a doorbell press and everything else in the Events section arrive this way. The poll interval has no effect on them at all.
There are three of these connections, and which one a device gets depends on what it serves:
| Transport | Used for | How it works |
|---|---|---|
eventManager.cgi multipart stream |
almost every camera and recorder | One HTTP connection the device streams event payloads down, held open for as long as the entry is loaded |
| DHIP on TCP port 5000 | doorbells (VTO) | A separate binary protocol connection, which is also what carries a doorbell's card reader and call events |
| RPC2 polling | firmware that serves no CGI at all | Some devices answer 404 to every /cgi-bin/ path. RPC2 has no readable subscription, so the alarm state of each selected code is polled and its edges are turned into the same event payloads. This is the only transport that is not push |
A connection that drops is reconnected with a backoff, so a camera that is unplugged is not contacted every few seconds for ever.
Settings are polled, every 30 seconds by default. Whether motion detection is on, which lights are on, the day/night profile, the PTZ preset, the recording mode: these are the device's own configuration, and the only way to know they changed is to ask. That is what the poll interval is, it can be set per entry from 10 seconds upwards, and it is also why a change made in the Dahua app takes up to one interval to appear in Home Assistant.
Turning a platform off stops the requests that exist only to feed it, so the poll gets cheaper as well as quieter. See Reducing entries in your device's log.
Reads are shared and cached where the device allows it: channels of one recorder share a single host wide read rather than asking once each, and a device that stops answering is backed off rather than retried at the same rate.
Events are streamed from the device and fired on the Home Assistant event bus.
Here's example event data:
{
"event_type": "dahua_event_received",
"data": {
"name": "Cam13",
"Code": "VideoMotion",
"action": "Start",
"index": "0",
"data": {
"Id": [
0
],
"RegionName": [
"Region1"
],
"SmartMotionEnable": false
},
"DeviceName": "Cam13"
},
"origin": "LOCAL",
"time_fired": "2021-06-30T04:00:28.605290+00:00",
"context": {
"id": "199542fe3f404f2a0a81031ee495bdd1",
"parent_id": null,
"user_id": null
}
}And here's how you configure and event trigger in an automation:
platform: event
event_type: dahua_event_received
event_data:
name: Cam13
Code: VideoMotion
action: StartAnd that's it! You can enable debug logging (See at the end of this readme) to print out events to the Home Assisant log
as they fire. That can help you understand the events. Or you can HA and open Developer Tools -> Events -> and under
"Listen to events" enter dahua_event_received and then click "Start Listening" and wait for events to fire (you might
need to walk in front of your cam to make motion events fire, or press a button, etc)
These are two separate things, and reading one as the other has produced several issue reports where nothing was actually broken.
Every event that arrives is put on the bus, before anything else happens. It is
fired with the raw code the device sent, before any translation and before any sensor
is considered. So if you see a code in dahua_event_received, the connection to the
device and the event stream are working. That is all it proves.
A binary sensor only updates if you selected that event for that entry. The
sensors that exist come from the event list on the entry, and an event you did not
select has no sensor and no listener, so nothing is written. (Doorbells are the one
exception: they always get Doorbell Pressed, Invite, Door Status and Call No
Answered, because almost everybody wants them.) Seeing
CrossRegionDetection on the bus while a Smart Motion sensor stays off is exactly
what a correctly working system looks like when SmartMotionHuman was not selected.
To change the selection: Settings, Devices and Services, Dahua, Configure, on the entry you mean. Ticking boxes in the camera's own web interface does not affect which Home Assistant entities exist.
Many cameras never send SmartMotionHuman at all. They send CrossLineDetection or
CrossRegionDetection carrying an object type, and the integration fires the matching
smart motion code as well:
Code: CrossRegionDetection
data:
Object:
ObjectType: Human
becomes both CrossRegionDetection and SmartMotionHuman, so on such a camera
SmartMotionHuman is the better sensor to use: it fires only for people, where the
Cross Region one fires for anything that trips the rule. Both fire when both are
selected. But the smart motion sensor only exists if you selected it, so on a camera
sending the payload above you can see CrossRegionDetection on the bus all day and
get nothing from Smart Motion until it is ticked.
On a recorder each channel is its own entry with its own event list, and an event
updates the sensor belonging to the channel it came from. If channel 1 has
SmartMotionHuman selected and channel 2 does not, motion on channel 2 appears on the
bus and updates nothing.
Some firmware serves the event stream perfectly and refuses a long list of codes. Measured
on two different cameras: an IPC-HFW4300S-V2 answers codes=[VideoMotion] with 200 and the
same request carrying nine codes with 400, and a Hero A1 answers 500 to those nine.
When that happens the integration notices the refusal and asks again with codes=[All],
filtering locally instead. Your event selection is unaffected, because the filtering
happens here rather than on the device. It is tried once per stream, and a warning naming
the status is logged so you can see it happened.
subscribed_as in the diagnostics says which form is in use. If it reads ["All"] and you
did not select every event, this is why.
This was the cause of #728, which read as "everyone with a single camera" rather than as a firmware quirk: the workaround existed before, but it was chosen by guessing whether a request looked too long instead of waiting for the device to say so, and that guess can never be true for a single camera.
If you deselect an event, its sensor is not created next time the entry loads, and
Home Assistant leaves the old entity behind showing unavailable with "This entity is
no longer being provided by the dahua integration". That is Home Assistant reporting
an entity nothing owns any more, not a fault in the integration, and it will never
update again. Either select the event again, or delete the entity from its own page.
Reloading or restarting will not clear it.
| Code | Description |
|---|---|
| BackKeyLight | Unit Events, See Below States |
| VideoMotion | motion detection event |
| VideoLoss | video loss detection event |
| VideoBlind | video blind detection event |
| AlarmLocal | alarm detection event |
| CrossLineDetection | tripwire event |
| CrossRegionDetection | intrusion event |
| LeftDetection | abandoned object detection |
| TakenAwayDetection | missing object detection |
| VideoAbnormalDetection | scene change event |
| FaceDetection | face detect event |
| AudioMutation | intensity change |
| AudioAnomaly | input abnormal |
| VideoUnFocus | defocus detect event |
| WanderDetection | loitering detection event |
| RioterDetection | People Gathering event |
| ParkingDetection | parking detection event |
| MoveDetection | fast moving event |
| MDResult | motion detection data reporting event. The motion detect window contains 18 rows and 22 columns. The event info contains motion detect data with mask of every row |
| HeatImagingTemper | temperature alarm event |
| State | Description |
|---|---|
| 0 | OK, No Call/Ring |
| 1, 2 | Call/Ring |
| 4 | Voice message |
| 5 | Call answered from VTH |
| 6 | Call not answered |
| 7 | VTH calling VTO |
| 8 | Unlock |
| 9 | Unlock failed |
| 11 | Device rebooted |
Note for ease of use, the integration tries to determine if your device supports certain services and entities and will conditionally add them. That is sometimes hard to determine, so where it is unclear the entity is added anyway — an extra entity you can disable is friendlier than a flow complicated enough to be wrong. The "door open state" on doorbells is an example: not every doorbell has one.
Where the device reports the answer plainly, the entity is only created if it is real. Smart Motion Detection is the clearest case: the device lists the channels that support it, so channels that are absent from that list get no switch rather than one that reads off forever and silently discards anything written to it.
| Service | Parameters | Description |
|---|---|---|
camera.enable_motion_detection |
Enables motion detection | |
camera.disable_motion_detection |
Disabled motion detection | |
dahua.set_infrared_mode |
target: camera.cam13_main mode: Auto, On, Off brightness: 0 - 100 inclusive |
Sets the infrared mode. Useful to set the mode back to Auto |
dahua.goto_preset_position |
target: camera.cam13_main position: 1 - 10 inclusive |
Go to a preset position |
dahua.set_video_profile_mode |
target: camera.cam13_main mode: Day, Night |
Sets the video profile mode to day or night |
dahua.set_focus_zoom |
target: camera.cam13_main focus: The focus level, e.g.: 0.81 0 - 1 inclusive zoom: The zoom level, e.g.: 0.72 0 - 1 inclusive |
Sets the focus and zoom level |
dahua.set_channel_title |
target: camera.cam13_main channel: The camera channel, e.g.: 0 text1: The text 1text2: The text 2 |
Sets the channel title |
dahua.set_text_overlay |
target: camera.cam13_main channel: The camera channel, e.g.: 0 group: The group, used to apply multiple of text as an overly, e.g.: 1 text1: The text 1text3: The text 3 text4: The text 4 text2: The text 2 |
Sets the text overlay on the video |
dahua.set_custom_overlay |
target: camera.cam13_main channel: The camera channel, e.g.: 0 group: The group, used to apply multiple of text as an overly, e.g.: 0 text1: The text 1text2: The text 2 |
Sets the custom overlay on the video |
dahua.enable_channel_title |
target: camera.cam13_main channel: The camera channel, e.g.: 0 enabled: True to enable, False to disable |
Enables or disables the channel title overlay on the video |
dahua.enable_time_overlay |
target: camera.cam13_main channel: The camera channel, e.g.: 0 enabled: True to enable, False to disable |
Enables or disables the time overlay on the video |
dahua.enable_text_overlay |
target: camera.cam13_main channel: The camera channel, e.g.: 0 group: The group, used to apply multiple of text as an overly, e.g.: 0 enabled: True to enable, False to disable |
Enables or disables the text overlay on the video |
dahua.enable_custom_overlay |
target: camera.cam13_main channel: The camera channel, e.g.: 0 group: The group, used to apply multiple of text as an overly, e.g.: 0 enabled: True to enable, False to disable |
Enables or disables the custom overlay on the video |
dahua.set_privacy_masking |
target: camera.cam13_main index: The mask index, e.g.: 0 enabled: True to enable, False to disable |
Enables or disabled a privacy mask on the camera |
dahua.set_record_mode |
target: camera.cam13_main mode: Auto, On, Off |
Sets the record mode. On is always on recording. Off is always off. Auto based on motion settings, etc. |
dahua.enable_all_ivs_rules |
target: camera.cam13_main channel: The camera channel, e.g.: 0 enabled: True to enable all IVS rules, False to disable all IVS rules |
Enables or disables all IVS rules |
dahua.enable_ivs_rule |
target: camera.cam13_main channel: The camera channel, e.g.: 0 index: The rule index enabled`: True to enable the IVS rule, False to disable the IVS rule |
Enable or disable an IVS rule |
dahua.vto_open_door |
target: camera.cam13_main door_id: The door ID to open, e.g.: 1 Opens a door via a VTO |
|
dahua.vto_cancel_call |
target: camera.cam13_main Cancels a call on a VTO device (Doorbell) |
|
dahua.vto_call |
target: camera.cam13_main room: The room to ring, e.g.: 9901 |
Rings an indoor monitor (VTH) from a VTO, as its call button does. 9901#0 is dialled as 9901, which rings the main monitor and its extensions. Measured on a DHI-VTO2211G-WP-S2 |
dahua.set_video_in_day_night_mode |
target: camera.cam13_main config_type: The config type: general, day, night mode: The mode: Auto, Color, BlackWhite. Note Auto is also known as Brightness by Dahua |
Set the camera's Day/Night Mode. For example, Color, BlackWhite, or Auto |
dahua.reboot |
target: camera.cam13_main Reboots the device |
|
dahua.set_illuminator_mode |
target: camera.cam13_main mode: Auto, On, Off brightness: 0 - 100 inclusive |
Sets the illuminator (white light) mode. The light entity can only switch it on or off, and off is not the same as automatic, so this is how control is handed back to the camera with Auto |
dahua.ptz_move |
target: camera.cam13_main direction: up, down, left, right, up_left, up_right, down_left, down_right, zoom_in, zoom_out speed: 1 - 8 duration: 0.1 - 10 seconds |
Pans, tilts or zooms for a moment. The camera moves while the command runs and is stopped afterwards, so the duration is how far it travels |
dahua.set_privacy_mode |
target: camera.cam13_main enabled: True to cover the lens, False to uncover it |
Physically covers the lens on cameras with a motorised cover, so the camera sees nothing at all. Only cameras reporting a LeLensMask table have this; on any other camera the call fails. To blank part of the picture instead, use dahua.set_privacy_masking |
dahua.get_overlay_text |
target: camera.cam13_main group: 0 - 100, default 0 |
Returns the overlay text the camera is currently showing, for when it may have been changed on the camera rather than from Home Assistant. This one responds with data |
This will provide a normal HA camera entity (can take snapshots, etc)
| Switch | Description |
|---|---|
| Motion | Enables or disables motion detection on the camera |
| Siren | If the camera has a siren, will turn on the siren. Note, it seems sirens only stay on for 10 to 15 seconds before switching off |
| Event Notifications | Enables or disables the device's event notifications |
| Smart Motion Detection | If the device supports it, enables or disables smart motion detection (human and vehicle filtering rather than plain pixel motion). Only created on channels the device reports as supporting it |
| IVS Rule | One switch per IVS rule the camera reports (tripwire, intrusion and so on), each keyed on the rule's own stable Dahua ID, so it is named after the rule as the device names it. Configuration entities |
| Alarm Output | A physical alarm or relay output on the device, switched directly |
| Privacy Mode | Covers the lens on cameras with a motorised cover. See dahua.set_privacy_mode |
| Disarming Linkage | Newer firmwares introduce a "disarming" feature, accessible from the camera web UI under Event → One-click disarm / Disarming. When enabled, the disarm toggle suppresses the linkage actions configured in the Disarming section specifically, while leaving all other alarm linkage actions untouched. Detection remains fully active throughout. This allows one to turn it on/off. |
| Light | Description |
|---|---|
| Infrared | Turns on/off the infrared light. Using this switch will disable the "auto" mode. If you want to enable auto mode again then use the service to enable auto. When in auto, this switch will not report the on/off state. |
| Illuminator | If the camera has one, turns on/off the illuminator light (white light). Using this switch will disable the "auto" mode. If you want to enable auto mode again then use the service to enable auto. When in auto, this switch will not report the on/off state. |
| Security | If the camera has one, turns on/off the security light (red/blue flashing light). This light stays on for 10 to 15 seconds before the camera auto turns it off. |
| Sensor | Description |
|---|---|
| Motion | A sensor that turns on when the camera detects motion |
| Button Pressed | A sensor that turns on when a doorbell button is pressed |
| Authorized Vehicle | Turns on when the camera's ANPR recognises a plate you have listed as authorized, and stays on for the hold time you set. Attributes carry the plate that matched and what the camera reported about the vehicle. Created on every camera and every channel of a recorder, so it existing does not mean that camera can read plates: it stays off unless the camera reports one and it is on your list |
| Others | A binary senor is created for evey event type selected when setting up the camera (Such as cross line, and face detection) |
Diagnostic sensors. These report values already read during setup or during the normal poll, so they cost no extra requests.
| Sensor | Description |
|---|---|
| Firmware Version | The firmware the device reports. Also shown on the device page, but as a sensor it can be templated and compared — which is what makes "tell me when a camera is behind" possible |
| Serial Number | The serial the device reports. On an NVR every channel reports the recorder's serial, because every channel is the same physical box |
| License Plate | The last recognized license plate reported by the camera's ANPR/Traffic AI, including attributes for confidence, vehicle type, vehicle color, brand/logo, model/series, and direction |
| Profile | Which day/night lighting profile the camera is using right now. Useful because a camera can change profile by itself, and the illuminator and infrared settings are stored per profile |
| Select | Description |
|---|---|
| Security Light | On a doorbell, sets the light to off, on, or strobe. A doorbell's light has three states rather than two, which is why it is a select and not a switch |
| Preset Position | Moves a PTZ camera to one of its stored preset positions, and reports the one it is at. Only created on cameras that report presets |
| Day/Night Mode | The camera's colour mode: Color, BlackWhite, or Auto (which Dahua also calls Brightness). Readable as well as settable, which is what makes it possible to notice a camera that changed mode by itself, such as one reverting to Auto after a power cut and then rendering black and white at night |
| Camera for <VTO> calls | On an indoor monitor (VTH), which camera its screen opens on when that VTO calls it, or none for the VTO's own picture. See Indoor monitors |
| Entity | Description |
|---|---|
| Doorbell | Home Assistant's own doorbell primitive, with the doorbell device class, which is what cards and other integrations built on it expect. It is momentary: it records that somebody rang and when. The Button Pressed binary sensor covers the other shape of the same fact, holding a state for a few seconds for an automation to wait on, so both exist and both are useful |
| Button | Description |
|---|---|
| Reboot | Reboots the device |
| Open Door | On a VTO (doorbell), opens the door |
| Cancel Call | On a VTO (doorbell), hangs up a call in progress. Reports whether the doorbell agreed, rather than always looking as though it worked |
Change the entity ids to your own. The event based ones use dahua_event_received,
described under Events; name is the device name the integration reports,
which is also in the event payload if you watch the bus.
A second doorbell that is not wired to the VTO rings the indoor monitors, showing its own camera.
Here a KNX push button (binary_sensor.gate_doorbell) rings room 9901 through the VTO, and the
monitors open the call on the gate camera instead of the VTO's picture. They are set back
afterwards, so the VTO's own button still shows the VTO.
alias: Gate doorbell rings the indoor monitors
mode: single
max_exceeded: silent
triggers:
- trigger: state
entity_id: binary_sensor.gate_doorbell
to: "on"
actions:
- action: select.select_option
target:
entity_id:
- select.vth_hall_camera_for_main_vto_calls
- select.vth_upstairs_camera_for_main_vto_calls
data:
option: Gate
continue_on_error: true
- action: dahua.vto_call
target:
entity_id: camera.front_door_main
data:
room: "9901"
continue_on_error: true
- delay:
seconds: 90
- action: select.select_option
target:
entity_id:
- select.vth_hall_camera_for_main_vto_calls
- select.vth_upstairs_camera_for_main_vto_calls
data:
option: noneSomebody rang the doorbell: notify a phone with a picture.
alias: Doorbell pressed
trigger:
- platform: state
entity_id: event.front_door_doorbell
action:
- service: camera.snapshot
target:
entity_id: camera.front_door_main
data:
filename: /config/www/doorbell.jpg
- service: notify.mobile_app_phone
data:
message: Somebody is at the front door
data:
image: /local/doorbell.jpg
mode: singleLight the drive on motion after dark, then hand the camera back its automatic mode. Turning the illuminator on switches the camera out of Auto, so the last step is what stops it staying that way.
alias: Drive light on motion
trigger:
- platform: state
entity_id: binary_sensor.drive_motion_alarm
to: "on"
condition:
- condition: state
entity_id: sun.sun
state: below_horizon
action:
- service: light.turn_on
target:
entity_id: light.drive_illuminator
- delay: "00:02:00"
- service: dahua.set_illuminator_mode
target:
entity_id: camera.drive_main
data:
mode: Auto
mode: restartSomebody crossed the tripwire out of hours: siren and flashers. Both stop by themselves after 10 to 15 seconds, which is the device's own behaviour.
alias: Tripwire deterrence
trigger:
- platform: event
event_type: dahua_event_received
event_data:
name: Yard
Code: CrossLineDetection
action: Start
condition:
- condition: time
after: "22:00:00"
before: "06:00:00"
action:
- service: switch.turn_on
target:
entity_id: switch.yard_siren
- service: light.turn_on
target:
entity_id: light.yard_security
mode: singleA car you know arrives: open the gate. Needs plates listed under Authorized license plates.
alias: Open the gate for a known car
trigger:
- platform: state
entity_id: binary_sensor.gate_authorized_vehicle
to: "on"
action:
- service: dahua.vto_open_door
target:
entity_id: camera.gate_main
data:
door_id: 1
mode: singleStop the cameras watching the house while somebody is home.
alias: Motion detection follows presence
trigger:
- platform: state
entity_id: group.family
action:
- service: "switch.turn_{{ 'off' if trigger.to_state.state == 'home' else 'on' }}"
target:
entity_id:
- switch.hall_motion
- switch.landing_motion
mode: singleSettings live in two places, because a recorder is one config entry holding one subentry per channel.
For the device: open the integration, find the device and choose Configure.
For one channel of a recorder: open the device, find the channel and choose Reconfigure. Only the settings that genuinely differ per channel are here, because asking the same question once per channel on a 64 channel recorder would be its own kind of unusable. On a single camera there are no channels, so everything is on the Configure form.
| Option | Default | Description |
|---|---|---|
| Seconds between device polls | 30 | How often the device is asked for the state of its settings. The minimum is 10. Events do not use this: they arrive on a separate connection and are unaffected by a longer interval. See How data is updated |
| Camera, Switch, Light, Select, Binary sensor, Button, Sensor, Event | on | Which platforms this entry creates. These also stop the requests that exist only to feed a platform, so turning one off reduces how much the device is asked, not just how many entities you see |
| Read configuration over one RPC2 session per device | off | Reads settings over a single logged in RPC2 session instead of a separate authenticated HTTP call each. Far fewer lines in the device's own log. Off by default because not every firmware serves RPC2; leave it off if unsure, and see Reducing entries in your device's log |
| Authorized license plates | empty | A comma separated list, for example ABC1234, XYZ5678. The Authorized Vehicle binary sensor exists either way; this is what it matches against, so while the list is empty it never turns on. Needs a camera that reports ANPR to turn on at all |
| Authorized vehicle hold time | 60 seconds | How long the Authorized Vehicle sensor stays on after a plate it recognises. It also resumes correctly across a restart, so a car recognised just before a reload does not lose the remaining time |
| Area | unset | Moves this device into a Home Assistant area |
On a single camera these are on the Configure form above. On a recorder they belong to one channel and are edited by reconfiguring it.
| Option | Default | Description |
|---|---|---|
| Name | the channel's name | What this channel is called |
| Area | unset | Moves this channel into an area. A channel does not inherit the recorder's area, so channels can be filed by room |
| Events to subscribe to | motion and the common smart-detection events | Which of the device's events become binary sensors. Most of the rest do nothing on most cameras, and each one selected adds an entity. An empty selection is honoured, which turns the event connection off for this channel. If you want an event that is not listed, open an issue |
| Auto-detect channel index | on | Some firmwares number channels from 0 and others from 1. Turn this off if the detection gets it wrong on your camera |
| Enable NVR active deterrence controls | off | Adds Warning Light and Alarm entities for a camera behind an NVR. Off by default because whether the NVR relays these commands varies by model: on some it accepts them and does nothing |
| Manually enable Siren entity | off | Turn this on if the camera has a working siren and the integration did not create the Siren entity |
| Manually enable Security Light entity | off | Turn this on if the camera has a working security light and the integration did not create the Security Light entity |
| Don't open the two-way audio channel when streaming | off | Stops the RTSP backchannel being opened. Turn it on if a doorbell gets stuck in a call when Home Assistant streams it, or if talkback in the Dahua or Amcrest app stops working. It also disables talking from Home Assistant |
Dahua devices write a line to their own log for every login, and each request the integration makes is a separate HTTP call with its own authentication. Fewer calls therefore means fewer log entries. Three things help, in order of effect:
- Turn off platforms you do not use. If you only want the camera and motion events, switching off
switch,lightandselectremoves most of what a poll asks for. The two reads that happen on every poll — PTZ position and coaxial (siren/white light) status — belong toselectand tolight/switchrespectively. - Raise the poll interval to 120–180 seconds. Settings you change from the Dahua app will take that long to appear in Home Assistant; motion and other events are unaffected.
- Keep the integration up to date. Config reads are cached, channels of one NVR share a single read, and a device that stops answering is backed off rather than retried at the same rate.
This reduces the entries; it does not eliminate them. A device that is polled will log logins.
If you wish to work on this component, the easiest way is to follow HACS Dev Container README. In short:
- Install Docker
- Install Visual Studio Code
- Install the devcontainer Visual Code plugin
- Clone this repo and open it in Visual Studio Code
- View -> Command Palette. Type
Tasks: Run Taskand select it, then clickRun Home Assistant on port 9123 - Open Home Assistant at http://localhost:9123
Add to your configuration.yaml:
logger:
default: info
logs:
custom_components.dahua: debug# Stream events
curl -s --digest -u admin:$DAHUA_PASSWORD "http://192.168.1.203/cgi-bin/eventManager.cgi?action=attach&codes=[All]&heartbeat=5"
# List IVS rules
http://192.168.1.203/cgi-bin/configManager.cgi?action=getConfig&name=VideoAnalyseRule
# Enable/Disable IVS rules for [0][3] ... 0 is the channel, 3 is the rule index. Use the right index as required
http://192.168.1.203/cgi-bin/configManager.cgi?action=setConfig&VideoAnalyseRule[0][3].Enable=false
# Enable/disable Audio Linkage for an IVS rule
http://192.168.1.203/cgi-bin/configManager.cgi?action=setConfig&VideoAnalyseRule[0][3].EventHandler.VoiceEnable=false
# Read the lighting profiles, to check for an illuminator left on by 0.9.84-0.9.92 (see Known Issues).
# In Lighting_V2[a][b][c], a is the channel, b the profile (0 Day, 1 Night, 2 the one General mode uses)
# and c the light. The light order is NOT the same on every model, so read the
# LightType lines in the output before writing anything: on many cameras light 0
# is the white illuminator, but some report 0 as InfraredLight and the white
# light at 1. Use whichever index says LightType=WhiteLight.
http://192.168.1.203/cgi-bin/configManager.cgi?action=getConfig&name=Lighting_V2
# Clear it. Only run this if the Mode above is Manual on a profile the camera is
# not using, and change the last index to whichever one is the WhiteLight above.
http://192.168.1.203/cgi-bin/configManager.cgi?action=setConfig&Lighting_V2[0][0][0].Mode=Off- Thanks to @elad-ba for his work on https://github.com/elad-bar/DahuaVTO2MQTT which was copied and modified and then used here for VTO devices
- Thanks for the DAHUA_HTTP_API_V2.76.pdf API reference found at http://www.ipcamtalk.com
- Thanks to all the people opening issues, reporting bugs, pasting commands, etc
