<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Dahua on Wojciech Marusiak IT Blog</title>
        <link>https://www.wojcieh.net/tags/dahua/</link>
        <description>Recent content in Dahua on Wojciech Marusiak IT Blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en-us</language>
        <lastBuildDate>Wed, 11 Nov 2026 10:00:00 +0100</lastBuildDate><atom:link href="https://www.wojcieh.net/tags/dahua/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>How Google Antigravity Reverse-Engineered My Dahua H5A Camera Protocol for Home Assistant</title>
        <link>https://www.wojcieh.net/reverse-engineering-dahua-h5a-protocol-home-assistant-hacs/</link>
        <pubDate>Wed, 11 Nov 2026 10:00:00 +0100</pubDate>
        
        <guid>https://www.wojcieh.net/reverse-engineering-dahua-h5a-protocol-home-assistant-hacs/</guid>
        <category>Google Antigravity</category>
        <category>Gemini</category>
        <category>Dahua</category>
        <category>Home Assistant</category>
        <category>HACS</category>
        <category>Interoperability</category>
        <category>Python</category>
        <category>IoT</category>
        <category>Homelab &amp; Infrastructure</category>
        <category>AI &amp; LLM Ops</category>
        <description>&lt;p&gt;&lt;img src=&#34;https://www.wojcieh.net/images/uploads/2026/11/dahua-h5a-reverse-engineering-netsdk-37777-hacs.webp&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Reverse Engineering Dahua H5A Port 37777 for Home Assistant&#34;
	
	
&gt;&lt;/p&gt;
&lt;p&gt;I recently bought a &lt;strong&gt;Dahua H5A 5MP 360° Indoor Wi-Fi 6 (&lt;code&gt;DH-H5A&lt;/code&gt; / &lt;code&gt;IPC-H5A&lt;/code&gt;)&lt;/strong&gt; pan-tilt camera and placed it on my isolated camera VLAN (&lt;code&gt;172.16.60.0/24&lt;/code&gt;) with internet access blocked at the firewall. My only goal was simple: add my own camera to &lt;strong&gt;Home Assistant&lt;/strong&gt; so I could toggle the physical privacy shutter, AI human/pet detection, status LED, and PTZ locally. Five minutes after plugging it in, I hit a wall—opening &lt;code&gt;http://172.16.60.46/&lt;/code&gt; returned &lt;code&gt;404 Page Not Found&lt;/code&gt;, and none of the standard Dahua &lt;code&gt;/cgi-bin/*.cgi&lt;/code&gt; endpoints worked.&lt;/p&gt;
&lt;p&gt;I am not a reverse engineer and I have zero interest in reading assembly by hand—I didn&amp;rsquo;t even know how half of these binary protocols worked under the hood, I just wanted the camera I bought to work in Home Assistant. So I downloaded the official Dahua apps (macOS, Windows, and Android) into a local folder, handed the directory and the camera IP to &lt;strong&gt;Google Antigravity&lt;/strong&gt; running &lt;strong&gt;Gemini 4 Argon High&lt;/strong&gt;, and asked the agent to figure out how the camera communicates and build an open-source Home Assistant integration for me. Within a single session, Antigravity autonomously unpacked the installers, analyzed the binary protocol on &lt;strong&gt;TCP Port &lt;code&gt;37777&lt;/code&gt;&lt;/strong&gt;, and generated &lt;strong&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/wojciehm/open-dahua-h5a&#34;  title=&#34;open-dahua-h5a on GitHub&#34;
     target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;open-dahua-h5a&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;—a clean-room Python library, CLI (&lt;code&gt;dahua-h5a&lt;/code&gt;), and multi-camera &lt;strong&gt;HACS integration&lt;/strong&gt; (&lt;code&gt;custom_components/dahua_h5a&lt;/code&gt;).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Legal &amp;amp; Interoperability Disclaimer (EU Directive 2009/24/EC &amp;amp; § 69e UrhG):&lt;/strong&gt;&lt;br&gt;
This project and article were created &lt;strong&gt;exclusively for interoperability purposes&lt;/strong&gt;—specifically to allow legal owners of Dahua H5A / Hero-series hardware to integrate their own devices with open-source smart home software (&lt;strong&gt;Home Assistant&lt;/strong&gt;) over a local network.&lt;br&gt;
Under &lt;strong&gt;Article 6 of the EU Software Directive (2009/24/EC)&lt;/strong&gt; and &lt;strong&gt;§ 69e of the German Copyright Act (&lt;em&gt;Urheberrechtsgesetz — Dekompilierung&lt;/em&gt;)&lt;/strong&gt;, observing, studying, and decompiling software to obtain the information necessary to achieve interoperability of an independently created program is explicitly permitted by law when that protocol information is not publicly documented by the manufacturer.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No security bypass or hacking:&lt;/strong&gt; This integration does &lt;strong&gt;not&lt;/strong&gt; bypass authentication, encryption, or access controls. You must know and provide your own valid &lt;code&gt;admin&lt;/code&gt; password to communicate with the camera.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;100% Clean-Room Open Source:&lt;/strong&gt; The &lt;a class=&#34;link&#34; href=&#34;https://github.com/wojciehm/open-dahua-h5a&#34;  title=&#34;open-dahua-h5a on GitHub&#34;
     target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;open-dahua-h5a&lt;/code&gt;&lt;/a&gt; repository contains &lt;strong&gt;zero&lt;/strong&gt; vendor code, proprietary SDK libraries, binary blobs, or firmware files—only an independent Python &lt;code&gt;asyncio&lt;/code&gt; client written from scratch.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No affiliation:&lt;/strong&gt; This project is an independent community interoperability effort and is not affiliated with, endorsed by, or supported by Dahua Technology.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;1-why-existing-dahua-integrations-fail-on-the-h5a&#34;&gt;1. Why Existing Dahua Integrations Fail on the H5A
