Skip to content

GoProClient

gopro_sdk.client.GoProClient

GoProClient(
    target: str,
    offline_mode: bool = True,
    timeout_config: TimeoutConfig | None = None,
    config_manager: CohnConfigManager | None = None,
    wifi_ssid: str | None = None,
    wifi_password: str | None = None,
)

Bases: HealthCheckMixin

GoPro client.

Design principles: - Supports offline mode (BLE only) and online mode (BLE+WiFi) - Offline mode is default (suitable for no WiFi or slow WiFi scenarios) - Composition over inheritance (holds command interface instances) - Delegation pattern (provides concise API) - Single responsibility (separates connection management and command execution)

Usage examples

Method 1 - Offline mode (default, BLE only, recommended for no WiFi or slow WiFi):

async with GoProClient("1332") as client: # offline_mode=True (default) ... await client.start_recording() # ✅ Control via BLE ... await client.set_date_time() # ✅ Sync time via BLE ... # await client.start_preview() # ❌ Not supported in offline mode

Method 2 - Online mode (BLE+WiFi, supports preview, download, etc.):

async with GoProClient("1332", offline_mode=False, wifi_ssid="MyWiFi", wifi_password="pass") as client: ... await client.start_recording() # ✅ Control via BLE ... await client.start_preview() # ✅ Preview via HTTP ... await client.download_media(...) # ✅ Download via HTTP

Method 3 - Dynamic mode switching:

async with GoProClient("1332") as client: # Start in offline mode ... await client.start_recording() # Via BLE ... # Switch to online mode when preview needed ... await client.switch_to_online_mode(wifi_ssid="MyWiFi", wifi_password="pass") ... await client.start_preview() # Preview now available

Method 4 - Camera already connected to WiFi (online mode, simplest):

async with GoProClient("1332", offline_mode=False) as client: ... await client.start_preview() # Directly use already connected WiFi

Initialize the client.

Parameters:

Name Type Description Default
target str

Camera serial number last four digits

required
offline_mode bool

Whether to use offline mode (default True) - True: BLE only, no WiFi connection, no preview/download support (suitable for no WiFi scenarios) - False: BLE+WiFi, supports all features (requires WiFi network)

True
timeout_config TimeoutConfig | None

Timeout configuration

None
config_manager CohnConfigManager | None

COHN configuration manager

None
wifi_ssid str | None

WiFi SSID (optional, for automatic connection with async with, only effective in online mode)

None
wifi_password str | None

WiFi password (optional, used together with wifi_ssid)

None
Note
  • In offline mode, wifi_ssid/wifi_password will be ignored
  • In online mode, if WiFi info is not provided, camera must already be connected to WiFi
  • Can dynamically switch to online mode via switch_to_online_mode()

Raises:

Type Description
ValueError

Provided wifi_ssid but not wifi_password

Source code in src/gopro_sdk/client.py
def __init__(
    self,
    target: str,
    offline_mode: bool = True,
    timeout_config: TimeoutConfig | None = None,
    config_manager: CohnConfigManager | None = None,
    wifi_ssid: str | None = None,
    wifi_password: str | None = None,
) -> None:
    """Initialize the client.

    Args:
        target: Camera serial number last four digits
        offline_mode: Whether to use offline mode (default True)
            - True: BLE only, no WiFi connection, no preview/download support (suitable for no WiFi scenarios)
            - False: BLE+WiFi, supports all features (requires WiFi network)
        timeout_config: Timeout configuration
        config_manager: COHN configuration manager
        wifi_ssid: WiFi SSID (optional, for automatic connection with async with, only effective in online mode)
        wifi_password: WiFi password (optional, used together with wifi_ssid)

    Note:
        - In offline mode, wifi_ssid/wifi_password will be ignored
        - In online mode, if WiFi info is not provided, camera must already be connected to WiFi
        - Can dynamically switch to online mode via switch_to_online_mode()

    Raises:
        ValueError: Provided wifi_ssid but not wifi_password
    """
    if wifi_ssid is not None and wifi_password is None:
        raise ValueError("Provided wifi_ssid but not wifi_password")

    self.target = target
    self._offline_mode = offline_mode
    self._timeout = timeout_config or TimeoutConfig()
    self._config_manager = config_manager or CohnConfigManager()
    self._wifi_ssid = wifi_ssid
    self._wifi_password = wifi_password

    # Connection managers
    self.ble = BleConnectionManager(target, self._timeout)
    self.http = HttpConnectionManager(target, self._timeout)

    # Command interfaces (composition)
    self.ble_commands = BleCommands(self.ble)
    self.http_commands = HttpCommands(self.http)
    self.media_commands = MediaCommands(self.http)
    self.webcam_commands = WebcamCommands(self.http)

    # Health check configuration
    self._enable_auto_reconnect = True
    self._max_reconnect_attempts = self._timeout.max_reconnect_attempts
    self._last_health_check: float | None = None

    mode_str = "Offline mode (BLE only)" if offline_mode else "Online mode (BLE+WiFi)"
    logger.info(f"Initializing GoProClient, target camera: {target}, mode: {mode_str}")

