Skip to content

Yumshare Solo 2 camera cold open takes ~25s #289

Description

@1eft0ver

System Health details

System Information

version core-2026.7.1
installation_type Unsupported Third Party Container
dev false
hassio false
docker true
container_arch null
user abc
virtualenv false
python_version 3.14.6
os_name Linux
os_version 6.12.75+rpt-rpi-2712
arch aarch64
timezone Europe/Berlin
config_dir /config
Home Assistant Cloud
logged_in true
subscription_expiration June 4, 2027
relayer_connected true
relayer_region eu-central-1
remote_enabled true
remote_connected true
remote_server <redacted>
alexa_enabled true
google_enabled true
cloud_ice_servers_enabled true
certificate_status ready
instance_id <redacted>
iot_state connected
iot_tries 0
certificate_expire_date August 27, 2026
certificate_fingerprint <redacted>
certificate_alternative_names <redacted>
HACS
GitHub API ok
GitHub Content ok
GitHub Web ok
HACS Data ok
GitHub API Calls Remaining 4996
Installed Version 2.0.5
Stage running
Available Repositories 3513
Downloaded Repositories 24
Dashboards
dashboards 6
resources 11
views 10
mode storage
Network Configuration
adapters lo (disabled), eth0 (enabled, default, auto), tailscale0 (disabled), zt6jywns53 (disabled), br-2b6e6dc88239 (disabled), br-57990f82327e (disabled), br-b5ca5fe4a44e (disabled), br-bfcf5424b1e1 (disabled), br-d169d0905728 (disabled), br-d6fd87355d84 (disabled), docker0 (disabled), br-0f6f2b802e5d (disabled), wpan0 (disabled)
ipv4_addresses lo (127.0.0.1/8), eth0 (192.168.0.2/24), tailscale0 (100.107.127.96/32), zt6jywns53 (172.25.0.1/16), docker bridges (172.17-172.25.0.1/16)
ipv6_addresses eth0 (<global IPv6 redacted>, fd0f:…/64, fe80::…/64), docker0 (fd00:dead:beef::1/64), wpan0 (fd00:db8:a0::…/64)
announce_addresses 192.168.0.2, <global IPv6 redacted>
Recorder
oldest_recorder_run July 18, 2026 at 8:20 PM
current_recorder_run July 29, 2026 at 6:37 AM
estimated_db_size 3433.36 MiB
database_engine sqlite
database_version 3.53.2

go2rtc is the HA-managed instance, version 1.9.14. The LAN is wired, behind a
consumer router, with no restricted NAT and no UDP filtering.

Integration version ?

1.27.0

In which region is your Petkit application registered?

Germany

Device type

Feeder (Yumshare Solo 2)

Checklist

  • I have enabled debug logging for my installation.
  • This issue only contains 1 issue.
  • This issue is not a duplicate issue of any previous issues.

Describe the issue

Opening the camera takes 21–27 s whenever the stream is cold. Once it opens
the stream is fine, and reopening it while still warm takes 1.7 s.

It is reproducible on demand and the timings barely vary. On every cold open the
debug log shows the same sequence:

  1. The SDP answer is not handed to go2rtc when the Agora join completes — the
    log says Waiting for on_add_video_stream before finalizing SDP answer.
  2. The stream announcement (on_add_video_stream) arrives 3.0–3.5 s after
    the WebSocket connects.
  3. Agora reports p2p_lost: code=1 error=Timeout exactly 10.2 s after that
    announcement
    ; the session never reaches on_p2p_ok.
  4. go2rtc gives up on the producer and rebuilds it (~6.4 s).
  5. The second attempt succeeds in well under a second, because the device is
    publishing by then and the announcement arrives 0.1–0.7 s after the join.

So about 20 s of the ~26 s is spent on an attempt that never gets anywhere, plus
the producer rebuild.

What I measured

Across 6 cold opens (12 joins) plus follow-up runs, success tracks exactly one
variable — how long after the join the stream is announced:

announcement delay outcome
0.1–3.0 s (device already publishing) always OK, join → p2p_ok 0.3–3.1 s
5.8–7.0 s (device starting from cold) always LOST, timeout 10.2 s after the announcement

p2p_lost fired at announcement + 10.3 / 10.2 / 10.2 / 10.2 / 10.2 / 10.2 s
— a fixed timer rather than a network race.

