#2488·go2rtc

xiaomi: `midr.cateye.ph300` 需要 MIoT 醒目操作,才能使 `miss_get_vendor` 返回密钥

作者: xaoscode创建于 2026年9月12日更新于 2026年9月12日

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")
…