Attributes

offline_mode property

offline_mode: bool

Get current mode.

Returns:

Type Description
bool

True for offline mode, False for online mode

is_online property

is_online: bool

Check if in online mode.

Returns:

Type Description
bool

True for online mode, False for offline mode

Functions

open async

open(
    wifi_ssid: str | None = None,
    wifi_password: str | None = None,
) -> None

Establish connection to the camera.

The connection method is determined by offline_mode: - Offline mode (offline_mode=True): BLE only, WiFi parameters ignored - Online mode (offline_mode=False): BLE + WiFi/COHN setup + HTTP initialization

Online mode workflow: 1. Connect via BLE 2. If WiFi credentials provided: - Query current camera WiFi status - If not connected or connected to different WiFi, reconfigure WiFi - If already connected to target WiFi, skip configuration 3. Attempt to load saved COHN credentials 4. If no credentials exist, configure COHN (camera auto-connects to remembered WiFi) 5. Initialize HTTP client (lazy connection)

WiFi parameter behavior (online mode only): - No WiFi credentials: Assumes camera is already on WiFi, directly configures COHN - If configuration fails, hints that WiFi credentials are needed - WiFi credentials provided: Actively connects to specified WiFi - Camera remembers WiFi password, next time can auto-connect with only SSID

Important notes: - Computer and camera must be on the same WiFi network, otherwise HTTP (COHN) connection will fail - Parameters passed to this method override constructor parameters - WiFi parameters are ignored in offline mode

Parameters:

Name Type Description Default
wifi_ssid str | None

WiFi SSID (optional, only effective in online mode, overrides constructor parameter)

None
wifi_password str | None

WiFi password (optional, used with wifi_ssid)

None

Raises:

Type Description
BleConnectionError

BLE connection failed or WiFi/COHN configuration failed

HttpConnectionError

HTTP connection failed (online mode only)

ValueError

wifi_ssid provided but wifi_password missing

Examples:

Offline mode:

>>> async with GoProClient("1332") as client:  # offline_mode=True (default)
...     await client.start_recording()  # Works via BLE only

Online mode:

>>> async with GoProClient("1332", offline_mode=False, wifi_ssid="MyWiFi", wifi_password="pass") as client:
...     await client.start_preview()  # Works via HTTP
Source code in src/gopro_sdk/client.py
async def open(self, wifi_ssid: str | None = None, wifi_password: str | None = None) -> None:
    """Establish connection to the camera.

    The connection method is determined by offline_mode:
    - **Offline mode (offline_mode=True)**: BLE only, WiFi parameters ignored
    - **Online mode (offline_mode=False)**: BLE + WiFi/COHN setup + HTTP initialization

    Online mode workflow:
    1. Connect via BLE
    2. If WiFi credentials provided:
       - Query current camera WiFi status
       - If not connected or connected to different WiFi, reconfigure WiFi
       - If already connected to target WiFi, skip configuration
    3. Attempt to load saved COHN credentials
    4. If no credentials exist, configure COHN (camera auto-connects to remembered WiFi)
    5. Initialize HTTP client (lazy connection)

    WiFi parameter behavior (online mode only):
    - **No WiFi credentials**: Assumes camera is already on WiFi, directly configures COHN
      - If configuration fails, hints that WiFi credentials are needed
    - **WiFi credentials provided**: Actively connects to specified WiFi
      - Camera remembers WiFi password, next time can auto-connect with only SSID

    Important notes:
    - **Computer and camera must be on the same WiFi network**, otherwise HTTP (COHN) connection will fail
    - Parameters passed to this method override constructor parameters
    - WiFi parameters are ignored in offline mode

    Args:
        wifi_ssid: WiFi SSID (optional, only effective in online mode, overrides constructor parameter)
        wifi_password: WiFi password (optional, used with wifi_ssid)

    Raises:
        BleConnectionError: BLE connection failed or WiFi/COHN configuration failed
        HttpConnectionError: HTTP connection failed (online mode only)
        ValueError: wifi_ssid provided but wifi_password missing

    Examples:
        Offline mode:
        >>> async with GoProClient("1332") as client:  # offline_mode=True (default)
        ...     await client.start_recording()  # Works via BLE only

        Online mode:
        >>> async with GoProClient("1332", offline_mode=False, wifi_ssid="MyWiFi", wifi_password="pass") as client:
        ...     await client.start_preview()  # Works via HTTP
    """
    mode_str = "Offline mode (BLE only)" if self._offline_mode else "Online mode (BLE+WiFi)"
    logger.info(f"Starting connection to camera {self.target}, mode: {mode_str}")

    # Merge parameters: open() method parameters take precedence over constructor parameters
    final_wifi_ssid = wifi_ssid if wifi_ssid is not None else self._wifi_ssid
    final_wifi_password = wifi_password if wifi_password is not None else self._wifi_password

    # Parameter validation
    if final_wifi_ssid is not None and final_wifi_password is None:
        raise ValueError("wifi_ssid provided but wifi_password is missing")

    # Step 1: Connect BLE
    await self.ble.connect()

    # In offline mode, only connect BLE, skip WiFi/COHN configuration
    if self._offline_mode:
        logger.info(f"✅ Camera {self.target} connected (offline mode, BLE only)")
        logger.info("💡 Note: Offline mode does not support preview, download, etc.")
        logger.info("   To use these features, call switch_to_online_mode()")
        return

    # ========== Online mode workflow below ==========

    # Step 2-4: Setup COHN credentials (WiFi connection + credential management)
    await self._setup_cohn_credentials(final_wifi_ssid, final_wifi_password)

    logger.info(f"✅ Camera {self.target} connected successfully (BLE + COHN configured)")

close async

close() -> None

Close all connections.

Source code in src/gopro_sdk/client.py
async def close(self) -> None:
    """Close all connections."""
    # Only disconnect connections that are actually connected
    # In offline mode, http was never connected, so we shouldn't call disconnect
    if self.http.is_connected:
        await self.http.disconnect()

    if self.ble.is_connected:
        await self.ble.disconnect()

    logger.info(f"All connections to camera {self.target} closed")

switch_to_online_mode async

switch_to_online_mode(
    wifi_ssid: str | None = None,
    wifi_password: str | None = None,
) -> None

Switch to online mode (dynamic switching).

If the client was initialized with offline mode, this method can switch to online mode to use features that require WiFi, such as preview and download.

Parameters:

Name Type Description Default
wifi_ssid str | None

WiFi SSID (optional, not needed if camera is already on WiFi)

None
wifi_password str | None

WiFi password (optional, used with wifi_ssid)

None

Raises:

Type Description
BleConnectionError

WiFi/COHN configuration failed

ValueError

wifi_ssid provided but wifi_password missing

Examples:

>>> async with GoProClient("1332") as client:  # Default offline mode
...     await client.start_recording()  # Works via BLE
...     # Switch to online mode when preview is needed
...     await client.switch_to_online_mode(wifi_ssid="MyWiFi", wifi_password="pass")
...     await client.start_preview()  # Now preview works
Source code in src/gopro_sdk/client.py
async def switch_to_online_mode(self, wifi_ssid: str | None = None, wifi_password: str | None = None) -> None:
    """Switch to online mode (dynamic switching).

    If the client was initialized with offline mode, this method can switch to online mode
    to use features that require WiFi, such as preview and download.

    Args:
        wifi_ssid: WiFi SSID (optional, not needed if camera is already on WiFi)
        wifi_password: WiFi password (optional, used with wifi_ssid)

    Raises:
        BleConnectionError: WiFi/COHN configuration failed
        ValueError: wifi_ssid provided but wifi_password missing

    Examples:
        >>> async with GoProClient("1332") as client:  # Default offline mode
        ...     await client.start_recording()  # Works via BLE
        ...     # Switch to online mode when preview is needed
        ...     await client.switch_to_online_mode(wifi_ssid="MyWiFi", wifi_password="pass")
        ...     await client.start_preview()  # Now preview works
    """
    if not self._offline_mode:
        logger.info("✅ Already in online mode, no need to switch")
        return

    logger.info("🔄 Switching to online mode...")

    # Parameter validation
    if wifi_ssid is not None and wifi_password is None:
        raise ValueError("wifi_ssid provided but wifi_password is missing")

    # Merge parameters
    final_wifi_ssid = wifi_ssid if wifi_ssid is not None else self._wifi_ssid
    final_wifi_password = wifi_password if wifi_password is not None else self._wifi_password

    # Ensure BLE is connected
    if not self.ble.is_connected:
        raise BleConnectionError("BLE not connected, cannot switch to online mode")

    # Setup COHN credentials (reuse the same logic as open())
    await self._setup_cohn_credentials(final_wifi_ssid, final_wifi_password)

    # Switch mode flag
    self._offline_mode = False
    logger.info("✅ Switched to online mode (BLE+WiFi)")

set_shutter async

set_shutter(enable: bool) -> None

Control recording shutter.

Always uses BLE for more reliable recording control.

Parameters:

Name Type Description Default
enable bool

True to start recording, False to stop recording

required
Source code in src/gopro_sdk/client.py
async def set_shutter(self, enable: bool) -> None:
    """Control recording shutter.

    Always uses BLE for more reliable recording control.

    Args:
        enable: True to start recording, False to stop recording
    """
    # Always use BLE for recording control (more reliable)
    await self.ble_commands.set_shutter(enable)

start_recording async

start_recording() -> None

Start recording. Convenience wrapper for set_shutter(True).

Source code in src/gopro_sdk/client.py
async def start_recording(self) -> None:
    """Start recording. Convenience wrapper for set_shutter(True)."""
    await self.set_shutter(True)

stop_recording async

stop_recording() -> None

Stop recording. Convenience wrapper for set_shutter(False).

Source code in src/gopro_sdk/client.py
async def stop_recording(self) -> None:
    """Stop recording. Convenience wrapper for set_shutter(False)."""
    await self.set_shutter(False)

set_preview_stream async

