Skip to content

Repository files navigation

Xiaomi Doorbell 3S to Yandex Home

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.


What works

  • ✅ 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 approach (how it actually works)

The hard part isn't the codec — it's getting a usable stream out of the device at all. Findings, distilled:

  1. 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 (...:32108 LAN 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.

  2. 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 region de — not your home country. The web UI lists the device per region.

  3. 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=udp in the stream URL pins the working path.

  4. 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.

  5. Yandex requires a transcode. Yandex Smart Home's video_stream accepts 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

Hardware requirements

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) ⚠️ HW only via Android MediaCodec; on Linux = software @720p
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.


Quick start

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 --build

1. Log in to your Mi Account & find the doorbell

Open 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.

2. Wire up go2rtc.yaml

Put your user, doorbell_ip, did into the two streams: entries (see go2rtc.yaml.example), keep &transport=udp, then restart:

docker compose restart go2rtc

3. Verify

# 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 vaapi

4. Home Assistant + Yandex

See 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.


Configuration notes

  • Pick one doorbell_h264 line in go2rtc.yaml for your hardware (VAAPI / rkmpp / software). Examples are in go2rtc.yaml.example.
  • network_mode: host is mandatory — CS2 P2P/LAN discovery breaks under Docker bridge networking.
  • Keep-warm: either the keepwarm container or HA's "Preload stream" — not both. Needed because the doorbell's cold start is slower than Yandex's 4 s.

Key limitations (read this)

  • 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 doorbell source 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 stream only 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 under by.
  • 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.

How it's built / launched

  • Dockerfile clones a pinned upstream go2rtc commit, applies patches/, builds the Go binary, and layers it onto the official alexxit/go2rtc image (which provides ffmpeg with VAAPI/QSV).
  • docker-compose.yml runs it with network_mode: host, /dev/dri passthrough, and an optional keepwarm sidecar.
  • To rebase onto a newer go2rtc: bump GO2RTC_REF in the Dockerfile, 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

Credits

  • 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.

License

MIT — see LICENSE. Patches are derivative work of go2rtc (also MIT).

About

Live-stream the Xiaomi Doorbell 3S (madv.cateye.mi3sg, MISS/CS2) into Home Assistant and Yandex Smart Home via a patched go2rtc + hardware-transcoded HLS.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages