feat(go3s): Insta360 Go3S adapter with BLE trigger + WiFi aggregation - #11
Merged
Conversation
- Add live_preview: bool = True field to StreamCapabilities for routing Go3S streams to standalone recorder panel (defaults to True for backward compatibility) - Include live_preview in to_dict() serialization - Extend FinalizationReport.status Literal with pending_aggregation value to express background WiFi aggregation jobs - Create comprehensive test files test_types_capabilities.py and test_types_finalization.py with full coverage - Update existing test_types.py tests to expect live_preview in dict Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Implements Go3SBLECamera with Future-per-seq dispatch, SYNC handshake, CMD_CHECK_AUTH auth, start/stop capture, and CaptureResult. Adds pytest-asyncio and asyncio_mode=auto to pyproject.toml. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Implements the Go3SStream lifecycle class (Task 10) that subclasses StreamBase and bridges the sync orchestrator API to the async BLE helper, building an AggregationJob on stop_recording and enqueuing it per the configured aggregation_policy. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…host roles When a Go3SStream with aggregation_policy="eager" is added to a session whose role is LeaderRole or FollowerRole, the policy is automatically downgraded to "on_demand" so the host's WiFi adapter stays connected to lab WiFi (needed for mDNS multihost coordination) instead of switching to the camera AP during recording. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Add AggregationSnapshot dataclass to state.py and wire it into snapshot_to_dict so the /ws/control and /api/status payloads include an aggregation section (active_job, queue_length, recent_jobs). A best-effort listener on the global Go3S aggregation queue keeps the state live; a no-op if the camera extra is not installed. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Add handle_control_command() dispatcher in viewer/server.py for the three new WS commands (aggregate_episode, retry_aggregation, cancel_aggregation), and add the corresponding methods to SessionOrchestrator that delegate to the Go3S aggregation queue. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Renders a standalone-recorder card body (no live preview) for video streams where capabilities.live_preview is false, showing recording / aggregating / ready / failed states with a Retry button on failure. - New component: standalone-recorder-panel.tsx - stream-card.tsx: dispatcher branch for live_preview=false video streams - types.ts: StreamCapabilities, AggregationSnapshotWS, AggregationActiveJob, extended ControlAction with aggregation commands - state.py / poller.py: surface live_preview from StreamCapabilities - server.py: emit capabilities in WS stream dict; route aggregation action commands (retry_aggregation, cancel_aggregation, aggregate_episode) through handle_control_command in _handle_command Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Implements T16: mounts a persistent AggregationStatusBar below the stop-result banner in RecordView (running = animated progress bar + bytes, failed = Retry button). Adds AggregationBadge to EpisodeTable and EpisodeCard in the review mode, sourced from the live WS aggregation snapshot (active_job + recent_jobs). Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Add `add_go3s_stream` command to `handle_control_command` with a `_next_default_id` helper that auto-increments the stream id. Route the command through `_handle_command` (WS action dispatcher). Extend the discovery modal with `isGo3SDevice` name-pattern detection and `deviceTypeLabel` to render "Insta360 Go3S" instead of the raw adapter string for devices whose BLE name contains "go 3" or "go3". Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Adds a 'camera' optional-dependencies entry for the Insta360 Go3S adapter (bleak + aiohttp) and rolls the new package into the 'all' extra. Install with: uv add 'syncfield[camera]'. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Empty string bypassed the prior None guard and produced an AggregationJob with sd_path='' that failed opaquely in the worker. Now raises a clear error at stop_recording() with diagnostic guidance.
The aggregation queue has had crash-recovery support since T08, but no production callsite invoked it. Now scan SYNCFIELD_GO3S_RECOVERY_ROOT (default: cwd) at singleton init and re-enqueue any leftover PENDING/ RUNNING aggregation jobs from prior runs.
…ng_loop() Both call sites are inside running coroutines, so get_running_loop() is the correct API. Eliminates DeprecationWarning on Python 3.10+ and prevents the RuntimeError that 3.14 will raise.
Module-level mutable list bled state across instances and was mutated from the aggregation worker thread without synchronization.
Was sending only 3 of 5 fields; the TS StreamCapabilities interface declares all 5. Use to_dict() so future consumers don't see undefined for supports_precise_timestamps / is_removable.
…apter # Conflicts: # src/syncfield/viewer/frontend/src/components/stream-card.tsx # src/syncfield/viewer/frontend/tsconfig.tsbuildinfo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an Insta360 Go3S camera adapter to syncfield-python. Wireless start/stop via BLE, background WiFi/OSC file download after recording, viewer UI for status + retry.
Go3SStreamadapter (StreamBasesubclass) that drives BLE start/stop and enqueues a per-episode aggregation job. Background queue runs on a dedicated daemon thread + asyncio loop; atomic per-camera + per-episode semantics with selective retry. SDK-restart crash recovery viaaggregation.jsonscan.on_demandpolicy so lab WiFi (mDNS) isn't broken mid-session.StandaloneRecorderPanel("Live preview unavailable"), persistentAggregationStatusBar, per-episode status badges in both table and card views, discovery modal recognizesgo 3/go3BLE names, 3 new WS commands (aggregate_episode, retry_aggregation, cancel_aggregation).syncfield[camera](bleak + aiohttp).Reference: BLE protocol ported verbatim from
opengraph-studio/recorder, validated against Go3S firmware v8.0.4.11.Design docs
docs/superpowers/specs/2026-04-14-insta360-go3s-adapter-design.mddocs/superpowers/plans/2026-04-14-insta360-go3s-adapter.mdTest plan
yarn buildclean (TS + Vite + Tailwind v4).examples/insta360_go3s/record.py); verify episode dir contents (mp4 + aggregation.json withstate: completed).on_demandand lab WiFi stays up during recording.Known follow-ups (non-blocking)
manifest.jsonGo3S-specific fields (ble_address, sd_path, aggregation_policy)formatBytesduplication in frontend → extract tolib/format.ts🤖 Generated with Claude Code