set_preview_stream(
    enable: bool, port: int | None = None
) -> None

Control preview stream.

Parameters:

Name Type Description Default
enable bool

True to enable, False to disable

required
port int | None

Preview stream port (only needed when enabling)

None

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Preview stream control")
async def set_preview_stream(self, enable: bool, port: int | None = None) -> None:
    """Control preview stream.

    Args:
        enable: True to enable, False to disable
        port: Preview stream port (only needed when enabling)

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    await self.http_commands.set_preview_stream(enable, port)

start_preview async

start_preview(port: int = 8554) -> str

Start preview stream.

Parameters:

Name Type Description Default
port int

Preview stream port, default 8554

8554

Returns:

Type Description
str

Preview stream URL (udp://ip:port)

Raises:

Type Description
HttpConnectionError

HTTP connection failed or unavailable

GoproError

Camera rejected preview request

Design philosophy

Direct attempt without polling - let operations fail fast with clear errors. Camera will return appropriate HTTP status codes if not ready (e.g., 409 if busy).

Source code in src/gopro_sdk/client.py
async def start_preview(self, port: int = 8554) -> str:
    """Start preview stream.

    Args:
        port: Preview stream port, default 8554

    Returns:
        Preview stream URL (udp://ip:port)

    Raises:
        HttpConnectionError: HTTP connection failed or unavailable
        GoproError: Camera rejected preview request

    Design philosophy:
        Direct attempt without polling - let operations fail fast with clear errors.
        Camera will return appropriate HTTP status codes if not ready (e.g., 409 if busy).
    """
    # Attempt to stop any existing preview/recording directly
    # Failures are expected and ignored - camera handles state internally
    with contextlib.suppress(Exception):
        await self.set_preview_stream(False)

    with contextlib.suppress(Exception):
        await self.set_shutter(False)

    # Brief pause to let camera update state
    await asyncio.sleep(self._timeout.preview_state_settle_delay)

    # Direct attempt to start preview - camera will reject if not ready
    await self.set_preview_stream(True, port)

    # Return preview stream URL
    stream_url = f"udp://127.0.0.1:{port}"
    logger.info(f"📹 [{self.target}] Preview stream started on port {port}")

    return stream_url

stop_preview async

stop_preview() -> None

Stop preview stream. Convenience wrapper for set_preview_stream(False).

Source code in src/gopro_sdk/client.py
async def stop_preview(self) -> None:
    """Stop preview stream. Convenience wrapper for set_preview_stream(False)."""
    await self.set_preview_stream(False)

tag_hilight async

tag_hilight() -> None

Tag highlight (during recording).

Note

Always uses BLE command for more reliable operation.

Source code in src/gopro_sdk/client.py
async def tag_hilight(self) -> None:
    """Tag highlight (during recording).

    Note:
        Always uses BLE command for more reliable operation.
    """
    await self.ble_commands.tag_hilight()

get_camera_state async

get_camera_state() -> dict[str, Any]

Get camera status (raw format).

Returns:

Type Description
dict[str, Any]

Raw status dictionary in format: { "status": {"10": 0, "32": 1, ...}, "settings": {"2": 1, "3": 8, ...} }

Note

Returns raw format (integer IDs). To parse as enum types, use the get_parsed_state() method.

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Get camera status")
async def get_camera_state(self) -> dict[str, Any]:
    """Get camera status (raw format).

    Returns:
        Raw status dictionary in format:
            {
                "status": {"10": 0, "32": 1, ...},
                "settings": {"2": 1, "3": 8, ...}
            }

    Note:
        Returns raw format (integer IDs). To parse as enum types,
        use the `get_parsed_state()` method.

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.http_commands.get_camera_state()

get_parsed_state async

get_parsed_state() -> dict[Any, Any]

Get parsed camera status (enum format).

Returns:

Type Description
dict[Any, Any]

Parsed status dictionary using StatusId/SettingId enums as keys,

dict[Any, Any]

in format: { StatusId.ENCODING: False, StatusId.PREVIEW_STREAM: True, SettingId.VIDEO_RESOLUTION: VideoResolution.NUM_4K, ... }

Examples:

>>> state = await client.get_parsed_state()
>>> if state[StatusId.ENCODING]:
...     print("🔴 Camera is recording")
Source code in src/gopro_sdk/client.py
async def get_parsed_state(self) -> dict[Any, Any]:
    """Get parsed camera status (enum format).

    Returns:
        Parsed status dictionary using StatusId/SettingId enums as keys,
        in format:
            {
                StatusId.ENCODING: False,
                StatusId.PREVIEW_STREAM: True,
                SettingId.VIDEO_RESOLUTION: VideoResolution.NUM_4K,
                ...
            }

    Examples:
        >>> state = await client.get_parsed_state()
        >>> if state[StatusId.ENCODING]:
        ...     print("🔴 Camera is recording")
    """
    raw_state = await self.get_camera_state()
    return parse_camera_state(raw_state)

get_camera_info async

get_camera_info() -> dict[str, Any]

Get camera information.

Returns:

Type Description
dict[str, Any]

Camera information dictionary

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Get camera info")
async def get_camera_info(self) -> dict[str, Any]:
    """Get camera information.

    Returns:
        Camera information dictionary

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.http_commands.get_camera_info()

set_keep_alive async

set_keep_alive() -> None

Send keep-alive signal.

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Keep-alive signal")
async def set_keep_alive(self) -> None:
    """Send keep-alive signal.

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    await self.http_commands.set_keep_alive()

set_date_time async

set_date_time(
    dt: datetime | None = None,
    tz_offset: int = 0,
    is_dst: bool = False,
) -> None

Set camera date and time.

Parameters:

Name Type Description Default
dt datetime | None

Datetime object, defaults to current time

None
tz_offset int

Timezone offset (hours)

0
is_dst bool

Whether daylight saving time

False
Note

Always uses BLE command for time sync (more reliable than HTTP)

Source code in src/gopro_sdk/client.py
async def set_date_time(self, dt: datetime | None = None, tz_offset: int = 0, is_dst: bool = False) -> None:
    """Set camera date and time.

    Args:
        dt: Datetime object, defaults to current time
        tz_offset: Timezone offset (hours)
        is_dst: Whether daylight saving time

    Note:
        Always uses BLE command for time sync (more reliable than HTTP)
    """
    # Always use BLE for time sync (more reliable)
    await self.ble_commands.set_date_time(dt, tz_offset, is_dst)

get_date_time async

get_date_time() -> datetime

Get camera date and time.

Returns:

Type Description
datetime

Datetime object

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Get camera time")
async def get_date_time(self) -> datetime:
    """Get camera date and time.

    Returns:
        Datetime object

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.http_commands.get_date_time()

get_setting async

get_setting(setting_id: int) -> Any

Get the value of specified setting.

Parameters:

Name Type Description Default
setting_id int

Setting ID

required

Returns:

Type Description
Any

Setting value

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Get setting")
async def get_setting(self, setting_id: int) -> Any:
    """Get the value of specified setting.

    Args:
        setting_id: Setting ID

    Returns:
        Setting value

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.http_commands.get_setting(setting_id)

set_setting async

set_setting(setting_id: int, value: int) -> None

Modify the value of specified setting.

Parameters:

Name Type Description Default
setting_id int

Setting ID

required
value int

Setting value

required

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Set setting")
async def set_setting(self, setting_id: int, value: int) -> None:
    """Modify the value of specified setting.

    Args:
        setting_id: Setting ID
        value: Setting value

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    await self.http_commands.set_setting(setting_id, value)

get_preset_status async

get_preset_status(
    include_hidden: bool = False,
) -> dict[str, Any]

Get preset status.

Parameters:

Name Type Description Default
include_hidden bool

Whether to include hidden presets

False

Returns:

Type Description
dict[str, Any]

Preset status dictionary

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Get preset status")
async def get_preset_status(self, include_hidden: bool = False) -> dict[str, Any]:
    """Get preset status.

    Args:
        include_hidden: Whether to include hidden presets

    Returns:
        Preset status dictionary

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.http_commands.get_preset_status(include_hidden)

load_preset async

load_preset(preset_id: int) -> None

Load specified preset.

Parameters:

Name Type Description Default
preset_id int

Preset ID

required
Note

Always uses BLE command for more reliable operation.

Source code in src/gopro_sdk/client.py
async def load_preset(self, preset_id: int) -> None:
    """Load specified preset.

    Args:
        preset_id: Preset ID

    Note:
        Always uses BLE command for more reliable operation.
    """
    await self.ble_commands.load_preset(preset_id)

load_preset_group async

load_preset_group(group_id: int) -> None

Load preset group.

Parameters:

Name Type Description Default
group_id int

Preset group ID

required
Note

Always uses BLE command for more reliable operation.

Source code in src/gopro_sdk/client.py
async def load_preset_group(self, group_id: int) -> None:
    """Load preset group.

    Args:
        group_id: Preset group ID

    Note:
        Always uses BLE command for more reliable operation.
    """
    await self.ble_commands.load_preset_group(group_id)

set_digital_zoom async

set_digital_zoom(percent: int) -> None

Set digital zoom.

Parameters:

Name Type Description Default
percent int

Zoom percentage (0-100)

required

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Digital zoom")
async def set_digital_zoom(self, percent: int) -> None:
    """Set digital zoom.

    Args:
        percent: Zoom percentage (0-100)

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    await self.http_commands.set_digital_zoom(percent)

sleep async

sleep() -> None

Put camera to sleep.

Note

Uses BLE command which works in both online and offline modes.

Source code in src/gopro_sdk/client.py
async def sleep(self) -> None:
    """Put camera to sleep.

    Note:
        Uses BLE command which works in both online and offline modes.
    """
    await self.ble_commands.sleep()

reboot async

reboot() -> None

Reboot camera.

Note

Uses BLE command which works in both online and offline modes.

Source code in src/gopro_sdk/client.py
async def reboot(self) -> None:
    """Reboot camera.

    Note:
        Uses BLE command which works in both online and offline modes.
    """
    await self.ble_commands.reboot()

get_media_list async

get_media_list() -> list[MediaFile]

Get list of all media files.

Returns:

Type Description
list[MediaFile]

List of media files (MediaFile objects)

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Media file list")
async def get_media_list(self) -> list[MediaFile]:
    """Get list of all media files.

    Returns:
        List of media files (MediaFile objects)

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.media_commands.get_media_list()

download_file async

download_file(
    media_file: MediaFile | str,
    save_path: str | Path,
    progress_callback: Callable[[int, int], None]
    | None = None,
) -> int

Download media file.

Parameters:

Name Type Description Default
media_file MediaFile | str

MediaFile object or file path

required
save_path str | Path

Save path

required
progress_callback Callable[[int, int], None] | None

Progress callback function (downloaded: int, total: int) -> None

None

Returns:

Type Description
int

Number of bytes downloaded

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Media download")
async def download_file(
    self,
    media_file: MediaFile | str,
    save_path: str | Path,
    progress_callback: Callable[[int, int], None] | None = None,
) -> int:
    """Download media file.

    Args:
        media_file: MediaFile object or file path
        save_path: Save path
        progress_callback: Progress callback function (downloaded: int, total: int) -> None

    Returns:
        Number of bytes downloaded

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.media_commands.download_file(media_file, save_path, progress_callback)

delete_file async

delete_file(path: str) -> None

Delete single media file.

Parameters:

Name Type Description Default
path str

File path

required

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Delete media file")
async def delete_file(self, path: str) -> None:
    """Delete single media file.

    Args:
        path: File path

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    await self.media_commands.delete_file(path)

delete_all_media async

delete_all_media() -> None

Delete all media files.

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Delete all media")
async def delete_all_media(self) -> None:
    """Delete all media files.

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    await self.media_commands.delete_all_media()

get_media_metadata async

get_media_metadata(path: str) -> dict[str, Any]

Get media file metadata.

Parameters:

Name Type Description Default
path str

File path

required

Returns:

Type Description
dict[str, Any]

Metadata dictionary

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Get media metadata")
async def get_media_metadata(self, path: str) -> dict[str, Any]:
    """Get media file metadata.

    Args:
        path: File path

    Returns:
        Metadata dictionary

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.media_commands.get_media_metadata(path)

get_last_captured_media async

get_last_captured_media() -> dict[str, Any]

Get last captured media file information.

Returns:

Type Description
dict[str, Any]

Media information dictionary

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Get last captured media")
async def get_last_captured_media(self) -> dict[str, Any]:
    """Get last captured media file information.

    Returns:
        Media information dictionary

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.media_commands.get_last_captured_media()

set_turbo_mode async

set_turbo_mode(enable: bool) -> None

Enable/disable Turbo transfer mode.

Parameters:

Name Type Description Default
enable bool

True to enable, False to disable

required

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Turbo transfer mode")
async def set_turbo_mode(self, enable: bool) -> None:
    """Enable/disable Turbo transfer mode.

    Args:
        enable: True to enable, False to disable

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    await self.media_commands.set_turbo_mode(enable)

start_webcam async

start_webcam(
    resolution: int | None = None,
    fov: int | None = None,
    port: int | None = None,
    protocol: str | None = None,
) -> dict[str, Any]

Start Webcam mode.

Parameters:

Name Type Description Default
resolution int | None

Resolution

None
fov int | None

Field of view

None
port int | None

Port

None
protocol str | None

Protocol

None

Returns:

Type Description
dict[str, Any]

Webcam response

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Webcam mode")
async def start_webcam(
    self,
    resolution: int | None = None,
    fov: int | None = None,
    port: int | None = None,
    protocol: str | None = None,
) -> dict[str, Any]:
    """Start Webcam mode.

    Args:
        resolution: Resolution
        fov: Field of view
        port: Port
        protocol: Protocol

    Returns:
        Webcam response

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.webcam_commands.webcam_start(resolution, fov, port, protocol)

stop_webcam async

stop_webcam() -> dict[str, Any]

Stop Webcam mode.

Returns:

Type Description
dict[str, Any]

Webcam response

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Webcam mode")
async def stop_webcam(self) -> dict[str, Any]:
    """Stop Webcam mode.

    Returns:
        Webcam response

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.webcam_commands.webcam_stop()

get_webcam_status async

get_webcam_status() -> dict[str, Any]

Get Webcam status.

Returns:

Type Description
dict[str, Any]

Webcam status dictionary

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Webcam status")
async def get_webcam_status(self) -> dict[str, Any]:
    """Get Webcam status.

    Returns:
        Webcam status dictionary

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.webcam_commands.webcam_status()

start_webcam_preview async

start_webcam_preview() -> dict[str, Any]

Start Webcam preview.

Returns:

Type Description
dict[str, Any]

Webcam response

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Webcam preview")
async def start_webcam_preview(self) -> dict[str, Any]:
    """Start Webcam preview.

    Returns:
        Webcam response

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.webcam_commands.webcam_preview()

webcam_exit async

webcam_exit() -> dict[str, Any]

Exit Webcam mode.

Returns:

Type Description
dict[str, Any]

Webcam response

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Webcam mode")
async def webcam_exit(self) -> dict[str, Any]:
    """Exit Webcam mode.

    Returns:
        Webcam response

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.webcam_commands.webcam_exit()

get_webcam_version async

get_webcam_version() -> str

Get Webcam implementation version.

Returns:

Type Description
str

Version string

Raises:

Type Description
OfflineModeError

This feature is not supported in offline mode

Source code in src/gopro_sdk/client.py
@_require_online("Webcam version")
async def get_webcam_version(self) -> str:
    """Get Webcam implementation version.

    Returns:
        Version string

    Raises:
        OfflineModeError: This feature is not supported in offline mode
    """
    return await self.webcam_commands.get_webcam_version()

reset_cohn async

reset_cohn() -> CohnCredentials

Reset COHN configuration (clear certificate and recreate).

⚠️ Only use in these special cases: 1. Camera executed "Reset Network Settings" (certificate cleared) 2. Certificate expired (Root CA certificate valid for 1 year) 3. Certificate corrupted (validation failed) 4. Failed to get credentials and cannot be fixed via open()

✅ No need to call this method in normal cases: - Changed WiFi network → certificate still valid, only need to refresh IP - Router reset → certificate still valid, IP change handled automatically - Camera reboot → certificate still valid, COHN configuration applied automatically

Important

This method only resets the COHN certificate. It does NOT clear the camera's network cache. If experiencing COHN timeout due to cached network connections, you must manually reset via camera menu: Preferences → Connections → Reset Connections

Note: This operation clears existing certificate, camera must be connected to WiFi to complete configuration.

Returns:

Type Description
CohnCredentials

New COHN credentials

Raises:

Type Description
BleConnectionError

Configuration failed (camera not connected to WiFi, etc.)

Source code in src/gopro_sdk/client.py
async def reset_cohn(self) -> CohnCredentials:
    """Reset COHN configuration (clear certificate and recreate).

    ⚠️ Only use in these special cases:
    1. **Camera executed "Reset Network Settings"** (certificate cleared)
    2. **Certificate expired** (Root CA certificate valid for 1 year)
    3. **Certificate corrupted** (validation failed)
    4. **Failed to get credentials and cannot be fixed via open()**

    ✅ No need to call this method in normal cases:
    - Changed WiFi network → certificate still valid, only need to refresh IP
    - Router reset → certificate still valid, IP change handled automatically
    - Camera reboot → certificate still valid, COHN configuration applied automatically

    Important:
        This method only resets the COHN certificate. It does NOT clear the camera's
        network cache. If experiencing COHN timeout due to cached network connections,
        you must manually reset via camera menu:
        Preferences → Connections → Reset Connections

    Note: This operation clears existing certificate, camera must be connected to WiFi to complete configuration.

    Returns:
        New COHN credentials

    Raises:
        BleConnectionError: Configuration failed (camera not connected to WiFi, etc.)
    """
    logger.warning("🔄 Resetting COHN configuration (clearing and recreating certificate)...")
    credentials = await self.ble_commands.configure_cohn()
    self._config_manager.save(self.target, credentials)
    logger.info(f"✅ COHN reset successful, IP: {credentials.ip_address}")
    return credentials

configure_cohn async

configure_cohn() -> CohnCredentials

Configure COHN (first-time configuration).

Returns:

Type Description
CohnCredentials

Successfully configured COHN credentials

Source code in src/gopro_sdk/client.py
async def configure_cohn(self) -> CohnCredentials:
    """Configure COHN (first-time configuration).

    Returns:
        Successfully configured COHN credentials
    """
    credentials = await self.ble_commands.configure_cohn()
    self._config_manager.save(self.target, credentials)
    return credentials

setup_wifi async

setup_wifi(
    ssid: str,
    password: str,
    timeout: float | None = None,
    has_cohn_credentials: bool = False,
) -> None

Configure camera to connect to specified WiFi network.

Strategy (based on COHN credentials): 1. Has COHN credentials: Indicates camera connected before → Try RequestConnect first (no password) → Fallback to RequestConnectNew if failed (with password)

  1. No COHN credentials: First-time configuration → Directly use RequestConnectNew (with password)

Parameters:

Name Type Description Default
ssid str

WiFi SSID

required
password str

WiFi password

required
timeout float | None

Connection timeout (seconds), defaults to configured value

None
has_cohn_credentials bool

Whether has COHN credentials (passed by caller)

False

Raises:

Type Description
BleConnectionError

Connection failed

Examples:

>>> async with GoProClient("1332") as client:
...     await client.setup_wifi("MyHomeWiFi", "password123")
Source code in src/gopro_sdk/client.py
async def setup_wifi(
    self,
    ssid: str,
    password: str,
    timeout: float | None = None,
    has_cohn_credentials: bool = False,
) -> None:
    """Configure camera to connect to specified WiFi network.

    Strategy (based on COHN credentials):
    1. **Has COHN credentials**: Indicates camera connected before
       → Try RequestConnect first (no password)
       → Fallback to RequestConnectNew if failed (with password)

    2. **No COHN credentials**: First-time configuration
       → Directly use RequestConnectNew (with password)

    Args:
        ssid: WiFi SSID
        password: WiFi password
        timeout: Connection timeout (seconds), defaults to configured value
        has_cohn_credentials: Whether has COHN credentials (passed by caller)

    Raises:
        BleConnectionError: Connection failed

    Examples:
        >>> async with GoProClient("1332") as client:
        ...     await client.setup_wifi("MyHomeWiFi", "password123")
    """
    try:
        await self.ble_commands.connect_to_wifi(ssid, password, timeout, has_cohn_credentials=has_cohn_credentials)
    except TimeoutError as e:
        # Provide more detailed error information
        error_msg = (
            f"WiFi connection timeout ({timeout} seconds). Possible causes:\n"
            f"1. ❌ WiFi name incorrect: '{ssid}' (check spelling)\n"
            f"2. ❌ WiFi password incorrect\n"
            f"3. ❌ Router signal too weak\n"
            f"4. ❌ Camera too far from router\n"
            f"5. 📌 Camera may have connected but BLE disconnected (COHN mode)\n"
            f"\n"
            f"Suggestions:\n"
            f"- Check WiFi configuration is correct\n"
            f"- Ensure camera is within router signal range\n"
            f"- If repeatedly fails, try manually resetting network settings on camera"
        )
        logger.error(error_msg)
        raise BleConnectionError(error_msg) from e

scan_wifi_networks async

scan_wifi_networks(
    timeout: float | None = None,
) -> list[Any]

Scan WiFi networks.

Note: Camera must be in AP mode (not connected to any network) to scan.

Parameters:

Name Type Description Default
timeout float | None

Scan timeout (seconds), defaults to configured value

None

Returns:

Type Description
list[Any]

List of WiFi networks

Raises:

Type Description
BleConnectionError

Scan failed (possibly camera already connected to network)

Source code in src/gopro_sdk/client.py
async def scan_wifi_networks(self, timeout: float | None = None) -> list[Any]:
    """Scan WiFi networks.

    Note: Camera must be in AP mode (not connected to any network) to scan.

    Args:
        timeout: Scan timeout (seconds), defaults to configured value

    Returns:
        List of WiFi networks

    Raises:
        BleConnectionError: Scan failed (possibly camera already connected to network)
    """
    return await self.ble_commands.scan_wifi_networks(timeout)

connect_to_wifi async

connect_to_wifi(
    ssid: str,
    password: str | None = None,
    timeout: float | None = None,
) -> None

Connect to WiFi network.

Parameters:

Name Type Description Default
ssid str

WiFi SSID

required
password str | None

WiFi password (can be None if already configured)

None
timeout float | None

Connection timeout (seconds), defaults to configured value

None
Source code in src/gopro_sdk/client.py
async def connect_to_wifi(self, ssid: str, password: str | None = None, timeout: float | None = None) -> None:
    """Connect to WiFi network.

    Args:
        ssid: WiFi SSID
        password: WiFi password (can be None if already configured)
        timeout: Connection timeout (seconds), defaults to configured value
    """
    await self.ble_commands.connect_to_wifi(ssid, password, timeout)

Usage Examples

Basic Connection (Offline Mode)

import asyncio
from gopro_sdk import GoProClient

async def main():
    # Default offline mode (BLE only)
    async with GoProClient("1234") as client:
        # Recording control
        await client.start_recording()
        await asyncio.sleep(5)
        await client.stop_recording()

        # Time sync
        await client.set_date_time()

asyncio.run(main())

Online Mode (BLE + WiFi)

import asyncio
from gopro_sdk import GoProClient

async def main():
    async with GoProClient(
        "1234",
        offline_mode=False,
        wifi_ssid="YourWiFi",
        wifi_password="YourPassword"
    ) as client:
        # Get camera status
        status = await client.get_camera_state()
        print(f"Camera state: {status}")

        # Start preview stream
        stream_url = await client.start_preview()
        print(f"Preview: {stream_url}")

asyncio.run(main())

Dynamic Mode Switching

async def main():
    # Start in offline mode
    async with GoProClient("1234") as client:
        await client.start_recording()
        await asyncio.sleep(5)
        await client.stop_recording()

        # Switch to online mode when needed
        await client.switch_to_online_mode(
            wifi_ssid="YourWiFi",
            wifi_password="YourPassword"
        )

        # Now online features work
        media = await client.get_media_list()
        print(f"Found {len(media)} files")

With Custom Timeouts

from gopro_sdk import GoProClient
from gopro_sdk.config import TimeoutConfig

timeout_config = TimeoutConfig(
    ble_connect_timeout=30.0,
    http_request_timeout=60.0,
    wifi_provision_timeout=120.0,
)

async with GoProClient(
    "1234",
    timeout_config=timeout_config,
    offline_mode=False,
) as client:
    await client.start_recording()

See Also