#2488·go2rtc

xiaomi: `midr.cateye.ph300` needs a MIoT wake action before `miss_get_vendor` returns keys

Author: xaoscodeCreated Sep 12, 2026Updated Sep 12, 2026

Camera

name Xiaomi Smart Cat Eye 2 (MJMY01BY)
model midr.cateye.ph300
fw_ver 5.3.1_0347
hw_ver BL616_ECO
miio_ver 0.0.9
region CN
go2rtc v1.9.14 and master (c245815)
Not in #1982. Filing per the "create a new issue if the camera doesn't work" note.

Summary

Three separate problems, in the order they are hit. The first two have fixes and are verified on this device; the third is where it still fails.

1. wakeup times out, wakeup_host works

Same as #2373. Back to back against home/rpc/{did} on this model:

method params cloud response
wakeup {"video":"1"} timeout
wakeup_host {} ok (empty result)
#2373 fixes this for midr.* and the fix is correct for ph300 too.

2. miss_get_vendor needs a MIoT action first (not covered by any PR)

With only the RPC wake — including the fixed wakeup_host — the cloud refuses to hand out P2P credentials:

miss_get_vendor  ERR  xiaomi: rpc response code error

This is stable: it fails identically for support_vendors = TUTK_CS2_MTP, TUTK, CS2, MTP, AGORA, TUTK_CS2, CS2_MTP, and at t+0/3/5/8/12/20s after the wake (each attempt taking ~10s, i.e. a device-side RPC timeout). /device/devicepass is no help either — it returns only {"region":"CN"}, no p2p_id and no password, so the legacy fallback is dead as well. miIO.info succeeds throughout, so the device is awake and reachable the whole time. The missing step is a MIoT action. The spec for this model (urn:miot-spec-v2:device:video-doorbell:0000A03A:midr-ph300:2) has:

siid=2  Video Doorbell    aiid=3  Wake Up
siid=12 PP Stream         aiid=1  Start P2P Stream

Calling /miotspec/action with siid=2, aiid=3 returns code: 0 and immediately unblocks the vendor negotiation:

action 2/3       OK  {"code":0,...}
miss_get_vendor  OK  {"vendor":{"vendor":4,"vendor_params":{"p2p_id":"...",
                      "license":"...","crc_key":"...","init_string":"..."}},
                      "public_key":"...","sign":"...","region":"CN",
                      "miss_version":"3.2.12.1"}

siid=12, aiid=1 ("Start P2P Stream") returns an error code (-704002000 / -706012015, varies) and does not appear to be required — 2/3 alone is what flips it. Note this differs from #2434, which uses service 7 action 1 for loock.cateye.v06; the service ids are per-model, so this probably wants a small per-model table rather than a constant. Patch I used locally on top of #2373:

go
// miotWakeActions returns the MIoT (siid, aiid) actions that must be called to
// bring a model into a streamable state. Empty for models that don't need it.
func miotWakeActions(model string) [][2]int {
	switch {
	case strings.HasPrefix(model, "midr.") && strings.Contains(model, ".cateye."):
		return [][2]int{{2, 3}, {12, 1}}
	}
	return nil
}
func miotAction(url *url.URL, siid, aiid int) error {
	did := url.Query().Get("did")
	params := fmt.Sprintf(`{"params":{"did":"%s","siid":%d,"aiid":%d,"in":[]}}`, did, siid, aiid)
	_, err := cloudUserRequest(url.User, "/miotspec/action", params)
	return err
}

called from getCameraURL right after wakeUpCamera.

3. Still blocked: no LAN CS2 port, and the cloud relay times out

With keys in hand, go2rtc dials cs2 and fails:

xiaomi: dial xiaomi://***&model=midr.cateye.ph300&vendor=cs2
[rtsp] error="streams: read udp [::]:NNNNN: i/o timeout"

The doorbell never answers the CS2 LAN search. Sending F1 30 00 00 to UDP 32108 from the same subnet gets no reply on any of:

  • unicast to the device IP
  • subnet-directed broadcast
  • limited broadcast 255.255.255.255 So this is the "no LAN port" class of device described in #2264. Applying #2264 on top does switch it to the relay path, but:
xiaomi: cs2 cloud-relay mode, redirecting to 47.236.156.107
[rtsp] error="streams: cs2 cloud: timeout waiting for 0x40 NAT-punch info"

vendor_params here carries license, crc_key and init_string alongside p2p_id. The init_string is 84 chars over the alphabet AP, i.e. 42 nibble-encoded bytes, and the decoded bytes are not plaintext — no readable addresses. Since #2264 uses a hardcoded relay pool, my guess is the correct relay endpoints for this device come from init_string instead, but I have not decoded it. Happy to run further probes against this device if that helps — I have a small Go harness on top of pkg/xiaomi that can call arbitrary cloud endpoints with the account's credentials.

Extra data on the relay path (may help #2264)

Instrumenting the handshake shows the relay is reachable and does answer — it just never sends 0x40:

[cs2dbg] handshake start relay=47.236.156.107 p2p_id=XM****-******-*****
[cs2dbg] relay=47.236.156.107 rx 8 bytes: f1210004fd000000
[cs2dbg] relay=47.236.156.107 rx 8 bytes: f1210004fd000000   (repeats, then timeout)

So 0x21 here carries a 4-byte status fd 00 00 00 rather than acting as a plain ACK. Replaying the captured 0x20/0xF9 pair against other hosts:

host reply
47.236.156.107 f1210004fd000000
54.84.37.235 (www.cs2-network.com) f1210004fd000000
47.88.30.183, 47.88.30.225 silent
m1/m2/m3.iotcplatform.com silent
Identical status from two unrelated CS2 master servers suggests the UID simply
isn't registered on the ones being tried, i.e. the relay pool is wrong for this
device rather than the handshake being malformed. This device's p2p_id prefix
is XMCN.., and its region is CN, while the hardcoded pool looks
international.
I could not find a cloud endpoint that returns a server list — these all 404 on
api.io.mi.com: miss_get_server, get_p2p_server, miss_get_relay,
range_get_vendor, p2p_info, get_relay_server, miss_server,
miss_get_vendor_v2. That leaves init_string as the likely carrier of the
master-server list, matching how the CS2/TUTK SDK is initialised.
On init_string: 84 chars over AP decode to 42 bytes either way round.
42 = 7 × 6 exactly, which would fit seven IPv4:port entries, but no decoding I
tried yields plausible addresses or port 32100/32108, so it is presumably
obfuscated. The P2P_Proprietary_Encrypt cipher from #2264 (key
SSD@cs2-network., both feedback directions, also keyed with the accompanying
license and crc_key) does not produce structure either.