&lt;/h2&gt;&lt;p&gt;&lt;img src=&#34;https://www.wojcieh.net/images/uploads/2026/11/dahua-h5a-hero-pt-camera.webp&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Dahua H5A / Hero Series 5MP 360° Indoor Wi-Fi 6 PT Camera&#34;
	
	
&gt;&lt;/p&gt;
&lt;p&gt;Standard commercial Dahua IPCs expose an HTTP CGI API (&lt;code&gt;/cgi-bin/magicBox.cgi&lt;/code&gt;, &lt;code&gt;/cgi-bin/configManager.cgi&lt;/code&gt;) on port &lt;code&gt;80&lt;/code&gt;. Consumer Hero-series cameras like the &lt;strong&gt;Dahua H5A&lt;/strong&gt; (&lt;code&gt;FW V2.860.0000000.26.R&lt;/code&gt;) disable the embedded web UI and CGI endpoints completely. When Antigravity queried &lt;code&gt;magicBox.getProductDefinition&lt;/code&gt; on the camera, the firmware reported:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;DeviceWebCaps&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;SupportLocalWebSource&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;SupportWebService&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Scanning the camera on the local VLAN showed only three open TCP ports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TCP &lt;code&gt;80&lt;/code&gt; (&lt;code&gt;gSOAP/2.8&lt;/code&gt;):&lt;/strong&gt; Runs a minimal ONVIF service (&lt;code&gt;/onvif/device_service&lt;/code&gt;, &lt;code&gt;/onvif/media_service&lt;/code&gt;, &lt;code&gt;/onvif/ptz_service&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TCP &lt;code&gt;554&lt;/code&gt; (&lt;code&gt;RTSP&lt;/code&gt;):&lt;/strong&gt; Streams 5MP H.265 video (&lt;code&gt;subtype=0&lt;/code&gt;) and SD substream (&lt;code&gt;subtype=1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TCP &lt;code&gt;37777&lt;/code&gt; (&lt;code&gt;Dahua NetSDK / DVR2&lt;/code&gt;):&lt;/strong&gt; The binary control channel used by Dahua &lt;code&gt;ConfigTool&lt;/code&gt; and the &lt;code&gt;DMSS&lt;/code&gt; mobile app.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note / Gotcha:&lt;/strong&gt; During testing, Antigravity discovered a nasty trap with ONVIF on port &lt;code&gt;80&lt;/code&gt;. The H5A keeps a separate &lt;code&gt;ONVIF&lt;/code&gt; user table where &lt;code&gt;PasswordChangeFlag&lt;/code&gt; defaults to &lt;code&gt;false&lt;/code&gt; even after you initialize the camera&amp;rsquo;s &lt;code&gt;admin&lt;/code&gt; password. Every failed WS-UsernameToken request against &lt;code&gt;/onvif/media_service&lt;/code&gt; decrements a hardware lockout counter (&lt;code&gt;You still have 28 attempt(s)&lt;/code&gt;). Because of that, the integration avoids ONVIF completely and uses TCP &lt;code&gt;37777&lt;/code&gt; for control and RTSP &lt;code&gt;554&lt;/code&gt; for video and snapshots.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;2-letting-google-antigravity-analyze-the-vendor-protocol&#34;&gt;2. Letting Google Antigravity Analyze the Vendor Protocol
&lt;/h2&gt;&lt;p&gt;Instead of spending weeks learning binary protocol analysis myself, I dropped the vendor installers into &lt;code&gt;/home/wojcieh/DevProjects/dahua/&lt;/code&gt; and told &lt;strong&gt;Google Antigravity&lt;/strong&gt;: &lt;em&gt;&amp;ldquo;Here is the camera IP and password, and here are the Windows, macOS, and Android apps—plan the analysis so we can build an open-source client and control every feature in Home Assistant.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Antigravity set up an isolated workspace and inspected the official client packages purely to understand the wire format needed for interoperability:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;macOS &lt;code&gt;ConfigTool.app&lt;/code&gt;:&lt;/strong&gt; Inspected the shared libraries (&lt;code&gt;libdhnetsdk.so&lt;/code&gt;, &lt;code&gt;libdhconfigsdk.so&lt;/code&gt;) to see how desktop clients frame TCP &lt;code&gt;37777&lt;/code&gt; packets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Android &lt;code&gt;DMSS 2.6.22&lt;/code&gt;:&lt;/strong&gt; Checked the mobile configuration tables (&lt;code&gt;libnetsdk.so&lt;/code&gt;, &lt;code&gt;libconfigsdk.so&lt;/code&gt;) for consumer-only IoT features like the privacy lens mask and baby cry detection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows &lt;code&gt;ConfigTool V5.001&lt;/code&gt;:&lt;/strong&gt; Cross-checked the configuration schema definitions (&lt;code&gt;dhconfigsdk.dll&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To be completely transparent: I barely understand the low-level assembly or byte offsets that Antigravity extracted below—my role was defining the goal and verifying that the physical camera in my bedroom actually moved and closed its shutter when I ran the resulting commands.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;Protocol Handler in Client SDK&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;Wire Function&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;CDevLogin::PacketStep1_dvr2&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Builds the 32-byte &lt;code&gt;0xa0&lt;/code&gt; login challenge request&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;CDevLogin::ParseStep1Rsp_dvr2&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Parses &lt;code&gt;Encryption&lt;/code&gt; (&lt;code&gt;Default&lt;/code&gt;), &lt;code&gt;Random&lt;/code&gt;, and &lt;code&gt;Realm&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;DH_Superencipherment&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Iterative MD5 -&amp;gt; Base62 password hash (&lt;code&gt;Default&lt;/code&gt; mode)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;CDevLogin::PacketStep2_dvr2&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Sends the authenticated &lt;code&gt;&amp;quot;{user}&amp;amp;&amp;amp;{H1}{H2}&amp;quot;&lt;/code&gt; credential frame&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;sendJsonPacket_dvr2&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Wraps JSON-RPC 2.0 payloads inside 32-byte &lt;code&gt;0xf6&lt;/code&gt; headers&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;Parse_f6&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Reassembles multi-chunk &lt;code&gt;0xf6&lt;/code&gt; JSON-RPC responses and events&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;3-how-the-port-37777-interoperability-protocol-works&#34;&gt;3. How the Port &lt;code&gt;37777&lt;/code&gt; Interoperability Protocol Works
&lt;/h2&gt;&lt;p&gt;Based on Antigravity&amp;rsquo;s protocol spec (&lt;a class=&#34;link&#34; href=&#34;https://github.com/wojciehm/open-dahua-h5a&#34;  title=&#34;open-dahua-h5a on GitHub&#34;
     target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;docs/PROTOCOL_SPEC.md&lt;/code&gt;&lt;/a&gt;), every frame on TCP port &lt;code&gt;37777&lt;/code&gt; starts with a &lt;strong&gt;32-byte little-endian header&lt;/strong&gt; (&lt;code&gt;hdr[0]&lt;/code&gt; = packet command, &lt;code&gt;hdr[4:8]&lt;/code&gt; = &lt;code&gt;uint32_le(payload_len)&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&#34;two-step-0xa0-challenge-response-authentication&#34;&gt;Two-Step &lt;code&gt;0xa0&lt;/code&gt; Challenge-Response Authentication
&lt;/h3&gt;&lt;p&gt;When connecting to &lt;code&gt;172.16.60.46:37777&lt;/code&gt;, the client sends a 32-byte &lt;code&gt;0xa0&lt;/code&gt; challenge request with trailer bytes &lt;code&gt;01 02 00 01 3c 00 a1 aa&lt;/code&gt; at &lt;code&gt;hdr[24:32]&lt;/code&gt;. The camera replies with a &lt;code&gt;0xb0&lt;/code&gt; challenge containing its &lt;code&gt;Realm&lt;/code&gt; and a one-time &lt;code&gt;Random&lt;/code&gt; nonce:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Encryption:Default
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Random:1132920513
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Realm:Login to CD0479BGAGXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;In Step 2, the client hashes the user&amp;rsquo;s password using two MD5 digests (&lt;code&gt;H1&lt;/code&gt; for the &lt;code&gt;Realm&lt;/code&gt; and &lt;code&gt;H2&lt;/code&gt; using a Base62 &lt;code&gt;DH_Superencipherment&lt;/code&gt; transformation combined with the &lt;code&gt;Random&lt;/code&gt; nonce) and sends &lt;code&gt;&amp;quot;{user}&amp;amp;&amp;amp;{H1}{H2}&amp;quot;&lt;/code&gt;. When the password is valid, the camera returns &lt;code&gt;hdr[8] == 0x00&lt;/code&gt; and assigns a 32-bit &lt;code&gt;session_id&lt;/code&gt; at &lt;code&gt;hdr[16:20]&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;embedded-0xf6-json-rpc-framing&#34;&gt;Embedded &lt;code&gt;0xf6&lt;/code&gt; JSON-RPC Framing
&lt;/h3&gt;&lt;p&gt;Once logged in, all configuration and PTZ commands travel over the same TCP socket as &lt;code&gt;0xf6&lt;/code&gt; packets:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Offset  00 01 02 03  04 05 06 07  08 09 0a 0b  0c 0d 0e 0f
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x0000  f6 00 00 00  [chunk_len ] [rpc_seq_id] [00 00 00 00]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x0010  [total_len ] [00 00 00 00] [session_id] [00 00 00 00]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x0020  {&amp;#34;method&amp;#34;:&amp;#34;...&amp;#34;,&amp;#34;params&amp;#34;:...,&amp;#34;id&amp;#34;:N,&amp;#34;session&amp;#34;:S}\x0a
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Querying &lt;code&gt;configManager.getMemberNames&lt;/code&gt; and &lt;code&gt;&amp;lt;component&amp;gt;.listMethod&lt;/code&gt; on the camera exposed &lt;strong&gt;126 configuration tables&lt;/strong&gt; and &lt;strong&gt;316 RPC methods&lt;/strong&gt;, which Antigravity mapped into clean Python methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;AELensMask&lt;/code&gt;:&lt;/strong&gt; Physical privacy shutter (&lt;code&gt;Status: true&lt;/code&gt; hides the lens inside the housing; &lt;code&gt;false&lt;/code&gt; opens it).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;SmartMotionDetect&lt;/code&gt;:&lt;/strong&gt; On-device AI human detection (&lt;code&gt;ObjectTypes.Human&lt;/code&gt;), pet detection (&lt;code&gt;ObjectTypes.Animal&lt;/code&gt;), and PTZ auto-tracking (&lt;code&gt;SmartTrack&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;AudioDetect&lt;/code&gt;:&lt;/strong&gt; Baby cry and abnormal sound detection (&lt;code&gt;Enable&lt;/code&gt;, &lt;code&gt;AnomalyDetect&lt;/code&gt;, &lt;code&gt;AnomalySensitive&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;LightGlobal&lt;/code&gt;:&lt;/strong&gt; Front status LED toggle (&lt;code&gt;Enable&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Lighting&lt;/code&gt; + &lt;code&gt;VideoInDayNight&lt;/code&gt;:&lt;/strong&gt; IR illuminator mode (&lt;code&gt;Auto&lt;/code&gt;/&lt;code&gt;Manual&lt;/code&gt;/&lt;code&gt;Off&lt;/code&gt;) and ICR filter (&lt;code&gt;Brightness&lt;/code&gt;/&lt;code&gt;Color&lt;/code&gt;/&lt;code&gt;BlackWhite&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ptz.factory.instance&lt;/code&gt;:&lt;/strong&gt; Controls &lt;code&gt;ptz.start&lt;/code&gt;, &lt;code&gt;ptz.stop&lt;/code&gt;, &lt;code&gt;ptz.gotoPreset&lt;/code&gt;, &lt;code&gt;ptz.setPreset&lt;/code&gt;, and &lt;code&gt;ptz.restartPtz&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;eventManager.attach&lt;/code&gt;:&lt;/strong&gt; Subscribes the TCP socket to real-time &lt;code&gt;client.notifyEventStream&lt;/code&gt; push events (&lt;code&gt;VideoMotion&lt;/code&gt;, &lt;code&gt;SmartMotionHuman&lt;/code&gt;, &lt;code&gt;SmartMotionAnimal&lt;/code&gt;, &lt;code&gt;AudioMutation&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;4-using-the-odh-cli-and-python-library&#34;&gt;4. Using the &lt;code&gt;odh&lt;/code&gt; CLI and Python Library
&lt;/h2&gt;&lt;p&gt;The resulting open-source project &lt;strong&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/wojciehm/open-dahua-h5a&#34;  title=&#34;open-dahua-h5a on GitHub&#34;
     target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;open-dahua-h5a&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; (available on &lt;a class=&#34;link&#34; href=&#34;https://github.com/wojciehm/open-dahua-h5a&#34;  title=&#34;open-dahua-h5a on GitHub&#34;
     target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;GitHub&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;https://codeberg.org/wojcieh/open-dahua-h5a&#34;  title=&#34;open-dahua-h5a on Codeberg&#34;
     target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Codeberg&lt;/a&gt;) uses only Python&amp;rsquo;s standard &lt;code&gt;asyncio&lt;/code&gt; library—no vendor SDKs or compiled binaries required. The CLI is available as &lt;strong&gt;&lt;code&gt;odh&lt;/code&gt;&lt;/strong&gt; (&lt;em&gt;Open Dahua&lt;/em&gt;) or &lt;strong&gt;&lt;code&gt;dahua-h5a&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Clone the repository and install it in a virtual environment:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://github.com/wojciehm/open-dahua-h5a.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; open-dahua-h5a
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv venv .venv
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv pip install --python .venv/bin/python -e &lt;span class=&#34;s2&#34;&gt;&amp;#34;.[dev]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;Run &lt;code&gt;odh&lt;/code&gt; commands against your camera:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;17
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;18
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;19
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;20
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Query hardware, firmware, serial number, and RTSP URLs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.venv/bin/odh info
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Inspect complete camera state (privacy shutter, AI, LED, audio, PTZ, MicroSD)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.venv/bin/odh status
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Close or open the physical privacy lens shutter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.venv/bin/odh privacy on
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.venv/bin/odh privacy off
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Toggle AI Human/Pet detection and PTZ Smart Auto-Tracking&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.venv/bin/odh human-detect on
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.venv/bin/odh pet-detect on
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.venv/bin/odh smart-track on
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Move PTZ or jump to a saved preset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.venv/bin/odh ptz left --speed &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; --duration 0.4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.venv/bin/odh ptz preset --index &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Capture a 5MP (2880x1620) JPEG snapshot from RTSP Main Stream&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.venv/bin/odh snapshot -o /tmp/h5a_5mp.jpg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;5-multi-camera-home-assistant-integration-via-hacs&#34;&gt;5. Multi-Camera Home Assistant Integration via HACS
&lt;/h2&gt;&lt;p&gt;What I really cared about was having a plug-and-play Home Assistant integration where you simply enter the camera&amp;rsquo;s IP address and password in the UI—and can add as many cameras as you want without touching YAML. Antigravity packaged a complete &lt;strong&gt;Home Assistant Custom Integration (&lt;code&gt;custom_components/dahua_h5a&lt;/code&gt;)&lt;/strong&gt; with &lt;code&gt;ConfigFlow&lt;/code&gt;, &lt;code&gt;ReconfigureFlow&lt;/code&gt;, and &lt;code&gt;OptionsFlow&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://www.wojcieh.net/images/uploads/2026/11/dahua-h5a-dvr2-0xa0-0xf6-protocol-flow.webp&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Multi-Camera HACS Architecture and Entity Mapping for Dahua H5A&#34;
	
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;installing-via-hacs&#34;&gt;Installing via HACS
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;HACS&lt;/strong&gt; in Home Assistant, click the three-dot menu in the top right corner, and select &lt;strong&gt;Custom repositories&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Paste &lt;code&gt;https://github.com/wojciehm/open-dahua-h5a&lt;/code&gt; and choose &lt;strong&gt;Integration&lt;/strong&gt; as the category.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Download&lt;/strong&gt; and restart Home Assistant.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Settings -&amp;gt; Devices &amp;amp; Services -&amp;gt; Add Integration&lt;/strong&gt; and search for &lt;strong&gt;Dahua H5A (Local NetSDK)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter the camera&amp;rsquo;s &lt;strong&gt;IP / Hostname&lt;/strong&gt; (e.g., &lt;code&gt;172.16.60.46&lt;/code&gt;), &lt;strong&gt;NetSDK Port (&lt;code&gt;37777&lt;/code&gt;)&lt;/strong&gt;, &lt;strong&gt;RTSP Port (&lt;code&gt;554&lt;/code&gt;)&lt;/strong&gt;, &lt;strong&gt;Username (&lt;code&gt;admin&lt;/code&gt;)&lt;/strong&gt;, and &lt;strong&gt;Password&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you have multiple H5A or Hero-series cameras across different rooms, click &lt;strong&gt;Add Integration&lt;/strong&gt; for each one. During setup, &lt;code&gt;config_flow.py&lt;/code&gt; logs in over TCP &lt;code&gt;37777&lt;/code&gt;, fetches the hardware serial number via &lt;code&gt;magicBox.getSerialNo&lt;/code&gt; as the &lt;code&gt;unique_id&lt;/code&gt;, and names the device after its configured &lt;code&gt;MachineName&lt;/code&gt; (for example, &lt;code&gt;Sypialnia&lt;/code&gt; or &lt;code&gt;Kuchnia&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://www.wojcieh.net/images/uploads/2026/11/dahua-h5a-home-assistant-live-device.webp&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Dahua H5A Live Device Dashboard and Controls in Home Assistant&#34;
	
	
&gt;&lt;/p&gt;
&lt;p&gt;Each camera exposes &lt;strong&gt;31 native entities&lt;/strong&gt; out of the box (with English and Polish translations):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;camera&lt;/code&gt; (1):&lt;/strong&gt; 5MP H.265 Live Stream (&lt;code&gt;subtype=0&lt;/code&gt;) or Sub Stream (&lt;code&gt;subtype=1&lt;/code&gt;), RTSP snapshots, &lt;code&gt;turn_on&lt;/code&gt;/&lt;code&gt;turn_off&lt;/code&gt; tied to the physical privacy shutter, and entity services (&lt;code&gt;dahua_h5a.ptz_move&lt;/code&gt;, &lt;code&gt;dahua_h5a.ptz_goto_preset&lt;/code&gt;, &lt;code&gt;dahua_h5a.ptz_set_preset&lt;/code&gt;, &lt;code&gt;dahua_h5a.trigger_siren&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;switch&lt;/code&gt; (10):&lt;/strong&gt; Privacy Mask, AI Human Detection, AI Pet Detection, Smart Auto-Tracking, Motion Detection, Abnormal Sound / Baby Cry Detection, Status LED, Stream Audio Recording, Image Mirror, and 180° Image Flip.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;select&lt;/code&gt; (2):&lt;/strong&gt; Night Vision IR Mode (&lt;code&gt;auto&lt;/code&gt; / &lt;code&gt;off&lt;/code&gt; / &lt;code&gt;on&lt;/code&gt;) and dynamic PTZ Preset selector.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;number&lt;/code&gt; (3):&lt;/strong&gt; Speaker Volume (&lt;code&gt;0–100%&lt;/code&gt;), Microphone Sensitivity (&lt;code&gt;0–100%&lt;/code&gt;), and Sound Detection Sensitivity (&lt;code&gt;1–100%&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;button&lt;/code&gt; (6):&lt;/strong&gt; PTZ Tilt Up, Tilt Down, Pan Left, Pan Right, Calibrate PTZ, and Trigger Siren.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;binary_sensor&lt;/code&gt; (4):&lt;/strong&gt; Real-time push sensors (&lt;code&gt;local_push&lt;/code&gt;) for Motion, Person Detected, Sound / Cry Detected, and Privacy Shutter Closed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sensor&lt;/code&gt; (5):&lt;/strong&gt; MicroSD Card Status, MicroSD Used (&lt;code&gt;%&lt;/code&gt;), MicroSD Free Space (&lt;code&gt;GB&lt;/code&gt;), PTZ Pan Angle, and PTZ Tilt Angle.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary
&lt;/h2&gt;&lt;p&gt;For me, this was the ultimate test of agentic engineering with &lt;strong&gt;Google Antigravity&lt;/strong&gt;: I started with an offline camera that had no web UI and no documented HTTP API, gave the agent the vendor apps and my goal, and ended up with a clean-room Python library and a multi-camera HACS plugin that controls every hardware feature locally. All code and interoperability documentation are available in &lt;strong&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/wojciehm/open-dahua-h5a&#34;  title=&#34;open-dahua-h5a on GitHub&#34;
     target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;open-dahua-h5a&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; under the MIT license.&lt;/p&gt;</description>
        </item>
        
    </channel>
</rss>
