Live-stream the Xiaomi Smart Doorbell 3S (madv.cateye.mi3sg) into
Home Assistant and Yandex Smart Home (Алиса / Станция) — no cloud
account scraping, no Mi Home app, fully on your LAN.
The Doorbell 3S is a long-standing "unsupported" device: it speaks Xiaomi's proprietary MISS/CS2 P2P protocol and is missing from go2rtc's device list, Home Assistant, and every off-the-shelf integration. This project makes it work with a small patched go2rtc plus a hardware-accelerated transcode for Yandex.
Interoperability reverse engineering of a device you own, for personal use. No DRM circumvention, no credential theft — it logs in with your Mi Account.
- ✅ Live H.265 + audio from the doorbell, pulled over local CS2 UDP P2P
- ✅ Local viewing in HA / browser (MSE) — no transcode, ~0 % CPU
- ✅ Two-way audio capability is exposed by the device (OPUS send + receive)
- ✅ Yandex Smart Home camera via a hardware-transcoded H.264 / AAC / 1080p HLS
- ✅ Belarus (
by) added to the Mi Account region list
The hard part isn't the codec — it's getting a usable stream out of the device at all. Findings, distilled:
-
The video never leaves the LAN unless you ask it to locally. Xiaomi cloud is used only for auth and to negotiate a P2P "vendor"; the actual media is a direct CS2 P2P session to the doorbell's local IP (
...:32108LAN search, then UDP). There is no public API to pull the stream from Xiaomi's cloud — so the streamer must run on the same LAN as the doorbell. -
Region matters. A Mi Account device is pinned to a regional data center when added in Mi Home. Our Doorbell 3S is registered on the Europe (
de) server, so it only appears (and only streams) when you log in with regionde— not your home country. The web UI lists the device per region. -
CS2 has two transports; only UDP works on the 3S. The handshake can come back "ready" over UDP or TCP. The TCP path connects but then stalls (handshake bytes only, no media). Forcing
transport=udpin the stream URL pins the working path. -
Cold start needs a retry. Doorbells/battery cameras must be woken first. Until the device is online the cloud returns
rpc response code error. A reconnecting player retries and succeeds ~9 s later; a single request fails. The patch re-sends the wakeup RPC and retries a few times. -
Yandex requires a transcode. Yandex Smart Home's
video_streamaccepts only HLS + H.264 + AAC, max 1920×1080, and must answer within 4 s. The doorbell gives H.265 + OPUS at 2K — so for Yandex (and only Yandex) we transcode H265→H264, OPUS→AAC, and downscale to 1080p, ideally on a hardware video engine (Intel QSV/VAAPI) so it costs almost no CPU.
The patches we apply to go2rtc (see patches/):
| Patch | File | Why |
|---|---|---|
| Belarus region | www/add.html, internal/xiaomi/xiaomi.go |
by → Russia (ru) API host (Belarus has no own host) |
| Cold-start retry + re-wakeup | internal/xiaomi/xiaomi.go |
survive rpc response code error on doorbells |
transport=udp is an existing go2rtc URL param — no patch, just config.
┌─────────────┐ CS2/UDP P2P ┌───────────────────────────────────────┐
│ Doorbell 3S │◄───(LAN)─────►│ Always-on box (Intel QSV) on the LAN │
│ H265 + OPUS │ 192.168.1.59 │ go2rtc (patched) ── ffmpeg/VAAPI ──┐ │
└─────────────┘ │ │ doorbell (H265, MSE) │ │
Xiaomi cloud ◄─auth/vendor─►│ ▼ doorbell_h264 (H264/AAC/1080p)
└───┬─────────────────────────────┬───┘
│ RTSP/HLS (local) │ HLS (Yandex)
▼ ▼
Home Assistant ───────────► Yandex Smart Home
The streamer must be always-on and on the doorbell's LAN. For the Yandex path it also needs a working hardware video engine (HEVC decode + H.264 encode), or it will burn CPU transcoding 24/7.
| Class | Examples | Yandex transcode |
|---|---|---|
| Intel QSV (Sandy Bridge 2011+) | N100 mini-PC, used i5-8500T Tiny, N100 NAS board | ✅ HW, ~free — recommended |
| AMD APU with iGPU | Ryzen w/ Radeon (VAAPI) | ✅ HW |
| Rockchip RK3588 | Orange Pi 5, Radxa Rock 5 | ✅ HW via ffmpeg-rockchip (fiddlier) |
| Amlogic (Android only) | TX/TOX boxes (S905X4) | |
| Pre-HEVC / tiny-RAM | Apple TV 1/2, iPad 2, old Atom/Core 2, routers | ❌ no HEVC decode and/or no HW encode |
Local-viewing only (no Yandex) is far lighter — go2rtc just remuxes H265, so almost anything with enough RAM works; transcode is not needed.
A NAS combo works great: an Intel N100 NAS board (4–6× SATA) runs go2rtc + Home Assistant + file shares on ~10–15 W.
Prereqs: Docker + Docker Compose on a Linux box on the doorbell's LAN, with
/dev/dri present (Intel/AMD) for hardware transcode.
git clone https://github.com/dmitrybelsky/Xiaomi-Doorbell-3S-to-Yandex-Home.git
cd Xiaomi-Doorbell-3S-to-Yandex-Home
cp go2rtc.yaml.example go2rtc.yaml # gitignored; holds your token later
docker compose up -d --buildOpen http://<host>:1984/add.html → Xiaomi → log in (captcha/2FA handled in
the browser). Click load devices and try regions until the doorbell appears
— it's usually Europe, not your country. Note its URL:
xiaomi://<user>:de@<doorbell_ip>?did=<did>&model=madv.cateye.mi3sg
go2rtc writes your V1:... token into go2rtc.yaml automatically.
Put your user, doorbell_ip, did into the two streams: entries (see
go2rtc.yaml.example), keep &transport=udp, then restart:
docker compose restart go2rtc# original H265 — plays in Safari/Chrome via MSE:
# http://<host>:1984/stream.html?src=doorbell&mode=mse
# Yandex stream must be H264 + AAC:
curl -s "http://<host>:1984/api/stream.m3u8?src=doorbell_h264"
# -> CODECS="avc1.640029,mp4a.40.2"
# confirm hardware encode (not libx264):
docker logs go2rtc 2>&1 | grep -i vaapiSee homeassistant/configuration.yaml.example:
add a generic camera pointing at rtsp://<host>:8554/doorbell_h264, install
the yandex_smart_home HACS
component with cloud_stream: true, and enable Preload stream on the camera.
- Pick one
doorbell_h264line ingo2rtc.yamlfor your hardware (VAAPI / rkmpp / software). Examples are ingo2rtc.yaml.example. network_mode: hostis mandatory — CS2 P2P/LAN discovery breaks under Docker bridge networking.- Keep-warm: either the
keepwarmcontainer or HA's "Preload stream" — not both. Needed because the doorbell's cold start is slower than Yandex's 4 s.
- Same LAN, always-on. The streamer must sit on the doorbell's subnet. A cloud server / serverless function cannot do this — CS2 connects to the device's local IP. (Yandex's cloud only consumes the finished HLS.)
- One P2P session at a time. The Doorbell 3S serves a single CS2 session.
A dirty disconnect (killed process, stalled TCP) leaves a phantom session and
new connections hang until it times out (minutes) or you power-cycle the
doorbell. Don't run two cold producers at once — mux many consumers off the one
doorbellsource instead. - Yandex = mandatory transcode. H.264 + AAC + ≤1080p + 4 s response are hard
requirements of Yandex's protocol. H.265 is not accepted; OPUS is not
accepted (even HA's
streamonly does AAC/MP3). No way around it for Yandex. - Region lock. The doorbell only appears/streams in the region it was added
to in Mi Home (often
de). Belarus (by) maps to the Russia server; if your device isn't there, it won't show up underby. - Token, not password. go2rtc stores a Mi Account session token. If Xiaomi
invalidates it (password change, security event) you re-login via
add.html. - Hardware encode is not universal. Amlogic exposes its H.264 encoder only through Android MediaCodec (no Linux/V4L2 path); old/pre-HEVC chips can't decode the source at all. See the hardware table.
- Cold start can exceed 4 s → keep the Yandex stream warm (see above), or the first Yandex request times out.
- Latency. CS2 + HLS + Yandex cloud adds several seconds of delay; this is a doorbell-grade live view, not a low-latency intercom.
- Unofficial / fragile. This rides on reverse-engineered protocol behavior. A doorbell firmware update or a go2rtc change may break it; the patch is pinned to a specific go2rtc commit for that reason.
Dockerfileclones a pinned upstream go2rtc commit, appliespatches/, builds the Go binary, and layers it onto the officialalexxit/go2rtcimage (which provides ffmpeg with VAAPI/QSV).docker-compose.ymlruns it withnetwork_mode: host,/dev/dripassthrough, and an optionalkeepwarmsidecar.- To rebase onto a newer go2rtc: bump
GO2RTC_REFin theDockerfile, re-apply / refresh the patch, rebuild.
docker compose up -d --build # build + run
docker compose logs -f go2rtc # watch the CS2 handshake (xiaomi: debug)
docker compose restart go2rtc # after editing go2rtc.yaml- go2rtc by AlexxIT — the streaming engine and the original Xiaomi MISS/CS2 implementation this builds on.
- yandex_smart_home by dext0r — the Home Assistant ↔ Yandex bridge.
MIT — see LICENSE. Patches are derivative work of go2rtc (also MIT).