AlexxIT/go2rtc · error

can't get device SDP

Error message

can't get device SDP

What it means

Roborock Connect timeout: after sending the WebRTC offer, the client polled GetDeviceSDP every second for 5 seconds without receiving the device's answer SDP. The vacuum did not answer signaling in time, so SetAnswer was never possible and Connect gives up.

Solutions

  1. Verify the device is online and responsive in the Roborock app
  2. Retry Connect once the device wakes up (off dock / out of sleep)
  3. Increase the SDP wait deadline if your network is slow
  4. Ensure no competing streaming session holds the camera
Defensive patterns

Strategy: retry

Validate before calling

if status, _ := c.GetHomesecConnectStatus(); status == "" {
    return errors.New("device not reachable for SDP exchange")
}

Try / catch

err := client.Connect(ctx)
if err != nil && err.Error() == "can't get device SDP" {
    time.Sleep(5 * time.Second)
    err = client.Connect(ctx)
}

Prevention

When it happens

Trigger: The Roborock IoT call requesting the device SDP gets no response before the deadline — device offline, slow to respond, or the MQTT/RPC channel to the camera stalls.

Common situations: Robot vacuum sleeping or out of dock connectivity; weak Wi-Fi on the device; camera busy with another session so it ignores the SDP request.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/c62526bc996ffd45. Report an issue: GitHub.

Appendix: source

Thrown at pkg/roborock/client.go:171

	}

	sendOffer.Done()

	// 6. Receive answer
	ts := time.Now().Add(time.Second * 5)
	for {
		time.Sleep(time.Second)

		if desc, _ := c.GetDeviceSDP(); desc != nil {
			//log.Printf("[roborock] answer\n%s", desc.SDP)
			if err = c.conn.SetAnswer(desc.SDP); err != nil {
				return err
			}
			break
		}

		if time.Now().After(ts) {
			return errors.New("can't get device SDP")
		}
	}

	ticker := time.NewTicker(time.Second * 2)
	for {
		select {
		case <-ticker.C:
			// 7. Receive remote candidates
			if pc.ICEConnectionState() == pion.ICEConnectionStateCompleted {
				ticker.Stop()
				continue
			}

			if ice, _ := c.GetDeviceICE(); ice != nil {
				for _, candidate := range ice {
					_ = c.conn.AddCandidate(candidate)
				}
			}

View on GitHub (pinned to c245815e75)