What I ruled out

  • Gateway selection. The same edge produced both outcomes: in one capture
    the failing join and the succeeding join used the same host and the same
    port
    . Across runs, all three edge pools show up on both sides.
  • ICE / STUN / TURN. I ran a separate go2rtc instance with public STUN
    servers configured; the upstream offer then carried 16 srflx candidates
    including the public IPv4 — and the open time did not change (26.4 s vs
    23.8 s, within the 21–27 s noise). Agora's answer advertises publicly
    reachable host candidates (… 98.98.166.38 4702 typ host), so the subscriber
    side never needs to be reachable to begin with.
  • Local network / candidate list. Also tested with a clean go2rtc on host
    networking with a fixed LAN candidate (26 candidates cut to 8): no change.
  • Waking the device earlier. I sent start_live 8 s and 20 s before
    opening. The announcement still arrived 3.11–3.13 s after the join in every
    case (variance 0.02 s), so the announcement clock starts at the join, not at
    start_live.
  • join_v3 success did not include ORTC parameters. This ERROR appears on
    successful joins too — a second join response without ORTC arrives ~16 ms
    after the first one that has them — so it cannot be used to spot a failed open.

Relation to #243

I first assumed this was #243,
since the log fingerprints match (did not include ORTC parameters,
p2p_lost: Timeout, channel stun timeout, repeated subscribes). After reading
the latest investigation there — restricted network / NAT / UDP conditions plus
go2rtc's upstream path not using Agora's TURN servers — I tested that
hypothesis on this setup and it does not apply: unrestricted wired LAN, adding
STUN changed nothing, and Agora's answer needs no relay.

The symptoms differ as well. Nothing is broken here: no black screens, freezes
or mid-stream drops, the stream always opens and stays stable — it is purely a
deterministic delay. The signaling failures reported in #243 (Signaling start_live failed after 5 attempts, go2rtc upstream start_live/heartbeat not active) never occur here. That is why I am opening this separately instead of
commenting there.

If useful for triage, the gap between on_add_video_stream and p2p_lost seems
to separate the two cases: ≈10.2 s with the very next join succeeding looks like
what I see, whereas no announcement at all or repeated p2p failures looks like
#243.

Reproduction steps

  1. Feeder with camera (Yumshare Solo 2), integration 1.27.0, HA-managed go2rtc.
  2. Leave the camera unviewed for at least 60 s so the stream goes fully cold.
  3. Open the camera, or fetch a frame from the go2rtc stream:
    curl "http://<go2rtc>/api/frame.jpeg?src=petkit_<device_id>".
  4. Time until the first frame: 21–27 s, every time.
  5. Now keep the stream open for a while, close it, and reopen within ~30 s:
    1.7 s.

Debug logs

home-assistant-debug-redacted.txt

Excerpts below cover both opens; identifiers are replaced with placeholders. I
also have the full log from HA startup through both opens and can attach it if
the excerpts are not enough.

Cold open — 21.16 s:

08:33:42.971 DEBUG AgoraRTMSignaling => start_live
08:33:43.202 INFO  Connected to Agora WebSocket: wss://23-236-112-222.edge.agora.io:4702
08:33:43.228 DEBUG Waiting for on_add_video_stream before finalizing SDP answer
08:33:46.287 DEBUG Agora on_add_video_stream: uid=<DEVICE_ID> ssrc=40000     <-- WS + 3.09 s
08:33:56.504 WARN  Agora p2p_lost: code=1 error=Timeout                      <-- announcement + 10.22 s
   (go2rtc tears down the producer and reconnects)
08:34:02.890 DEBUG AgoraRTMSignaling => start_live
08:34:03.137 INFO  Connected to Agora WebSocket: wss://104-166-142-147.edge.agora.io:3478
08:34:03.167 DEBUG Waiting for on_add_video_stream before finalizing SDP answer
08:34:03.328 DEBUG Agora on_add_video_stream: uid=<DEVICE_ID> ssrc=40000     <-- WS + 0.19 s
08:34:03.609 DEBUG WS <- [on_p2p_ok]                                          --> first frame

Warm reopen 9 s later — 1.74 s. Identical path, including the same
Waiting for on_add_video_stream step; the only difference is that the
announcement arrives in 0.73 s instead of 3.09 s:

08:34:12.262 DEBUG AgoraRTMSignaling => start_live
08:34:12.438 INFO  Connected to Agora WebSocket: wss://23-236-112-222.edge.agora.io:4717
08:34:12.460 DEBUG Waiting for on_add_video_stream before finalizing SDP answer
08:34:13.189 DEBUG Agora on_add_video_stream: uid=<DEVICE_ID> ssrc=40000     <-- WS + 0.73 s
08:34:13.452 DEBUG WS <- [on_p2p_ok]                                          --> first frame
08:34:44.457 WARN  Agora p2p_lost: code=1 error=channel stun timeout          (session ends ~30 s later)

Nothing about the network, the gateway or the device differs between those two
opens — only how long the answer was withheld.

Earlier capture: the same edge host and port failed, then succeeded
06:16:42.885 INFO  Connected to Agora WebSocket: wss://38-123-109-221.edge.agora.io:3478
06:16:46.011 DEBUG Agora on_add_video_stream       <-- WS + 3.03 s
06:16:56.233 WARN  Agora p2p_lost: code=1 error=Timeout
06:17:02.993 INFO  Connected to Agora WebSocket: wss://38-123-109-221.edge.agora.io:3478
06:17:03.098 DEBUG Agora on_add_video_stream       <-- WS + 0.11 s
06:17:03.365 DEBUG WS <- [on_p2p_ok]

Diagnostics dump

Device diagnostics (redacted)
{
  "home_assistant": {
    "arch": "aarch64",
    "dev": false,
    "docker": true,
    "hassio": false,
    "installation_type": "Unsupported Third Party Container",
    "os_name": "Linux",
    "os_version": "6.12.75+rpt-rpi-2712",
    "python_version": "3.14.6",
    "timezone": "Europe/Berlin",
    "version": "2026.7.1",
    "virtualenv": false,
    "run_as_root": false
  },
  "custom_components": {
    "xgimi": {
      "documentation": "https://github.com/manymuch/Xgimi-4-Home-Assistant",
      "version": "v0.0.8",
      "requirements": [
        "asyncudp",
        "bluez-peripheral"
      ]
    },
    "tado_hijack": {
      "documentation": "https://github.com/banter240/tado_hijack",
      "version": "5.7.1",
      "requirements": [
        "tadoasync==0.2.2"
      ]
    },
    "sleep_as_android": {
      "documentation": "https://github.com/IATkachenko/HA-SleepAsAndroid/wiki",
      "version": "2.3.2",
      "requirements": [
        "pyhaversion"
      ]
    },
    "pyscript": {
      "documentation": "https://github.com/custom-components/pyscript",
      "version": "2.0.1",
      "requirements": [
        "croniter==6.0.0",
        "watchdog==6.0.0"
      ]
    },
    "dreo": {
      "documentation": "https://github.com/jeffsteinbok/hass-dreo/blob/master/README.md",
      "version": "1.10.9",
      "requirements": [
        "websockets"
      ]
    },
    "petkit": {
      "documentation": "https://github.com/Jezza34000/homeassistant_petkit",
      "version": "1.27.0",
      "requirements": [
        "pypetkitapi==1.28.0",
        "aiofiles==24.1.0",
        "paho-mqtt==2.1.0",
        "websockets==15.0.1",
        "sdp-transform==1.1.0"
      ]
    },
    "bermuda": {
      "documentation": "https://github.com/agittins/bermuda",
      "version": "0.8.7",
      "requirements": []
    },
    "tplink_router": {
      "documentation": "https://github.com/AlexandrErohin/home-assistant-tplink-router",
      "version": "v2.30.0",
      "requirements": [
        "tplinkrouterc6u==5.26.0"
      ]
    },
    "reolink": {
      "documentation": "https://www.home-assistant.io/integrations/reolink",
      "version": "2026.7.1+baichuan-vod",
      "requirements": [
        "reolink-aio @ file:///config/deps_src/reolink_aio"
      ]
    },
    "sleep_as_android_mqtt": {
      "documentation": "https://github.com/IATkachenko/HA-SleepAsAndroid/wiki",
      "version": "3.0.2",
      "requirements": [
        "pyhaversion"
      ]
    },
    "webrtc": {
      "documentation": "https://github.com/AlexxIT/WebRTC",
      "version": "v3.6.1",
      "requirements": []
    },
    "philips_airpurifier_coap": {
      "documentation": "https://github.com/kongo09/philips-airpurifier-coap",
      "version": "v0.37",
      "requirements": [
        "aioairctrl==0.3.1",
        "getmac>=0.9.4"
      ]
    },
    "hacs": {
      "documentation": "https://hacs.xyz/docs/use/",
      "version": "2.0.5",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    },
    "hass_agent": {
      "documentation": "https://github.com/hass-agent/HASS.Agent-Integration",
      "version": "2.1.2",
      "requirements": []
    },
    "midea_ac_lan": {
      "documentation": "https://github.com/wuwentao/midea_ac_lan#readme",
      "version": "0.7.1",
      "requirements": [
        "midea-local==6.11.1"
      ]
    },
    "zone_mapper": {
      "documentation": "https://github.com/ApolloAutomation/zone-mapper",
      "version": "1.0.1",
      "requirements": []
    }
  },
  "integration_manifest": {
    "domain": "petkit",
    "name": "Petkit",
    "after_dependencies": [
      "web_rtc",
      "go2rtc"
    ],
    "codeowners": [
      "Jezza34000"
    ],
    "config_flow": true,
    "dependencies": [
      "http"
    ],
    "documentation": "https://github.com/Jezza34000/homeassistant_petkit",
    "iot_class": "cloud_polling",
    "issue_tracker": "https://github.com/Jezza34000/homeassistant_petkit/issues",
    "loggers": [
      "petkit"
    ],
    "requirements": [
      "pypetkitapi==1.28.0",
      "aiofiles==24.1.0",
      "paho-mqtt==2.1.0",
      "websockets==15.0.1",
      "sdp-transform==1.1.0"
    ],
    "version": "1.27.0",
    "is_built_in": false,
    "overwrites_built_in": false
  },
  "setup_times": {
    "null": {
      "setup": 3.874099638778716e-05
    },
    "01KWHG9KVF6KC9AMGEN9T51W2M": {
      "wait_import_platforms": -0.29581585100095253,
      "config_entry_setup": 2.8904389269955573
    }
  },
  "data": {
    "config_entry": {
      "password": "<REDACTED>",
      "username": "<REDACTED>"
    },
    "device": {
      "auto_upgrade": 1,
      "bt_mac": "<REDACTED>",
      "cloud_product": {
        "charge_type": "FREE",
        "name": "Free Trial",
        "service_id": 27806,
        "subscribe": 0,
        "work_indate": 1783634399,
        "work_time": 1782997139
      },
      "created_at": "2026-07-02T12:57:43.369+0000",
      "desc": null,
      "device_records": {
        "eat": [
          {
            "add_amount": null,
            "add_amount1": null,
            "add_amount2": null,
            "day": 0,
            "device_id": 0,
            "eat_count": null,
            "eat_amount": null,
            "items": [],
            "plan_amount": null,
            "real_amount": null,
            "amount": null,
            "times": null,
            "user_id": null
          }
        ],
        "feed": [
          {
            "add_amount": 0,
            "add_amount1": null,
            "add_amount2": null,
            "day": 20260729,
            "device_id": 0,
            "eat_count": 0,
            "eat_amount": null,
            "items": [],
            "plan_amount": 0,
            "real_amount": 0,
            "amount": 0,
            "times": null,
            "user_id": null
          }
        ],
        "move": [],
        "pet": [],
        "device_type": null,
        "type_code": 0
      },
      "firmware": "852",
      "firmware_details": [
        {
          "module": "app",
          "version": 260406
        },
        {
          "module": "alg",
          "version": 260402
        },
        {
          "module": "audio",
          "version": 253502
        },
        {
          "module": "kernel",
          "version": 255102
        },
        {
          "module": "soc",
          "version": 253703
        },
        {
          "module": "ble",
          "version": 159
        }
      ],
      "hardware": 2,
      "id": "<DEVICE_ID>",
      "locale": "Europe/Berlin",
      "live_feed": null,
      "mac": "<REDACTED>",
      "manual_feed": null,
      "model_code": 2,
      "multi_config": true,
      "multi_feed_item": {
        "feed_daily_list": [
          {
            "count": null,
            "items": [],
            "repeats": 1,
            "suspended": 0,
            "total_amount": null,
            "total_amount1": null,
            "total_amount2": null
          },
          {
            "count": null,
            "items": [],
            "repeats": 2,
            "suspended": 0,
            "total_amount": null,
            "total_amount1": null,
            "total_amount2": null
          },
          {
            "count": null,
            "items": [],
            "repeats": 3,
            "suspended": 0,
            "total_amount": null,
            "total_amount1": null,
            "total_amount2": null
          },
          {
            "count": null,
            "items": [],
            "repeats": 4,
            "suspended": 0,
            "total_amount": null,
            "total_amount1": null,
            "total_amount2": null
          },
          {
            "count": null,
            "items": [],
            "repeats": 5,
            "suspended": 0,
            "total_amount": null,
            "total_amount1": null,
            "total_amount2": null
          },
          {
            "count": null,
            "items": [],
            "repeats": 6,
            "suspended": 0,
            "total_amount": null,
            "total_amount1": null,
            "total_amount2": null
          },
          {
            "count": null,
            "items": [],
            "repeats": 7,
            "suspended": 0,
            "total_amount": null,
            "total_amount1": null,
            "total_amount2": null
          }
        ],
        "is_executed": 1,
        "user_id": "1"
      },
      "name": "Yumshare Solo 2",
      "p2p_type": null,
      "secret": "<REDACTED>",
      "service_status": 2,
      "settings": {
        "attire_id": -1,
        "attire_switch": 1,
        "auto_product": 0,
        "bucket_name1": null,
        "bucket_name2": null,
        "camera": 1,
        "camera_config": 1,
        "camera_multi_new": null,
        "camera_multi_range": [],
        "color_setting": null,
        "conservation": null,
        "control_settings": 0,
        "desiccant_notify": 1,
        "detect_config": 1,
        "detect_interval": 0,
        "detect_multi_range": [],
        "eat_detection": 1,
        "eat_notify": 1,
        "eat_sensitivity": 3,
        "eat_video": 1,
        "factor": 10,
        "feed_notify": 1,
        "feed_picture": 1,
        "feed_sound": null,
        "food_notify": 1,
        "food_warn": 0,
        "food_warn_range": [
          480,
          1200
        ],
        "highlight": 1,
        "light_config": 1,
        "light_mode": 1,
        "light_multi_range": [],
        "live_encrypt": 1,
        "low_battery_notify": 1,
        "manual_lock": 0,
        "microphone": 1,
        "move_detection": 0,
        "move_notify": 0,
        "move_sensitivity": 1,
        "night": 1,
        "num_limit": 5,
        "pet_detection": 1,
        "pet_notify": 1,
        "pet_sensitivity": 3,
        "pre_live": 1,
        "selected_sound": 1,
        "shortest": null,
        "smart_frame": 1,
        "sound_enable": 1,
        "surplus": null,
        "surplus_control": 0,
        "surplus_standard": 2,
        "system_sound_enable": 1,
        "time_display": 1,
        "tone_config": 2,
        "tone_mode": 1,
        "tone_multi_range": [
          [
            1320,
            360
          ]
        ],
        "upload": 1,
        "volume": 5
      },
      "share_open": 0,
      "signup_at": "2026-07-28T12:44:17.572+0000",
      "sn": "<REDACTED>",
      "state": {
        "battery_power": 4,
        "battery_status": 0,
        "block": null,
        "bowl": 0,
        "broadcast": null,
        "camera_status": 1,
        "charge": null,
        "conservation_status": null,
        "desiccant_left_days": 3,
        "desiccant_time": 0,
        "door": 1,
        "eating": null,
        "error_code": null,
        "error_detail": null,
        "error_level": null,
        "error_msg": null,
        "feed_state": {
          "add_amount_total": 0,
          "add_amount_total1": null,
          "add_amount_total2": null,
          "eat_amount_total": null,
          "eat_avg": 0,
          "eat_count": 0,
          "eat_times": [],
          "feed_times": {},
          "plan_amount_total": 0,
          "plan_amount_total1": null,
          "plan_amount_total2": null,
          "plan_real_amount_total": 0,
          "plan_real_amount_total1": null,
          "plan_real_amount_total2": null,
          "real_amount_total": 0,
          "real_amount_total1": null,
          "real_amount_total2": null,
          "times": 0
        },
        "feeding": 0,
        "food": 0,
        "food1": null,
        "food2": null,
        "ota": 0,
        "overall": 1,
        "pim": 1,
        "runtime": 0,
        "weight": null,
        "wifi": {
          "bssid": "<REDACTED>",
          "rsq": -42,
          "ssid": "<REDACTED>"
        }
      },
      "timezone": 2.0,
      "user": {
        "id": "<ID>",
        "nick": "Ethan (Primary)"
      },
      "device_nfo": {
        "created_at": 1782997099505,
        "device_id": "<DEVICE_ID>",
        "device_name": "yumshare solo 2",
        "device_type": "d4h",
        "group_id": 300661147,
        "modele_name": "Yumshare Solo 2",
        "type": 26,
        "type_code": 2,
        "unique_id": "<DEVICE_ID>-26"
      },
      "medias": [],
      "sound_list": null
    }
  },
  "issues": []
}

My current workaround

I patched my own copy so that the integration stops withholding the SDP answer:
it answers as soon as the join response is available, reusing the SSRC from the
previously announced stream (remembered across restarts) instead of waiting for
a fresh announcement, and re-issues the subscription when the real announcement
arrives.

before after
cold open 21–27 s ~4.0 s
on_p2p_ok after the WebSocket opens never (times out) 0.29–0.32 s
warm reopen 1.7 s 1.7 s (unchanged)

From the outside that looks close to how fast the official Petkit app opens the
same camera, though I have no insight into what the app actually does — the
point is only that the ~20 s appears avoidable rather than inherent to the
device.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions