diff --git a/.admin/proto_build/.dockerignore b/.admin/proto_build/.dockerignore new file mode 100644 index 00000000..6af6d45b --- /dev/null +++ b/.admin/proto_build/.dockerignore @@ -0,0 +1,4 @@ +** + +!entrypoint.sh +!requirements.txt diff --git a/.admin/proto_build/Dockerfile b/.admin/proto_build/Dockerfile new file mode 100644 index 00000000..009fd57b --- /dev/null +++ b/.admin/proto_build/Dockerfile @@ -0,0 +1,15 @@ +# Dockerfile/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:54 UTC 2024 + +FROM python:3.11-bookworm + +RUN apt-get update && apt-get install -y \ + protobuf-compiler \ + bash + +COPY . /workdir +RUN pip install -r /workdir/requirements.txt + +RUN chmod +x /workdir/entrypoint.sh + +ENTRYPOINT [ "/workdir/entrypoint.sh" ] diff --git a/.admin/proto_build/README.md b/.admin/proto_build/README.md new file mode 100644 index 00000000..28fa9574 --- /dev/null +++ b/.admin/proto_build/README.md @@ -0,0 +1,22 @@ +# Protobuf Builder + +This is a Docker image to build the [Protobuf](../../protobuf/) files in this repo. It currently only build Python +output but should be used in the future for other languages. + +## Usage + +It is intended to be used via the [docker compose configuration](../../docker-compose.yml). + +First build: + +```shell +docker compose build proto-build +``` + +Then build the protobuf files with: + +```shell +docker compose run --rm proto-build +``` + +The output files will be placed in the [build directory](../../.build/protobuf). diff --git a/.admin/proto_build/entrypoint.sh b/.admin/proto_build/entrypoint.sh new file mode 100644 index 00000000..d772529a --- /dev/null +++ b/.admin/proto_build/entrypoint.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# entrypoint.sh/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:54 UTC 2024 + + +PROTO_SRC_DIR=/proto_in +PROTO_PYTHON_OUT_DIR=/proto_python_out + +rm -rf $PROTO_PYTHON_OUT_DIR && mkdir -p $PROTO_PYTHON_OUT_DIR + +echo +echo "Building protobuf python files and stubs from .proto source files..." +pushd $PROTO_SRC_DIR +protoc --include_imports --descriptor_set_out=$PROTO_PYTHON_OUT_DIR/descriptors --python_out=$PROTO_PYTHON_OUT_DIR --mypy_out=$PROTO_PYTHON_OUT_DIR * +popd + +pushd $PROTO_PYTHON_OUT_DIR +echo +echo "Converting relative imports to absolute..." +protol -o . --in-place raw descriptors +rm descriptors + +# Format generated files +echo +echo "Formatting..." +black . +popd diff --git a/.admin/proto_build/requirements.txt b/.admin/proto_build/requirements.txt new file mode 100644 index 00000000..49d735aa --- /dev/null +++ b/.admin/proto_build/requirements.txt @@ -0,0 +1,3 @@ +mypy-protobuf==3.5.0 +protoletariat==3.2.19 +black \ No newline at end of file diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index ea98ca5f..77a5fa53 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -9,7 +9,32 @@ on: workflow_dispatch: jobs: + copyright: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + token: ${{ secrets.PUSH_FROM_WORKFLOW_TO_RETRIGGER }} + + - name: Check for (and add) missing copyrights + shell: bash + run: | + make copyright + echo "NUM_MODIFIED=$(git diff --numstat | wc -l)" >> $GITHUB_ENV + + - name: Push changes + if: env.NUM_MODIFIED != 0 + shell: bash + run: | + git config core.fileMode false + git config user.name github-actions + git config user.email github-actions@github.com + git add . + git commit -m "updating copyrights from pre merge check in github action" + git push + check: + needs: copyright name: Check modified files for Python SDK changes runs-on: ubuntu-latest outputs: @@ -29,16 +54,16 @@ jobs: git diff --name-only HEAD^ HEAD >files.txt while IFS= read -r file; do if [[ $file != demos/python/sdk_wireless_camera_control* ]]; then - echo "::set-output name=run_job::false" + echo "{run_job}={false}" >> $GITHUB_OUTPUT else echo "Found a Python SDK modified file" - echo "::set-output name=run_job::true" + echo "{run_job}={true}" >> $GITHUB_OUTPUT break fi done > $GITHUB_ENV - - - name: Push changes - if: env.NUM_MODIFIED != 0 - shell: bash - run: | - git config core.fileMode false - git config user.name github-actions - git config user.email github-actions@github.com - git add . - git commit -m "updating copyrights from pre merge check in github action" - git push -f origin HEAD:${{ steps.extract_branch.outputs.branch }} - test_github_pages: - needs: copyright timeout-minutes: 5 runs-on: ubuntu-latest steps: @@ -60,6 +27,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - uses: actions/checkout@v3 + - name: Test Jekyll Build and Check Links run: make tests @@ -71,7 +39,7 @@ jobs: uses: actions/checkout@v3 with: ref: release - ssh-key: ${{ secrets.PUSH_FROM_WORKFLOW_TO_RETRIGGER }} + - name: Verify synchronized if release shell: bash run: | diff --git a/.github/workflows/publish_python_sdk.yml b/.github/workflows/publish_python_sdk.yml new file mode 100644 index 00000000..92bb1de1 --- /dev/null +++ b/.github/workflows/publish_python_sdk.yml @@ -0,0 +1,22 @@ +# publish_python_sdk.yml/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed, Sep 1, 2021 5:05:35 PM + +name: Publish the Python SDK to PyPi + +on: + workflow_dispatch: + +jobs: + build-and-publish: + name: Build and Publish + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Build and publish to pypi + uses: JRubics/poetry-publish@v2.0 + with: + package_directory: ./demos/python/sdk_wireless_camera_control/ + python_version: 3.11.4 + pypi_token: ${{ secrets.PYTHON_SDK_PYPI_TOKEN }} diff --git a/.gitignore b/.gitignore index 64db009c..fdf3c187 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +**/*.crt +/.build + /.env **.log diff --git a/Makefile b/Makefile index 0eeb5f50..c148d8ba 100644 --- a/Makefile +++ b/Makefile @@ -17,38 +17,50 @@ help: ## Display this help which is generated from Make goal comments # Docker images are currently not public. So we build if pull fails for the local use case. .PHONY: docker-setup docker-setup: - -@docker-compose pull || docker-compose build + -@docker compose pull jekyll plant-uml || docker compose build jekyll plant-uml .PHONY: docker-kill docker-kill: - -@docker kill jekyll plant_uml > /dev/null 2>&1 + -@docker kill jekyll plant-uml > /dev/null 2>&1 .PHONY: clean clean: ## Clean cached jekyll files @echo "🧼 Cleaning jekyll artifacts..." - -@docker-compose down > /dev/null 2>&1 + -@docker compose down > /dev/null 2>&1 @rm -rf docs/_site docs/.jekyll-cache docs/.jekyll-metadata .PHONY: serve serve: docker-kill docker-setup serve: ## Serve site locally @echo COMMAND="-u http://localhost:4998/ -b \"\" -p 4998 serve" > .env - @docker-compose up + @docker compose up @rm -rf .env .PHONY: build build: docker-setup build: ## Build site for deployment @echo COMMAND=\"-u ${BUILD_HOST_URL} -b ${BUILD_BASE_URL} build\" > .env - @docker-compose up --abort-on-container-exit + @docker compose up --abort-on-container-exit @rm -rf .env +PROTO_BUILD_DIR=.build/protobuf/python/* +PYTHON_TUTORIAL_PROTO_DIR=demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto +PYTHON_SDK_PROTO_DIR=demos/python/sdk_wireless_camera_control/open_gopro/proto + +.PHONY: protos +protos: ## Build generated code from protobuf files + @docker compose run --build --rm proto-build + @rm -rf ${PYTHON_TUTORIAL_PROTO_DIR}/*pb2.py* && mkdir -p ${PYTHON_TUTORIAL_PROTO_DIR} + @cp ${PROTO_BUILD_DIR} ${PYTHON_TUTORIAL_PROTO_DIR} + @rm -rf ${PYTHON_SDK_PROTO_DIR}/*pb2.py* && mkdir -p ${PYTHON_SDK_PROTO_DIR} + @cp ${PROTO_BUILD_DIR} ${PYTHON_SDK_PROTO_DIR} + .PHONY: tests tests: docker-setup clean tests: ## Serve, then run link checker. Times out after 5 minutes. - -@docker-compose pull linkchecker || docker-compose build linkchecker + -@docker compose pull linkchecker || docker compose build linkchecker @echo COMMAND="-u http://jekyll:4998/ -b \"\" -p 4998 serve" > .env - @docker-compose --profile test up --abort-on-container-exit + @docker compose --profile test up --abort-on-container-exit @rm -rf .env .PHONY: copyright diff --git a/demos/kotlin/tutorial/.gitignore b/demos/kotlin/tutorial/.gitignore index aa724b77..1faf7e30 100644 --- a/demos/kotlin/tutorial/.gitignore +++ b/demos/kotlin/tutorial/.gitignore @@ -1,3 +1,4 @@ +/.idea/ *.iml .gradle /local.properties diff --git a/demos/kotlin/tutorial/.idea/compiler.xml b/demos/kotlin/tutorial/.idea/compiler.xml index fb7f4a8a..b589d56e 100644 --- a/demos/kotlin/tutorial/.idea/compiler.xml +++ b/demos/kotlin/tutorial/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/demos/kotlin/tutorial/.idea/gradle.xml b/demos/kotlin/tutorial/.idea/gradle.xml index a2d7c213..0897082f 100644 --- a/demos/kotlin/tutorial/.idea/gradle.xml +++ b/demos/kotlin/tutorial/.idea/gradle.xml @@ -4,15 +4,15 @@ diff --git a/demos/kotlin/tutorial/.idea/misc.xml b/demos/kotlin/tutorial/.idea/misc.xml index bdd92780..8978d23d 100644 --- a/demos/kotlin/tutorial/.idea/misc.xml +++ b/demos/kotlin/tutorial/.idea/misc.xml @@ -1,7 +1,6 @@ - - + diff --git a/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/tutorials/Tutorial2SendBleCommands.kt b/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/tutorials/Tutorial2SendBleCommands.kt index 3a398581..7cd3295c 100644 --- a/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/tutorials/Tutorial2SendBleCommands.kt +++ b/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/tutorials/Tutorial2SendBleCommands.kt @@ -41,7 +41,7 @@ class Tutorial2SendBleCommands(number: Int, name: String, prerequisites: List { +sealed class Response(val uuid: GoProUUID) { private enum class Header(val value: UByte) { GENERAL(0b00U), EXT_13(0b01U), EXT_16(0b10U), RESERVED(0b11U); @@ -40,18 +45,10 @@ sealed class Response { } private var bytesRemaining = 0 - protected var packet = ubyteArrayOf() - abstract val data: T - var id by notNull() - protected set - var status by notNull() + var rawBytes = ubyteArrayOf() protected set val isReceived get() = bytesRemaining == 0 - var isParsed = false - protected set - - override fun toString() = prettyJson.encodeToString(data.toJsonElement()) fun accumulate(data: UByteArray) { var buf = data @@ -60,72 +57,65 @@ sealed class Response { buf = buf.drop(1).toUByteArray() // Pop the header byte } else { // This is a new packet so start with empty array - packet = ubyteArrayOf() + rawBytes = ubyteArrayOf() when (Header.fromValue((buf.first() and Mask.Header.value).toInt() shr 5)) { Header.GENERAL -> { bytesRemaining = buf[0].and(Mask.GenLength.value).toInt() buf = buf.drop(1).toUByteArray() } + Header.EXT_13 -> { bytesRemaining = ((buf[0].and(Mask.Ext13Byte0.value) .toLong() shl 8) or buf[1].toLong()).toInt() buf = buf.drop(2).toUByteArray() } + Header.EXT_16 -> { bytesRemaining = ((buf[1].toLong() shl 8) or buf[2].toLong()).toInt() buf = buf.drop(3).toUByteArray() } + Header.RESERVED -> { throw Exception("Unexpected RESERVED header") } } } // Accumulate the payload now that headers are handled and dropped - packet += buf + rawBytes += buf bytesRemaining -= buf.size - Timber.i("Received packet of length ${buf.size}. $bytesRemaining bytes remaining") + Timber.d("Received packet of length ${buf.size}. $bytesRemaining bytes remaining") if (bytesRemaining < 0) { throw Exception("Unrecoverable parsing error. Received too much data.") } } - abstract fun parse() - - class Complex : Response>() { - override val data: MutableList = mutableListOf() + open class Tlv(uuid: GoProUUID) : Response(uuid) { + var payload = ubyteArrayOf() + private set + var id by notNull() + private set + var status by notNull() + private set - override fun parse() { + open fun parse() { require(isReceived) - // Parse header bytes - id = packet[0].toInt() - status = packet[1].toInt() - var buf = packet.drop(2) - // Parse remaining packet - while (buf.isNotEmpty()) { - // Get each parameter's ID and length - val paramLen = buf[0].toInt() - buf = buf.drop(1) - // Get the parameter's value - val paramVal = buf.take(paramLen) - // Store in data list - data += paramVal.toUByteArray() - // Advance the buffer for continued parsing - buf = buf.drop(paramLen) - } - isParsed = true + id = rawBytes[0].toInt() + status = rawBytes[1].toInt() + // Store remainder as payload for further parsing later + payload = rawBytes.drop(2).toUByteArray() } + + override fun toString(): String = "ID: $id, Status: $status, Payload: ${payload.toHexString()}" } - class Query : Response>() { - override val data: MutableMap = mutableMapOf() + class Query(uuid: GoProUUID) : Tlv(uuid) { + val data: MutableMap = mutableMapOf() + override fun toString() = prettyJson.encodeToString(data.toJsonElement()) override fun parse() { - require(isReceived) - id = packet[0].toInt() - status = packet[1].toInt() - // Parse remaining packet - var buf = packet.drop(2) + super.parse() + var buf = payload.toList() while (buf.isNotEmpty()) { // Get each parameter's ID and length val paramId = buf[0] @@ -138,57 +128,124 @@ sealed class Response { // Advance the buffer for continued parsing buf = buf.drop(paramLen) } - isParsed = true } } + class Unknown(uuid: GoProUUID): Response(uuid) {} + companion object { - fun fromUuid(uuid: GoProUUID): Response<*> = - when (uuid) { - GoProUUID.CQ_COMMAND_RSP -> Complex() - GoProUUID.CQ_QUERY_RSP -> Query() - else -> throw Exception("Not supported") + fun muxByUuid(uuid: GoProUUID) : Response { + return when (uuid) { + GoProUUID.CQ_SETTING_RSP, GoProUUID.CQ_COMMAND_RSP -> Tlv(uuid) + GoProUUID.CQ_QUERY_RSP -> Query(uuid) + else -> Unknown(uuid) } + } } +} +@OptIn(ExperimentalUnsignedTypes::class) +data class OpenGoProVersion(val minor: Int, val major: Int) { + companion object { + fun fromBytes(data: UByteArray): OpenGoProVersion { + var buf = data.toUByteArray() + val majorLen = buf[0].toInt() + buf = buf.drop(1).toUByteArray() + val major = buf.take(majorLen).toInt() + buf = buf.drop(1).toUByteArray() + val minorLen = buf[0].toInt() + buf = buf.drop(1).toUByteArray() + val minor = buf.take(minorLen).toInt() + return OpenGoProVersion(minor, major) + } + } } @OptIn(ExperimentalUnsignedTypes::class) -class Tutorial3ParseBleTlvResponses(number: Int, name: String, prerequisites: List) : - Tutorial(number, name, prerequisites) { - private val receivedResponse: Channel> = Channel() - private var response: Response<*>? = null +data class HardwareInfo( + val modelNumber: Int, + val modelName: String, + val firmwareVersion: String, + val serialNumber: String, + val apSsid: String, + val apMacAddress: String +) { + companion object { + fun fromBytes(data: UByteArray): HardwareInfo { + // Parse header bytes + var buf = data.toUByteArray() + // Get model number + val modelNumLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + val model = buf.take(modelNumLength).toInt() + buf = buf.drop(modelNumLength).toUByteArray() + // Get model name + val modelNameLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + val modelName = buf.take(modelNameLength).decodeToString() + buf = buf.drop(modelNameLength).toUByteArray() + // Advance past deprecated bytes + val deprecatedLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + buf = buf.drop(deprecatedLength).toUByteArray() + // Get firmware version + val firmwareLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + val firmware = buf.take(firmwareLength).decodeToString() + buf = buf.drop(firmwareLength).toUByteArray() + // Get serial number + val serialLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + val serial = buf.take(serialLength).decodeToString() + buf = buf.drop(serialLength).toUByteArray() + // Get AP SSID + val ssidLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + val ssid = buf.take(ssidLength).decodeToString() + buf = buf.drop(ssidLength).toUByteArray() + // Get MAC Address + val macLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + val mac = buf.take(macLength).decodeToString() - @OptIn(ExperimentalUnsignedTypes::class) - private fun tlvResponseNotificationHandler(characteristic: UUID, data: UByteArray) { - GoProUUID.fromUuid(characteristic)?.let { uuid -> - // If response is currently empty, create a new one - response = response ?: Response.fromUuid(uuid) + return HardwareInfo(model, modelName, firmware, serial, ssid, mac) } - ?: return // We don't care about non-GoPro characteristics (i.e. the BT Core Battery service) - - Timber.d("Received response on $characteristic: ${data.toHexString()}") + } +} - response?.let { rsp -> - rsp.accumulate(data) - if (rsp.isReceived) { - rsp.parse() +@OptIn(ExperimentalUnsignedTypes::class) +class Tutorial3ParseBleTlvResponses( + number: Int, + name: String, + prerequisites: List +) : + Tutorial(number, name, prerequisites) { + private val receivedResponses: Channel = Channel() + private val responsesByUuid = GoProUUID.mapByUuid { Response.muxByUuid(it) } - // If the response has success status... - if (rsp.status == 0) Timber.i("Received the expected successful response") - else Timber.i("Received unexpected response") + @OptIn(ExperimentalUnsignedTypes::class) + private fun notificationHandler(characteristic: UUID, data: UByteArray) { + // Get the UUID (assuming it is a GoPro UUID) + val uuid = GoProUUID.fromUuid(characteristic) ?: return + Timber.d("Received response on $uuid") - // Notify the command sender the the procedure is complete - response = null // Clear for next command - CoroutineScope(Dispatchers.IO).launch { receivedResponse.send(rsp) } + responsesByUuid[uuid]?.let { response -> + response.accumulate(data) + if (response.isReceived) { + if (uuid == GoProUUID.CQ_COMMAND_RSP) { + CoroutineScope(Dispatchers.IO).launch { receivedResponses.send(response) } + } else { + Timber.e("Unexpected Response") + } + responsesByUuid[uuid] = Response.muxByUuid(uuid) } - } ?: throw Exception("This should be impossible") + } } @OptIn(ExperimentalUnsignedTypes::class) private val bleListeners by lazy { BleEventListener().apply { - onNotification = ::tlvResponseNotificationHandler + onNotification = ::notificationHandler } } @@ -203,26 +260,27 @@ class Tutorial3ParseBleTlvResponses(number: Int, name: String, prerequisites: Li ble.registerListener(goproAddress, bleListeners) Timber.i("Getting the Open GoPro version") - val getVersion = ubyteArrayOf(0x01U, 0x51U) - ble.writeCharacteristic(goproAddress, GoProUUID.CQ_COMMAND.uuid, getVersion) - val version = receivedResponse.receive() as Response.Complex // Wait to receive response - val major = version.data[0].first().toInt() - val minor = version.data[1].first().toInt() - Timber.i("Got the Open GoPro version successfully: $major.$minor") - - Timber.i("Getting the camera's settings") - val getCameraSettings = ubyteArrayOf(0x01U, 0x12U) - ble.writeCharacteristic(goproAddress, GoProUUID.CQ_QUERY.uuid, getCameraSettings) - val settings = receivedResponse.receive() - Timber.i("Got the camera's settings successfully") - Timber.i(settings.toString()) - - Timber.i("Getting the camera's statuses") - val getCameraStatuses = ubyteArrayOf(0x01U, 0x13U) - ble.writeCharacteristic(goproAddress, GoProUUID.CQ_QUERY.uuid, getCameraStatuses) - val statuses = receivedResponse.receive() - Timber.i("Got the camera's statuses successfully") - Timber.i(statuses.toString()) + val versionRequest = ubyteArrayOf(0x01U, 0x51U) + ble.writeCharacteristic(goproAddress, GoProUUID.CQ_COMMAND.uuid, versionRequest) + // Wait to receive response the parse it + var tlvResponse = receivedResponses.receive() as Response.Tlv + tlvResponse.parse() + Timber.i("Received response: $tlvResponse") + val version = OpenGoProVersion.fromBytes(tlvResponse.payload) + Timber.i("Got the Open GoPro version successfully: ${version.major}.${version.minor}") + + Timber.i("Getting the Hardware Info") + val hardwareInfoRequest = ubyteArrayOf(0x01U, 0x3CU) + ble.writeCharacteristic( + goproAddress, + GoProUUID.CQ_COMMAND.uuid, + hardwareInfoRequest + ) + // Wait to receive response the parse it + tlvResponse = receivedResponses.receive() as Response.Tlv + tlvResponse.parse() + val hardwareInfo = HardwareInfo.fromBytes(tlvResponse.payload) + Timber.i("Got the Hardware Info successfully: $hardwareInfo") // Other tutorials will use their own notification handler so unregister ours now ble.unregisterListener(bleListeners) diff --git a/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/tutorials/Tutorial4BleQueries.kt b/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/tutorials/Tutorial4BleQueries.kt index 2c47d009..c2f47bc5 100644 --- a/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/tutorials/Tutorial4BleQueries.kt +++ b/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/tutorials/Tutorial4BleQueries.kt @@ -8,14 +8,14 @@ import com.example.open_gopro_tutorial.AppContainer import com.example.open_gopro_tutorial.DataStore import com.example.open_gopro_tutorial.network.BleEventListener import com.example.open_gopro_tutorial.network.Bluetooth -import com.example.open_gopro_tutorial.util.* +import com.example.open_gopro_tutorial.util.GoProUUID import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.launch import timber.log.Timber import java.io.File -import java.util.* +import java.util.UUID private const val RESOLUTION_ID: UByte = 2U @@ -26,6 +26,7 @@ class Tutorial4BleQueries(number: Int, name: String, prerequisites: List = Channel() - private var response: Response.Query? = null private lateinit var resolution: Resolution - - @RequiresPermission(allOf = ["android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT"]) - private suspend fun performPollingTutorial(ble: Bluetooth, goproAddress: String) { - @OptIn(ExperimentalUnsignedTypes::class) - fun resolutionPollingNotificationHandler(characteristic: UUID, data: UByteArray) { - GoProUUID.fromUuid(characteristic)?.let { - // If response is currently empty, create a new one - response = - response ?: Response.Query() // We're only handling queries in this tutorial - } - ?: return // We don't care about non-GoPro characteristics (i.e. the BT Core Battery service) - - Timber.d("Received response on $characteristic: ${data.toHexString()}") - - response?.let { rsp -> - rsp.accumulate(data) - if (rsp.isReceived) { - rsp.parse() - - // If this is a query response, it must contain a resolution value - if (characteristic == GoProUUID.CQ_QUERY_RSP.uuid) { - Timber.i("Received resolution query response") - } - // If this is a setting response, it will just show the status - else if (characteristic == GoProUUID.CQ_SETTING_RSP.uuid) { - Timber.i("Command sent successfully") + private lateinit var receivedResponses: Channel + private val responsesByUuid = GoProUUID.mapByUuid { Response.muxByUuid(it) } + + @OptIn(ExperimentalUnsignedTypes::class) + private fun notificationHandler(characteristic: UUID, data: UByteArray) { + // Get the UUID (assuming it is a GoPro UUID) + val uuid = GoProUUID.fromUuid(characteristic) ?: return + Timber.d("Received response on $uuid") + + responsesByUuid[uuid]?.let { response -> + response.accumulate(data) + if (response.isReceived) { + when (uuid) { + GoProUUID.CQ_QUERY_RSP -> { + Timber.d("Received Query Response") + CoroutineScope(Dispatchers.IO).launch { + receivedResponses.send( + response + ) + } } - // Anything else is unexpected. This shouldn't happen - else { - Timber.i("Received unexpected response") + + GoProUUID.CQ_SETTING_RSP -> { + CoroutineScope(Dispatchers.IO).launch { + receivedResponses.send( + response + ) + } + Timber.d("Received set setting response.") } - // Notify the command sender the the procedure is complete - response = null // Clear for next command - CoroutineScope(Dispatchers.IO).launch { receivedResponse.send(rsp) } + else -> Timber.e("Unexpected Response") } + responsesByUuid[uuid] = Response.muxByUuid(uuid) } } + } - @OptIn(ExperimentalUnsignedTypes::class) - val bleListeners by lazy { - BleEventListener().apply { - onNotification = ::resolutionPollingNotificationHandler - } + @OptIn(ExperimentalUnsignedTypes::class) + val bleListeners by lazy { + BleEventListener().apply { + onNotification = ::notificationHandler } + } - // Register our notification handler callback for characteristic change updates - ble.registerListener(goproAddress, bleListeners) + @RequiresPermission(allOf = ["android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT"]) + private suspend fun performPollingTutorial(ble: Bluetooth, goproAddress: String) { + // Flush the channel. Just create a new one. + receivedResponses = Channel() // Write to query BleUUID to poll the current resolution Timber.i("Polling the current resolution") val pollResolution = ubyteArrayOf(0x02U, 0x12U, RESOLUTION_ID) ble.writeCharacteristic(goproAddress, GoProUUID.CQ_QUERY.uuid, pollResolution) - resolution = Resolution.fromValue( - receivedResponse.receive().data.getValue(RESOLUTION_ID).first() - ) + val queryResponse = (receivedResponses.receive() as Response.Query).apply { parse() } + resolution = Resolution.fromValue(queryResponse.data.getValue(RESOLUTION_ID).first()) Timber.i("Camera resolution is $resolution") // Write to command request BleUUID to change the video resolution (either to 1080 or 2.7K) - val newResolution = + val targetResolution = if (resolution == Resolution.RES_2_7K) Resolution.RES_1080 else Resolution.RES_2_7K - Timber.i("Changing the resolution to $newResolution") - val setResolution = ubyteArrayOf(0x03U, RESOLUTION_ID, 0x01U, newResolution.value) + Timber.i("Changing the resolution to $targetResolution") + val setResolution = ubyteArrayOf(0x03U, RESOLUTION_ID, 0x01U, targetResolution.value) ble.writeCharacteristic(goproAddress, GoProUUID.CQ_SETTING.uuid, setResolution) - val setResolutionResponse = receivedResponse.receive() + val setResolutionResponse = (receivedResponses.receive() as Response.Tlv).apply { parse() } if (setResolutionResponse.status == 0) { Timber.i("Resolution successfully changed") } else { - Timber.e("Failed to set resolution") + Timber.e("Failed to set resolution to to $targetResolution. Ensure camera is in a valid state to allow this resolution.") + return } // Now let's poll until an update occurs Timber.i("Polling the resolution until it changes") - while (resolution != newResolution) { + while (resolution != targetResolution) { ble.writeCharacteristic(goproAddress, GoProUUID.CQ_QUERY.uuid, pollResolution) - resolution = Resolution.fromValue( - receivedResponse.receive().data.getValue(RESOLUTION_ID).first() - ) + val queryNotification = + (receivedResponses.receive() as Response.Query).apply { parse() } + resolution = + Resolution.fromValue(queryNotification.data.getValue(RESOLUTION_ID).first()) Timber.i("Camera resolution is currently $resolution") } - - // Other tutorials will use their own notification handler so unregister ours now - ble.unregisterListener(bleListeners) } @RequiresPermission(allOf = ["android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT"]) private suspend fun performRegisteringForAsyncUpdatesTutorial( ble: Bluetooth, goproAddress: String ) { - @OptIn(ExperimentalUnsignedTypes::class) - fun resolutionRegisteringNotificationHandler(characteristic: UUID, data: UByteArray) { - GoProUUID.fromUuid(characteristic)?.let { - // If response is currently empty, create a new one - response = response ?: Response.Query() // We're only handling queries in this tutorial - } ?: return // We don't care about non-GoPro characteristics (i.e. the BT Core Battery service) - - Timber.d("Received response on $characteristic: ${data.toHexString()}") - - response?.let { rsp -> - rsp.accumulate(data) - - if (rsp.isReceived) { - rsp.parse() - - // If this is a query response, it must contain a resolution value - if (characteristic == GoProUUID.CQ_QUERY_RSP.uuid) { - Timber.i("Received resolution query response") - resolution = Resolution.fromValue(rsp.data.getValue(RESOLUTION_ID).first()) - Timber.i("Resolution is now $resolution") - } - // If this is a setting response, it will just show the status - else if (characteristic == GoProUUID.CQ_SETTING_RSP.uuid) { - Timber.i("Command sent successfully") - } - // Anything else is unexpected. This shouldn't happen - else { - Timber.i("Received unexpected response") - } - - // Notify the command sender the the procedure is complete - response = null - CoroutineScope(Dispatchers.IO).launch { receivedResponse.send(rsp) } - } - } - } - - @OptIn(ExperimentalUnsignedTypes::class) - val bleListeners by lazy { - BleEventListener().apply { - onNotification = ::resolutionRegisteringNotificationHandler - } - } - - // Register our notification handler callback for characteristic change updates - ble.registerListener(goproAddress, bleListeners) + // Flush the channel. Just create a new one. + receivedResponses = Channel() // Register with the GoPro for updates when resolution updates occur Timber.i("Registering for resolution value updates") val registerResolutionUpdates = ubyteArrayOf(0x02U, 0x52U, RESOLUTION_ID) ble.writeCharacteristic(goproAddress, GoProUUID.CQ_QUERY.uuid, registerResolutionUpdates) + val queryResponse = + (receivedResponses.receive() as Response.Query).apply { parse() } + resolution = + Resolution.fromValue(queryResponse.data.getValue(RESOLUTION_ID).first()) Timber.i("Camera resolution is $resolution") // Write to command request BleUUID to change the video resolution (either to 1080 or 2.7K) - val newResolution = + val targetResolution = if (resolution == Resolution.RES_2_7K) Resolution.RES_1080 else Resolution.RES_2_7K - Timber.i("Changing the resolution to $newResolution") - val setResolution = ubyteArrayOf(0x03U, RESOLUTION_ID, 0x01U, newResolution.value) + Timber.i("Changing the resolution to $targetResolution") + val setResolution = ubyteArrayOf(0x03U, RESOLUTION_ID, 0x01U, targetResolution.value) ble.writeCharacteristic(goproAddress, GoProUUID.CQ_SETTING.uuid, setResolution) - val setResolutionResponse = receivedResponse.receive() + val setResolutionResponse = (receivedResponses.receive() as Response.Tlv).apply { parse() } if (setResolutionResponse.status == 0) { Timber.i("Resolution successfully changed") } else { - Timber.e("Failed to set resolution") + Timber.e("Failed to set resolution to to $targetResolution. Ensure camera is in a valid state to allow this resolution.") + return } // Verify we receive the update from the camera when the resolution changes - while (resolution != newResolution) { + while (resolution != targetResolution) { Timber.i("Waiting for camera to inform us about the resolution change") - receivedResponse.receive() + val queryNotification = + (receivedResponses.receive() as Response.Query).apply { parse() } + resolution = + Resolution.fromValue(queryNotification.data.getValue(RESOLUTION_ID).first()) + Timber.i("Camera resolution is $resolution") } - // Other tutorials will use their own notification handler so unregister ours now - ble.unregisterListener(bleListeners) + Timber.i("Resolution Update Notification has been received.") + + // Unregister for notifications + Timber.i("Unregistering for resolution value updates") + val unregisterResolutionUpdates = ubyteArrayOf(0x02U, 0x72U, RESOLUTION_ID) + ble.writeCharacteristic(goproAddress, GoProUUID.CQ_QUERY.uuid, unregisterResolutionUpdates) + receivedResponses.receive() } @RequiresPermission(allOf = ["android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT"]) @@ -211,10 +179,15 @@ class Tutorial4BleQueries(number: Int, name: String, prerequisites: List.toInt(): Int { + var value = 0 + this.forEachIndexed { index, byte -> + value += (byte.toInt() shl (index * 8)) + } + return value +} + + fun ByteArray.toHexString(): String = joinToString(separator = ":") { String.format("%02X", it) } @OptIn(ExperimentalUnsignedTypes::class) @@ -23,6 +41,9 @@ fun UByteArray.toHexString(): String = this.toByteArray().toHexString() @OptIn(ExperimentalUnsignedTypes::class) fun UByteArray.decodeToString(): String = this.toByteArray().decodeToString() +@OptIn(ExperimentalUnsignedTypes::class) +fun List.decodeToString() = this.toUByteArray().decodeToString() + fun BluetoothGatt.findCharacteristic(uuid: UUID): BluetoothGattCharacteristic? { services?.forEach { service -> service.characteristics?.firstOrNull { characteristic -> diff --git a/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/util/GoProData.kt b/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/util/GoProData.kt index 0201017b..ec503f75 100644 --- a/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/util/GoProData.kt +++ b/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/util/GoProData.kt @@ -19,8 +19,10 @@ enum class GoProUUID(val uuid: UUID) { CQ_QUERY_RSP(UUID.fromString(GOPRO_BASE_UUID.format("0077"))); companion object { - private val map: Map by lazy { GoProUUID.values().associateBy { it.uuid } } - fun fromUuid(uuid: UUID): GoProUUID? = map[uuid] + private val uuidToGoProUUID: Map by lazy { GoProUUID.values().associateBy { it.uuid } } + fun fromUuid(uuid: UUID): GoProUUID? = uuidToGoProUUID[uuid] + fun mapByUuid(valueCreator: ((GoProUUID) -> T)): MutableMap = + values().associateWith { valueCreator(it) }.toMutableMap() } } diff --git a/demos/kotlin/tutorial/app/src/test/java/com/example/open_gopro_tutorial/ExampleUnitTest.kt b/demos/kotlin/tutorial/app/src/test/java/com/example/open_gopro_tutorial/ExampleUnitTest.kt index 043773ff..c962b195 100644 --- a/demos/kotlin/tutorial/app/src/test/java/com/example/open_gopro_tutorial/ExampleUnitTest.kt +++ b/demos/kotlin/tutorial/app/src/test/java/com/example/open_gopro_tutorial/ExampleUnitTest.kt @@ -1,11 +1,15 @@ + /* ExampleUnitTest.kt/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). */ /* This copyright was auto-generated on Mon Mar 6 17:45:15 UTC 2023 */ package com.example.open_gopro_tutorial +import com.example.open_gopro_tutorial.tutorials.Response +import com.example.open_gopro_tutorial.util.GoProUUID import org.junit.Test import org.junit.Assert.* +import timber.log.Timber /** * Example local unit test, which will execute on the development machine (host). @@ -17,4 +21,4 @@ class ExampleUnitTest { fun addition_isCorrect() { assertEquals(4, 2 + 2) } -} \ No newline at end of file +} diff --git a/demos/kotlin/tutorial/build.gradle b/demos/kotlin/tutorial/build.gradle index c7cf3d98..571c806c 100644 --- a/demos/kotlin/tutorial/build.gradle +++ b/demos/kotlin/tutorial/build.gradle @@ -4,7 +4,7 @@ buildscript { } }// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '7.3.1' apply false - id 'com.android.library' version '7.3.1' apply false + id 'com.android.application' version '8.3.1' apply false + id 'com.android.library' version '8.3.1' apply false id 'org.jetbrains.kotlin.android' version '1.7.0' apply false } \ No newline at end of file diff --git a/demos/kotlin/tutorial/gradle.properties b/demos/kotlin/tutorial/gradle.properties index 3c5031eb..f19c7b9b 100644 --- a/demos/kotlin/tutorial/gradle.properties +++ b/demos/kotlin/tutorial/gradle.properties @@ -20,4 +20,5 @@ kotlin.code.style=official # Enables namespacing of each library's R class so that its R class includes only the # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library -android.nonTransitiveRClass=true \ No newline at end of file +android.nonTransitiveRClass=true +android.nonFinalResIds=false \ No newline at end of file diff --git a/demos/kotlin/tutorial/gradle/wrapper/gradle-wrapper.properties b/demos/kotlin/tutorial/gradle/wrapper/gradle-wrapper.properties index 4c783d53..39e0b57b 100644 --- a/demos/kotlin/tutorial/gradle/wrapper/gradle-wrapper.properties +++ b/demos/kotlin/tutorial/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Wed Feb 15 10:09:42 PST 2023 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/demos/python/sdk_wireless_camera_control/.gitignore b/demos/python/sdk_wireless_camera_control/.gitignore index bfbe3baf..01e74e54 100644 --- a/demos/python/sdk_wireless_camera_control/.gitignore +++ b/demos/python/sdk_wireless_camera_control/.gitignore @@ -1,13 +1,13 @@ **/*.crt +**/*.jpg +**/*.mp4 **/temp -.reports/ # Docs output docs/build # Test artifacts -/*.jpg -/*.mp4 +.reports/ # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/demos/python/sdk_wireless_camera_control/docs/api.rst b/demos/python/sdk_wireless_camera_control/docs/api.rst index cb769bf4..cd685526 100644 --- a/demos/python/sdk_wireless_camera_control/docs/api.rst +++ b/demos/python/sdk_wireless_camera_control/docs/api.rst @@ -86,19 +86,19 @@ GoPro Enum BLE Setting ^^^^^^^^^^^ -.. inheritance-diagram:: open_gopro.api.builders.BleSetting +.. inheritance-diagram:: open_gopro.api.builders.BleSettingFacade :parts: 1 -.. autoclass:: open_gopro.api.builders.BleSetting +.. autoclass:: open_gopro.api.builders.BleSettingFacade :exclude-members: get_name, get_capabilities_names BLE Status ^^^^^^^^^^ -.. inheritance-diagram:: open_gopro.api.builders.BleStatus +.. inheritance-diagram:: open_gopro.api.builders.BleStatusFacade :parts: 1 -.. autoclass:: open_gopro.api.builders.BleStatus +.. autoclass:: open_gopro.api.builders.BleStatusFacade HTTP Setting ^^^^^^^^^^^^ @@ -108,6 +108,11 @@ HTTP Setting .. autoclass:: open_gopro.api.builders.HttpSetting +Method Protocols +^^^^^^^^^^^^^^^^ + +.. autoclass:: open_gopro.api.builders.BuilderProtocol + Message Bases ^^^^^^^^^^^^^ @@ -134,8 +139,6 @@ but the end user should never need to use these directly. .. autoclass:: open_gopro.communicator_interface.MessageRules -.. autoclass:: open_gopro.communicator_interface.RuleSignature - Parameters ---------- diff --git a/demos/python/sdk_wireless_camera_control/docs/changelog.rst b/demos/python/sdk_wireless_camera_control/docs/changelog.rst index c886e2b6..b72ad215 100644 --- a/demos/python/sdk_wireless_camera_control/docs/changelog.rst +++ b/demos/python/sdk_wireless_camera_control/docs/changelog.rst @@ -9,6 +9,13 @@ All notable changes to this project will be documented in this file. The format is based on `Keep a Changelog `_, and this project adheres to `Semantic Versioning `_. +0.16.0 (April-9-2024) +--------------------- +* Refactor all network operations to operate on common Message class +* Add PUT Operation support +* Add Custom Preset Update +* Update Bleak to 0.21.1 + 0.15.1 (December-6-2023) ------------------------ * Fix livestream demo. diff --git a/demos/python/sdk_wireless_camera_control/docs/conf.py b/demos/python/sdk_wireless_camera_control/docs/conf.py index ab6330bb..206edc0b 100644 --- a/demos/python/sdk_wireless_camera_control/docs/conf.py +++ b/demos/python/sdk_wireless_camera_control/docs/conf.py @@ -90,6 +90,7 @@ (r".*", r".*response.T*"), ] + # This is the expected signature of the handler for this event, cf doc def autodoc_skip_member_handler(app, what, name, *_): for skip in ("internal", "deprecated"): diff --git a/demos/python/sdk_wireless_camera_control/docs/usage.rst b/demos/python/sdk_wireless_camera_control/docs/usage.rst index 94fd9152..851db2f6 100644 --- a/demos/python/sdk_wireless_camera_control/docs/usage.rst +++ b/demos/python/sdk_wireless_camera_control/docs/usage.rst @@ -248,7 +248,7 @@ Commands are callable instance attributes of a Messages class instance Statuses ^^^^^^^^ -Statuses are instances of a BleStatus(:class:`~open_gopro.api.builders.BleStatus`). They can be read +Statuses are instances of a BleStatus(:class:`~open_gopro.api.builders.BleStatusFacade`). They can be read synchronously using their `get_value` method as such: .. code-block:: python @@ -272,7 +272,7 @@ It is also possible to read all statuses at once via: Settings ^^^^^^^^ -Settings are instances of a BleSetting(:class:`~open_gopro.api.builders.BleSetting`) +Settings are instances of a BleSetting(:class:`~open_gopro.api.builders.BleSettingFacade`) or HttpSetting(:class:`~open_gopro.api.builders.HttpSetting`). They can be interacted synchronously in several ways. @@ -319,9 +319,9 @@ This section describes how to register for and handle asynchronous push notifica It is possible to enable push notifications for any of the following: -- setting values via :meth:`~open_gopro.api.builders.BleSetting.register_value_update` -- setting capabilities via :meth:`~open_gopro.api.builders.BleSetting.register_capability_update` -- status values via :meth:`~open_gopro.api.builders.BleStatus.register_value_update` +- setting values via :meth:`~open_gopro.api.builders.BleSettingFacade.register_value_update` +- setting capabilities via :meth:`~open_gopro.api.builders.BleSettingFacade.register_capability_update` +- status values via :meth:`~open_gopro.api.builders.BleStatusFacade.register_value_update` Firstly, the desired settings / ID must be registered for and given a callback to handle received notifications. @@ -332,9 +332,9 @@ responses will then be sent to the registered callback for handling. It is possible to stop receiving notifications by issuing the relevant unregister command, i.e.: -- setting values via :meth:`~open_gopro.api.builders.BleSetting.unregister_value_update` -- setting capabilities via :meth:`~open_gopro.api.builders.BleSetting.unregister_capability_update` -- status values via :meth:`~open_gopro.api.builders.BleStatus.unregister_value_update` +- setting values via :meth:`~open_gopro.api.builders.BleSettingFacade.unregister_value_update` +- setting capabilities via :meth:`~open_gopro.api.builders.BleSettingFacade.unregister_capability_update` +- status values via :meth:`~open_gopro.api.builders.BleStatusFacade.unregister_value_update` Here is an example of registering for and receiving FOV updates: diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/api/__init__.py b/demos/python/sdk_wireless_camera_control/open_gopro/api/__init__.py index 863a6ce2..2a7e681a 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/api/__init__.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/api/__init__.py @@ -10,16 +10,13 @@ BleAsyncResponse, BleProtoCommand, BleReadCommand, - BleSetting, - BleStatus, + BleSettingFacade, + BleStatusFacade, BleWriteCommand, - HttpGetBinary, - HttpGetJsonCommand, HttpSetting, RegisterUnregisterAll, ) from .http_commands import HttpCommands, HttpSettings -# TODO find a better way to set up parsers, etc besides instantiating - +# We need to ensure the API instantiated so that all parsers are set up. WirelessApi(None) # type: ignore diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/api/ble_commands.py b/demos/python/sdk_wireless_camera_control/open_gopro/api/ble_commands.py index bb9ecee0..179d87c0 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/api/ble_commands.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/api/ble_commands.py @@ -28,10 +28,10 @@ ) from open_gopro import proto, types +from open_gopro.api.builders import BleAsyncResponse +from open_gopro.api.builders import BleSettingFacade as BleSetting +from open_gopro.api.builders import BleStatusFacade as BleStatus from open_gopro.api.builders import ( - BleAsyncResponse, - BleSetting, - BleStatus, RegisterUnregisterAll, ble_proto_command, ble_read_command, @@ -50,7 +50,6 @@ CmdId, FeatureId, GoProUUIDs, - QueryCmdId, SettingId, StatusId, ) @@ -64,7 +63,7 @@ logger = logging.getLogger(__name__) -class BleCommands(BleMessages[BleMessage, CmdId]): +class BleCommands(BleMessages[BleMessage]): """All of the BLE commands. To be used as a delegate for a GoProBle instance to build commands @@ -78,10 +77,10 @@ class BleCommands(BleMessages[BleMessage, CmdId]): uuid=GoProUUIDs.CQ_COMMAND, cmd=CmdId.SET_SHUTTER, param_builder=Int8ub, - rules={ - MessageRules.FASTPASS: lambda **kwargs: kwargs["shutter"] == Params.Toggle.DISABLE, - MessageRules.WAIT_FOR_ENCODING_START: lambda **kwargs: kwargs["shutter"] == Params.Toggle.ENABLE, - }, + rules=MessageRules( + fastpass_analyzer=lambda **kwargs: kwargs["shutter"] == Params.Toggle.DISABLE, + wait_for_encoding_analyzer=lambda **kwargs: kwargs["shutter"] == Params.Toggle.ENABLE, + ), ) async def set_shutter(self, *, shutter: Params.Toggle) -> GoProResp[None]: """Set the Shutter to start / stop encoding @@ -343,7 +342,6 @@ async def get_wifi_password(self) -> GoProResp[str]: GoProUUIDs.CQ_QUERY, CmdId.REGISTER_ALL_STATUSES, update_set=StatusId, - responded_cmd=QueryCmdId.STATUS_VAL_PUSH, # TODO probably remove this action=RegisterUnregisterAll.Action.REGISTER, ) async def register_for_all_statuses(self, callback: types.UpdateCb) -> GoProResp[None]: @@ -360,7 +358,6 @@ async def register_for_all_statuses(self, callback: types.UpdateCb) -> GoProResp GoProUUIDs.CQ_QUERY, CmdId.UNREGISTER_ALL_STATUSES, update_set=StatusId, - responded_cmd=QueryCmdId.STATUS_VAL_PUSH, action=RegisterUnregisterAll.Action.UNREGISTER, ) async def unregister_for_all_statuses(self, callback: types.UpdateCb) -> GoProResp[None]: @@ -377,7 +374,6 @@ async def unregister_for_all_statuses(self, callback: types.UpdateCb) -> GoProRe GoProUUIDs.CQ_QUERY, CmdId.REGISTER_ALL_SETTINGS, update_set=SettingId, - responded_cmd=QueryCmdId.SETTING_VAL_PUSH, action=RegisterUnregisterAll.Action.REGISTER, ) async def register_for_all_settings(self, callback: types.UpdateCb) -> GoProResp[None]: @@ -394,7 +390,6 @@ async def register_for_all_settings(self, callback: types.UpdateCb) -> GoProResp GoProUUIDs.CQ_QUERY, CmdId.UNREGISTER_ALL_SETTINGS, update_set=SettingId, - responded_cmd=QueryCmdId.SETTING_VAL_PUSH, action=RegisterUnregisterAll.Action.UNREGISTER, ) async def unregister_for_all_settings(self, callback: types.UpdateCb) -> GoProResp[None]: @@ -411,7 +406,6 @@ async def unregister_for_all_settings(self, callback: types.UpdateCb) -> GoProRe GoProUUIDs.CQ_QUERY, CmdId.REGISTER_ALL_CAPABILITIES, update_set=SettingId, - responded_cmd=QueryCmdId.SETTING_CAPABILITY_PUSH, action=RegisterUnregisterAll.Action.REGISTER, ) async def register_for_all_capabilities(self, callback: types.UpdateCb) -> GoProResp[None]: @@ -428,7 +422,6 @@ async def register_for_all_capabilities(self, callback: types.UpdateCb) -> GoPro GoProUUIDs.CQ_QUERY, CmdId.UNREGISTER_ALL_CAPABILITIES, update_set=SettingId, - responded_cmd=QueryCmdId.SETTING_CAPABILITY_PUSH, action=RegisterUnregisterAll.Action.UNREGISTER, ) async def unregister_for_all_capabilities(self, callback: types.UpdateCb) -> GoProResp[None]: @@ -838,7 +831,7 @@ async def cohn_set_setting(self, *, mode: Params.Toggle) -> GoProResp[None]: return {"cohn_active": mode} # type: ignore -class BleSettings(BleMessages[BleSetting, SettingId]): +class BleSettings(BleMessages[BleSetting.BleSettingMessageBase]): # pylint: disable=missing-class-docstring, unused-argument """The collection of all BLE Settings. @@ -917,12 +910,12 @@ def __init__(self, communicator: GoProBle): ) """Camera controls configuration.""" - self.video_easy_mode: BleSetting[Params.Speed] = BleSetting[Params.Speed]( + self.video_easy_mode: BleSetting[int] = BleSetting[int]( communicator, SettingId.VIDEO_EASY_MODE, - Params.Speed, + Int8ub, ) - """Video easy mode speed.""" + """Video easy mode speed. It is not feasible to maintain this setting without code generation so just read as int.""" self.photo_easy_mode: BleSetting[Params.PhotoEasyMode] = BleSetting[Params.PhotoEasyMode]( communicator, @@ -1114,7 +1107,7 @@ def add_parsers(cls) -> None: GlobalParsers.add_feature_action_id_mapping(response.feature_id, response.action_id) -class BleStatuses(BleMessages[BleStatus, StatusId]): +class BleStatuses(BleMessages[BleStatus.BleStatusMessageBase]): """All of the BLE Statuses. To be used by a GoProBle delegate to build status messages. @@ -1131,7 +1124,6 @@ def __init__(self, communicator: GoProBle) -> None: self.batt_level: BleStatus[int] = BleStatus(communicator, StatusId.BATT_LEVEL, Int8ub) """Rough approximation of internal battery level in bars.""" - # TODO can we just not define deprecated statuses? self.deprecated_3: BleStatus[Any] = BleStatus( communicator, StatusId.DEPRECATED_3, ByteParserBuilders.DeprecatedMarker() ) diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/api/builders.py b/demos/python/sdk_wireless_camera_control/open_gopro/api/builders.py index a79611ab..4df7263c 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/api/builders.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/api/builders.py @@ -10,14 +10,14 @@ from collections.abc import Iterable from dataclasses import dataclass from pathlib import Path -from typing import Any, Callable, Final, Generic, TypeVar, Union -from urllib.parse import urlencode +from typing import Any, Callable, Final, Generic, Protocol, TypeVar, Union import construct import wrapt from open_gopro import types -from open_gopro.api.parsers import ByteParserBuilders, JsonParsers +from open_gopro.api.parsers import ByteParserBuilders +from open_gopro.ble import BleUUID from open_gopro.communicator_interface import ( BleMessage, BleMessages, @@ -26,11 +26,9 @@ HttpMessage, HttpMessages, MessageRules, - RuleSignature, ) from open_gopro.constants import ( ActionId, - BleUUID, CmdId, FeatureId, GoProUUIDs, @@ -40,15 +38,12 @@ ) from open_gopro.enum import GoProIntEnum from open_gopro.logger import Logger -from open_gopro.models.general import HttpInvalidSettingResponse from open_gopro.models.response import GlobalParsers, GoProResp from open_gopro.parser_interface import BytesBuilder, BytesParserBuilder, Parser -from open_gopro.util import pretty_print logger = logging.getLogger(__name__) ValueType = TypeVar("ValueType") -IdType = TypeVar("IdType") QueryParserType = Union[construct.Construct, type[GoProIntEnum], BytesParserBuilder] @@ -58,7 +53,7 @@ T = TypeVar("T") -class BleReadCommand(BleMessage[BleUUID]): +class BleReadCommand(BleMessage): """A BLE command that reads data from a BleUUID""" def __init__(self, uuid: BleUUID, parser: Parser) -> None: @@ -70,30 +65,35 @@ def __init__(self, uuid: BleUUID, parser: Parser) -> None: """ super().__init__(uuid=uuid, parser=parser, identifier=uuid) - async def __call__(self, __communicator__: GoProBle, **kwargs: Any) -> GoProResp: # noqa: D102 - logger.info(Logger.build_log_tx_str(pretty_print(self._as_dict()))) - response = await __communicator__._read_characteristic(self._uuid) - logger.info(Logger.build_log_rx_str(response)) - return response + def _build_data(self, **kwargs: Any) -> bytearray: + # Read commands do not have data + raise NotImplementedError def __str__(self) -> str: return f"Read {self._uuid.name.lower().replace('_', ' ').title()}" - def _as_dict(self, *_: Any, **kwargs: Any) -> types.JsonDict: + def _as_dict(self, **kwargs: Any) -> types.JsonDict: """Return the attributes of the command as a dict Args: - *_ (Any): unused **kwargs (Any): additional entries for the dict Returns: types.JsonDict: command as dict """ - return {"id": "Read " + self._uuid.name, **self._base_dict} | kwargs + return {"id": self._uuid, **self._base_dict} | kwargs + +class BleWriteCommand(BleMessage): + """A BLE command that writes to a BleUUID and retrieves responses by accumulating notifications -class BleWriteCommand(BleMessage[CmdId]): - """A BLE command that writes to a BleUUID and does not accept any parameters""" + Args: + uuid (BleUUID): UUID to write to + cmd (CmdId): command identifier + param_builder (BytesBuilder | None, optional): builds bytes from params. Defaults to None. + parser (Parser | None, optional): response parser to parse received bytes. Defaults to None. + rules (MessageRules): rules this Message must obey. Defaults to MessageRules(). + """ def __init__( self, @@ -101,34 +101,14 @@ def __init__( cmd: CmdId, param_builder: BytesBuilder | None = None, parser: Parser | None = None, - rules: dict[MessageRules, RuleSignature] | None = None, + rules: MessageRules = MessageRules(), ) -> None: - """Constructor - - Args: - uuid (BleUUID): BleUUID to write to - cmd (CmdId): Command ID that is being sent - param_builder (BytesBuilder, optional): is responsible for building the bytestream to send from the input params - parser (BytesParser. optional): the parser that will parse the received bytestream into a JSON dict - rules (Optional[dict[MessageRules, RuleSignature]], optional): rules to apply when executing this - message. Defaults to None. - """ self.param_builder = param_builder self.cmd = cmd - super().__init__(uuid, parser, cmd, rules) - - async def __call__(self, __communicator__: GoProBle, **kwargs: Any) -> GoProResp: - """Execute the command by sending it via BLE - - Args: - __communicator__ (GoProBle): BLE communicator to send the message - **kwargs (Any): arguments to BLE write command - - Returns: - GoProResp: Response received via BLE - """ - logger.info(Logger.build_log_tx_str(pretty_print(self._as_dict(**kwargs)))) + self.rules = rules + super().__init__(uuid, cmd, parser) + def _build_data(self, **kwargs: Any) -> bytearray: data = bytearray([self.cmd.value]) params = bytearray() if self.param_builder: @@ -139,20 +119,15 @@ async def __call__(self, __communicator__: GoProBle, **kwargs: Any) -> GoProResp if params: data.append(len(params)) data.extend(params) - response = await __communicator__._send_ble_message( - self._uuid, data, self._identifier, rules=self._evaluate_rules(**kwargs) - ) - # logger.info(Logger.build_log_rx_str(response)) - return response + return data def __str__(self) -> str: return self.cmd.name.lower().replace("_", " ").removeprefix("cmdid").title() - def _as_dict(self, *_: Any, **kwargs: Any) -> types.JsonDict: + def _as_dict(self, **kwargs: Any) -> types.JsonDict: """Return the attributes of the command as a dict Args: - *_ (Any): unused **kwargs (Any): additional entries for the dict Returns: @@ -180,7 +155,6 @@ def __init__( uuid: BleUUID, cmd: CmdId, update_set: type[SettingId] | type[StatusId], - responded_cmd: QueryCmdId, action: Action, parser: Parser | None = None, ) -> None: @@ -190,28 +164,15 @@ def __init__( uuid (BleUUID): UUID to write to cmd (CmdId): Command ID that is being sent update_set (type[SettingId] | type[StatusId]): what are registering / unregistering for? - responded_cmd (QueryCmdId): not used currently action (Action): whether to register or unregister parser (Optional[BytesParser], optional): Optional response parser. Defaults to None. """ self.action = action self.update_set = update_set - self.responded_cmd = responded_cmd super().__init__(uuid=uuid, cmd=cmd, parser=parser) - async def __call__(self, __communicator__: GoProBle, **kwargs: Any) -> GoProResp: # noqa: D102 - response = await super().__call__(__communicator__) - if response.ok: - for update in self.update_set: - ( # type: ignore - __communicator__.register_update - if self.action is RegisterUnregisterAll.Action.REGISTER - else __communicator__.unregister_update - )(kwargs["callback"], update) - return response - -class BleProtoCommand(BleMessage[ActionId]): +class BleProtoCommand(BleMessage): """A BLE command that is sent and received as using the Protobuf protocol""" def __init__( @@ -241,7 +202,7 @@ def __init__( """ p = parser or Parser() p.byte_json_adapter = ByteParserBuilders.Protobuf(response_proto) - super().__init__(uuid=uuid, parser=p, identifier=action_id) + super().__init__(uuid=uuid, parser=p, identifier=response_action_id) self.feature_id = feature_id self.action_id = action_id self.response_action_id = response_action_id @@ -253,7 +214,7 @@ def __init__( GlobalParsers.add(matching_id, self._parser) GlobalParsers.add_feature_action_id_mapping(self.feature_id, self.response_action_id) - def build_data(self, **kwargs: Any) -> bytearray: + def _build_data(self, **kwargs: Any) -> bytearray: """Build the byte data to prepare for command sending Args: @@ -278,23 +239,13 @@ def build_data(self, **kwargs: Any) -> bytearray: # Prepend headers and serialize return bytearray([self.feature_id.value, self.action_id.value, *proto.SerializeToString()]) - async def __call__(self, __communicator__: GoProBle, **kwargs: Any) -> GoProResp: # noqa: D102 - # The method that will actually build and send the protobuf command - logger.info(Logger.build_log_tx_str(pretty_print(self._as_dict(**kwargs)))) - data = self.build_data(**kwargs) - # Allow exception to pass through if protobuf not completely initialized - response = await __communicator__._send_ble_message(self._uuid, data, self.response_action_id) - # logger.info(Logger.build_log_rx_str(response)) - return response - def __str__(self) -> str: return self.action_id.name.lower().replace("_", " ").removeprefix("actionid").title() - def _as_dict(self, *_: Any, **kwargs: Any) -> types.JsonDict: + def _as_dict(self, **kwargs: Any) -> types.JsonDict: """Return the attributes of the command as a dict Args: - *_ (Any): unused **kwargs (Any): additional entries for the dict Returns: @@ -308,31 +259,31 @@ def ble_write_command( cmd: CmdId, param_builder: BytesBuilder | None = None, parser: Parser | None = None, - rules: dict[MessageRules, RuleSignature] | None = None, + rules: MessageRules = MessageRules(), ) -> Callable: - """Factory to build a BleWriteCommand and wrapper to execute it + """Decorator to build and encapsulate a BleWriteCommand in a Callable Args: - uuid (BleUUID): BleUUID to write to - cmd (CmdId): Command ID that is being sent - param_builder (BytesBuilder, optional): is responsible for building the bytestream to send from the input params - parser (Parser, optional): the parser that will parse the received bytestream into a JSON dict - rules (dict[MessageRules, RuleSignature], optional): Rules to be applied to message execution + uuid (BleUUID): UUID to write to + cmd (CmdId): command identifier + param_builder (BytesBuilder | None, optional): builds bytes from params. Defaults to None. + parser (Parser | None, optional): response parser to parse received bytes. Defaults to None. + rules (MessageRules): rules this Message must obey. Defaults to MessageRules(). Returns: - Callable: Generated method to perform command + Callable: built callable to perform operation """ - message = BleWriteCommand(uuid, cmd, param_builder, parser, rules=rules) + message = BleWriteCommand(uuid, cmd, param_builder, parser) @wrapt.decorator async def wrapper(wrapped: Callable, instance: BleMessages, _: Any, kwargs: Any) -> GoProResp: - return await message(instance._communicator, **(await wrapped(**kwargs) or kwargs)) + return await instance._communicator._send_ble_message(message, rules, **(await wrapped(**kwargs) or kwargs)) return wrapper def ble_read_command(uuid: BleUUID, parser: Parser) -> Callable: - """Factory to build a BleReadCommand and wrapper to execute it + """Decorator to build a BleReadCommand and wrapper to execute it Args: uuid (BleUUID): BleUUID to read from @@ -345,7 +296,7 @@ def ble_read_command(uuid: BleUUID, parser: Parser) -> Callable: @wrapt.decorator async def wrapper(wrapped: Callable, instance: BleMessages, _: Any, kwargs: Any) -> GoProResp: - return await message(instance._communicator, **(await wrapped(**kwargs) or kwargs)) + return await instance._communicator._read_ble_characteristic(message, **(await wrapped(**kwargs) or kwargs)) return wrapper @@ -354,28 +305,26 @@ def ble_register_command( uuid: BleUUID, cmd: CmdId, update_set: type[SettingId] | type[StatusId], - responded_cmd: QueryCmdId, action: RegisterUnregisterAll.Action, parser: Parser | None = None, ) -> Callable: - """Factory to build a RegisterUnregisterAll command and wrapper to execute it + """Decorator to build a RegisterUnregisterAll command and wrapper to execute it Args: uuid (BleUUID): UUID to write to cmd (CmdId): Command ID that is being sent update_set (type[SettingId] | type[StatusId]): set of ID's being registered for - responded_cmd (QueryCmdId): not currently used action (Action): whether to register or unregister parser (Parser, optional): Optional response parser. Defaults to None. Returns: Callable: Generated method to perform command """ - message = RegisterUnregisterAll(uuid, cmd, update_set, responded_cmd, action, parser) + message = RegisterUnregisterAll(uuid, cmd, update_set, action, parser) @wrapt.decorator async def wrapper(wrapped: Callable, instance: BleMessages, _: Any, kwargs: Any) -> GoProResp: - return await message(instance._communicator, **(await wrapped(**kwargs) or kwargs)) + return await instance._communicator._send_ble_message(message, **(await wrapped(**kwargs) or kwargs)) return wrapper @@ -390,7 +339,7 @@ def ble_proto_command( parser: Parser | None = None, additional_matching_ids: set[ActionId | CmdId] | None = None, ) -> Callable: - """Factory to build a BLE Protobuf command and wrapper to execute it + """Decorator to build a BLE Protobuf command and wrapper to execute it Args: uuid (BleUUID): BleUUID to write to @@ -399,10 +348,10 @@ def ble_proto_command( response_action_id (ActionId): the action ID that will be in the response to this command request_proto (type[types.Protobuf]): the action ID that will be in the response response_proto (type[types.Protobuf]): protobuf used to parse received bytestream - parser (Parser | None, optional): _description_. Defaults to None. + parser (Parser | None, optional): Response parser to transform received Protobuf bytes. Defaults to None. additional_matching_ids (Optional[set[Union[ActionId, CmdId]]], optional): Other action ID's to share this parser. This is used, for example, if a notification shares the same ID as the - synchronous response. Defaults to None.. Defaults to None. + synchronous response. Defaults to None. Returns: Callable: Generated method to perform command @@ -420,7 +369,7 @@ def ble_proto_command( @wrapt.decorator async def wrapper(wrapped: Callable, instance: BleMessages, _: Any, kwargs: Any) -> GoProResp: - return await message(instance._communicator, **(await wrapped(**kwargs) or kwargs)) + return await instance._communicator._send_ble_message(message, **(await wrapped(**kwargs) or kwargs)) return wrapper @@ -442,23 +391,50 @@ def __str__(self) -> str: return self.action_id.name.lower().replace("_", " ").removeprefix("actionid").title() -class BleSetting(BleMessage[SettingId], Generic[ValueType]): - """An individual camera setting that is interacted with via BLE.""" +class BuilderProtocol(Protocol): + """Protocol definition of data building methods""" + + def __call__(self, **kwargs: Any) -> bytearray: # noqa: D102 + ... + + +class BleSettingFacade(Generic[ValueType]): + """Wrapper around BleSetting since a BleSetting's message definition changes based on how it is being operated on. + + Args: + communicator (GoProBle): BLE communicator that will operate on this object. + identifier (SettingId): Setting Identifier + parser_builder (QueryParserType): Parses responses from bytes and builds requests to bytes. + """ SETTER_UUID: Final[BleUUID] = GoProUUIDs.CQ_SETTINGS READER_UUID: Final[BleUUID] = GoProUUIDs.CQ_QUERY - def __init__(self, communicator: GoProBle, identifier: SettingId, parser_builder: QueryParserType) -> None: - """Constructor + class BleSettingMessageBase(BleMessage): + """Actual BLE Setting Message that is wrapped by the facade. Args: - communicator (GoProBle): BLE communicator to interact with setting - identifier (SettingId): ID of setting - parser_builder (QueryParserType): object to both parse and build setting - - Raises: - TypeError: Invalid parser_builder type + uuid (BleUUID): UUID to access this setting. + identifier (SettingId | QueryCmdId): How responses to operations on this message will be identified. + setting_id: (SettingId): Setting identifier. May match identifier in some cases. + builder (BuilderProtocol): Build request bytes from the current message. """ + + def __init__( + self, uuid: BleUUID, identifier: SettingId | QueryCmdId, setting_id: SettingId, builder: BuilderProtocol + ) -> None: + self._build = builder + self._setting_id = setting_id + super().__init__(uuid, identifier, None) # type: ignore + + def _build_data(self, **kwargs: Any) -> bytearray: + return self._build(**kwargs) + + def _as_dict(self, **kwargs: Any) -> types.JsonDict: + d = {"id": self._identifier, "setting_id": self._setting_id, **self._base_dict} | kwargs + return d + + def __init__(self, communicator: GoProBle, identifier: SettingId, parser_builder: QueryParserType) -> None: # TODO abstract this parser = Parser[types.CameraState]() if isinstance(parser_builder, construct.Construct): @@ -469,40 +445,22 @@ def __init__(self, communicator: GoProBle, identifier: SettingId, parser_builder parser.byte_json_adapter = ByteParserBuilders.GoProEnum(parser_builder) else: raise TypeError(f"Unexpected {parser_builder=}") + GlobalParsers.add(identifier, parser) + self._identifier = identifier self._builder = parser.byte_json_adapter self._communicator = communicator - BleMessage.__init__(self, uuid=self.SETTER_UUID, parser=parser, identifier=identifier) - - def __str__(self) -> str: - return str(self._identifier).lower().replace("_", " ").title() - - async def __call__(self, __communicator__: GoProBle, **kwargs: Any) -> Any: - """Not applicable for a BLE setting - - Args: - __communicator__ (GoProBle): BLE communicator - **kwargs (Any): not used - Raises: - NotImplementedError: Not applicable - """ - raise NotImplementedError - - def _as_dict( # pylint: disable = arguments-differ - self, identifier: QueryCmdId | SettingId | str, *_: Any, **kwargs: Any - ) -> types.JsonDict: - """Return the attributes of the message as a dict + def _build_cmd(self, cmd: QueryCmdId) -> bytearray: + """Build the data Args: - identifier (Union[QueryCmdId, SettingId, str]): identifier of the message for this send - *_ (Any): unused - **kwargs (Any): additional entries for the dict + cmd (QueryCmdId): query command Returns: - types.JsonDict: setting as dict + bytearray: built data """ - return {"id": identifier, **self._base_dict} | kwargs + return bytearray([cmd.value, int(self._identifier)]) async def set(self, value: ValueType) -> GoProResp[None]: """Set the value of the setting. @@ -513,33 +471,24 @@ async def set(self, value: ValueType) -> GoProResp[None]: Returns: GoProResp: Status of set """ - logger.info(Logger.build_log_tx_str(pretty_print(self._as_dict(f"Set {str(self._identifier)}", value=value)))) - # Special case. Can't use _send_query - data = bytearray([int(self._identifier)]) - try: - param = self._builder.build(value) - data.extend([len(param), *param]) - except IndexError: - pass - - response = await self._communicator._send_ble_message(self.SETTER_UUID, data, self._identifier) - logger.info(Logger.build_log_rx_str(response)) - return response - - async def _send_query(self, response_id: QueryCmdId) -> GoProResp[types.CameraState | None]: - """Build the byte data and query setting information - Args: - response_id (QueryCmdId): expected identifier of response + def _build_data(**kwargs: Any) -> bytearray: + # Special case. Can't use _send_query + data = bytearray([int(self._identifier)]) + try: + param = self._builder.build(kwargs["value"]) + data.extend([len(param), *param]) + except IndexError: + pass + return data - Returns: - GoProResp: query response - """ - data = self._build_cmd(response_id) - logger.info(Logger.build_log_tx_str(pretty_print(self._as_dict(f"{str(response_id)}.{str(self._identifier)}")))) - response = await self._communicator._send_ble_message(self.READER_UUID, data, response_id) - logger.info(Logger.build_log_rx_str(response)) - return response + message = BleSettingFacade.BleSettingMessageBase( + BleSettingFacade.SETTER_UUID, + self._identifier, + self._identifier, + lambda **_: _build_data(value=value), + ) + return await self._communicator._send_ble_message(message) async def get_value(self) -> GoProResp[ValueType]: """Get the settings value. @@ -547,7 +496,13 @@ async def get_value(self) -> GoProResp[ValueType]: Returns: GoProResp: settings value """ - return await self._send_query(QueryCmdId.GET_SETTING_VAL) # type: ignore + message = BleSettingFacade.BleSettingMessageBase( + BleSettingFacade.READER_UUID, + QueryCmdId.GET_SETTING_VAL, + self._identifier, + lambda **_: self._build_cmd(QueryCmdId.GET_SETTING_VAL), + ) + return await self._communicator._send_ble_message(message) async def get_name(self) -> GoProResp[str]: """Get the settings name. @@ -563,7 +518,13 @@ async def get_capabilities_values(self) -> GoProResp[list[ValueType]]: Returns: GoProResp: settings capabilities values """ - return await self._send_query(QueryCmdId.GET_CAPABILITIES_VAL) # type: ignore + message = BleSettingFacade.BleSettingMessageBase( + BleSettingFacade.READER_UUID, + QueryCmdId.GET_CAPABILITIES_VAL, + self._identifier, + lambda **_: self._build_cmd(QueryCmdId.GET_CAPABILITIES_VAL), + ) + return await self._communicator._send_ble_message(message) async def get_capabilities_names(self) -> GoProResp[list[str]]: """Get currently supported settings capabilities names. @@ -582,9 +543,15 @@ async def register_value_update(self, callback: types.UpdateCb) -> GoProResp[Non Returns: GoProResp: Current value of respective setting ID """ - if (response := await self._send_query(QueryCmdId.REG_SETTING_VAL_UPDATE)).ok: + message = BleSettingFacade.BleSettingMessageBase( + BleSettingFacade.READER_UUID, + QueryCmdId.REG_SETTING_VAL_UPDATE, + self._identifier, + lambda **_: self._build_cmd(QueryCmdId.REG_SETTING_VAL_UPDATE), + ) + if (response := await self._communicator._send_ble_message(message)).ok: self._communicator.register_update(callback, self._identifier) - return response # type: ignore + return response async def unregister_value_update(self, callback: types.UpdateCb) -> GoProResp[None]: """Stop receiving notifications when a given setting ID's value updates. @@ -595,9 +562,15 @@ async def unregister_value_update(self, callback: types.UpdateCb) -> GoProResp[N Returns: GoProResp: Status of unregister """ - if (response := await self._send_query(QueryCmdId.UNREG_SETTING_VAL_UPDATE)).ok: + message = BleSettingFacade.BleSettingMessageBase( + BleSettingFacade.READER_UUID, + QueryCmdId.UNREG_SETTING_VAL_UPDATE, + self._identifier, + lambda **_: self._build_cmd(QueryCmdId.UNREG_SETTING_VAL_UPDATE), + ) + if (response := await self._communicator._send_ble_message(message)).ok: self._communicator.unregister_update(callback, self._identifier) - return response # type: ignore + return response async def register_capability_update(self, callback: types.UpdateCb) -> GoProResp[None]: """Register for asynchronous notifications when a given setting ID's capabilities update. @@ -608,9 +581,15 @@ async def register_capability_update(self, callback: types.UpdateCb) -> GoProRes Returns: GoProResp: Current capabilities of respective setting ID """ - if (response := await self._send_query(QueryCmdId.REG_CAPABILITIES_UPDATE)).ok: - self._communicator.register_update(callback, self._identifier) - return response # type: ignore + message = BleSettingFacade.BleSettingMessageBase( + BleSettingFacade.READER_UUID, + QueryCmdId.REG_CAPABILITIES_UPDATE, + self._identifier, + lambda **_: self._build_cmd(QueryCmdId.REG_CAPABILITIES_UPDATE), + ) + if (response := await self._communicator._send_ble_message(message)).ok: + self._communicator.unregister_update(callback, self._identifier) + return response async def unregister_capability_update(self, callback: types.UpdateCb) -> GoProResp[None]: """Stop receiving notifications when a given setting ID's capabilities change. @@ -621,39 +600,62 @@ async def unregister_capability_update(self, callback: types.UpdateCb) -> GoProR Returns: GoProResp: Status of unregister """ - if (response := await self._send_query(QueryCmdId.UNREG_CAPABILITIES_UPDATE)).ok: + message = BleSettingFacade.BleSettingMessageBase( + BleSettingFacade.READER_UUID, + QueryCmdId.UNREG_CAPABILITIES_UPDATE, + self._identifier, + lambda **_: self._build_cmd(QueryCmdId.UNREG_CAPABILITIES_UPDATE), + ) + if (response := await self._communicator._send_ble_message(message)).ok: self._communicator.unregister_update(callback, self._identifier) - return response # type: ignore + return response - def _build_cmd(self, cmd: QueryCmdId) -> bytearray: - """Build the data to send a settings query over-the-air. + def __str__(self) -> str: + return str(self._identifier).lower().replace("_", " ").title() - Args: - cmd (QueryCmdId): command to build - Returns: - bytearray: data to send over-the-air - """ - ret = bytearray([cmd.value, int(self._identifier)]) - return ret +class BleStatusFacade(Generic[ValueType]): + """Wrapper around BleStatus since a BleStatus's message definition changes based on how it is being operated on. + Args: + communicator (GoProBle): BLE communicator that will operate on this object. + identifier (StatusId): Status identifier + parser (QueryParserType): Parser responses from bytes -class BleStatus(BleMessage[StatusId], Generic[ValueType]): - """An individual camera status that is interacted with via BLE.""" + Raises: + TypeError: Attempted to pass an invalid parser type + """ UUID: Final[BleUUID] = GoProUUIDs.CQ_QUERY - def __init__(self, communicator: GoProBle, identifier: StatusId, parser: QueryParserType) -> None: - """Constructor + class BleStatusMessageBase(BleMessage): + """An individual camera status that is interacted with via BLE. Args: - communicator (GoProBle): Adapter to read status data - identifier (StatusId): ID of status - parser (QueryParserType): construct to parse or enum to represent status value - - Raises: - TypeError: Invalid parser type + uuid (BleUUID): UUID to access this status. + identifier (StatusId | QueryCmdId): How responses to operations on this message will be identified. + status_id (StatusId): Status identifier. May match identifier in some cases. + builder (Callable[[Any], bytearray]): Build request bytes from the current message. """ + + def __init__( + self, + uuid: BleUUID, + identifier: StatusId | QueryCmdId, + status_id: StatusId, + builder: Callable[[Any], bytearray], + ) -> None: + self._build = builder + self._status_id = status_id + super().__init__(uuid, identifier, None) # type: ignore + + def _build_data(self, **kwargs: Any) -> bytearray: + return self._build(self, **kwargs) + + def _as_dict(self, **kwargs: Any) -> types.JsonDict: + return {"id": self._identifier, "status_id": self._status_id, **self._base_dict} | kwargs + + def __init__(self, communicator: GoProBle, identifier: StatusId, parser: QueryParserType) -> None: # TODO abstract this parser_builder = Parser[types.CameraState]() # Is it a protobuf enum? @@ -665,66 +667,27 @@ def __init__(self, communicator: GoProBle, identifier: StatusId, parser: QueryPa parser_builder.byte_json_adapter = ByteParserBuilders.GoProEnum(parser) else: raise TypeError(f"Unexpected {parser_builder=}") + GlobalParsers.add(identifier, parser_builder) self._communicator = communicator - BleMessage.__init__(self, uuid=self.UUID, parser=parser_builder, identifier=identifier) self._identifier = identifier - async def __call__(self, __communicator__: GoProBle, **kwargs: Any) -> Any: - """Not applicable for a BLE status - - Args: - __communicator__ (GoProBle): BLE communicator - **kwargs (Any): not used - - Raises: - NotImplementedError: Not applicable - """ - raise NotImplementedError - def __str__(self) -> str: return str(self._identifier).lower().replace("_", " ").title() - async def _send_query(self, response_id: QueryCmdId) -> GoProResp: - """Build the byte data and query setting information - - Args: - response_id (QueryCmdId): expected identifier of response - - Returns: - GoProResp: query response - """ - data = self._build_cmd(response_id) - logger.info(Logger.build_log_tx_str(pretty_print(self._as_dict(f"{response_id.name}.{str(self._identifier)}")))) - response = await self._communicator._send_ble_message(self.UUID, data, response_id) - # logger.info(Logger.build_log_rx_str(response)) - return response - - def _as_dict( # pylint: disable = arguments-differ - self, - identifier: QueryCmdId | SettingId | str, - *_: Any, - **kwargs: Any, - ) -> types.JsonDict: - """Return the attributes of the command as a dict - - Args: - identifier (Union[QueryCmdId, SettingId, str]): identifier of the command for this send - *_ (Any): unused - **kwargs (Any): additional entries for the dict - - Returns: - types.JsonDict: command as dict - """ - return {"id": identifier, **self._base_dict} | kwargs - async def get_value(self) -> GoProResp[ValueType]: """Get the current value of a status. Returns: GoProResp: current status value """ - return await self._send_query(QueryCmdId.GET_STATUS_VAL) + message = BleStatusFacade.BleStatusMessageBase( + BleStatusFacade.UUID, + QueryCmdId.GET_STATUS_VAL, + self._identifier, + lambda *args: self._build_cmd(QueryCmdId.GET_STATUS_VAL), + ) + return await self._communicator._send_ble_message(message) async def register_value_update(self, callback: types.UpdateCb) -> GoProResp[ValueType]: """Register for asynchronous notifications when a status changes. @@ -735,7 +698,13 @@ async def register_value_update(self, callback: types.UpdateCb) -> GoProResp[Val Returns: GoProResp: current status value """ - if (response := await self._send_query(QueryCmdId.REG_STATUS_VAL_UPDATE)).ok: + message = BleStatusFacade.BleStatusMessageBase( + BleStatusFacade.UUID, + QueryCmdId.REG_STATUS_VAL_UPDATE, + self._identifier, + lambda *args: self._build_cmd(QueryCmdId.REG_STATUS_VAL_UPDATE), + ) + if (response := await self._communicator._send_ble_message(message)).ok: self._communicator.register_update(callback, self._identifier) return response @@ -748,8 +717,14 @@ async def unregister_value_update(self, callback: types.UpdateCb) -> GoProResp: Returns: GoProResp: Status of unregister """ - if (response := await self._send_query(QueryCmdId.UNREG_STATUS_VAL_UPDATE)).ok: - self._communicator.unregister_update(callback, self._identifier) + message = BleStatusFacade.BleStatusMessageBase( + BleStatusFacade.UUID, + QueryCmdId.UNREG_STATUS_VAL_UPDATE, + self._identifier, + lambda *args: self._build_cmd(QueryCmdId.UNREG_STATUS_VAL_UPDATE), + ) + if (response := await self._communicator._send_ble_message(message)).ok: + self._communicator.register_update(callback, self._identifier) return response def _build_cmd(self, cmd: QueryCmdId) -> bytearray: @@ -761,226 +736,142 @@ def _build_cmd(self, cmd: QueryCmdId) -> bytearray: Returns: bytearray: data to send over-the-air """ - ret = bytearray([cmd.value, int(self._identifier)]) - return ret + return bytearray([cmd.value, int(self._identifier)]) ######################################################## HTTP ################################################# -class HttpCommand(HttpMessage[str]): - """The base class for HTTP Commands""" - - def __init__( - self, - endpoint: str, - components: list[str] | None = None, - arguments: list[str] | None = None, - parser: Parser | None = None, - identifier: str | None = None, - rules: dict[MessageRules, RuleSignature] | None = None, - ) -> None: - """Constructor - - Args: - endpoint (str): base endpoint - components (Optional[list[str]]): conditional endpoint components. Defaults to None. - arguments (Optional[list[str]]): URL argument names. Defaults to None. - parser (Optional[JsonParser]): additional parsing of JSON response. Defaults to None. - identifier (Optional[IdType]): explicitly set message identifier. Defaults to None (generated from endpoint). - rules (Optional[dict[MessageRules, RuleSignature]], optional): rules to apply when executing this - message. Defaults to None. - """ - if not identifier: - # Build human-readable name from endpoint - identifier = endpoint.lower().removeprefix("gopro/").replace("/", " ").replace("_", " ").title() - try: - identifier = identifier.split("?")[0].strip("{}") - except IndexError: - pass - - super().__init__(endpoint, identifier, components, arguments, parser, rules) - - def build_url(self, **kwargs: Any) -> str: - """Build the URL string from the passed in components and arguments - - Args: - **kwargs (Any): additional entries for the dict - - Returns: - str: built URL - """ - url = self._endpoint - for component in self._components or []: - url += "/" + kwargs.pop(component) - # Append parameters - if self._args and ( - arg_part := urlencode( - { - k: kwargs[k].value if isinstance(kwargs[k], enum.Enum) else kwargs[k] - for k in self._args - if kwargs[k] is not None - }, - safe="/", - ) - ): - url += "?" + arg_part - return url - - -class HttpGetJsonCommand(HttpCommand): - """An HTTP command that performs a GET operation and receives JSON as response""" - - async def __call__( - self, - __communicator__: GoProHttp, - rules: list[MessageRules] | None = None, - **kwargs: Any, - ) -> GoProResp: - """Execute the command by sending it via HTTP - - Args: - __communicator__ (GoProHttp): HTTP communicator - rules (Optional[dict[MessageRules, RuleSignature]], optional): rules to apply when executing this - message. Defaults to None. - **kwargs (Any): arguments to message - - Returns: - GoProResp: Response received via HTTP - """ - url = self.build_url(**kwargs) - # Send to camera - logger.info(Logger.build_log_tx_str(pretty_print(self._as_dict(**kwargs, endpoint=url)))) - response = await __communicator__._http_get(url, self._parser, rules=rules) - response.identifier = self._identifier - logger.info(Logger.build_log_rx_str(response)) - return response - +def http_get_json_command( + endpoint: str, + components: list[str] | None = None, + arguments: list[str] | None = None, + parser: Parser | None = None, + identifier: str | None = None, + rules: MessageRules = MessageRules(), +) -> Callable: + """Decorator to build and encapsulate a an Http Message that performs a GET to return JSON. -# pylint: disable = missing-class-docstring, arguments-differ -class HttpGetBinary(HttpCommand): - """An HTTP command that performs a GET operation and receives a binary stream as response""" + Args: + endpoint (str): base endpoint + components (list[str] | None): Additional path components (i.e. endpoint/{COMPONENT}). Defaults to None. + arguments (list[str] | None): Any arguments to be appended after endpoint (i.e. endpoint?{ARGUMENT}). Defaults to None. + parser (Parser | None, optional): Parser to handle received JSON. Defaults to None. + identifier (types.IdType | None): explicit message identifier. If None, will be generated from endpoint. + rules (MessageRules): rules this Message must obey. Defaults to MessageRules(). - async def __call__( # type: ignore - self, - __communicator__: GoProHttp, - *, - camera_file: str, - local_file: Path | None = None, - ) -> GoProResp: - """Execute the command by getting the binary data from the communicator + Returns: + Callable: built callable to perform operation + """ + message = HttpMessage( + endpoint=endpoint, identifier=identifier, components=components, arguments=arguments, parser=parser + ) - Args: - __communicator__ (GoProHttp): HTTP communicator to query - camera_file (str): file on camera to access - local_file (Optional[Path], optional): file on local device to write to. Defaults to None - (camera-file will be used). + @wrapt.decorator + async def wrapper(wrapped: Callable, instance: HttpMessages, _: Any, kwargs: Any) -> GoProResp: + return await instance._communicator._get_json(message, rules=rules, **(await wrapped(**kwargs) or kwargs)) - Returns: - GoProResp: location on local device that file was written to - """ - # The method that will actually send the command and receive the stream - local_file = local_file or Path(".") / Path(camera_file).name - url = self.build_url(path=camera_file) - logger.info( - Logger.build_log_tx_str( - pretty_print(self._as_dict(endpoint=url, camera_file=camera_file, local_file=local_file)) - ) - ) - # Send to camera - response = await __communicator__._stream_to_file(url, local_file) - logger.info( - Logger.build_log_rx_str(pretty_print(self._as_dict(status="SUCCESS", endpoint=url, local_file=local_file))) - ) - return response + return wrapper -def http_get_json_command( +def http_get_binary_command( endpoint: str, components: list[str] | None = None, arguments: list[str] | None = None, parser: Parser | None = None, identifier: str | None = None, - rules: dict[MessageRules, RuleSignature] | None = None, + rules: MessageRules = MessageRules(), ) -> Callable: - """Factory to build an HttpGetJson command and wrapper to execute it + """Decorator to build and encapsulate a an Http Message that performs a GET to return a binary. Args: endpoint (str): base endpoint - components (Optional[list[str]]): conditional endpoint components. Defaults to None. - arguments (Optional[list[str]]): URL argument names. Defaults to None. - parser (Optional[JsonParser]): additional parsing of JSON response. Defaults to None. - identifier (Optional[str]): explicitly set message identifier. Defaults to None (generated from endpoint). - rules (dict[MessageRules, RuleSignature], optional): Rules to be applied to message execution + components (list[str] | None): Additional path components (i.e. endpoint/{COMPONENT}). Defaults to None. + arguments (list[str] | None): Any arguments to be appended after endpoint (i.e. endpoint?{ARGUMENT}). Defaults to None. + parser (Parser | None, optional): Parser to handle received JSON. Defaults to None. + identifier (types.IdType | None): explicit message identifier. If None, will be generated from endpoint. + rules (MessageRules): rules this Message must obey. Defaults to MessageRules(). Returns: - Callable: Generated method to perform command + Callable: built callable to perform operation """ - message = HttpGetJsonCommand(endpoint, components, arguments, parser, identifier, rules=rules) + message = HttpMessage( + endpoint=endpoint, identifier=identifier, components=components, arguments=arguments, parser=parser + ) @wrapt.decorator async def wrapper(wrapped: Callable, instance: HttpMessages, _: Any, kwargs: Any) -> GoProResp: - return await message( - instance._communicator, message._evaluate_rules(**kwargs), **(await wrapped(**kwargs) or kwargs) + kwargs = await wrapped(**kwargs) or kwargs + # If no local file was passed, used the file name of the camera file + kwargs["local_file"] = ( + kwargs.pop("local_file") if "local_file" in kwargs else Path(kwargs["camera_file"].split("/")[-1]) ) + return await instance._communicator._get_stream(message, rules=rules, **kwargs) return wrapper -def http_get_binary_command( +def http_put_json_command( endpoint: str, components: list[str] | None = None, arguments: list[str] | None = None, + body_args: list[str] | None = None, parser: Parser | None = None, identifier: str | None = None, + rules: MessageRules = MessageRules(), ) -> Callable: - """Factory to build an HttpGetBinary command and wrapper to execute it + """Decorator to build and encapsulate a an Http Message that performs a PUT to return JSON. Args: endpoint (str): base endpoint - components (Optional[list[str]]): conditional endpoint components. Defaults to None. - arguments (Optional[list[str]]): URL argument names. Defaults to None. - parser (Optional[JsonParser]): additional parsing of JSON response. Defaults to None. - identifier (Optional[IdType]): explicitly set message identifier. Defaults to None (generated from endpoint). + components (list[str] | None): Additional path components (i.e. endpoint/{COMPONENT}). Defaults to None. + arguments (list[str] | None): Any arguments to be appended after endpoint (i.e. endpoint?{ARGUMENT}). Defaults to None. + body_args (list[str] | None, optional): Arguments to be added to the body JSON. Defaults to None. + parser (Parser | None, optional): Parser to handle received JSON. Defaults to None. + identifier (types.IdType | None): explicit message identifier. If None, will be generated from endpoint. + rules (MessageRules): rules this Message must obey. Defaults to MessageRules(). Returns: - Callable: Generated method to perform command + Callable: built callable to perform operation """ - message = HttpGetBinary(endpoint, components, arguments, parser, identifier) + message = HttpMessage( + endpoint=endpoint, + identifier=identifier, + body_args=body_args, + arguments=arguments, + components=components, + parser=parser, + ) @wrapt.decorator async def wrapper(wrapped: Callable, instance: HttpMessages, _: Any, kwargs: Any) -> GoProResp: - return await message(instance._communicator, **(await wrapped(**kwargs) or kwargs)) + return await instance._communicator._put_json(message, rules=rules, **(await wrapped(**kwargs) or kwargs)) return wrapper -class HttpSetting(HttpMessage[SettingId], Generic[ValueType]): +class HttpSetting(HttpMessage, Generic[ValueType]): """An individual camera setting that is interacted with via Wifi.""" def __init__(self, communicator: GoProHttp, identifier: SettingId) -> None: - super().__init__( - "gopro/camera/setting?setting={}&option={}", - identifier=identifier, - ) + super().__init__("gopro/camera/setting?setting={setting}&option={option}", identifier) self._communicator = communicator # Note! It is assumed that BLE and HTTP settings are symmetric so we only add to the communicator's # parser in the BLE Setting. - async def __call__(self, __communicator__: GoProHttp, **kwargs: Any) -> Any: - """Not applicable for settings + def __str__(self) -> str: + return str(self._identifier).lower().replace("_", " ").title() + + def build_url(self, **kwargs: Any) -> str: + """Build the endpoint from the current arguments Args: - __communicator__ (GoProHttp): HTTP communicator - **kwargs (Any): not used + kwargs (Any): run-time arguments - Raises: - NotImplementedError: not applicable + Returns: + str: built URL """ - raise NotImplementedError - - def __str__(self) -> str: - return str(self._identifier).lower().replace("_", " ").title() + return self._endpoint.format(setting=int(self._identifier), option=int(kwargs["value"])) async def set(self, value: ValueType) -> GoProResp: """Set the value of the setting. @@ -991,16 +882,7 @@ async def set(self, value: ValueType) -> GoProResp: Returns: GoProResp: Status of set """ - value = value.value if isinstance(value, enum.Enum) else value - url = self._endpoint.format(int(self._identifier), value) - logger.info(Logger.build_log_tx_str(pretty_print(self._as_dict(value=value, endpoint=url)))) - # Send to camera - if response := await self._communicator._http_get( - url, - parser=Parser( - json_parser=JsonParsers.LambdaParser(lambda data: HttpInvalidSettingResponse(**data) if data else data) - ), - ): - response.identifier = self._identifier - logger.info(Logger.build_log_rx_str(response)) + response = await self._communicator._get_json(self, value=value) + response.identifier = self._identifier + logger.info(Logger.build_log_rx_str(response)) return response diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/api/http_commands.py b/demos/python/sdk_wireless_camera_control/open_gopro/api/http_commands.py index 7d601575..26843b1d 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/api/http_commands.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/api/http_commands.py @@ -16,6 +16,7 @@ HttpSetting, http_get_binary_command, http_get_json_command, + http_put_json_command, ) from open_gopro.api.parsers import JsonParsers from open_gopro.communicator_interface import ( @@ -24,7 +25,7 @@ HttpMessages, MessageRules, ) -from open_gopro.constants import CmdId, SettingId +from open_gopro.constants import SettingId from open_gopro.models import CameraInfo, MediaList, MediaMetadata, MediaPath from open_gopro.models.general import WebcamResponse from open_gopro.models.response import GoProResp @@ -35,16 +36,12 @@ logger = logging.getLogger(__name__) -class HttpCommands(HttpMessages[HttpMessage, CmdId]): +class HttpCommands(HttpMessages[HttpMessage]): """All of the HTTP commands. To be used as a delegate for a GoProHttp to build commands """ - ##################################################################################################### - # HTTP GET JSON COMMANDS - ##################################################################################################### - @http_get_json_command( endpoint="gopro/media/last_captured", parser=Parser(json_parser=JsonParsers.PydanticAdapter(MediaPath)), @@ -56,25 +53,28 @@ async def get_last_captured_media(self) -> GoProResp[MediaPath]: GoProResp[MediaPath]: path of last captured media file """ - # async def update_custom_preset( - # self, - # icon_id: proto.EnumPresetIcon.ValueType | None = None, - # title: str | proto.EnumPresetTitle.ValueType | None = None, - # ) -> GoProResp[MediaPath]: - # """Update a custom preset title and / or icon - - # Args: - # icon_id (proto.EnumPresetIcon.ValueType | None, optional): Icon ID. Defaults to None. - # title (str | proto.EnumPresetTitle.ValueType | None, optional): Custom Preset name or Factory Title ID. Defaults to None. + @http_put_json_command( + endpoint="gopro/camera/presets/update_custom", + body_args=["custom_name", "icon_id", "title_id"], + ) + async def update_custom_preset( + self, + *, + icon_id: proto.EnumPresetIcon.ValueType | None = None, + title_id: str | proto.EnumPresetTitle.ValueType | None = None, + custom_name: str | None = None, + ) -> GoProResp[None]: + """For a custom preset, update the Icon and / or the Title - # Raises: - # ValueError: Did not set a parameter - # TypeError: Title was not proto.EnumPresetTitle.ValueType or string + Args: + icon_id (proto.EnumPresetIcon.ValueType | None): Icon to use. Defaults to None. + title_id (str | proto.EnumPresetTitle.ValueType | None): Title to use. Defaults to None. + custom_name (str | None): Custom name to use if title_id is set to + `proto.EnumPresetTitle.PRESET_TITLE_USER_DEFINED_CUSTOM_NAME`. Defaults to None. - # Returns: - # GoProResp[proto.ResponseGeneric]: status of preset update - # """ - # raise NotImplementedError("Need to add support for PUT requests") + Returns: + GoProResp: command status + """ @http_get_json_command(endpoint="gopro/camera/digital_zoom", arguments=["percent"]) async def set_digital_zoom(self, *, percent: int) -> GoProResp[None]: @@ -90,7 +90,7 @@ async def set_digital_zoom(self, *, percent: int) -> GoProResp[None]: @http_get_json_command( endpoint="gopro/camera/state", parser=Parser(json_parser=JsonParsers.CameraStateParser()), - rules={MessageRules.FASTPASS: lambda **kwargs: True}, + rules=MessageRules(fastpass_analyzer=MessageRules.always_true), ) async def get_camera_state(self) -> GoProResp[types.CameraState]: """Get all camera statuses and settings @@ -122,11 +122,11 @@ async def set_keep_alive(self) -> GoProResp[None]: arguments=["path"], parser=Parser(json_parser=JsonParsers.PydanticAdapter(MediaMetadata)), ) - async def get_media_metadata(self, *, file: str) -> GoProResp[MediaMetadata]: + async def get_media_metadata(self, *, path: str) -> GoProResp[MediaMetadata]: """Get media metadata for a file. Args: - file (str): Media file to get metadata for + path (str): Path on camera of media file to get metadata for Returns: GoProResp: Media metadata JSON structure @@ -166,7 +166,7 @@ async def get_open_gopro_api_version(self) -> GoProResp[str]: GoProResp: Open GoPro Version """ - # TODO make pydantic + # TODO make pydantic model of preset status @http_get_json_command(endpoint="gopro/camera/presets/get") async def get_preset_status(self) -> GoProResp[types.JsonDict]: """Get status of current presets @@ -226,10 +226,10 @@ async def set_third_party_client_info(self) -> GoProResp[None]: @http_get_json_command( endpoint="gopro/camera/shutter", components=["mode"], - rules={ - MessageRules.FASTPASS: lambda **kwargs: kwargs["shutter"] == Params.Toggle.DISABLE, - MessageRules.WAIT_FOR_ENCODING_START: lambda **kwargs: kwargs["shutter"] == Params.Toggle.ENABLE, - }, + rules=MessageRules( + fastpass_analyzer=lambda **kwargs: kwargs["mode"] == "stop", + wait_for_encoding_analyzer=lambda **kwargs: kwargs["mode"] == "start", + ), ) async def set_shutter(self, *, shutter: Params.Toggle) -> GoProResp[None]: """Set the shutter on or off @@ -340,6 +340,7 @@ async def remove_file_hilight( @http_get_json_command( endpoint="gopro/webcam/exit", parser=Parser(json_parser=JsonParsers.PydanticAdapter(WebcamResponse)), + rules=MessageRules(fastpass_analyzer=MessageRules.always_true), ) async def webcam_exit(self) -> GoProResp[WebcamResponse]: """Exit the webcam. @@ -351,6 +352,7 @@ async def webcam_exit(self) -> GoProResp[WebcamResponse]: @http_get_json_command( endpoint="gopro/webcam/preview", parser=Parser(json_parser=JsonParsers.PydanticAdapter(WebcamResponse)), + rules=MessageRules(fastpass_analyzer=MessageRules.always_true), ) async def webcam_preview(self) -> GoProResp[WebcamResponse]: """Start the webcam preview. @@ -363,6 +365,7 @@ async def webcam_preview(self) -> GoProResp[WebcamResponse]: endpoint="gopro/webcam/start", arguments=["res", "fov", "port", "protocol"], parser=Parser(json_parser=JsonParsers.PydanticAdapter(WebcamResponse)), + rules=MessageRules(fastpass_analyzer=MessageRules.always_true), ) async def webcam_start( self, @@ -390,7 +393,7 @@ async def webcam_start( @http_get_json_command( endpoint="gopro/webcam/stop", - rules={MessageRules.FASTPASS: lambda **kwargs: True}, + rules=MessageRules(fastpass_analyzer=MessageRules.always_true), parser=Parser(json_parser=JsonParsers.PydanticAdapter(WebcamResponse)), ) async def webcam_stop(self) -> GoProResp[WebcamResponse]: @@ -403,6 +406,7 @@ async def webcam_stop(self) -> GoProResp[WebcamResponse]: @http_get_json_command( endpoint="gopro/webcam/status", parser=Parser(json_parser=JsonParsers.PydanticAdapter(WebcamResponse)), + rules=MessageRules(fastpass_analyzer=MessageRules.always_true), ) async def webcam_status(self) -> GoProResp[WebcamResponse]: """Get the current status of the webcam @@ -426,10 +430,6 @@ async def wired_usb_control(self, *, control: Params.Toggle) -> GoProResp[None]: """ return {"p": control} # type: ignore - ###################################################################################################### - # HTTP GET BINARY COMMANDS - ###################################################################################################### - @http_get_binary_command(endpoint="gopro/media/gpmf", arguments=["path"]) async def get_gpmf_data(self, *, camera_file: str, local_file: Path | None = None) -> GoProResp[Path]: """Get GPMF data for a file. @@ -501,7 +501,7 @@ async def download_file(self, *, camera_file: str, local_file: Path | None = Non """ -class HttpSettings(HttpMessages[HttpSetting, SettingId]): +class HttpSettings(HttpMessages[HttpSetting]): # pylint: disable=missing-class-docstring, unused-argument """The collection of all HTTP Settings @@ -566,9 +566,7 @@ def __init__(self, communicator: GoProHttp): ) """Camera controls configuration.""" - self.video_easy_mode: HttpSetting[Params.Speed] = HttpSetting[Params.Speed]( - communicator, SettingId.VIDEO_EASY_MODE - ) + self.video_easy_mode: HttpSetting[int] = HttpSetting[int](communicator, SettingId.VIDEO_EASY_MODE) """Video easy mode speed.""" self.photo_easy_mode: HttpSetting[Params.PhotoEasyMode] = HttpSetting[Params.PhotoEasyMode]( diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/api/params.py b/demos/python/sdk_wireless_camera_control/open_gopro/api/params.py index d7451fc4..1926b5cb 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/api/params.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/api/params.py @@ -20,9 +20,9 @@ class Resolution(GoProIntEnum): RES_4K_4_3 = 18 RES_5K = 24 RES_5K_4_3 = 25 - RES_5_3K_8_7 = 26 + RES_5_3K_8_7_LEGACY = 26 RES_5_3K_4_3 = 27 - RES_4K_8_7 = 28 + RES_4K_8_7_LEGACY = 28 RES_4K_9_16 = 29 RES_1080_9_16 = 30 RES_5_3K = 100 @@ -32,6 +32,11 @@ class Resolution(GoProIntEnum): RES_2_7K_16_9 = 104 RES_2_7K_4_3_TODO = 105 RES_1080_16_9 = 106 + RES_5_3K_8_7 = 107 + RES_4K_8_7 = 108 + RES_4K_8_7_ = 109 + RES_1080_8_7 = 110 + RES_2_7_K_8_7 = 11 class WebcamResolution(GoProIntEnum): @@ -302,58 +307,6 @@ class HorizonLeveling(GoProIntEnum): LOCKED = 2 -class Speed(GoProIntEnum): - ULTRA_SLO_MO_8X = 0 - SUPER_SLO_MO_4X = 1 - SLO_MO_2X = 2 - LOW_LIGHT_1X = 3 - SUPER_SLO_MO_4X_EXT_BATT = 4 - SLO_MO_2X_EXT_BATT = 5 - LOW_LIGHT_1X_EXT_BATT = 6 - ULTRA_SLO_MO_8X_50_HZ = 7 - SUPER_SLO_MO_4X_50_HZ = 8 - SLO_MO_2X_50_HZ = 9 - LOW_LIGHT_1X_50_HZ = 10 - SUPER_SLO_MO_4X_EXT_BATT_50_HZ = 11 - SLO_MO_2X_EXT_BATT_50_HZ = 12 - LOW_LIGHT_1X_EXT_BATT_50_HZ = 13 - ULTRA_SLO_MO_8X_EXT_BATT = 14 - ULTRA_SLO_MO_8X_EXT_BATT_50_HZ = 15 - ULTRA_SLO_MO_8X_LONG_BATT = 16 - SUPER_SLO_MO_4X_LONG_BATT = 17 - SLO_MO_2X_LONG_BATT = 18 - LOW_LIGHT_1X_LONG_BATT = 19 - ULTRA_SLO_MO_8X_LONG_BATT_50_HZ = 20 - SUPER_SLO_MO_4X_LONG_BATT_50_HZ = 21 - SLO_MO_2X_LONG_BATT_50_HZ = 22 - LOW_LIGHT_1X_LONG_BATT_50_HZ = 23 - SLO_MO_2X_4K = 24 - SUPER_SLO_MO_4X_2_7_K = 25 - SLO_MO_2X_4K_50_HZ = 26 - SUPER_SLO_MO_4X_2_7_K_50_HZ = 27 - SUPER_SLO_MO_4X_2_7K_50HZ = 27 - SPEED_1X_LOW_LIGHT = 28 - SPEED_1X_LOW_LIGHT_2 = 29 - SLO_MO_2X_2 = 30 - SLO_MO_2X_3 = 31 - SPEED_1X_LOW_LIGHT_3 = 32 - SPEED_1X_LOW_LIGHT_4 = 33 - SLO_MO_2X_4 = 34 - SLO_MO_2X_5 = 35 - SPEED_1X_LOW_LIGHT_5 = 36 - SPEED_1X_LOW_LIGHT_6 = 37 - SPEED_1X_LOW_LIGHT_7 = 38 - SPEED_1X_LOW_LIGHT_8 = 39 - SLO_MO_2X_6 = 40 - SLO_MO_2X_7 = 41 - SLO_MO_2X_8 = 42 - SLO_MO_2X_9 = 43 - SPEED_1X_LOW_LIGHT_9 = 44 - SPEED_1X_LOW_LIGHT_10 = 45 - SPEED_1X_LOW_LIGHT_11 = 46 - SPEED_1X_LOW_LIGHT_12 = 47 - - class PhotoEasyMode(GoProIntEnum): OFF = 0 ON = 1 @@ -468,3 +421,9 @@ class PhotoDuration(GoProIntEnum): HOUR_1 = 7 HOUR_2 = 8 HOUR_3 = 9 + + +class PresetGroup(GoProIntEnum): + VIDEO = 1000 + PHOTO = 1001 + TIMELAPSE = 1002 diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/api/parsers.py b/demos/python/sdk_wireless_camera_control/open_gopro/api/parsers.py index 41e51a62..d165c032 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/api/parsers.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/api/parsers.py @@ -33,32 +33,6 @@ ProtobufPrinter = google.protobuf.json_format._Printer # type: ignore # noqa original_field_to_json = ProtobufPrinter._FieldToJsonObject - -# TODO move into below class -def construct_adapter_factory(target: Construct) -> BytesParserBuilder: - """Build a construct parser adapter from a construct - - Args: - target (Construct): construct to use for parsing and building - - Returns: - BytesParserBuilder: instance of generated class - """ - - class ParserBuilder(BytesParserBuilder): - """Adapt the construct for our interface""" - - container = target - - def parse(self, data: bytes) -> Any: - return self.container.parse(data) - - def build(self, *args: Any, **kwargs: Any) -> bytes: - return self.container.build(*args, **kwargs) - - return ParserBuilder() - - T = TypeVar("T") @@ -250,14 +224,14 @@ class ProtobufByteParser(BytesParser[dict]): protobuf = proto - # TODO can we do this without relying on Protobuf internal implementation # pylint: disable=not-callable def parse(self, data: bytes) -> Any: response: types.Protobuf = self.protobuf().FromString(bytes(data)) + # TODO can translate from Protobuf enums without relying on Protobuf internal implementation? # Monkey patch the field-to-json function to use our enum translation - ProtobufPrinter._FieldToJsonObject = ( - lambda self, field, value: enum_factory(field.enum_type)(value) + ProtobufPrinter._FieldToJsonObject = lambda self, field, value: ( + enum_factory(field.enum_type)(value) if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM else original_field_to_json(self, field, value) ) @@ -331,7 +305,31 @@ class Construct(BytesParserBuilder): """ def __init__(self, construct: Construct) -> None: - self._construct = construct_adapter_factory(construct) + self._construct = self._construct_adapter_factory(construct) + + @classmethod + def _construct_adapter_factory(cls, target: Construct) -> BytesParserBuilder: + """Build a construct parser adapter from a construct + + Args: + target (Construct): construct to use for parsing and building + + Returns: + BytesParserBuilder: instance of generated class + """ + + class ParserBuilder(BytesParserBuilder): + """Adapt the construct for our interface""" + + container = target + + def parse(self, data: bytes) -> Any: + return self.container.parse(data) + + def build(self, *args: Any, **kwargs: Any) -> bytes: + return self.container.build(*args, **kwargs) + + return ParserBuilder() def parse(self, data: bytes) -> Construct: """Parse bytes into construct container diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/communicator_interface.py b/demos/python/sdk_wireless_camera_control/open_gopro/communicator_interface.py index feeed018..4379d1de 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/communicator_interface.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/communicator_interface.py @@ -11,7 +11,8 @@ import re from abc import ABC, abstractmethod from pathlib import Path -from typing import Any, Generator, Generic, Pattern, Protocol, TypeVar, Union +from typing import Any, Generator, Generic, Pattern, Protocol, TypeVar +from urllib.parse import urlencode from construct import Bit, BitsInteger, BitStruct, Const, Construct, Padding @@ -25,7 +26,7 @@ DisconnectHandlerType, NotiHandlerType, ) -from open_gopro.constants import ActionId, CmdId, GoProUUIDs, SettingId, StatusId +from open_gopro.constants import GoProUUIDs from open_gopro.models.response import GoProResp, Header from open_gopro.parser_interface import ( BytesParser, @@ -39,6 +40,60 @@ logger = logging.getLogger(__name__) + +class MessageRules: + """Message Rules Manager + + Args: + fastpass_analyzer (Analyzer): used to check if message is fastpass. Defaults to always_false. + wait_for_encoding_analyer (Analyzer): Used to check if message should wait for encoding. Defaults to always_false. + """ + + class Analyzer(Protocol): + """Protocol definition of message rules analyzer""" + + def __call__(self, **kwargs: Any) -> bool: + """Analyze the current inputs to see if the rule should be applied + + Args: + kwargs (Any): input arguments + + Returns: + bool: Should the rule be applied? + """ + + always_false: Analyzer = lambda **kwargs: False + always_true: Analyzer = lambda **kwargs: True + + def __init__( + self, fastpass_analyzer: Analyzer = always_false, wait_for_encoding_analyzer: Analyzer = always_false + ) -> None: + self._analyze_fastpass = fastpass_analyzer + self._analyze_wait_for_encoding = wait_for_encoding_analyzer + + def is_fastpass(self, **kwargs: Any) -> bool: + """Is this command fastpass? + + Args: + kwargs (Any) : Arguments passed into the message + + Returns: + bool: result of rule check + """ + return self._analyze_fastpass(**kwargs) + + def should_wait_for_encoding_start(self, **kwargs: Any) -> bool: + """Should this message wait for encoding to start? + + Args: + kwargs (Any) : Arguments passed into the message + + Returns: + bool: result of rule check + """ + return self._analyze_wait_for_encoding(**kwargs) + + ############################################################################################################## ####### Communicators / Clients ############################################################################################################## @@ -70,33 +125,55 @@ def unregister_update(self, callback: types.UpdateCb, update: types.UpdateType | class GoProHttp(BaseGoProCommunicator): - """Base class interface for all HTTP commands""" + """Interface definition for all HTTP communicators""" @abstractmethod - async def _http_get(self, url: str, parser: Parser | None = None, **kwargs: Any) -> GoProResp: - """Send an HTTP GET request to a string endpoint. + async def _get_json( + self, message: HttpMessage, *, timeout: int = 0, rules: MessageRules | None = MessageRules(), **kwargs: Any + ) -> GoProResp: + """Perform a GET operation that returns JSON Args: - url (str): endpoint not including GoPro base path - parser (Optional[JsonParser]): Optional parser to further parse received JSON dict. Defaults to - None. - **kwargs (Any): - - rules (list[MessageRules]): rules to be enforced for this message + message (HttpMessage): operation description + timeout (int): time (in seconds) to wait to receive response before returning error. Defaults to 0. + rules (MessageRules | None): message rules that this operation will obey. Defaults to MessageRules(). + kwargs (Any) : any run-time arguments to apply to the operation Returns: - GoProResp: GoPro response + GoProResp: response parsed from received JSON """ - raise NotImplementedError @abstractmethod - async def _stream_to_file(self, url: str, file: Path) -> GoProResp: - """Send an HTTP GET request to an Open GoPro endpoint to download a binary file. + async def _get_stream( + self, message: HttpMessage, *, timeout: int = 0, rules: MessageRules | None = MessageRules(), **kwargs: Any + ) -> GoProResp: + """Perform a GET operation that returns a binary stream Args: - url (str): endpoint URL - file (Path): location where file should be downloaded to + message (HttpMessage): operation description + timeout (int): time (in seconds) to wait to receive response before returning error. Defaults to 0. + rules (MessageRules | None): message rules that this operation will obey. Defaults to MessageRules(). + kwargs (Any) : any run-time arguments to apply to the operation + + Returns: + GoProResp: response wrapper around downloaded binary + """ + + @abstractmethod + async def _put_json( + self, message: HttpMessage, *, timeout: int = 0, rules: MessageRules | None = MessageRules(), **kwargs: Any + ) -> GoProResp: + """Perform a PUT operation that returns JSON + + Args: + message (HttpMessage): operation description + timeout (int): time (in seconds) to wait to receive response before returning error. Defaults to 0. + rules (MessageRules | None): message rules that this operation will obey. Defaults to MessageRules(). + kwargs (Any) : any run-time arguments to apply to the operation + + Returns: + GoProResp: response parsed from received JSON """ - raise NotImplementedError class GoProWifi(GoProHttp): @@ -107,7 +184,6 @@ class GoProWifi(GoProHttp): """ def __init__(self, controller: WifiController): - GoProHttp.__init__(self) self._wifi: WifiClient = WifiClient(controller) @property @@ -156,34 +232,35 @@ def __init__( @abstractmethod async def _send_ble_message( - self, uuid: BleUUID, data: bytearray, response_id: types.ResponseType, **kwargs: Any + self, message: BleMessage, rules: MessageRules = MessageRules(), **kwargs: Any ) -> GoProResp: - """Write a characteristic and block until its corresponding notification response is received. + """Perform a GATT write with response and accumulate received notifications into a response. Args: - uuid (BleUUID): characteristic to write to - data (bytearray): bytes to write - response_id (types.ResponseType): identifier to claim parsed response in notification handler - **kwargs (Any): - - rules (list[MessageRules]): rules to be enforced for this message + message (BleMessage): BLE operation description + rules (MessageRules): message rules that this operation will obey. Defaults to MessageRules(). + kwargs (Any) : any run-time arguments to apply to the operation Returns: - GoProResp: received response + GoProResp: response parsed from accumulated BLE notifications """ - raise NotImplementedError @abstractmethod - async def _read_characteristic(self, uuid: BleUUID) -> GoProResp: - """Read a characteristic and block until its corresponding notification response is received. + async def _read_ble_characteristic( + self, message: BleMessage, rules: MessageRules = MessageRules(), **kwargs: Any + ) -> GoProResp: + """Perform a direct GATT read of a characteristic Args: - uuid (BleUUID): characteristic ro read + message (BleMessage): BLE operation description + rules (MessageRules): message rules that this operation will obey. Defaults to MessageRules(). + kwargs (Any) : any run-time arguments to apply to the operation Returns: - GoProResp: data read from characteristic + GoProResp: response parsed from bytes read from characteristic """ - raise NotImplementedError + # TODO this should be somewhere else @classmethod def _fragment(cls, data: bytearray) -> Generator[bytearray, None, None]: """Fragment data in to MAX_BLE_PKT_LEN length packets @@ -246,7 +323,7 @@ def _fragment(cls, data: bytearray) -> Generator[bytearray, None, None]: yield packet -class GoProWiredInterface(GoProHttp): +class GoProWiredInterface(BaseGoProCommunicator): """The top-level interface for a Wired Open GoPro controller""" @@ -279,8 +356,6 @@ def __init__( GoProWifi.__init__(self, wifi_controller) -CommunicatorType = TypeVar("CommunicatorType", bound=Union[GoProBle, GoProHttp]) -IdType = TypeVar("IdType", SettingId, StatusId, ActionId, CmdId, BleUUID, str) ParserType = TypeVar("ParserType", BytesParser, JsonParser) FilterType = TypeVar("FilterType", BytesTransformer, JsonTransformer) @@ -290,82 +365,22 @@ def __init__( ############################################################################################################## -class RuleSignature(Protocol): - """Protocol definition for a rule evaluation function""" - - def __call__(self, **kwargs: Any) -> bool: - """Function signature to evaluate a message rule - - Args: - **kwargs (Any): arguments to user-facing message method - - Returns: - bool: Whether or not message rule is currently enforced - """ - - -class MessageRules(enum.Enum): - """Rules to be applied when message is executed""" - - FASTPASS = enum.auto() #: Message can be sent when the camera is busy and / or encoding - WAIT_FOR_ENCODING_START = enum.auto() #: Message must not complete until encoding has started - - -class Message(Generic[CommunicatorType, IdType], ABC): +class Message(ABC): """Base class for all messages that will be contained in a Messages class""" def __init__( self, - identifier: IdType, + identifier: types.IdType, parser: Parser | None = None, - rules: dict[MessageRules, RuleSignature] | None = None, ) -> None: - """Constructor - - Args: - identifier (IdType): id to access this message by - parser (ParserType): optional parser and builder - rules (dict[MessageRules, RuleSignature] | None): rules to apply when executing this - message. Defaults to None. - """ - self._identifier: IdType = identifier + self._identifier: types.IdType = identifier self._parser = parser - self._rules = rules or {} - - def _evaluate_rules(self, **kwargs: Any) -> list[MessageRules]: - """Given the arguments for the current message execution, which rules should be enforced? - - Args: - **kwargs (Any): user-facing arguments to the current message execution - - Returns: - list[MessageRules]: list of rules to be enforced - """ - enforced_rules = [] - for rule, evaluator in self._rules.items(): - if evaluator(**kwargs): - enforced_rules.append(rule) - return enforced_rules - - @abstractmethod - async def __call__(self, __communicator__: CommunicatorType, **kwargs: Any) -> Any: - """Execute the message by sending it to the target device - - Args: - __communicator__ (CommunicatorType): communicator to send the message - **kwargs (Any): not used - - Returns: - Any: Value received from the device - """ - raise NotImplementedError @abstractmethod - def _as_dict(self, *_: Any, **kwargs: Any) -> types.JsonDict: + def _as_dict(self, **kwargs: Any) -> types.JsonDict: """Return the attributes of the message as a dict Args: - *_ (Any): unused **kwargs (Any): additional entries for the dict Returns: @@ -374,7 +389,7 @@ def _as_dict(self, *_: Any, **kwargs: Any) -> types.JsonDict: raise NotImplementedError -class BleMessage(Message[GoProBle, IdType]): +class BleMessage(Message): """The base class for all BLE messages to store common info Args: @@ -385,59 +400,81 @@ class BleMessage(Message[GoProBle, IdType]): def __init__( self, uuid: BleUUID, + identifier: types.IdType, parser: Parser | None, - identifier: IdType, - rules: dict[MessageRules, RuleSignature] | None = None, ) -> None: - Message.__init__(self, identifier, parser, rules) + Message.__init__(self, identifier, parser) self._uuid = uuid - self._base_dict = {"protocol": "BLE", "uuid": self._uuid} + self._base_dict = {"protocol": GoProResp.Protocol.BLE, "uuid": self._uuid} if parser: GlobalParsers.add(identifier, parser) + @abstractmethod + def _build_data(self, **kwargs: Any) -> bytearray: + """Build the raw write request from operation description and run-time arguments -class HttpMessage(Message[GoProHttp, IdType]): - """The base class for all HTTP messages. Stores common information.""" + Args: + kwargs (Any) : run-time arguments + + Returns: + bytearray: raw bytes request + """ + + +class HttpMessage(Message): + """The base class for all HTTP messages. Stores common information. + + Args: + endpoint (str): base endpoint + identifier (types.IdType | None): explicit message identifier. If None, will be generated from endpoint. + components (list[str] | None): Additional path components (i.e. endpoint/{COMPONENT}). Defaults to None. + arguments (list[str] | None): Any arguments to be appended after endpoint (i.e. endpoint?{ARGUMENT}). Defaults to None. + body_args (list[str] | None): Arguments to be added to the body JSON. Defaults to None. + headers (dict[str, Any] | None): A dict of values to be set in the HTTP operation headers. Defaults to None. + certificate (Path | None): Path to SSL certificate bundle. Defaults to None. + parser (Parser | None): Parser to interpret HTTP responses. Defaults to None. + """ def __init__( self, endpoint: str, - identifier: IdType, + identifier: types.IdType | None, components: list[str] | None = None, arguments: list[str] | None = None, + body_args: list[str] | None = None, + headers: dict[str, Any] | None = None, + certificate: Path | None = None, parser: Parser | None = None, - rules: dict[MessageRules, RuleSignature] | None = None, ) -> None: - """Constructor - - Args: - endpoint (str): base endpoint - identifier (IdType): explicitly set message identifier. Defaults to None (generated from endpoint). - components (list[str] | None): conditional endpoint components. Defaults to None. - arguments (list[str] | None): URL argument names. Defaults to None. - parser (Parser | None]): additional parsing of JSON response. Defaults to None. - rules (dict[MessageRules, RuleSignature] | None): rules to apply when executing this - message. Defaults to None. - """ + if not identifier: + # Build human-readable name from endpoint + identifier = endpoint.lower().removeprefix("gopro/").replace("/", " ").replace("_", " ").title() + try: + identifier = identifier.split("?")[0].strip("{}") + except IndexError: + pass + + self._headers = headers or {} self._endpoint = endpoint - self._components = components - self._args = arguments - Message.__init__(self, identifier, parser, rules=rules) + self._components = components or [] + self._arguments = arguments or [] + self._body_args = body_args or [] + self._certificate = certificate + Message.__init__(self, identifier, parser) self._base_dict: types.JsonDict = { "id": self._identifier, - "protocol": "HTTP", + "protocol": GoProResp.Protocol.HTTP, "endpoint": self._endpoint, } def __str__(self) -> str: return str(self._identifier).title() - def _as_dict(self, *_: Any, **kwargs: Any) -> types.JsonDict: + def _as_dict(self, **kwargs: Any) -> types.JsonDict: """Return the attributes of the message as a dict Args: - *_ (Any): unused **kwargs (Any): additional entries for the dict Returns: @@ -446,11 +483,53 @@ def _as_dict(self, *_: Any, **kwargs: Any) -> types.JsonDict: # If any kwargs keys were to conflict with base dict, append underscore return self._base_dict | {f"{'_' if k in ['id', 'protocol'] else ''}{k}": v for k, v in kwargs.items()} + def build_body(self, **kwargs: Any) -> dict[str, Any]: + """Build JSON body from run-time body arguments + + Args: + **kwargs (Any): run-time arguments to check to see if each should be added to the body + + Returns: + dict[str, Any]: built JSON body + """ + body: dict[str, Any] = {} + for name, value in kwargs.items(): + if name in self._body_args: + body[name] = value + return body + + def build_url(self, **kwargs: Any) -> str: + """Build the URL string from the passed in components and arguments + + Args: + **kwargs (Any): additional entries for the dict + + Returns: + str: built URL + """ + url = self._endpoint + for component in self._components: + url += "/" + kwargs.pop(component) + # Append parameters + if self._arguments and ( + arg_part := urlencode( + { + k: kwargs[k].value if isinstance(kwargs[k], enum.Enum) else kwargs[k] + for k in self._arguments + if kwargs[k] is not None + }, + safe="/", + ) + ): + url += "?" + arg_part + return url + MessageType = TypeVar("MessageType", bound=Message) +CommunicatorType = TypeVar("CommunicatorType", bound=BaseGoProCommunicator) -class Messages(ABC, dict, Generic[MessageType, IdType, CommunicatorType]): +class Messages(ABC, dict, Generic[MessageType, CommunicatorType]): """Base class for setting and status containers Allows message groups to be iterable and supports dict-like access. @@ -467,10 +546,10 @@ def __init__(self, communicator: CommunicatorType) -> None: """ self._communicator = communicator # Append any automatically discovered instance attributes (i.e. for settings and statuses) - message_map: dict[IdType | str, MessageType] = {} + message_map: dict[types.IdType, MessageType] = {} for message in self.__dict__.values(): - if isinstance(message, Message): - message_map[message._identifier] = message # type: ignore + if hasattr(message, "_identifier"): + message_map[message._identifier] = message # Append any automatically discovered methods (i.e. for commands) for name, method in inspect.getmembers(self, predicate=inspect.ismethod): if not name.startswith("_"): @@ -478,14 +557,14 @@ def __init__(self, communicator: CommunicatorType) -> None: dict.__init__(self, message_map) -class BleMessages(Messages[MessageType, IdType, GoProBle]): +class BleMessages(Messages[MessageType, GoProBle]): """A container of BLE Messages. Identical to Messages and it just used for typing """ -class HttpMessages(Messages[MessageType, IdType, GoProHttp]): +class HttpMessages(Messages[MessageType, GoProHttp]): """A container of HTTP Messages. Identical to Messages and it just used for typing diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/demos/cohn.py b/demos/python/sdk_wireless_camera_control/open_gopro/demos/cohn.py index 2bf126c6..e0fac91a 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/demos/cohn.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/demos/cohn.py @@ -1,13 +1,12 @@ -# cohn.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Tue Oct 24 19:08:07 UTC 2023 - +# cohn.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Tue Oct 24 19:08:07 UTC 2023 + """Entrypoint for configuring and demonstrating Camera On the Home Network (COHN).""" from __future__ import annotations import argparse import asyncio -import logging from rich.console import Console @@ -17,19 +16,18 @@ console = Console() # rich consoler printer -logger: logging.Logger - MDNS_SERVICE = "_gopro-web._tcp.local." async def main(args: argparse.Namespace) -> None: - global logger logger = setup_logging(__name__, args.log) gopro: WirelessGoPro | None = None try: # Start with Wifi Disabled (i.e. don't allow camera in AP mode). async with WirelessGoPro(args.identifier, enable_wifi=False) as gopro: + await gopro.ble_command.cohn_clear_certificate() + if await gopro.is_cohn_provisioned: console.print("[yellow]COHN is already provisioned") else: @@ -42,6 +40,7 @@ async def main(args: argparse.Namespace) -> None: # Prove we can communicate via the COHN HTTP channel without a BLE or Wifi connection assert (await gopro.http_command.get_camera_state()).ok + console.print("Successfully communicated via COHN!!") except Exception as e: # pylint: disable = broad-except logger.error(repr(e)) diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/demos/custom_preset_udpate_demo.py b/demos/python/sdk_wireless_camera_control/open_gopro/demos/custom_preset_udpate_demo.py index 737d36de..17de6b68 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/demos/custom_preset_udpate_demo.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/demos/custom_preset_udpate_demo.py @@ -1,63 +1,57 @@ -# photo.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Wed, Sep 1, 2021 5:05:45 PM +# custom_preset_udpate_demo.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Thu Mar 28 20:25:41 UTC 2024 + +"""Simple demo to modify a currently accessible custom preset's title and icon.""" -"""Entrypoint for taking a picture demo.""" - -import argparse import asyncio from pathlib import Path from rich.console import Console -from open_gopro import WiredGoPro, WirelessGoPro, proto -from open_gopro.gopro_base import GoProBase +from open_gopro import WiredGoPro, proto from open_gopro.logger import setup_logging -from open_gopro.util import add_cli_args_and_parse console = Console() -async def main(args: argparse.Namespace) -> None: - logger = setup_logging(__name__, args.log) - gopro: GoProBase | None = None +async def main() -> None: + logger = setup_logging(__name__, Path("custom_preset.log")) + gopro: WiredGoPro | None = None try: - async with ( - WiredGoPro(args.identifier) # type: ignore - if args.wired - else WirelessGoPro(args.identifier, wifi_interface=args.wifi_interface) - ) as gopro: - assert gopro - ble_last_file = (await gopro.ble_command.get_last_captured_media()).data - http_last_file = (await gopro.http_command.get_last_captured_media()).data - assert ble_last_file.media.folder == http_last_file.folder - assert ble_last_file.media.file == http_last_file.file - - presets = (await gopro.ble_command.get_preset_status()).data + async with WiredGoPro() as gopro: + presets = (await gopro.http_command.get_preset_status()).data custom_preset_id: int | None = None - for group in presets.preset_group_array: - for preset in group.preset_array: - if preset.user_defined: - custom_preset_id = preset.id + for group in presets["presetGroupArray"]: + for preset in group["presetArray"]: + if preset["userDefined"]: + custom_preset_id = preset["id"] if not custom_preset_id: raise RuntimeError("Could not find a custom preset.") # Ensure we can load it - assert (await gopro.ble_command.load_preset(preset=custom_preset_id)).ok + assert (await gopro.http_command.load_preset(preset=custom_preset_id)).ok # Now try to update it assert ( - await gopro.ble_command.custom_preset_update( - icon_id=proto.EnumPresetTitle.PRESET_TITLE_BIKE, - title="custom title", + await gopro.http_command.update_custom_preset( + icon_id=proto.EnumPresetIcon.PRESET_ICON_SNOW, + title_id=proto.EnumPresetTitle.PRESET_TITLE_SNOW, + ) + ).ok + input("press enter to continue") + assert ( + await gopro.http_command.update_custom_preset( + icon_id=proto.EnumPresetIcon.PRESET_ICON_MOTOR, + title_id=proto.EnumPresetTitle.PRESET_TITLE_MOTOR, ) ).ok input("press enter to continue") assert ( - await gopro.ble_command.custom_preset_update( - icon_id=proto.EnumPresetTitle.PRESET_TITLE_MOTOR, - title=proto.EnumPresetTitle.PRESET_TITLE_MOTOR, + await gopro.http_command.update_custom_preset( + custom_name="Custom Name", + icon_id=proto.EnumPresetIcon.PRESET_ICON_BIKE, + title_id=proto.EnumPresetTitle.PRESET_TITLE_USER_DEFINED_CUSTOM_NAME, ) ).ok - print("cheese") except Exception as e: # pylint: disable = broad-except logger.error(repr(e)) @@ -66,27 +60,5 @@ async def main(args: argparse.Namespace) -> None: await gopro.close() -def parse_arguments() -> argparse.Namespace: - parser = argparse.ArgumentParser(description="Connect to a GoPro camera, take a photo, then download it.") - parser.add_argument( - "--output", - type=Path, - help="Where to write the photo to. If not set, write to 'photo.jpg'", - default=Path("photo.jpg"), - ) - parser.add_argument( - "--wired", - action="store_true", - help="Set to use wired (USB) instead of wireless (BLE / WIFI) interface", - ) - - return add_cli_args_and_parse(parser) - - -# Needed for poetry scripts defined in pyproject.toml -def entrypoint() -> None: - asyncio.run(main(parse_arguments())) - - if __name__ == "__main__": - entrypoint() + asyncio.run(main()) diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/demos/gui/livestream.py b/demos/python/sdk_wireless_camera_control/open_gopro/demos/gui/livestream.py index 32735bc5..a67a6b44 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/demos/gui/livestream.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/demos/gui/livestream.py @@ -50,7 +50,7 @@ async def wait_for_livestream_start(_: Any, update: proto.NotifyLiveStreamStatus console.print("[yellow]Waiting for livestream to be ready...\n") await livestream_is_ready.wait() - # TODO Is this still needed + # TODO Is this still needed? await asyncio.sleep(2) console.print("[yellow]Starting livestream") diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/demos/gui/webcam.py b/demos/python/sdk_wireless_camera_control/open_gopro/demos/gui/webcam.py index 72853aa4..24233237 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/demos/gui/webcam.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/demos/gui/webcam.py @@ -1,7 +1,7 @@ # usb.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). # This copyright was auto-generated on Fri Nov 18 00:18:13 UTC 2022 -"""USB webcam demo""" +"""USB / wireless webcam demo""" import argparse import asyncio diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/demos/log_battery.py b/demos/python/sdk_wireless_camera_control/open_gopro/demos/log_battery.py index cf3117d9..0239cc4e 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/demos/log_battery.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/demos/log_battery.py @@ -119,6 +119,7 @@ async def log_battery() -> None: ).data # Append initial sample SAMPLES.append(Sample(index=SAMPLE_INDEX, percentage=last_percentage, bars=last_bars)) + SAMPLE_INDEX += 1 console.print(str(SAMPLES[-1])) console.print("[bold green]Receiving battery notifications until it dies...") diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/demos/photo.py b/demos/python/sdk_wireless_camera_control/open_gopro/demos/photo.py index 67ff68ed..5034b237 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/demos/photo.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/demos/photo.py @@ -19,6 +19,7 @@ async def main(args: argparse.Namespace) -> None: logger = setup_logging(__name__, args.log) + gopro: GoProBase | None = None try: @@ -28,33 +29,24 @@ async def main(args: argparse.Namespace) -> None: else WirelessGoPro(args.identifier, wifi_interface=args.wifi_interface) ) as gopro: assert gopro - # Configure settings to prepare for photo - await gopro.http_setting.video_performance_mode.set(Params.PerformanceMode.MAX_PERFORMANCE) - await gopro.http_setting.max_lens_mode.set(Params.MaxLensMode.DEFAULT) - await gopro.http_setting.camera_ux_mode.set(Params.CameraUxMode.PRO) - await gopro.http_command.set_turbo_mode(mode=Params.Toggle.DISABLE) assert (await gopro.http_command.load_preset_group(group=proto.EnumPresetGroup.PRESET_GROUP_ID_PHOTO)).ok - # # Get the media list before - # media_set_before = set((await gopro.http_command.get_media_list()).data.files) + # Get the media list before + media_set_before = set((await gopro.http_command.get_media_list()).data.files) + # Take a photo - # console.print("Capturing a photo...") - # assert (await gopro.http_command.set_shutter(shutter=Params.Toggle.ENABLE)).ok - - # # Get the media list after - # media_set_after = set((await gopro.http_command.get_media_list()).data.files) - # # The photo is (most likely) the difference between the two sets - # photo = media_set_after.difference(media_set_before).pop() - - # Get the last captured media - test = await gopro.http_command.get_last_captured_media() - # test = await gopro.ble_command.get_last_captured_media() - print(f"Photo from new command ==> {test.data.folder} ::: {test.data.file}") - - # # Download the photo - # console.print(f"Downloading {photo.filename}...") - # await gopro.http_command.download_file(camera_file=photo.filename, local_file=args.output) - # console.print(f"Success!! :smiley: File has been downloaded to {args.output}") + assert (await gopro.http_command.set_shutter(shutter=Params.Toggle.ENABLE)).ok + + # Get the media list after + media_set_after = set((await gopro.http_command.get_media_list()).data.files) + # The video (is most likely) the difference between the two sets + photo = media_set_after.difference(media_set_before).pop() + + # Download the photo + console.print(f"Downloading {photo.filename}...") + await gopro.http_command.download_file(camera_file=photo.filename, local_file=args.output) + console.print(f"Success!! :smiley: File has been downloaded to {Path(args.output).absolute()}") + except Exception as e: # pylint: disable = broad-except logger.error(repr(e)) diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/demos/video.py b/demos/python/sdk_wireless_camera_control/open_gopro/demos/video.py index 04c8e99d..ef80585b 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/demos/video.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/demos/video.py @@ -27,12 +27,6 @@ async def main(args: argparse.Namespace) -> None: else WirelessGoPro(args.identifier, wifi_interface=args.wifi_interface) ) as gopro: assert gopro - # Configure settings to prepare for video - await gopro.http_command.set_shutter(shutter=Params.Toggle.DISABLE) - await gopro.http_setting.video_performance_mode.set(Params.PerformanceMode.MAX_PERFORMANCE) - await gopro.http_setting.max_lens_mode.set(Params.MaxLensMode.DEFAULT) - await gopro.http_setting.camera_ux_mode.set(Params.CameraUxMode.PRO) - await gopro.http_command.set_turbo_mode(mode=Params.Toggle.DISABLE) assert (await gopro.http_command.load_preset_group(group=proto.EnumPresetGroup.PRESET_GROUP_ID_VIDEO)).ok # Get the media list before @@ -47,8 +41,9 @@ async def main(args: argparse.Namespace) -> None: media_set_after = set((await gopro.http_command.get_media_list()).data.files) # The video (is most likely) the difference between the two sets video = media_set_after.difference(media_set_before).pop() + # Download the video - console.print("Downloading the video...") + console.print(f"Downloading {video.filename}...") await gopro.http_command.download_file(camera_file=video.filename, local_file=args.output) console.print(f"Success!! :smiley: File has been downloaded to {args.output}") except Exception as e: # pylint: disable = broad-except diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/gopro_base.py b/demos/python/sdk_wireless_camera_control/open_gopro/gopro_base.py index 35db422f..3ac17141 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/gopro_base.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/gopro_base.py @@ -11,9 +11,8 @@ import logging import threading import traceback -from abc import ABC, abstractmethod -from pathlib import Path -from typing import Any, Awaitable, Callable, Final, Generic, Optional, TypeVar +from abc import abstractmethod +from typing import Any, Awaitable, Callable, Final, Generic, TypeVar import requests import wrapt @@ -29,9 +28,16 @@ WiredApi, WirelessApi, ) +from open_gopro.communicator_interface import ( + GoProHttp, + HttpMessage, + Message, + MessageRules, +) from open_gopro.constants import ErrorCode +from open_gopro.logger import Logger from open_gopro.models.response import GoProResp, RequestsHttpRespBuilderDirector -from open_gopro.parser_interface import Parser +from open_gopro.util import pretty_print logger = logging.getLogger(__name__) @@ -48,7 +54,7 @@ class GoProMessageInterface(enum.Enum): @wrapt.decorator -def catch_thread_exception(wrapped: Callable, instance: GoProBase, args: Any, kwargs: Any) -> Optional[Callable]: +def catch_thread_exception(wrapped: Callable, instance: GoProBase, args: Any, kwargs: Any) -> Callable | None: """Catch any exceptions from this method and pass them to the exception handler identifier by thread name Args: @@ -88,10 +94,26 @@ def wrapper(wrapped: Callable, instance: GoProBase, args: Any, kwargs: Any) -> C return wrapper -class GoProBase(ABC, Generic[ApiType]): +@wrapt.decorator +async def enforce_message_rules(wrapped: MessageMethodType, instance: GoProBase, args: Any, kwargs: Any) -> GoProResp: + """Decorator proxy to call the GoProBase's _enforce_message_rules method. + + Args: + wrapped (MessageMethodType): Operation to enforce + instance (GoProBase): GoProBase instance to use + args (Any): positional arguments to wrapped + kwargs (Any): keyword arguments to wrapped + + Returns: + GoProResp: common response object + """ + return await instance._enforce_message_rules(wrapped, *args, **kwargs) + + +class GoProBase(GoProHttp, Generic[ApiType]): """The base class for communicating with all GoPro Clients""" - GET_TIMEOUT: Final = 5 + HTTP_TIMEOUT: Final = 5 HTTP_GET_RETRIES: Final = 5 def __init__(self, **kwargs: Any) -> None: @@ -262,6 +284,22 @@ async def is_cohn_provisioned(self) -> bool: # End Public API ########################################################################################################## + @abstractmethod + async def _enforce_message_rules( + self, wrapped: Callable, message: Message, rules: MessageRules, **kwargs: Any + ) -> GoProResp: + """Rule Enforcer. Called by enforce_message_rules decorator. + + Args: + wrapped (Callable): operation to enforce + message (Message): message passed to operation + rules (MessageRules): rules to enforce + kwargs (Any) : arguments passed to operation + + Returns: + GoProResp: Operation response + """ + def _handle_exception(self, source: Any, context: types.JsonDict) -> None: """Gather exceptions from module threads and send through callback if registered. @@ -320,7 +358,7 @@ def _ensure_opened(interface: tuple[GoProMessageInterface]) -> Callable: return ensure_opened(interface) @staticmethod - def _catch_thread_exception(*args: Any, **kwargs: Any) -> Optional[Callable]: + def _catch_thread_exception(*args: Any, **kwargs: Any) -> Callable | None: """Catch any exceptions from this method and pass them to the exception handler identifier by thread name Args: @@ -332,54 +370,38 @@ def _catch_thread_exception(*args: Any, **kwargs: Any) -> Optional[Callable]: """ return catch_thread_exception(*args, **kwargs) - # TODO use requests in async manner - @ensure_opened((GoProMessageInterface.HTTP,)) - async def _http_get( # pylint: disable=unused-argument - self, - url: str, - parser: Parser | None, - headers: dict | None = None, - certificate: Path | None = None, - timeout: int = GET_TIMEOUT, - **kwargs: Any, - ) -> GoProResp: - """Send an HTTP GET request to an Open GoPro endpoint. - - There should hopefully not be a scenario where this needs to be called directly as it is generally - called from the instance's delegates (i.e. self.wifi_command and self.wifi_status) + def _build_http_request_args(self, message: HttpMessage) -> dict[str, Any]: + """Helper method to build request kwargs from message Args: - url (str): endpoint URL - parser (Parser, optional): Optional parser to further parse received JSON dict. - headers (dict | None, optional): dict of additional HTTP headers. Defaults to None. - certificate (Path | None, optional): path to certificate CA bundle. Defaults to None. - timeout (int): timeout in seconds before retrying. Defaults to GET_TIMEOUT - kwargs (Any): additional arguments to be consumed by decorator / subclass - - Raises: - ResponseTimeout: Response was not received in timeout seconds + message (HttpMessage): message to build args from Returns: - GoProResp: response + dict[str, Any]: built args """ - url = self._base_url + url - logger.debug(f"Sending: {url}") - # Dynamically build get kwargs request_args: dict[str, Any] = {} - if headers: - request_args["headers"] = headers - if certificate: - request_args["verify"] = str(certificate) - - response: Optional[GoProResp] = None + if message._headers: + request_args["headers"] = message._headers + if message._certificate: + request_args["verify"] = str(message._certificate) + return request_args + + @enforce_message_rules + async def _get_json( + self, message: HttpMessage, *, timeout: int = HTTP_TIMEOUT, rules: MessageRules = MessageRules(), **kwargs: Any + ) -> GoProResp: + url = self._base_url + message.build_url(**kwargs) + logger.debug(f"Sending: {url}") + logger.info(Logger.build_log_tx_str(pretty_print(message._as_dict(**kwargs)))) + response: GoProResp | None = None for retry in range(1, GoProBase.HTTP_GET_RETRIES + 1): try: - request = requests.get(url, timeout=timeout, **request_args) - logger.trace(f"received raw json: {json.dumps(request.json() if request.text else {}, indent=4)}") # type: ignore - if not request.ok: - logger.warning(f"Received non-success status {request.status_code}: {request.reason}") - response = RequestsHttpRespBuilderDirector(request, parser)() + http_response = requests.get(url, timeout=timeout, **self._build_http_request_args(message)) + logger.trace(f"received raw json: {json.dumps(http_response.json() if http_response.text else {}, indent=4)}") # type: ignore + if not http_response.ok: + logger.warning(f"Received non-success status {http_response.status_code}: {http_response.reason}") + response = RequestsHttpRespBuilderDirector(http_response, message._parser)() break except requests.exceptions.ConnectionError as e: # This appears to only occur after initial connection after pairing @@ -393,36 +415,51 @@ async def _http_get( # pylint: disable=unused-argument raise GpException.ResponseTimeout(GoProBase.HTTP_GET_RETRIES) assert response is not None + logger.info(Logger.build_log_rx_str(pretty_print(response._as_dict()))) return response - @ensure_opened((GoProMessageInterface.HTTP,)) - async def _stream_to_file(self, url: str, file: Path) -> GoProResp[Path]: - """Send an HTTP GET request to an Open GoPro endpoint to download a binary file. - - There should hopefully not be a scenario where this needs to be called directly as it is generally - called from the instance's delegates (i.e. self.wifi_command and self.wifi_status) - - Args: - url (str): endpoint URL - file (Path): location where file should be downloaded to - - Returns: - GoProResp: location of file that was written - """ - assert self.is_http_connected - - url = self._base_url + url - logger.debug(f"Sending: {url}") - with requests.get(url, stream=True, timeout=GoProBase.GET_TIMEOUT) as request: + @enforce_message_rules + async def _get_stream( + self, message: HttpMessage, *, timeout: int = HTTP_TIMEOUT, rules: MessageRules = MessageRules(), **kwargs: Any + ) -> GoProResp: + url = self._base_url + message.build_url(path=kwargs["camera_file"]) + logger.debug(f"Sending: {url}") + with requests.get(url, stream=True, timeout=timeout, **self._build_http_request_args(message)) as request: request.raise_for_status() + file = kwargs["local_file"] with open(file, "wb") as f: logger.debug(f"receiving stream to {file}...") for chunk in request.iter_content(chunk_size=8192): f.write(chunk) - return GoProResp( - protocol=GoProResp.Protocol.HTTP, - status=ErrorCode.SUCCESS, - data=file, - identifier=url, - ) + return GoProResp(protocol=GoProResp.Protocol.HTTP, status=ErrorCode.SUCCESS, data=file, identifier=url) + + @enforce_message_rules + async def _put_json( + self, message: HttpMessage, *, timeout: int = HTTP_TIMEOUT, rules: MessageRules = MessageRules(), **kwargs: Any + ) -> GoProResp: + url = self._base_url + message.build_url(**kwargs) + body = message.build_body(**kwargs) + logger.debug(f"Sending: {url} with body: {json.dumps(body, indent=4)}") + response: GoProResp | None = None + for retry in range(1, GoProBase.HTTP_GET_RETRIES + 1): + try: + http_response = requests.put(url, timeout=timeout, json=body, **self._build_http_request_args(message)) + logger.trace(f"received raw json: {json.dumps(http_response.json() if http_response.text else {}, indent=4)}") # type: ignore + if not http_response.ok: + logger.warning(f"Received non-success status {http_response.status_code}: {http_response.reason}") + response = RequestsHttpRespBuilderDirector(http_response, message._parser)() + break + except requests.exceptions.ConnectionError as e: + # This appears to only occur after initial connection after pairing + logger.warning(repr(e)) + # Back off before retrying. TODO This appears to be needed on MacOS + await asyncio.sleep(2) + except Exception as e: # pylint: disable=broad-exception-caught + logger.critical(f"Unexpected error: {repr(e)}") + logger.warning(f"Retrying #{retry} to send the command...") + else: + raise GpException.ResponseTimeout(GoProBase.HTTP_GET_RETRIES) + + assert response is not None + return response diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/gopro_wired.py b/demos/python/sdk_wireless_camera_control/open_gopro/gopro_wired.py index ef1db4ce..e0370991 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/gopro_wired.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/gopro_wired.py @@ -7,10 +7,7 @@ import asyncio import logging -from pathlib import Path -from typing import Any, Final - -import wrapt +from typing import Any, Callable, Final import open_gopro.exceptions as GpException import open_gopro.wifi.mdns_scanner # Imported this way for pytest monkeypatching @@ -24,9 +21,9 @@ Params, WiredApi, ) -from open_gopro.communicator_interface import GoProWiredInterface, MessageRules +from open_gopro.communicator_interface import GoProWiredInterface, Message, MessageRules from open_gopro.constants import StatusId -from open_gopro.gopro_base import GoProBase, MessageMethodType +from open_gopro.gopro_base import GoProBase from open_gopro.models import GoProResp logger = logging.getLogger(__name__) @@ -35,42 +32,6 @@ HTTP_GET_RETRIES: Final = 5 -@wrapt.decorator -async def enforce_message_rules(wrapped: MessageMethodType, instance: WiredGoPro, args: Any, kwargs: Any) -> GoProResp: - """Wrap the input message method, applying any message rules (MessageRules) - - Args: - wrapped (MessageMethodType): Method that will be wrapped - instance (WiredGoPro): owner of method - args (Any): positional arguments - kwargs (Any): keyword arguments - - Returns: - GoProResp: forward response of message method - """ - rules: list[MessageRules] = kwargs.pop("rules", []) - - # Acquire ready lock unless we are initializing or this is a Set Shutter Off command - if instance._should_maintain_state and instance.is_open and not MessageRules.FASTPASS in rules: - # Wait for not encoding and not busy - logger.trace("Waiting for camera to be ready to receive messages.") # type: ignore - await instance._wait_for_state({StatusId.ENCODING: False, StatusId.SYSTEM_BUSY: False}) - logger.trace("Camera is ready to receive messages") # type: ignore - response = await wrapped(*args, **kwargs) - else: # Either we're not maintaining state, we're not opened yet, or this is a fastpass message - response = await wrapped(*args, **kwargs) - - # Release the lock if we acquired it - if instance._should_maintain_state: - if response.ok: - # Is there any special handling required after receiving the response? - if MessageRules.WAIT_FOR_ENCODING_START in rules: - logger.trace("Waiting to receive encoding started.") # type: ignore - # Wait for encoding to start - await instance._wait_for_state({StatusId.ENCODING: True}) - return response - - class WiredGoPro(GoProBase[WiredApi], GoProWiredInterface): """The top-level USB interface to a Wired GoPro device. @@ -263,7 +224,7 @@ def is_http_connected(self) -> bool: Returns: bool: True if yes, False if no """ - return True # TODO find a better way to do this + return self.is_open def register_update(self, callback: types.UpdateCb, update: types.UpdateType) -> None: """Register for callbacks when an update occurs @@ -325,6 +286,29 @@ async def is_cohn_provisioned(self) -> bool: # End Public API ########################################################################################################## + async def _enforce_message_rules( + self, wrapped: Callable, message: Message, rules: MessageRules = MessageRules(), **kwargs: Any + ) -> GoProResp: + # Acquire ready lock unless we are initializing or this is a Set Shutter Off command + if self._should_maintain_state and self.is_open and not rules.is_fastpass(**kwargs): + # Wait for not encoding and not busy + logger.trace("Waiting for camera to be ready to receive messages.") # type: ignore + await self._wait_for_state({StatusId.ENCODING: False, StatusId.SYSTEM_BUSY: False}) + logger.trace("Camera is ready to receive messages") # type: ignore + response = await wrapped(message, **kwargs) + else: # Either we're not maintaining state, we're not opened yet, or this is a fastpass message + response = await wrapped(message, **kwargs) + + # Release the lock if we acquired it + if self._should_maintain_state: + if response.ok: + # Is there any special handling required after receiving the response? + if rules.should_wait_for_encoding_start(**kwargs): + logger.trace("Waiting to receive encoding started.") # type: ignore + # Wait for encoding to start + await self._wait_for_state({StatusId.ENCODING: True}) + return response + async def _wait_for_state(self, check: types.CameraState) -> None: """Poll the current state until a variable amount of states are all equal to desired values @@ -337,6 +321,7 @@ async def _wait_for_state(self, check: types.CameraState) -> None: state = (await self.http_command.get_camera_state()).data for key, value in check.items(): if state.get(key) != value: + logger.trace(f"Not ready ==> {key} != {value}") # type: ignore await asyncio.sleep(self._poll_period) break # Get new state and try again else: @@ -359,7 +344,3 @@ def _base_url(self) -> str: if not self._serial: raise GpException.GoProNotOpened("Serial / IP has not yet been discovered") return WiredGoPro._BASE_ENDPOINT.format(ip=WiredGoPro._BASE_IP.format(*self._serial[-3:])) - - @enforce_message_rules - async def _stream_to_file(self, url: str, file: Path) -> GoProResp: - return await super()._stream_to_file(url, file) diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/gopro_wireless.py b/demos/python/sdk_wireless_camera_control/open_gopro/gopro_wireless.py index 5ecea303..7467a81a 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/gopro_wireless.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/gopro_wireless.py @@ -6,14 +6,12 @@ from __future__ import annotations import asyncio +import enum import logging import queue from collections import defaultdict from copy import deepcopy -from pathlib import Path -from typing import Any, Final, Pattern - -import wrapt +from typing import Any, Callable, Final, Pattern import open_gopro.exceptions as GpException from open_gopro import proto, types @@ -27,14 +25,23 @@ WirelessApi, ) from open_gopro.ble import BleakWrapperController, BleUUID -from open_gopro.communicator_interface import GoProWirelessInterface, MessageRules +from open_gopro.communicator_interface import ( + BleMessage, + GoProWirelessInterface, + HttpMessage, + Message, + MessageRules, +) from open_gopro.constants import ActionId, GoProUUIDs, StatusId -from open_gopro.gopro_base import GoProBase, GoProMessageInterface, MessageMethodType +from open_gopro.gopro_base import ( + GoProBase, + GoProMessageInterface, + enforce_message_rules, +) from open_gopro.logger import Logger from open_gopro.models.general import CohnInfo from open_gopro.models.response import BleRespBuilder, GoProResp -from open_gopro.parser_interface import Parser -from open_gopro.util import SnapshotQueue, get_current_dst_aware_time +from open_gopro.util import SnapshotQueue, get_current_dst_aware_time, pretty_print from open_gopro.wifi import WifiCli logger = logging.getLogger(__name__) @@ -42,47 +49,6 @@ KEEP_ALIVE_INTERVAL: Final = 28 -@wrapt.decorator -async def enforce_message_rules( - wrapped: MessageMethodType, instance: WirelessGoPro, args: Any, kwargs: Any -) -> GoProResp: - """Wrap the input message method, applying any message rules (MessageRules) - - Args: - wrapped (MessageMethodType): Method that will be wrapped - instance (WirelessGoPro): owner of method - args (Any): positional arguments - kwargs (Any): keyword arguments - - Returns: - GoProResp: forward response of message method - """ - rules: list[MessageRules] = kwargs.pop("rules", []) - - # Acquire ready lock unless we are initializing or this is a Set Shutter Off command - have_lock = False - if instance._should_maintain_state and instance.is_open and not MessageRules.FASTPASS in rules: - logger.trace(f"{wrapped.__name__} acquiring lock") # type: ignore - await instance._ready_lock.acquire() - logger.trace(f"{wrapped.__name__} has the lock") # type: ignore - have_lock = True - response = await wrapped(*args, **kwargs) - else: # Either we're not maintaining state, we're not opened yet, or this is a fastpass message - response = await wrapped(*args, **kwargs) - - # Release the lock if we acquired it - if instance._should_maintain_state: - if have_lock: - instance._ready_lock.release() - logger.trace(f"{wrapped.__name__} released the lock") # type: ignore - # Is there any special handling required after receiving the response? - if MessageRules.WAIT_FOR_ENCODING_START in rules: - logger.trace("Waiting to receive encoding started.") # type: ignore - await instance._encoding_started.wait() - instance._encoding_started.clear() - return response - - class WirelessGoPro(GoProBase[WirelessApi], GoProWirelessInterface): """The top-level BLE and Wifi interface to a Wireless GoPro device. @@ -145,6 +111,12 @@ class WirelessGoPro(GoProBase[WirelessApi], GoProWirelessInterface): WRITE_TIMEOUT: Final = 5 + class _LockOwner(enum.Enum): + """Current owner of the communication lock""" + + RULE_ENFORCER = enum.auto() + STATE_MANAGER = enum.auto() + def __init__( self, target: Pattern | None = None, @@ -193,6 +165,8 @@ def __init__( self._ble_disconnect_event: asyncio.Event if self._should_maintain_state: + self._state_tasks: list[asyncio.Task] = [] + self._lock_owner: WirelessGoPro._LockOwner | None = WirelessGoPro._LockOwner.STATE_MANAGER self._ready_lock: asyncio.Lock self._keep_alive_task: asyncio.Task self._encoding: bool @@ -486,10 +460,6 @@ async def is_cohn_provisioned(self) -> bool: """ return (await self.ble_command.cohn_get_status(register=False)).data.enabled - ########################################################################################################## - # End Public API - ########################################################################################################## - @GoProBase._ensure_opened((GoProMessageInterface.BLE,)) async def keep_alive(self) -> bool: """Send a heartbeat to prevent the BLE connection from dropping. @@ -557,6 +527,34 @@ async def wait_for_provisioning(_: Any, result: proto.NotifProvisioningState) -> # End Public API ########################################################################################################## + async def _enforce_message_rules( + self, wrapped: Callable, message: Message, rules: MessageRules = MessageRules(), **kwargs: Any + ) -> GoProResp: + # Acquire ready lock unless we are initializing or this is a Set Shutter Off command + response: GoProResp + if self._should_maintain_state and self.is_open and not rules.is_fastpass(**kwargs): + logger.trace(f"{wrapped.__name__} acquiring lock") # type: ignore + await self._ready_lock.acquire() + logger.trace(f"{wrapped.__name__} has the lock") # type: ignore + self._lock_owner = WirelessGoPro._LockOwner.RULE_ENFORCER + response = await wrapped(message, **kwargs) + else: # Either we're not maintaining state, we're not opened yet, or this is a fastpass message + response = await wrapped(message, **kwargs) + + # Release the lock if we acquired it + if self._should_maintain_state: + if self._lock_owner is WirelessGoPro._LockOwner.RULE_ENFORCER: + logger.trace(f"{wrapped.__name__} releasing the lock") # type: ignore + self._lock_owner = None + self._ready_lock.release() + logger.trace(f"{wrapped.__name__} released the lock") # type: ignore + # Is there any special handling required after receiving the response? + if rules.should_wait_for_encoding_start(**kwargs): + logger.trace("Waiting to receive encoding started.") # type: ignore + await self._encoding_started.wait() + self._encoding_started.clear() + return response + async def _notify_listeners(self, update: types.UpdateType, value: Any) -> None: """Notify all registered listeners of this update @@ -595,13 +593,20 @@ async def _open_ble(self, timeout: int = 10, retries: int = 5) -> None: async def _update_internal_state(self, update: types.UpdateType, value: int) -> None: """Update the internal state based on a status update. + # Note!!! This needs to be reentrant-safe + Used to update encoding and / or busy status Args: update (types.UpdateType): type of update (status ID) value (int): updated value """ - have_lock = not await self.is_ready + # Cancel any currently pending state update tasks + for task in self._state_tasks: + logger.trace("Cancelling pending acquire task.") # type: ignore + task.cancel() + self._state_tasks = [] + logger.trace(f"State update received {update.name} ==> {value}") # type: ignore should_notify_encoding = False if update == StatusId.ENCODING: @@ -612,29 +617,29 @@ async def _update_internal_state(self, update: types.UpdateType, value: int) -> self._busy = bool(value) logger.trace(f"Current internal states: {self._encoding=} {self._busy=}") # type: ignore - ready_now = await self.is_ready - if have_lock and ready_now: + if self._lock_owner is WirelessGoPro._LockOwner.STATE_MANAGER and await self.is_ready: + logger.trace("Control releasing lock") # type: ignore + self._lock_owner = None self._ready_lock.release() logger.trace("Control released lock") # type: ignore - elif not have_lock and not ready_now: + elif not (self._lock_owner is WirelessGoPro._LockOwner.STATE_MANAGER) and not await self.is_ready: logger.trace("Control acquiring lock") # type: ignore - await self._ready_lock.acquire() + task = asyncio.create_task(self._ready_lock.acquire()) + self._state_tasks.append(task) + await task logger.trace("Control has lock") # type: ignore + self._lock_owner = WirelessGoPro._LockOwner.STATE_MANAGER if should_notify_encoding and self.is_open: logger.trace("Control setting encoded started") # type: ignore self._encoding_started.set() - # TODO this needs unit testing async def _route_response(self, response: GoProResp) -> None: """After parsing response, route it to any stakeholders (such as registered listeners) Args: - response (GoProResp): parsed response + response (GoProResp): parsed response to route """ - # Flatten data if possible - # from copy import copy - original_response = deepcopy(response) if response._is_query and not response._is_push: response.data = list(response.data.values())[0] @@ -675,22 +680,21 @@ async def _async_notification_handler() -> None: # Accumulate the packet self._active_builders[uuid].accumulate(data) if (builder := self._active_builders[uuid]).is_finished_accumulating: - response = builder.build() - # Perform response post-processing tasks - await self._route_response(response) + logger.trace(f"Finished accumulating on {uuid}") # type: ignore # Clear active response from response dict del self._active_builders[uuid] + await self._route_response(builder.build()) asyncio.run_coroutine_threadsafe(_async_notification_handler(), self._loop) async def _close_ble(self) -> None: """Terminate BLE connection if it is connected""" if self.is_ble_connected and self._ble is not None: - self._ble_disconnect_event.clear() if self._should_maintain_state: self._keep_alive_task.cancel() await self._ble.close() await self._ble_disconnect_event.wait() + # TODO this event is never cleared since this object is not designed to be re-opened. def _disconnect_handler(self, _: Any) -> None: """Disconnect callback from BLE controller @@ -705,29 +709,16 @@ def _disconnect_handler(self, _: Any) -> None: @GoProBase._ensure_opened((GoProMessageInterface.BLE,)) @enforce_message_rules async def _send_ble_message( - self, uuid: BleUUID, data: bytearray, response_id: types.ResponseType, **_: Any + self, message: BleMessage, rules: MessageRules = MessageRules(), **kwargs: Any ) -> GoProResp: - """Write a characteristic and block until its corresponding notification response is received. - - Args: - uuid (BleUUID): characteristic to write to - data (bytearray): bytes to write - response_id (types.ResponseType): identifier to claim parsed response in notification handler - **_ (Any): not used - - Raises: - ResponseTimeout: did not receive a response before timing out - - Returns: - GoProResp: received response - """ # Store information on the response we are expecting - await self._sync_resp_wait_q.put(response_id) + await self._sync_resp_wait_q.put(message._identifier) + logger.info(Logger.build_log_tx_str(pretty_print(message._as_dict(**kwargs)))) # Fragment data and write it - for packet in self._fragment(data): - logger.debug(f"Writing to [{uuid.name}] UUID: {packet.hex(':')}") - await self._ble.write(uuid, packet) + for packet in self._fragment(message._build_data(**kwargs)): + logger.debug(f"Writing to [{message._uuid.name}] UUID: {packet.hex(':')}") + await self._ble.write(message._uuid, packet) # Wait to be notified that response was received try: @@ -744,24 +735,42 @@ async def _send_ble_message( @GoProBase._ensure_opened((GoProMessageInterface.BLE,)) @enforce_message_rules - async def _read_characteristic(self, uuid: BleUUID) -> GoProResp: - """Read a characteristic's data by GoProUUIDs. + async def _read_ble_characteristic( + self, message: BleMessage, rules: MessageRules = MessageRules(), **kwargs: Any + ) -> GoProResp: + received_data = await self._ble.read(message._uuid) + logger.debug(f"Reading from {message._uuid.name}") + builder = BleRespBuilder() + builder.set_uuid(message._uuid) + builder.set_packet(received_data) + return builder.build() - There should hopefully not be a scenario where this needs to be called directly as it is generally - called from the instance's delegates (i.e. self.command, self.setting, self.ble_status) + # TODO make decorator? + def _handle_cohn(self, message: HttpMessage) -> HttpMessage: + """Prepend COHN headers if COHN is enabled Args: - uuid (BleUUID): characteristic data to read + message (HttpMessage): HTTP message to append headers to Returns: - GoProResp: response from UUID read + HttpMessage: potentially modified HTTP message """ - received_data = await self._ble.read(uuid) - logger.debug(f"Reading from {uuid.name}") - builder = BleRespBuilder() - builder.set_uuid(uuid) - builder.set_packet(received_data) - return builder.build() + if self._cohn: + message._headers["Authorization"] = self._cohn.auth_token + message._certificate = self._cohn.cert_path + return message + + async def _get_json(self, message: HttpMessage, *args: Any, **kwargs: Any) -> GoProResp: + message = self._handle_cohn(message) + return await super()._get_json(*args, message=message, **kwargs) + + async def _get_stream(self, message: HttpMessage, *args: Any, **kwargs: Any) -> GoProResp: + message = self._handle_cohn(message) + return await super()._get_stream(*args, message=message, **kwargs) + + async def _put_json(self, message: HttpMessage, *args: Any, **kwargs: Any) -> GoProResp: + message = self._handle_cohn(message) + return await super()._put_json(*args, message=message, **kwargs) @GoProBase._ensure_opened((GoProMessageInterface.BLE,)) async def _open_wifi(self, timeout: int = 10, retries: int = 5) -> None: @@ -794,31 +803,6 @@ async def _close_wifi(self) -> None: if hasattr(self, "_wifi"): # Corner case where instantiation fails before superclass is initialized self._wifi.close() - @enforce_message_rules - async def _http_get( - self, - url: str, - parser: Parser | None = None, - headers: dict | None = None, - certificate: Path | None = None, - timeout: int = GoProBase.GET_TIMEOUT, - **kwargs: Any, - ) -> GoProResp: - if self._cohn: - return await super()._http_get( - url, - parser, - headers=headers or {"Authorization": self._cohn.auth_token}, - certificate=certificate or self._cohn.cert_path, - timeout=timeout, - **kwargs, - ) - return await super()._http_get(url, parser, **kwargs) - - @enforce_message_rules - async def _stream_to_file(self, url: str, file: Path) -> GoProResp[Path]: - return await super()._stream_to_file(url, file) - @property def _base_url(self) -> str: return f"https://{self._cohn.ip_address}/" if self._cohn else "http://10.5.5.9:8080/" diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/logger.py b/demos/python/sdk_wireless_camera_control/open_gopro/logger.py index 6c863180..4762238f 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/logger.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/logger.py @@ -46,14 +46,15 @@ def __init__( "open_gopro.gopro_wired", "open_gopro.gopro_wireless", "open_gopro.api.builders", + "open_gopro.api.parsers", "open_gopro.api.http_commands", "open_gopro.api.ble_commands", - "open_gopro.communication_client", + "open_gopro.communicator_interface", "open_gopro.ble.adapters.bleak_wrapper", "open_gopro.ble.client", "open_gopro.wifi.adapters.wireless", "open_gopro.wifi.mdns_scanner", - "open_gopro.responses", + "open_gopro.models.response", "open_gopro.util", "bleak", "urllib3", diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/models/general.py b/demos/python/sdk_wireless_camera_control/open_gopro/models/general.py index 4c2497ea..3a5ded56 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/models/general.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/models/general.py @@ -62,7 +62,6 @@ class HttpInvalidSettingResponse(CustomBaseModel): supported_options: Optional[list[SupportedOption]] = Field(default=None) -# TODO add to / from json methods @dataclass class CohnInfo: """Data model to store Camera on the Home Network connection info""" @@ -76,6 +75,5 @@ class CohnInfo: def __post_init__(self) -> None: token = b64encode(f"{self.username}:{self.password}".encode("utf-8")).decode("ascii") self.auth_token = f"Basic {token}" - # self.token = f"Basic {token}" with open(self.cert_path, "w") as fp: fp.write(self.certificate) diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/models/media_list.py b/demos/python/sdk_wireless_camera_control/open_gopro/models/media_list.py index f00966ef..3077b226 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/models/media_list.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/models/media_list.py @@ -24,6 +24,18 @@ class MediaPath(ABC, CustomBaseModel): folder: str #: directory that media lives in file: str #: media file name (including file extension) + @property + def as_path(self) -> str: + """Return the model as a camera path (folder/file) + + Returns: + str: camera path + """ + return f"{self.folder}/{self.file}" + + def __str__(self) -> str: + return self.as_path + ############################################################################################################## # Metadata @@ -155,13 +167,17 @@ class MediaList(CustomBaseModel): def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - # self.thing = 1 # Modify each file name to use full path for directory in self.media: for media in directory.file_system: media.filename = f"{directory.directory}/{media.filename}" self._files.append(media) + def __contains__(self, key: MediaItem | MediaPath | str) -> bool: + if isinstance(key, MediaItem): + return key in self.files + return str(key) in [m.filename for m in self.files] + @property def files(self) -> list[MediaItem]: """Helper method to get list of media items diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/models/response.py b/demos/python/sdk_wireless_camera_control/open_gopro/models/response.py index dc9a022d..4a20ff5b 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/models/response.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/models/response.py @@ -304,23 +304,31 @@ def is_response_protobuf(self) -> bool: """ return isinstance(self._identifier, (ActionId, FeatureId)) - def _set_response_meta(self) -> None: - """Set the identifier based on what is currently known about the packet""" + @classmethod + def get_response_identifier(cls, uuid: BleUUID, packet: bytearray) -> types.ResponseType: + """Get the identifier based on what is currently known about the packet + + Args: + uuid (BleUUID): UUID packet was received on + packet (bytearray): raw bytes contained in packet + + Returns: + types.ResponseType: identifier of this response + """ # If it's a protobuf command - identifier = self._packet[0] + identifier = packet[0] try: FeatureId(identifier) - self._identifier = ActionId(self._packet[1]) + return ActionId(packet[1]) # Otherwise it's a TLV command except ValueError: - if self._uuid is GoProUUIDs.CQ_SETTINGS_RESP: - self._identifier = SettingId(identifier) - elif self._uuid is GoProUUIDs.CQ_QUERY_RESP: - self._identifier = QueryCmdId(identifier) - elif self._uuid in [GoProUUIDs.CQ_COMMAND_RESP, GoProUUIDs.CN_NET_MGMT_RESP]: - self._identifier = CmdId(identifier) - else: - self._identifier = self._uuid + if uuid is GoProUUIDs.CQ_SETTINGS_RESP: + return SettingId(identifier) + if uuid is GoProUUIDs.CQ_QUERY_RESP: + return QueryCmdId(identifier) + if uuid in [GoProUUIDs.CQ_COMMAND_RESP, GoProUUIDs.CN_NET_MGMT_RESP]: + return CmdId(identifier) + return uuid def set_parser(self, parser: Parser) -> None: """Store a parser. This is optional. @@ -429,15 +437,15 @@ def build(self) -> GoProResp: Returns: GoProResp: built response """ - self._set_response_meta() - buf = self._packet + try: + self._identifier = self.get_response_identifier(self._uuid, self._packet) + buf = self._packet - if not self._is_direct_read: # length byte - buf.pop(0) - if self._is_protobuf: # feature ID byte - buf.pop(0) + if not self._is_direct_read: # length byte + buf.pop(0) + if self._is_protobuf: # feature ID byte + buf.pop(0) - try: parsed: Any = None query_type: type[StatusId] | type[SettingId] | StatusId | SettingId | None = None # Need to delineate QueryCmd responses between settings and status @@ -480,7 +488,7 @@ def build(self) -> GoProResp: if not (parser := GlobalParsers.get_parser(param_id)): # We don't have defined params for all ID's yet. Just store raw bytes logger.warning(f"No parser defined for {param_id}") - camera_state[param_id] = param_val + camera_state[param_id] = param_val.hex(":") continue # These can be more than 1 value so use a list if self._identifier in [ @@ -527,7 +535,7 @@ def build(self) -> GoProResp: if parsed.get("result") == EnumResultGeneric.RESULT_SUCCESS else ErrorCode.ERROR ) - except KeyError as e: + except Exception as e: self._state = RespBuilder._State.ERROR raise ResponseParseError(str(self._identifier), buf) from e diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/parser_interface.py b/demos/python/sdk_wireless_camera_control/open_gopro/parser_interface.py index 7f136c7a..ebaad7f7 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/parser_interface.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/parser_interface.py @@ -120,7 +120,7 @@ def parse(self, data: bytes | bytearray | types.JsonDict) -> T: RuntimeError: attempted to parse bytes when a byte-json adapter does not exist Returns: - T: TODO + T: final parsed output """ parsed_json: types.JsonDict if isinstance(data, (bytes, bytearray)): @@ -196,9 +196,6 @@ class GlobalParsers: """Parsers that relate globally to ID's as opposed to contextualized per-message This is intended to be used as a singleton, i.e. not instantiated - - Returns: - _type_: _description_ """ _feature_action_id_map: ClassVar[dict[FeatureId, list[ActionId]]] = defaultdict(list) diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/cohn_pb2.py b/demos/python/sdk_wireless_camera_control/open_gopro/proto/cohn_pb2.py index d783ef5e..96c6a6b7 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/cohn_pb2.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/cohn_pb2.py @@ -1,37 +1,38 @@ # cohn_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Mon Dec 18 20:40:36 UTC 2023 +# This copyright was auto-generated on Wed Mar 27 22:05:47 UTC 2024 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder - -_sym_db = _symbol_database.Default() -from . import response_generic_pb2 as response__generic__pb2 - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n\ncohn.proto\x12\nopen_gopro\x1a\x16response_generic.proto"4\n\x14RequestGetCOHNStatus\x12\x1c\n\x14register_cohn_status\x18\x01 \x01(\x08"\xd9\x01\n\x10NotifyCOHNStatus\x12*\n\x06status\x18\x01 \x01(\x0e2\x1a.open_gopro.EnumCOHNStatus\x12/\n\x05state\x18\x02 \x01(\x0e2 .open_gopro.EnumCOHNNetworkState\x12\x10\n\x08username\x18\x03 \x01(\t\x12\x10\n\x08password\x18\x04 \x01(\t\x12\x11\n\tipaddress\x18\x05 \x01(\t\x12\x0f\n\x07enabled\x18\x06 \x01(\x08\x12\x0c\n\x04ssid\x18\x07 \x01(\t\x12\x12\n\nmacaddress\x18\x08 \x01(\t")\n\x15RequestCreateCOHNCert\x12\x10\n\x08override\x18\x01 \x01(\x08"\x16\n\x14RequestClearCOHNCert"\x11\n\x0fRequestCOHNCert"O\n\x10ResponseCOHNCert\x12-\n\x06result\x18\x01 \x01(\x0e2\x1d.open_gopro.EnumResultGeneric\x12\x0c\n\x04cert\x18\x02 \x01(\t",\n\x15RequestSetCOHNSetting\x12\x13\n\x0bcohn_active\x18\x01 \x01(\x08*>\n\x0eEnumCOHNStatus\x12\x16\n\x12COHN_UNPROVISIONED\x10\x00\x12\x14\n\x10COHN_PROVISIONED\x10\x01*\xec\x01\n\x14EnumCOHNNetworkState\x12\x13\n\x0fCOHN_STATE_Init\x10\x00\x12\x14\n\x10COHN_STATE_Error\x10\x01\x12\x13\n\x0fCOHN_STATE_Exit\x10\x02\x12\x13\n\x0fCOHN_STATE_Idle\x10\x05\x12\x1f\n\x1bCOHN_STATE_NetworkConnected\x10\x1b\x12"\n\x1eCOHN_STATE_NetworkDisconnected\x10\x1c\x12"\n\x1eCOHN_STATE_ConnectingToNetwork\x10\x1d\x12\x16\n\x12COHN_STATE_Invalid\x10\x1e' -) -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "cohn_pb2", globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _ENUMCOHNSTATUS._serialized_start = 537 - _ENUMCOHNSTATUS._serialized_end = 599 - _ENUMCOHNNETWORKSTATE._serialized_start = 602 - _ENUMCOHNNETWORKSTATE._serialized_end = 838 - _REQUESTGETCOHNSTATUS._serialized_start = 50 - _REQUESTGETCOHNSTATUS._serialized_end = 102 - _NOTIFYCOHNSTATUS._serialized_start = 105 - _NOTIFYCOHNSTATUS._serialized_end = 322 - _REQUESTCREATECOHNCERT._serialized_start = 324 - _REQUESTCREATECOHNCERT._serialized_end = 365 - _REQUESTCLEARCOHNCERT._serialized_start = 367 - _REQUESTCLEARCOHNCERT._serialized_end = 389 - _REQUESTCOHNCERT._serialized_start = 391 - _REQUESTCOHNCERT._serialized_end = 408 - _RESPONSECOHNCERT._serialized_start = 410 - _RESPONSECOHNCERT._serialized_end = 489 - _REQUESTSETCOHNSETTING._serialized_start = 491 - _REQUESTSETCOHNSETTING._serialized_end = 535 +"""Generated protocol buffer code.""" + +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder + +_sym_db = _symbol_database.Default() +from . import response_generic_pb2 as response__generic__pb2 + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\ncohn.proto\x12\nopen_gopro\x1a\x16response_generic.proto"4\n\x14RequestGetCOHNStatus\x12\x1c\n\x14register_cohn_status\x18\x01 \x01(\x08"\xd9\x01\n\x10NotifyCOHNStatus\x12*\n\x06status\x18\x01 \x01(\x0e2\x1a.open_gopro.EnumCOHNStatus\x12/\n\x05state\x18\x02 \x01(\x0e2 .open_gopro.EnumCOHNNetworkState\x12\x10\n\x08username\x18\x03 \x01(\t\x12\x10\n\x08password\x18\x04 \x01(\t\x12\x11\n\tipaddress\x18\x05 \x01(\t\x12\x0f\n\x07enabled\x18\x06 \x01(\x08\x12\x0c\n\x04ssid\x18\x07 \x01(\t\x12\x12\n\nmacaddress\x18\x08 \x01(\t")\n\x15RequestCreateCOHNCert\x12\x10\n\x08override\x18\x01 \x01(\x08"\x16\n\x14RequestClearCOHNCert"\x11\n\x0fRequestCOHNCert"O\n\x10ResponseCOHNCert\x12-\n\x06result\x18\x01 \x01(\x0e2\x1d.open_gopro.EnumResultGeneric\x12\x0c\n\x04cert\x18\x02 \x01(\t",\n\x15RequestSetCOHNSetting\x12\x13\n\x0bcohn_active\x18\x01 \x01(\x08*>\n\x0eEnumCOHNStatus\x12\x16\n\x12COHN_UNPROVISIONED\x10\x00\x12\x14\n\x10COHN_PROVISIONED\x10\x01*\xec\x01\n\x14EnumCOHNNetworkState\x12\x13\n\x0fCOHN_STATE_Init\x10\x00\x12\x14\n\x10COHN_STATE_Error\x10\x01\x12\x13\n\x0fCOHN_STATE_Exit\x10\x02\x12\x13\n\x0fCOHN_STATE_Idle\x10\x05\x12\x1f\n\x1bCOHN_STATE_NetworkConnected\x10\x1b\x12"\n\x1eCOHN_STATE_NetworkDisconnected\x10\x1c\x12"\n\x1eCOHN_STATE_ConnectingToNetwork\x10\x1d\x12\x16\n\x12COHN_STATE_Invalid\x10\x1e' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "cohn_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMCOHNSTATUS._serialized_start = 537 + _ENUMCOHNSTATUS._serialized_end = 599 + _ENUMCOHNNETWORKSTATE._serialized_start = 602 + _ENUMCOHNNETWORKSTATE._serialized_end = 838 + _REQUESTGETCOHNSTATUS._serialized_start = 50 + _REQUESTGETCOHNSTATUS._serialized_end = 102 + _NOTIFYCOHNSTATUS._serialized_start = 105 + _NOTIFYCOHNSTATUS._serialized_end = 322 + _REQUESTCREATECOHNCERT._serialized_start = 324 + _REQUESTCREATECOHNCERT._serialized_end = 365 + _REQUESTCLEARCOHNCERT._serialized_start = 367 + _REQUESTCLEARCOHNCERT._serialized_end = 389 + _REQUESTCOHNCERT._serialized_start = 391 + _REQUESTCOHNCERT._serialized_end = 408 + _RESPONSECOHNCERT._serialized_start = 410 + _RESPONSECOHNCERT._serialized_end = 489 + _REQUESTSETCOHNSETTING._serialized_start = 491 + _REQUESTSETCOHNSETTING._serialized_end = 535 diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/cohn_pb2.pyi b/demos/python/sdk_wireless_camera_control/open_gopro/proto/cohn_pb2.pyi index e0a2d73e..03516118 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/cohn_pb2.pyi +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/cohn_pb2.pyi @@ -1,263 +1,279 @@ -""" -@generated by mypy-protobuf. Do not edit manually! -isort:skip_file -* -Defines the structure of protobuf messages for Camera On the Home Network -""" -import builtins -import google.protobuf.descriptor -import google.protobuf.internal.enum_type_wrapper -import google.protobuf.message -from . import response_generic_pb2 -import sys -import typing - -if sys.version_info >= (3, 10): - import typing as typing_extensions -else: - import typing_extensions -DESCRIPTOR: google.protobuf.descriptor.FileDescriptor - -class _EnumCOHNStatus: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumCOHNStatusEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumCOHNStatus.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - COHN_UNPROVISIONED: _EnumCOHNStatus.ValueType - COHN_PROVISIONED: _EnumCOHNStatus.ValueType - -class EnumCOHNStatus(_EnumCOHNStatus, metaclass=_EnumCOHNStatusEnumTypeWrapper): ... - -COHN_UNPROVISIONED: EnumCOHNStatus.ValueType -COHN_PROVISIONED: EnumCOHNStatus.ValueType -global___EnumCOHNStatus = EnumCOHNStatus - -class _EnumCOHNNetworkState: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumCOHNNetworkStateEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumCOHNNetworkState.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - COHN_STATE_Init: _EnumCOHNNetworkState.ValueType - COHN_STATE_Error: _EnumCOHNNetworkState.ValueType - COHN_STATE_Exit: _EnumCOHNNetworkState.ValueType - COHN_STATE_Idle: _EnumCOHNNetworkState.ValueType - COHN_STATE_NetworkConnected: _EnumCOHNNetworkState.ValueType - COHN_STATE_NetworkDisconnected: _EnumCOHNNetworkState.ValueType - COHN_STATE_ConnectingToNetwork: _EnumCOHNNetworkState.ValueType - COHN_STATE_Invalid: _EnumCOHNNetworkState.ValueType - -class EnumCOHNNetworkState(_EnumCOHNNetworkState, metaclass=_EnumCOHNNetworkStateEnumTypeWrapper): ... - -COHN_STATE_Init: EnumCOHNNetworkState.ValueType -COHN_STATE_Error: EnumCOHNNetworkState.ValueType -COHN_STATE_Exit: EnumCOHNNetworkState.ValueType -COHN_STATE_Idle: EnumCOHNNetworkState.ValueType -COHN_STATE_NetworkConnected: EnumCOHNNetworkState.ValueType -COHN_STATE_NetworkDisconnected: EnumCOHNNetworkState.ValueType -COHN_STATE_ConnectingToNetwork: EnumCOHNNetworkState.ValueType -COHN_STATE_Invalid: EnumCOHNNetworkState.ValueType -global___EnumCOHNNetworkState = EnumCOHNNetworkState - -class RequestGetCOHNStatus(google.protobuf.message.Message): - """* - Get the current COHN status. - - This always returns a @ref NotifyCOHNStatus - - Additionally, asynchronous updates can also be registerd to return more @ref NotifyCOHNStatus when a value - changes. - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - REGISTER_COHN_STATUS_FIELD_NUMBER: builtins.int - register_cohn_status: builtins.bool - "1 to register, 0 to unregister" - - def __init__(self, *, register_cohn_status: builtins.bool | None = ...) -> None: ... - def HasField( - self, field_name: typing_extensions.Literal["register_cohn_status", b"register_cohn_status"] - ) -> builtins.bool: ... - def ClearField( - self, field_name: typing_extensions.Literal["register_cohn_status", b"register_cohn_status"] - ) -> None: ... - -global___RequestGetCOHNStatus = RequestGetCOHNStatus - -class NotifyCOHNStatus(google.protobuf.message.Message): - """ - Current COHN status triggered by a RequestGetCOHNStatus - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - STATUS_FIELD_NUMBER: builtins.int - STATE_FIELD_NUMBER: builtins.int - USERNAME_FIELD_NUMBER: builtins.int - PASSWORD_FIELD_NUMBER: builtins.int - IPADDRESS_FIELD_NUMBER: builtins.int - ENABLED_FIELD_NUMBER: builtins.int - SSID_FIELD_NUMBER: builtins.int - MACADDRESS_FIELD_NUMBER: builtins.int - status: global___EnumCOHNStatus.ValueType - "Current COHN status" - state: global___EnumCOHNNetworkState.ValueType - "Current COHN network state" - username: builtins.str - "Username used for http basic auth header" - password: builtins.str - "Password used for http basic auth header" - ipaddress: builtins.str - "Camera's IP address on the local network" - enabled: builtins.bool - "Is COHN currently enabled" - ssid: builtins.str - "Currently connected SSID" - macaddress: builtins.str - "MAC address of the wifi adapter" - - def __init__( - self, - *, - status: global___EnumCOHNStatus.ValueType | None = ..., - state: global___EnumCOHNNetworkState.ValueType | None = ..., - username: builtins.str | None = ..., - password: builtins.str | None = ..., - ipaddress: builtins.str | None = ..., - enabled: builtins.bool | None = ..., - ssid: builtins.str | None = ..., - macaddress: builtins.str | None = ... - ) -> None: ... - def HasField( - self, - field_name: typing_extensions.Literal[ - "enabled", - b"enabled", - "ipaddress", - b"ipaddress", - "macaddress", - b"macaddress", - "password", - b"password", - "ssid", - b"ssid", - "state", - b"state", - "status", - b"status", - "username", - b"username", - ], - ) -> builtins.bool: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "enabled", - b"enabled", - "ipaddress", - b"ipaddress", - "macaddress", - b"macaddress", - "password", - b"password", - "ssid", - b"ssid", - "state", - b"state", - "status", - b"status", - "username", - b"username", - ], - ) -> None: ... - -global___NotifyCOHNStatus = NotifyCOHNStatus - -class RequestCreateCOHNCert(google.protobuf.message.Message): - """* - Create the COHN certificate. - - Returns a @ref ResponseGeneric with the status of the creation - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - OVERRIDE_FIELD_NUMBER: builtins.int - override: builtins.bool - "Override current provisioning and create new cert" - - def __init__(self, *, override: builtins.bool | None = ...) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["override", b"override"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["override", b"override"]) -> None: ... - -global___RequestCreateCOHNCert = RequestCreateCOHNCert - -class RequestClearCOHNCert(google.protobuf.message.Message): - """* - Clear the COHN certificate. - - Returns a @ref ResponseGeneric with the status of the clear - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - - def __init__(self) -> None: ... - -global___RequestClearCOHNCert = RequestClearCOHNCert - -class RequestCOHNCert(google.protobuf.message.Message): - """* - Get the COHN certificate. - - Returns a @ref ResponseCOHNCert - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - - def __init__(self) -> None: ... - -global___RequestCOHNCert = RequestCOHNCert - -class ResponseCOHNCert(google.protobuf.message.Message): - """ - COHN Certificate response triggered by RequestCOHNCert - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - RESULT_FIELD_NUMBER: builtins.int - CERT_FIELD_NUMBER: builtins.int - result: response_generic_pb2.EnumResultGeneric.ValueType - "Was request successful?" - cert: builtins.str - "Root CA cert (ASCII text)" - - def __init__( - self, *, result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., cert: builtins.str | None = ... - ) -> None: ... - def HasField( - self, field_name: typing_extensions.Literal["cert", b"cert", "result", b"result"] - ) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["cert", b"cert", "result", b"result"]) -> None: ... - -global___ResponseCOHNCert = ResponseCOHNCert - -class RequestSetCOHNSetting(google.protobuf.message.Message): - """* - Enable and disable COHN if provisioned - - Returns a @ref ResponseGeneric - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - COHN_ACTIVE_FIELD_NUMBER: builtins.int - cohn_active: builtins.bool - "1 to enable, 0 to disable" - - def __init__(self, *, cohn_active: builtins.bool | None = ...) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["cohn_active", b"cohn_active"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["cohn_active", b"cohn_active"]) -> None: ... - -global___RequestSetCOHNSetting = RequestSetCOHNSetting +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf messages for Camera On the Home Network +""" + +import builtins +import google.protobuf.descriptor +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +from . import response_generic_pb2 +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumCOHNStatus: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumCOHNStatusEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumCOHNStatus.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + COHN_UNPROVISIONED: _EnumCOHNStatus.ValueType + COHN_PROVISIONED: _EnumCOHNStatus.ValueType + +class EnumCOHNStatus(_EnumCOHNStatus, metaclass=_EnumCOHNStatusEnumTypeWrapper): ... + +COHN_UNPROVISIONED: EnumCOHNStatus.ValueType +COHN_PROVISIONED: EnumCOHNStatus.ValueType +global___EnumCOHNStatus = EnumCOHNStatus + +class _EnumCOHNNetworkState: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumCOHNNetworkStateEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumCOHNNetworkState.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + COHN_STATE_Init: _EnumCOHNNetworkState.ValueType + COHN_STATE_Error: _EnumCOHNNetworkState.ValueType + COHN_STATE_Exit: _EnumCOHNNetworkState.ValueType + COHN_STATE_Idle: _EnumCOHNNetworkState.ValueType + COHN_STATE_NetworkConnected: _EnumCOHNNetworkState.ValueType + COHN_STATE_NetworkDisconnected: _EnumCOHNNetworkState.ValueType + COHN_STATE_ConnectingToNetwork: _EnumCOHNNetworkState.ValueType + COHN_STATE_Invalid: _EnumCOHNNetworkState.ValueType + +class EnumCOHNNetworkState(_EnumCOHNNetworkState, metaclass=_EnumCOHNNetworkStateEnumTypeWrapper): ... + +COHN_STATE_Init: EnumCOHNNetworkState.ValueType +COHN_STATE_Error: EnumCOHNNetworkState.ValueType +COHN_STATE_Exit: EnumCOHNNetworkState.ValueType +COHN_STATE_Idle: EnumCOHNNetworkState.ValueType +COHN_STATE_NetworkConnected: EnumCOHNNetworkState.ValueType +COHN_STATE_NetworkDisconnected: EnumCOHNNetworkState.ValueType +COHN_STATE_ConnectingToNetwork: EnumCOHNNetworkState.ValueType +COHN_STATE_Invalid: EnumCOHNNetworkState.ValueType +global___EnumCOHNNetworkState = EnumCOHNNetworkState + +@typing_extensions.final +class RequestGetCOHNStatus(google.protobuf.message.Message): + """* + Get the current COHN status. + + Response: @ref NotifyCOHNStatus + + Additionally, asynchronous updates can also be registered to return more @ref NotifyCOHNStatus when a value + changes. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + REGISTER_COHN_STATUS_FIELD_NUMBER: builtins.int + register_cohn_status: builtins.bool + "1 to register, 0 to unregister" + + def __init__(self, *, register_cohn_status: builtins.bool | None = ...) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["register_cohn_status", b"register_cohn_status"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["register_cohn_status", b"register_cohn_status"], + ) -> None: ... + +global___RequestGetCOHNStatus = RequestGetCOHNStatus + +@typing_extensions.final +class NotifyCOHNStatus(google.protobuf.message.Message): + """ + Current COHN status triggered by a @ref RequestGetCOHNStatus + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + STATUS_FIELD_NUMBER: builtins.int + STATE_FIELD_NUMBER: builtins.int + USERNAME_FIELD_NUMBER: builtins.int + PASSWORD_FIELD_NUMBER: builtins.int + IPADDRESS_FIELD_NUMBER: builtins.int + ENABLED_FIELD_NUMBER: builtins.int + SSID_FIELD_NUMBER: builtins.int + MACADDRESS_FIELD_NUMBER: builtins.int + status: global___EnumCOHNStatus.ValueType + "Current COHN status" + state: global___EnumCOHNNetworkState.ValueType + "Current COHN network state" + username: builtins.str + "Username used for http basic auth header" + password: builtins.str + "Password used for http basic auth header" + ipaddress: builtins.str + "Camera's IP address on the local network" + enabled: builtins.bool + "Is COHN currently enabled?" + ssid: builtins.str + "Currently connected SSID" + macaddress: builtins.str + "MAC address of the wifi adapter" + + def __init__( + self, + *, + status: global___EnumCOHNStatus.ValueType | None = ..., + state: global___EnumCOHNNetworkState.ValueType | None = ..., + username: builtins.str | None = ..., + password: builtins.str | None = ..., + ipaddress: builtins.str | None = ..., + enabled: builtins.bool | None = ..., + ssid: builtins.str | None = ..., + macaddress: builtins.str | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "enabled", + b"enabled", + "ipaddress", + b"ipaddress", + "macaddress", + b"macaddress", + "password", + b"password", + "ssid", + b"ssid", + "state", + b"state", + "status", + b"status", + "username", + b"username", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "enabled", + b"enabled", + "ipaddress", + b"ipaddress", + "macaddress", + b"macaddress", + "password", + b"password", + "ssid", + b"ssid", + "state", + b"state", + "status", + b"status", + "username", + b"username", + ], + ) -> None: ... + +global___NotifyCOHNStatus = NotifyCOHNStatus + +@typing_extensions.final +class RequestCreateCOHNCert(google.protobuf.message.Message): + """* + Create the Camera On the Home Network SSL/TLS certificate. + + Returns a @ref ResponseGeneric with the status of the creation + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + OVERRIDE_FIELD_NUMBER: builtins.int + override: builtins.bool + "Override current provisioning and create new cert" + + def __init__(self, *, override: builtins.bool | None = ...) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["override", b"override"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["override", b"override"]) -> None: ... + +global___RequestCreateCOHNCert = RequestCreateCOHNCert + +@typing_extensions.final +class RequestClearCOHNCert(google.protobuf.message.Message): + """* + Clear the COHN certificate. + + Returns a @ref ResponseGeneric with the status of the clear + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__(self) -> None: ... + +global___RequestClearCOHNCert = RequestClearCOHNCert + +@typing_extensions.final +class RequestCOHNCert(google.protobuf.message.Message): + """* + Get the COHN certificate. + + Returns a @ref ResponseCOHNCert + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__(self) -> None: ... + +global___RequestCOHNCert = RequestCOHNCert + +@typing_extensions.final +class ResponseCOHNCert(google.protobuf.message.Message): + """ + COHN Certificate response triggered by @ref RequestCOHNCert + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + RESULT_FIELD_NUMBER: builtins.int + CERT_FIELD_NUMBER: builtins.int + result: response_generic_pb2.EnumResultGeneric.ValueType + "Was request successful?" + cert: builtins.str + "Root CA cert (ASCII text)" + + def __init__( + self, *, result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., cert: builtins.str | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["cert", b"cert", "result", b"result"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["cert", b"cert", "result", b"result"], + ) -> None: ... + +global___ResponseCOHNCert = ResponseCOHNCert + +@typing_extensions.final +class RequestSetCOHNSetting(google.protobuf.message.Message): + """* + Configure a COHN Setting + + Returns a @ref ResponseGeneric + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + COHN_ACTIVE_FIELD_NUMBER: builtins.int + cohn_active: builtins.bool + "*\n 1 to enable COHN, 0 to disable COHN\n\n When set to 1, STA Mode connection will be dropped and camera will not automatically re-connect for COHN.\n " + + def __init__(self, *, cohn_active: builtins.bool | None = ...) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["cohn_active", b"cohn_active"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["cohn_active", b"cohn_active"]) -> None: ... + +global___RequestSetCOHNSetting = RequestSetCOHNSetting diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/live_streaming_pb2.py b/demos/python/sdk_wireless_camera_control/open_gopro/proto/live_streaming_pb2.py index 09aa4b94..9accf644 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/live_streaming_pb2.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/live_streaming_pb2.py @@ -1,33 +1,34 @@ # live_streaming_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Mon Dec 18 20:40:36 UTC 2023 +# This copyright was auto-generated on Wed Mar 27 22:05:47 UTC 2024 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder - -_sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n\x14live_streaming.proto\x12\nopen_gopro"\xa4\x04\n\x16NotifyLiveStreamStatus\x12<\n\x12live_stream_status\x18\x01 \x01(\x0e2 .open_gopro.EnumLiveStreamStatus\x12:\n\x11live_stream_error\x18\x02 \x01(\x0e2\x1f.open_gopro.EnumLiveStreamError\x12\x1a\n\x12live_stream_encode\x18\x03 \x01(\x08\x12\x1b\n\x13live_stream_bitrate\x18\x04 \x01(\x05\x12K\n\'live_stream_window_size_supported_array\x18\x05 \x03(\x0e2\x1a.open_gopro.EnumWindowSize\x12$\n\x1clive_stream_encode_supported\x18\x06 \x01(\x08\x12(\n live_stream_max_lens_unsupported\x18\x07 \x01(\x08\x12*\n"live_stream_minimum_stream_bitrate\x18\x08 \x01(\x05\x12*\n"live_stream_maximum_stream_bitrate\x18\t \x01(\x05\x12"\n\x1alive_stream_lens_supported\x18\n \x01(\x08\x12>\n live_stream_lens_supported_array\x18\x0b \x03(\x0e2\x14.open_gopro.EnumLens"\xbc\x01\n\x1aRequestGetLiveStreamStatus\x12M\n\x1bregister_live_stream_status\x18\x01 \x03(\x0e2(.open_gopro.EnumRegisterLiveStreamStatus\x12O\n\x1dunregister_live_stream_status\x18\x02 \x03(\x0e2(.open_gopro.EnumRegisterLiveStreamStatus"\xe6\x01\n\x18RequestSetLiveStreamMode\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x0e\n\x06encode\x18\x02 \x01(\x08\x12/\n\x0bwindow_size\x18\x03 \x01(\x0e2\x1a.open_gopro.EnumWindowSize\x12\x0c\n\x04cert\x18\x06 \x01(\x0c\x12\x17\n\x0fminimum_bitrate\x18\x07 \x01(\x05\x12\x17\n\x0fmaximum_bitrate\x18\x08 \x01(\x05\x12\x18\n\x10starting_bitrate\x18\t \x01(\x05\x12"\n\x04lens\x18\n \x01(\x0e2\x14.open_gopro.EnumLens*>\n\x08EnumLens\x12\r\n\tLENS_WIDE\x10\x00\x12\x0f\n\x0bLENS_LINEAR\x10\x04\x12\x12\n\x0eLENS_SUPERVIEW\x10\x03*\xde\x03\n\x13EnumLiveStreamError\x12\x1a\n\x16LIVE_STREAM_ERROR_NONE\x10\x00\x12\x1d\n\x19LIVE_STREAM_ERROR_NETWORK\x10\x01\x12"\n\x1eLIVE_STREAM_ERROR_CREATESTREAM\x10\x02\x12!\n\x1dLIVE_STREAM_ERROR_OUTOFMEMORY\x10\x03\x12!\n\x1dLIVE_STREAM_ERROR_INPUTSTREAM\x10\x04\x12\x1e\n\x1aLIVE_STREAM_ERROR_INTERNET\x10\x05\x12\x1f\n\x1bLIVE_STREAM_ERROR_OSNETWORK\x10\x06\x12,\n(LIVE_STREAM_ERROR_SELECTEDNETWORKTIMEOUT\x10\x07\x12#\n\x1fLIVE_STREAM_ERROR_SSL_HANDSHAKE\x10\x08\x12$\n LIVE_STREAM_ERROR_CAMERA_BLOCKED\x10\t\x12\x1d\n\x19LIVE_STREAM_ERROR_UNKNOWN\x10\n\x12"\n\x1eLIVE_STREAM_ERROR_SD_CARD_FULL\x10(\x12%\n!LIVE_STREAM_ERROR_SD_CARD_REMOVED\x10)*\x80\x02\n\x14EnumLiveStreamStatus\x12\x1a\n\x16LIVE_STREAM_STATE_IDLE\x10\x00\x12\x1c\n\x18LIVE_STREAM_STATE_CONFIG\x10\x01\x12\x1b\n\x17LIVE_STREAM_STATE_READY\x10\x02\x12\x1f\n\x1bLIVE_STREAM_STATE_STREAMING\x10\x03\x12&\n"LIVE_STREAM_STATE_COMPLETE_STAY_ON\x10\x04\x12$\n LIVE_STREAM_STATE_FAILED_STAY_ON\x10\x05\x12"\n\x1eLIVE_STREAM_STATE_RECONNECTING\x10\x06*\xbc\x01\n\x1cEnumRegisterLiveStreamStatus\x12&\n"REGISTER_LIVE_STREAM_STATUS_STATUS\x10\x01\x12%\n!REGISTER_LIVE_STREAM_STATUS_ERROR\x10\x02\x12$\n REGISTER_LIVE_STREAM_STATUS_MODE\x10\x03\x12\'\n#REGISTER_LIVE_STREAM_STATUS_BITRATE\x10\x04*P\n\x0eEnumWindowSize\x12\x13\n\x0fWINDOW_SIZE_480\x10\x04\x12\x13\n\x0fWINDOW_SIZE_720\x10\x07\x12\x14\n\x10WINDOW_SIZE_1080\x10\x0c' -) -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "live_streaming_pb2", globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _ENUMLENS._serialized_start = 1011 - _ENUMLENS._serialized_end = 1073 - _ENUMLIVESTREAMERROR._serialized_start = 1076 - _ENUMLIVESTREAMERROR._serialized_end = 1554 - _ENUMLIVESTREAMSTATUS._serialized_start = 1557 - _ENUMLIVESTREAMSTATUS._serialized_end = 1813 - _ENUMREGISTERLIVESTREAMSTATUS._serialized_start = 1816 - _ENUMREGISTERLIVESTREAMSTATUS._serialized_end = 2004 - _ENUMWINDOWSIZE._serialized_start = 2006 - _ENUMWINDOWSIZE._serialized_end = 2086 - _NOTIFYLIVESTREAMSTATUS._serialized_start = 37 - _NOTIFYLIVESTREAMSTATUS._serialized_end = 585 - _REQUESTGETLIVESTREAMSTATUS._serialized_start = 588 - _REQUESTGETLIVESTREAMSTATUS._serialized_end = 776 - _REQUESTSETLIVESTREAMMODE._serialized_start = 779 - _REQUESTSETLIVESTREAMMODE._serialized_end = 1009 +"""Generated protocol buffer code.""" + +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder + +_sym_db = _symbol_database.Default() +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x14live_streaming.proto\x12\nopen_gopro"\xa4\x04\n\x16NotifyLiveStreamStatus\x12<\n\x12live_stream_status\x18\x01 \x01(\x0e2 .open_gopro.EnumLiveStreamStatus\x12:\n\x11live_stream_error\x18\x02 \x01(\x0e2\x1f.open_gopro.EnumLiveStreamError\x12\x1a\n\x12live_stream_encode\x18\x03 \x01(\x08\x12\x1b\n\x13live_stream_bitrate\x18\x04 \x01(\x05\x12K\n\'live_stream_window_size_supported_array\x18\x05 \x03(\x0e2\x1a.open_gopro.EnumWindowSize\x12$\n\x1clive_stream_encode_supported\x18\x06 \x01(\x08\x12(\n live_stream_max_lens_unsupported\x18\x07 \x01(\x08\x12*\n"live_stream_minimum_stream_bitrate\x18\x08 \x01(\x05\x12*\n"live_stream_maximum_stream_bitrate\x18\t \x01(\x05\x12"\n\x1alive_stream_lens_supported\x18\n \x01(\x08\x12>\n live_stream_lens_supported_array\x18\x0b \x03(\x0e2\x14.open_gopro.EnumLens"\xbc\x01\n\x1aRequestGetLiveStreamStatus\x12M\n\x1bregister_live_stream_status\x18\x01 \x03(\x0e2(.open_gopro.EnumRegisterLiveStreamStatus\x12O\n\x1dunregister_live_stream_status\x18\x02 \x03(\x0e2(.open_gopro.EnumRegisterLiveStreamStatus"\xe6\x01\n\x18RequestSetLiveStreamMode\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x0e\n\x06encode\x18\x02 \x01(\x08\x12/\n\x0bwindow_size\x18\x03 \x01(\x0e2\x1a.open_gopro.EnumWindowSize\x12\x0c\n\x04cert\x18\x06 \x01(\x0c\x12\x17\n\x0fminimum_bitrate\x18\x07 \x01(\x05\x12\x17\n\x0fmaximum_bitrate\x18\x08 \x01(\x05\x12\x18\n\x10starting_bitrate\x18\t \x01(\x05\x12"\n\x04lens\x18\n \x01(\x0e2\x14.open_gopro.EnumLens*>\n\x08EnumLens\x12\r\n\tLENS_WIDE\x10\x00\x12\x0f\n\x0bLENS_LINEAR\x10\x04\x12\x12\n\x0eLENS_SUPERVIEW\x10\x03*\xde\x03\n\x13EnumLiveStreamError\x12\x1a\n\x16LIVE_STREAM_ERROR_NONE\x10\x00\x12\x1d\n\x19LIVE_STREAM_ERROR_NETWORK\x10\x01\x12"\n\x1eLIVE_STREAM_ERROR_CREATESTREAM\x10\x02\x12!\n\x1dLIVE_STREAM_ERROR_OUTOFMEMORY\x10\x03\x12!\n\x1dLIVE_STREAM_ERROR_INPUTSTREAM\x10\x04\x12\x1e\n\x1aLIVE_STREAM_ERROR_INTERNET\x10\x05\x12\x1f\n\x1bLIVE_STREAM_ERROR_OSNETWORK\x10\x06\x12,\n(LIVE_STREAM_ERROR_SELECTEDNETWORKTIMEOUT\x10\x07\x12#\n\x1fLIVE_STREAM_ERROR_SSL_HANDSHAKE\x10\x08\x12$\n LIVE_STREAM_ERROR_CAMERA_BLOCKED\x10\t\x12\x1d\n\x19LIVE_STREAM_ERROR_UNKNOWN\x10\n\x12"\n\x1eLIVE_STREAM_ERROR_SD_CARD_FULL\x10(\x12%\n!LIVE_STREAM_ERROR_SD_CARD_REMOVED\x10)*\x80\x02\n\x14EnumLiveStreamStatus\x12\x1a\n\x16LIVE_STREAM_STATE_IDLE\x10\x00\x12\x1c\n\x18LIVE_STREAM_STATE_CONFIG\x10\x01\x12\x1b\n\x17LIVE_STREAM_STATE_READY\x10\x02\x12\x1f\n\x1bLIVE_STREAM_STATE_STREAMING\x10\x03\x12&\n"LIVE_STREAM_STATE_COMPLETE_STAY_ON\x10\x04\x12$\n LIVE_STREAM_STATE_FAILED_STAY_ON\x10\x05\x12"\n\x1eLIVE_STREAM_STATE_RECONNECTING\x10\x06*\xbc\x01\n\x1cEnumRegisterLiveStreamStatus\x12&\n"REGISTER_LIVE_STREAM_STATUS_STATUS\x10\x01\x12%\n!REGISTER_LIVE_STREAM_STATUS_ERROR\x10\x02\x12$\n REGISTER_LIVE_STREAM_STATUS_MODE\x10\x03\x12\'\n#REGISTER_LIVE_STREAM_STATUS_BITRATE\x10\x04*P\n\x0eEnumWindowSize\x12\x13\n\x0fWINDOW_SIZE_480\x10\x04\x12\x13\n\x0fWINDOW_SIZE_720\x10\x07\x12\x14\n\x10WINDOW_SIZE_1080\x10\x0c' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "live_streaming_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMLENS._serialized_start = 1011 + _ENUMLENS._serialized_end = 1073 + _ENUMLIVESTREAMERROR._serialized_start = 1076 + _ENUMLIVESTREAMERROR._serialized_end = 1554 + _ENUMLIVESTREAMSTATUS._serialized_start = 1557 + _ENUMLIVESTREAMSTATUS._serialized_end = 1813 + _ENUMREGISTERLIVESTREAMSTATUS._serialized_start = 1816 + _ENUMREGISTERLIVESTREAMSTATUS._serialized_end = 2004 + _ENUMWINDOWSIZE._serialized_start = 2006 + _ENUMWINDOWSIZE._serialized_end = 2086 + _NOTIFYLIVESTREAMSTATUS._serialized_start = 37 + _NOTIFYLIVESTREAMSTATUS._serialized_end = 585 + _REQUESTGETLIVESTREAMSTATUS._serialized_start = 588 + _REQUESTGETLIVESTREAMSTATUS._serialized_end = 776 + _REQUESTSETLIVESTREAMMODE._serialized_start = 779 + _REQUESTSETLIVESTREAMMODE._serialized_end = 1009 diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/live_streaming_pb2.pyi b/demos/python/sdk_wireless_camera_control/open_gopro/proto/live_streaming_pb2.pyi index 2aeb277e..d658661e 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/live_streaming_pb2.pyi +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/live_streaming_pb2.pyi @@ -1,444 +1,458 @@ -""" -@generated by mypy-protobuf. Do not edit manually! -isort:skip_file -* -Defines the structure of protobuf messages for working with Live Streams -""" -import builtins -import collections.abc -import google.protobuf.descriptor -import google.protobuf.internal.containers -import google.protobuf.internal.enum_type_wrapper -import google.protobuf.message -import sys -import typing - -if sys.version_info >= (3, 10): - import typing as typing_extensions -else: - import typing_extensions -DESCRIPTOR: google.protobuf.descriptor.FileDescriptor - -class _EnumLens: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumLensEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumLens.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - LENS_WIDE: _EnumLens.ValueType - LENS_LINEAR: _EnumLens.ValueType - LENS_SUPERVIEW: _EnumLens.ValueType - -class EnumLens(_EnumLens, metaclass=_EnumLensEnumTypeWrapper): ... - -LENS_WIDE: EnumLens.ValueType -LENS_LINEAR: EnumLens.ValueType -LENS_SUPERVIEW: EnumLens.ValueType -global___EnumLens = EnumLens - -class _EnumLiveStreamError: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumLiveStreamErrorEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumLiveStreamError.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - LIVE_STREAM_ERROR_NONE: _EnumLiveStreamError.ValueType - "No error (success)" - LIVE_STREAM_ERROR_NETWORK: _EnumLiveStreamError.ValueType - "General network error during the stream" - LIVE_STREAM_ERROR_CREATESTREAM: _EnumLiveStreamError.ValueType - "Startup error: bad URL or valid with live stream server" - LIVE_STREAM_ERROR_OUTOFMEMORY: _EnumLiveStreamError.ValueType - "Not enough memory on camera to complete task" - LIVE_STREAM_ERROR_INPUTSTREAM: _EnumLiveStreamError.ValueType - "Failed to get stream from low level camera system" - LIVE_STREAM_ERROR_INTERNET: _EnumLiveStreamError.ValueType - "No internet access detected on startup of streamer" - LIVE_STREAM_ERROR_OSNETWORK: _EnumLiveStreamError.ValueType - "Error occured in linux networking stack. usually means the server closed the connection" - LIVE_STREAM_ERROR_SELECTEDNETWORKTIMEOUT: _EnumLiveStreamError.ValueType - "Timed out attemping to connect to the wifi network when attemping live stream" - LIVE_STREAM_ERROR_SSL_HANDSHAKE: _EnumLiveStreamError.ValueType - "SSL handshake failed (commonly caused due to incorrect time / time zone)" - LIVE_STREAM_ERROR_CAMERA_BLOCKED: _EnumLiveStreamError.ValueType - "Low level camera system rejected attempt to start live stream" - LIVE_STREAM_ERROR_UNKNOWN: _EnumLiveStreamError.ValueType - "Unknown" - LIVE_STREAM_ERROR_SD_CARD_FULL: _EnumLiveStreamError.ValueType - "Can not perform livestream because sd card is full" - LIVE_STREAM_ERROR_SD_CARD_REMOVED: _EnumLiveStreamError.ValueType - "Livestream stopped because sd card was removed" - -class EnumLiveStreamError(_EnumLiveStreamError, metaclass=_EnumLiveStreamErrorEnumTypeWrapper): ... - -LIVE_STREAM_ERROR_NONE: EnumLiveStreamError.ValueType -"No error (success)" -LIVE_STREAM_ERROR_NETWORK: EnumLiveStreamError.ValueType -"General network error during the stream" -LIVE_STREAM_ERROR_CREATESTREAM: EnumLiveStreamError.ValueType -"Startup error: bad URL or valid with live stream server" -LIVE_STREAM_ERROR_OUTOFMEMORY: EnumLiveStreamError.ValueType -"Not enough memory on camera to complete task" -LIVE_STREAM_ERROR_INPUTSTREAM: EnumLiveStreamError.ValueType -"Failed to get stream from low level camera system" -LIVE_STREAM_ERROR_INTERNET: EnumLiveStreamError.ValueType -"No internet access detected on startup of streamer" -LIVE_STREAM_ERROR_OSNETWORK: EnumLiveStreamError.ValueType -"Error occured in linux networking stack. usually means the server closed the connection" -LIVE_STREAM_ERROR_SELECTEDNETWORKTIMEOUT: EnumLiveStreamError.ValueType -"Timed out attemping to connect to the wifi network when attemping live stream" -LIVE_STREAM_ERROR_SSL_HANDSHAKE: EnumLiveStreamError.ValueType -"SSL handshake failed (commonly caused due to incorrect time / time zone)" -LIVE_STREAM_ERROR_CAMERA_BLOCKED: EnumLiveStreamError.ValueType -"Low level camera system rejected attempt to start live stream" -LIVE_STREAM_ERROR_UNKNOWN: EnumLiveStreamError.ValueType -"Unknown" -LIVE_STREAM_ERROR_SD_CARD_FULL: EnumLiveStreamError.ValueType -"Can not perform livestream because sd card is full" -LIVE_STREAM_ERROR_SD_CARD_REMOVED: EnumLiveStreamError.ValueType -"Livestream stopped because sd card was removed" -global___EnumLiveStreamError = EnumLiveStreamError - -class _EnumLiveStreamStatus: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumLiveStreamStatusEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumLiveStreamStatus.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - LIVE_STREAM_STATE_IDLE: _EnumLiveStreamStatus.ValueType - "Initial status. Livestream has not yet been configured" - LIVE_STREAM_STATE_CONFIG: _EnumLiveStreamStatus.ValueType - "Livestream is being configured" - LIVE_STREAM_STATE_READY: _EnumLiveStreamStatus.ValueType - "\n Livestream has finished configuration and is ready to start streaming\n " - LIVE_STREAM_STATE_STREAMING: _EnumLiveStreamStatus.ValueType - "Livestream is actively streaming" - LIVE_STREAM_STATE_COMPLETE_STAY_ON: _EnumLiveStreamStatus.ValueType - "Live stream is exiting. No errors occured." - LIVE_STREAM_STATE_FAILED_STAY_ON: _EnumLiveStreamStatus.ValueType - "Live stream is exiting. An error occurred." - LIVE_STREAM_STATE_RECONNECTING: _EnumLiveStreamStatus.ValueType - "An error occurred during livestream and stream is attempting to reconnect." - -class EnumLiveStreamStatus(_EnumLiveStreamStatus, metaclass=_EnumLiveStreamStatusEnumTypeWrapper): ... - -LIVE_STREAM_STATE_IDLE: EnumLiveStreamStatus.ValueType -"Initial status. Livestream has not yet been configured" -LIVE_STREAM_STATE_CONFIG: EnumLiveStreamStatus.ValueType -"Livestream is being configured" -LIVE_STREAM_STATE_READY: EnumLiveStreamStatus.ValueType -"\nLivestream has finished configuration and is ready to start streaming\n" -LIVE_STREAM_STATE_STREAMING: EnumLiveStreamStatus.ValueType -"Livestream is actively streaming" -LIVE_STREAM_STATE_COMPLETE_STAY_ON: EnumLiveStreamStatus.ValueType -"Live stream is exiting. No errors occured." -LIVE_STREAM_STATE_FAILED_STAY_ON: EnumLiveStreamStatus.ValueType -"Live stream is exiting. An error occurred." -LIVE_STREAM_STATE_RECONNECTING: EnumLiveStreamStatus.ValueType -"An error occurred during livestream and stream is attempting to reconnect." -global___EnumLiveStreamStatus = EnumLiveStreamStatus - -class _EnumRegisterLiveStreamStatus: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumRegisterLiveStreamStatusEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumRegisterLiveStreamStatus.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - REGISTER_LIVE_STREAM_STATUS_STATUS: _EnumRegisterLiveStreamStatus.ValueType - REGISTER_LIVE_STREAM_STATUS_ERROR: _EnumRegisterLiveStreamStatus.ValueType - REGISTER_LIVE_STREAM_STATUS_MODE: _EnumRegisterLiveStreamStatus.ValueType - REGISTER_LIVE_STREAM_STATUS_BITRATE: _EnumRegisterLiveStreamStatus.ValueType - -class EnumRegisterLiveStreamStatus( - _EnumRegisterLiveStreamStatus, metaclass=_EnumRegisterLiveStreamStatusEnumTypeWrapper -): ... - -REGISTER_LIVE_STREAM_STATUS_STATUS: EnumRegisterLiveStreamStatus.ValueType -REGISTER_LIVE_STREAM_STATUS_ERROR: EnumRegisterLiveStreamStatus.ValueType -REGISTER_LIVE_STREAM_STATUS_MODE: EnumRegisterLiveStreamStatus.ValueType -REGISTER_LIVE_STREAM_STATUS_BITRATE: EnumRegisterLiveStreamStatus.ValueType -global___EnumRegisterLiveStreamStatus = EnumRegisterLiveStreamStatus - -class _EnumWindowSize: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumWindowSizeEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumWindowSize.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - WINDOW_SIZE_480: _EnumWindowSize.ValueType - WINDOW_SIZE_720: _EnumWindowSize.ValueType - WINDOW_SIZE_1080: _EnumWindowSize.ValueType - -class EnumWindowSize(_EnumWindowSize, metaclass=_EnumWindowSizeEnumTypeWrapper): ... - -WINDOW_SIZE_480: EnumWindowSize.ValueType -WINDOW_SIZE_720: EnumWindowSize.ValueType -WINDOW_SIZE_1080: EnumWindowSize.ValueType -global___EnumWindowSize = EnumWindowSize - -class NotifyLiveStreamStatus(google.protobuf.message.Message): - """* - Live Stream status - - Sent either: - - as a syncrhonous response to initial @ref RequestGetLiveStreamStatus - - as asynchronous notifications registered for via @ref RequestGetLiveStreamStatus - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - LIVE_STREAM_STATUS_FIELD_NUMBER: builtins.int - LIVE_STREAM_ERROR_FIELD_NUMBER: builtins.int - LIVE_STREAM_ENCODE_FIELD_NUMBER: builtins.int - LIVE_STREAM_BITRATE_FIELD_NUMBER: builtins.int - LIVE_STREAM_WINDOW_SIZE_SUPPORTED_ARRAY_FIELD_NUMBER: builtins.int - LIVE_STREAM_ENCODE_SUPPORTED_FIELD_NUMBER: builtins.int - LIVE_STREAM_MAX_LENS_UNSUPPORTED_FIELD_NUMBER: builtins.int - LIVE_STREAM_MINIMUM_STREAM_BITRATE_FIELD_NUMBER: builtins.int - LIVE_STREAM_MAXIMUM_STREAM_BITRATE_FIELD_NUMBER: builtins.int - LIVE_STREAM_LENS_SUPPORTED_FIELD_NUMBER: builtins.int - LIVE_STREAM_LENS_SUPPORTED_ARRAY_FIELD_NUMBER: builtins.int - live_stream_status: global___EnumLiveStreamStatus.ValueType - "Live stream status" - live_stream_error: global___EnumLiveStreamError.ValueType - "Live stream error" - live_stream_encode: builtins.bool - "Is live stream encoding?" - live_stream_bitrate: builtins.int - "Live stream bitrate (Kbps)" - - @property - def live_stream_window_size_supported_array( - self, - ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___EnumWindowSize.ValueType]: - """Set of currently supported resolutions""" - live_stream_encode_supported: builtins.bool - "Does the camera support encoding while live streaming?" - live_stream_max_lens_unsupported: builtins.bool - "Is the Max Lens feature NOT supported?" - live_stream_minimum_stream_bitrate: builtins.int - "Camera-defined minimum bitrate (static) (Kbps)" - live_stream_maximum_stream_bitrate: builtins.int - "Camera-defined maximum bitrate (static) (Kbps)" - live_stream_lens_supported: builtins.bool - "Does camera support setting lens for live streaming?" - - @property - def live_stream_lens_supported_array( - self, - ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___EnumLens.ValueType]: - """Set of currently supported FOV options""" - def __init__( - self, - *, - live_stream_status: global___EnumLiveStreamStatus.ValueType | None = ..., - live_stream_error: global___EnumLiveStreamError.ValueType | None = ..., - live_stream_encode: builtins.bool | None = ..., - live_stream_bitrate: builtins.int | None = ..., - live_stream_window_size_supported_array: collections.abc.Iterable[global___EnumWindowSize.ValueType] - | None = ..., - live_stream_encode_supported: builtins.bool | None = ..., - live_stream_max_lens_unsupported: builtins.bool | None = ..., - live_stream_minimum_stream_bitrate: builtins.int | None = ..., - live_stream_maximum_stream_bitrate: builtins.int | None = ..., - live_stream_lens_supported: builtins.bool | None = ..., - live_stream_lens_supported_array: collections.abc.Iterable[global___EnumLens.ValueType] | None = ... - ) -> None: ... - def HasField( - self, - field_name: typing_extensions.Literal[ - "live_stream_bitrate", - b"live_stream_bitrate", - "live_stream_encode", - b"live_stream_encode", - "live_stream_encode_supported", - b"live_stream_encode_supported", - "live_stream_error", - b"live_stream_error", - "live_stream_lens_supported", - b"live_stream_lens_supported", - "live_stream_max_lens_unsupported", - b"live_stream_max_lens_unsupported", - "live_stream_maximum_stream_bitrate", - b"live_stream_maximum_stream_bitrate", - "live_stream_minimum_stream_bitrate", - b"live_stream_minimum_stream_bitrate", - "live_stream_status", - b"live_stream_status", - ], - ) -> builtins.bool: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "live_stream_bitrate", - b"live_stream_bitrate", - "live_stream_encode", - b"live_stream_encode", - "live_stream_encode_supported", - b"live_stream_encode_supported", - "live_stream_error", - b"live_stream_error", - "live_stream_lens_supported", - b"live_stream_lens_supported", - "live_stream_lens_supported_array", - b"live_stream_lens_supported_array", - "live_stream_max_lens_unsupported", - b"live_stream_max_lens_unsupported", - "live_stream_maximum_stream_bitrate", - b"live_stream_maximum_stream_bitrate", - "live_stream_minimum_stream_bitrate", - b"live_stream_minimum_stream_bitrate", - "live_stream_status", - b"live_stream_status", - "live_stream_window_size_supported_array", - b"live_stream_window_size_supported_array", - ], - ) -> None: ... - -global___NotifyLiveStreamStatus = NotifyLiveStreamStatus - -class RequestGetLiveStreamStatus(google.protobuf.message.Message): - """* - Get the current livestream status (and optionally register for future status changes) - - Both current status and future status changes are sent via @ref NotifyLiveStreamStatus - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - REGISTER_LIVE_STREAM_STATUS_FIELD_NUMBER: builtins.int - UNREGISTER_LIVE_STREAM_STATUS_FIELD_NUMBER: builtins.int - - @property - def register_live_stream_status( - self, - ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[ - global___EnumRegisterLiveStreamStatus.ValueType - ]: - """Array of live stream statuses to be notified about""" - @property - def unregister_live_stream_status( - self, - ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[ - global___EnumRegisterLiveStreamStatus.ValueType - ]: - """Array of live stream statuses to stop being notified about""" - def __init__( - self, - *, - register_live_stream_status: collections.abc.Iterable[global___EnumRegisterLiveStreamStatus.ValueType] - | None = ..., - unregister_live_stream_status: collections.abc.Iterable[global___EnumRegisterLiveStreamStatus.ValueType] - | None = ... - ) -> None: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "register_live_stream_status", - b"register_live_stream_status", - "unregister_live_stream_status", - b"unregister_live_stream_status", - ], - ) -> None: ... - -global___RequestGetLiveStreamStatus = RequestGetLiveStreamStatus - -class RequestSetLiveStreamMode(google.protobuf.message.Message): - """* - Configure lives streaming - - The current livestream status can be queried via @ref RequestGetLiveStreamStatus - - Response: @ref ResponseGeneric - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - URL_FIELD_NUMBER: builtins.int - ENCODE_FIELD_NUMBER: builtins.int - WINDOW_SIZE_FIELD_NUMBER: builtins.int - CERT_FIELD_NUMBER: builtins.int - MINIMUM_BITRATE_FIELD_NUMBER: builtins.int - MAXIMUM_BITRATE_FIELD_NUMBER: builtins.int - STARTING_BITRATE_FIELD_NUMBER: builtins.int - LENS_FIELD_NUMBER: builtins.int - url: builtins.str - "RTMP(S) URL used for live stream" - encode: builtins.bool - "Save media to sdcard while streaming?" - window_size: global___EnumWindowSize.ValueType - "*\n Resolution to use for live stream\n\n The set of supported lenses is only available from the `live_stream_window_size_supported_array` in @ref NotifyLiveStreamStatus)\n " - cert: builtins.bytes - "Certificate for servers that require it" - minimum_bitrate: builtins.int - "Minimum desired bitrate (may or may not be honored)" - maximum_bitrate: builtins.int - "Maximum desired bitrate (may or may not be honored)" - starting_bitrate: builtins.int - "Starting bitrate" - lens: global___EnumLens.ValueType - "*\n Lens to use for live stream\n\n The set of supported lenses is only available from the `live_stream_lens_supported_array` in @ref NotifyLiveStreamStatus)\n " - - def __init__( - self, - *, - url: builtins.str | None = ..., - encode: builtins.bool | None = ..., - window_size: global___EnumWindowSize.ValueType | None = ..., - cert: builtins.bytes | None = ..., - minimum_bitrate: builtins.int | None = ..., - maximum_bitrate: builtins.int | None = ..., - starting_bitrate: builtins.int | None = ..., - lens: global___EnumLens.ValueType | None = ... - ) -> None: ... - def HasField( - self, - field_name: typing_extensions.Literal[ - "cert", - b"cert", - "encode", - b"encode", - "lens", - b"lens", - "maximum_bitrate", - b"maximum_bitrate", - "minimum_bitrate", - b"minimum_bitrate", - "starting_bitrate", - b"starting_bitrate", - "url", - b"url", - "window_size", - b"window_size", - ], - ) -> builtins.bool: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "cert", - b"cert", - "encode", - b"encode", - "lens", - b"lens", - "maximum_bitrate", - b"maximum_bitrate", - "minimum_bitrate", - b"minimum_bitrate", - "starting_bitrate", - b"starting_bitrate", - "url", - b"url", - "window_size", - b"window_size", - ], - ) -> None: ... - -global___RequestSetLiveStreamMode = RequestSetLiveStreamMode +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf messages for working with Live Streams +""" + +import builtins +import collections.abc +import google.protobuf.descriptor +import google.protobuf.internal.containers +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumLens: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumLensEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumLens.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + LENS_WIDE: _EnumLens.ValueType + LENS_LINEAR: _EnumLens.ValueType + LENS_SUPERVIEW: _EnumLens.ValueType + +class EnumLens(_EnumLens, metaclass=_EnumLensEnumTypeWrapper): ... + +LENS_WIDE: EnumLens.ValueType +LENS_LINEAR: EnumLens.ValueType +LENS_SUPERVIEW: EnumLens.ValueType +global___EnumLens = EnumLens + +class _EnumLiveStreamError: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumLiveStreamErrorEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumLiveStreamError.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + LIVE_STREAM_ERROR_NONE: _EnumLiveStreamError.ValueType + "No error (success)" + LIVE_STREAM_ERROR_NETWORK: _EnumLiveStreamError.ValueType + "General network error during the stream" + LIVE_STREAM_ERROR_CREATESTREAM: _EnumLiveStreamError.ValueType + "Startup error: bad URL or valid with live stream server" + LIVE_STREAM_ERROR_OUTOFMEMORY: _EnumLiveStreamError.ValueType + "Not enough memory on camera to complete task" + LIVE_STREAM_ERROR_INPUTSTREAM: _EnumLiveStreamError.ValueType + "Failed to get stream from low level camera system" + LIVE_STREAM_ERROR_INTERNET: _EnumLiveStreamError.ValueType + "No internet access detected on startup of streamer" + LIVE_STREAM_ERROR_OSNETWORK: _EnumLiveStreamError.ValueType + "Error occured in linux networking stack. Usually means the server closed the connection" + LIVE_STREAM_ERROR_SELECTEDNETWORKTIMEOUT: _EnumLiveStreamError.ValueType + "Timed out attemping to connect to the wifi network when attemping live stream" + LIVE_STREAM_ERROR_SSL_HANDSHAKE: _EnumLiveStreamError.ValueType + "SSL handshake failed (commonly caused due to incorrect time / time zone)" + LIVE_STREAM_ERROR_CAMERA_BLOCKED: _EnumLiveStreamError.ValueType + "Low level camera system rejected attempt to start live stream" + LIVE_STREAM_ERROR_UNKNOWN: _EnumLiveStreamError.ValueType + "Unknown" + LIVE_STREAM_ERROR_SD_CARD_FULL: _EnumLiveStreamError.ValueType + "Can not perform livestream because sd card is full" + LIVE_STREAM_ERROR_SD_CARD_REMOVED: _EnumLiveStreamError.ValueType + "Livestream stopped because sd card was removed" + +class EnumLiveStreamError(_EnumLiveStreamError, metaclass=_EnumLiveStreamErrorEnumTypeWrapper): ... + +LIVE_STREAM_ERROR_NONE: EnumLiveStreamError.ValueType +"No error (success)" +LIVE_STREAM_ERROR_NETWORK: EnumLiveStreamError.ValueType +"General network error during the stream" +LIVE_STREAM_ERROR_CREATESTREAM: EnumLiveStreamError.ValueType +"Startup error: bad URL or valid with live stream server" +LIVE_STREAM_ERROR_OUTOFMEMORY: EnumLiveStreamError.ValueType +"Not enough memory on camera to complete task" +LIVE_STREAM_ERROR_INPUTSTREAM: EnumLiveStreamError.ValueType +"Failed to get stream from low level camera system" +LIVE_STREAM_ERROR_INTERNET: EnumLiveStreamError.ValueType +"No internet access detected on startup of streamer" +LIVE_STREAM_ERROR_OSNETWORK: EnumLiveStreamError.ValueType +"Error occured in linux networking stack. Usually means the server closed the connection" +LIVE_STREAM_ERROR_SELECTEDNETWORKTIMEOUT: EnumLiveStreamError.ValueType +"Timed out attemping to connect to the wifi network when attemping live stream" +LIVE_STREAM_ERROR_SSL_HANDSHAKE: EnumLiveStreamError.ValueType +"SSL handshake failed (commonly caused due to incorrect time / time zone)" +LIVE_STREAM_ERROR_CAMERA_BLOCKED: EnumLiveStreamError.ValueType +"Low level camera system rejected attempt to start live stream" +LIVE_STREAM_ERROR_UNKNOWN: EnumLiveStreamError.ValueType +"Unknown" +LIVE_STREAM_ERROR_SD_CARD_FULL: EnumLiveStreamError.ValueType +"Can not perform livestream because sd card is full" +LIVE_STREAM_ERROR_SD_CARD_REMOVED: EnumLiveStreamError.ValueType +"Livestream stopped because sd card was removed" +global___EnumLiveStreamError = EnumLiveStreamError + +class _EnumLiveStreamStatus: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumLiveStreamStatusEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumLiveStreamStatus.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + LIVE_STREAM_STATE_IDLE: _EnumLiveStreamStatus.ValueType + "Initial status. Livestream has not yet been configured" + LIVE_STREAM_STATE_CONFIG: _EnumLiveStreamStatus.ValueType + "Livestream is being configured" + LIVE_STREAM_STATE_READY: _EnumLiveStreamStatus.ValueType + "\n Livestream has finished configuration and is ready to start streaming\n " + LIVE_STREAM_STATE_STREAMING: _EnumLiveStreamStatus.ValueType + "Livestream is actively streaming" + LIVE_STREAM_STATE_COMPLETE_STAY_ON: _EnumLiveStreamStatus.ValueType + "Live stream is exiting. No errors occured." + LIVE_STREAM_STATE_FAILED_STAY_ON: _EnumLiveStreamStatus.ValueType + "Live stream is exiting. An error occurred." + LIVE_STREAM_STATE_RECONNECTING: _EnumLiveStreamStatus.ValueType + "An error occurred during livestream and stream is attempting to reconnect." + +class EnumLiveStreamStatus(_EnumLiveStreamStatus, metaclass=_EnumLiveStreamStatusEnumTypeWrapper): ... + +LIVE_STREAM_STATE_IDLE: EnumLiveStreamStatus.ValueType +"Initial status. Livestream has not yet been configured" +LIVE_STREAM_STATE_CONFIG: EnumLiveStreamStatus.ValueType +"Livestream is being configured" +LIVE_STREAM_STATE_READY: EnumLiveStreamStatus.ValueType +"\nLivestream has finished configuration and is ready to start streaming\n" +LIVE_STREAM_STATE_STREAMING: EnumLiveStreamStatus.ValueType +"Livestream is actively streaming" +LIVE_STREAM_STATE_COMPLETE_STAY_ON: EnumLiveStreamStatus.ValueType +"Live stream is exiting. No errors occured." +LIVE_STREAM_STATE_FAILED_STAY_ON: EnumLiveStreamStatus.ValueType +"Live stream is exiting. An error occurred." +LIVE_STREAM_STATE_RECONNECTING: EnumLiveStreamStatus.ValueType +"An error occurred during livestream and stream is attempting to reconnect." +global___EnumLiveStreamStatus = EnumLiveStreamStatus + +class _EnumRegisterLiveStreamStatus: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumRegisterLiveStreamStatusEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumRegisterLiveStreamStatus.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + REGISTER_LIVE_STREAM_STATUS_STATUS: _EnumRegisterLiveStreamStatus.ValueType + REGISTER_LIVE_STREAM_STATUS_ERROR: _EnumRegisterLiveStreamStatus.ValueType + REGISTER_LIVE_STREAM_STATUS_MODE: _EnumRegisterLiveStreamStatus.ValueType + REGISTER_LIVE_STREAM_STATUS_BITRATE: _EnumRegisterLiveStreamStatus.ValueType + +class EnumRegisterLiveStreamStatus( + _EnumRegisterLiveStreamStatus, + metaclass=_EnumRegisterLiveStreamStatusEnumTypeWrapper, +): ... + +REGISTER_LIVE_STREAM_STATUS_STATUS: EnumRegisterLiveStreamStatus.ValueType +REGISTER_LIVE_STREAM_STATUS_ERROR: EnumRegisterLiveStreamStatus.ValueType +REGISTER_LIVE_STREAM_STATUS_MODE: EnumRegisterLiveStreamStatus.ValueType +REGISTER_LIVE_STREAM_STATUS_BITRATE: EnumRegisterLiveStreamStatus.ValueType +global___EnumRegisterLiveStreamStatus = EnumRegisterLiveStreamStatus + +class _EnumWindowSize: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumWindowSizeEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumWindowSize.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + WINDOW_SIZE_480: _EnumWindowSize.ValueType + WINDOW_SIZE_720: _EnumWindowSize.ValueType + WINDOW_SIZE_1080: _EnumWindowSize.ValueType + +class EnumWindowSize(_EnumWindowSize, metaclass=_EnumWindowSizeEnumTypeWrapper): ... + +WINDOW_SIZE_480: EnumWindowSize.ValueType +WINDOW_SIZE_720: EnumWindowSize.ValueType +WINDOW_SIZE_1080: EnumWindowSize.ValueType +global___EnumWindowSize = EnumWindowSize + +@typing_extensions.final +class NotifyLiveStreamStatus(google.protobuf.message.Message): + """* + Live Stream status + + Sent either: + + - As a synchronous response to initial @ref RequestGetLiveStreamStatus + - As an asynchronous notifications registered for via @ref RequestGetLiveStreamStatus + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + LIVE_STREAM_STATUS_FIELD_NUMBER: builtins.int + LIVE_STREAM_ERROR_FIELD_NUMBER: builtins.int + LIVE_STREAM_ENCODE_FIELD_NUMBER: builtins.int + LIVE_STREAM_BITRATE_FIELD_NUMBER: builtins.int + LIVE_STREAM_WINDOW_SIZE_SUPPORTED_ARRAY_FIELD_NUMBER: builtins.int + LIVE_STREAM_ENCODE_SUPPORTED_FIELD_NUMBER: builtins.int + LIVE_STREAM_MAX_LENS_UNSUPPORTED_FIELD_NUMBER: builtins.int + LIVE_STREAM_MINIMUM_STREAM_BITRATE_FIELD_NUMBER: builtins.int + LIVE_STREAM_MAXIMUM_STREAM_BITRATE_FIELD_NUMBER: builtins.int + LIVE_STREAM_LENS_SUPPORTED_FIELD_NUMBER: builtins.int + LIVE_STREAM_LENS_SUPPORTED_ARRAY_FIELD_NUMBER: builtins.int + live_stream_status: global___EnumLiveStreamStatus.ValueType + "Live stream status" + live_stream_error: global___EnumLiveStreamError.ValueType + "Live stream error" + live_stream_encode: builtins.bool + "Is live stream encoding?" + live_stream_bitrate: builtins.int + "Live stream bitrate (Kbps)" + + @property + def live_stream_window_size_supported_array( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___EnumWindowSize.ValueType]: + """Set of currently supported resolutions""" + live_stream_encode_supported: builtins.bool + "Does the camera support encoding while live streaming?" + live_stream_max_lens_unsupported: builtins.bool + "Is the Max Lens feature NOT supported?" + live_stream_minimum_stream_bitrate: builtins.int + "Camera-defined minimum bitrate (static) (Kbps)" + live_stream_maximum_stream_bitrate: builtins.int + "Camera-defined maximum bitrate (static) (Kbps)" + live_stream_lens_supported: builtins.bool + "Does camera support setting lens for live streaming?" + + @property + def live_stream_lens_supported_array( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___EnumLens.ValueType]: + """Set of currently supported FOV options""" + def __init__( + self, + *, + live_stream_status: global___EnumLiveStreamStatus.ValueType | None = ..., + live_stream_error: global___EnumLiveStreamError.ValueType | None = ..., + live_stream_encode: builtins.bool | None = ..., + live_stream_bitrate: builtins.int | None = ..., + live_stream_window_size_supported_array: ( + collections.abc.Iterable[global___EnumWindowSize.ValueType] | None + ) = ..., + live_stream_encode_supported: builtins.bool | None = ..., + live_stream_max_lens_unsupported: builtins.bool | None = ..., + live_stream_minimum_stream_bitrate: builtins.int | None = ..., + live_stream_maximum_stream_bitrate: builtins.int | None = ..., + live_stream_lens_supported: builtins.bool | None = ..., + live_stream_lens_supported_array: (collections.abc.Iterable[global___EnumLens.ValueType] | None) = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "live_stream_bitrate", + b"live_stream_bitrate", + "live_stream_encode", + b"live_stream_encode", + "live_stream_encode_supported", + b"live_stream_encode_supported", + "live_stream_error", + b"live_stream_error", + "live_stream_lens_supported", + b"live_stream_lens_supported", + "live_stream_max_lens_unsupported", + b"live_stream_max_lens_unsupported", + "live_stream_maximum_stream_bitrate", + b"live_stream_maximum_stream_bitrate", + "live_stream_minimum_stream_bitrate", + b"live_stream_minimum_stream_bitrate", + "live_stream_status", + b"live_stream_status", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "live_stream_bitrate", + b"live_stream_bitrate", + "live_stream_encode", + b"live_stream_encode", + "live_stream_encode_supported", + b"live_stream_encode_supported", + "live_stream_error", + b"live_stream_error", + "live_stream_lens_supported", + b"live_stream_lens_supported", + "live_stream_lens_supported_array", + b"live_stream_lens_supported_array", + "live_stream_max_lens_unsupported", + b"live_stream_max_lens_unsupported", + "live_stream_maximum_stream_bitrate", + b"live_stream_maximum_stream_bitrate", + "live_stream_minimum_stream_bitrate", + b"live_stream_minimum_stream_bitrate", + "live_stream_status", + b"live_stream_status", + "live_stream_window_size_supported_array", + b"live_stream_window_size_supported_array", + ], + ) -> None: ... + +global___NotifyLiveStreamStatus = NotifyLiveStreamStatus + +@typing_extensions.final +class RequestGetLiveStreamStatus(google.protobuf.message.Message): + """* + Get the current livestream status (and optionally register for future status changes) + + Response: @ref NotifyLiveStreamStatus + + Notification: @ref NotifyLiveStreamStatus + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + REGISTER_LIVE_STREAM_STATUS_FIELD_NUMBER: builtins.int + UNREGISTER_LIVE_STREAM_STATUS_FIELD_NUMBER: builtins.int + + @property + def register_live_stream_status( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[ + global___EnumRegisterLiveStreamStatus.ValueType + ]: + """Array of live stream statuses to be notified about""" + @property + def unregister_live_stream_status( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[ + global___EnumRegisterLiveStreamStatus.ValueType + ]: + """Array of live stream statuses to stop being notified about""" + def __init__( + self, + *, + register_live_stream_status: ( + collections.abc.Iterable[global___EnumRegisterLiveStreamStatus.ValueType] | None + ) = ..., + unregister_live_stream_status: ( + collections.abc.Iterable[global___EnumRegisterLiveStreamStatus.ValueType] | None + ) = ... + ) -> None: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "register_live_stream_status", + b"register_live_stream_status", + "unregister_live_stream_status", + b"unregister_live_stream_status", + ], + ) -> None: ... + +global___RequestGetLiveStreamStatus = RequestGetLiveStreamStatus + +@typing_extensions.final +class RequestSetLiveStreamMode(google.protobuf.message.Message): + """* + Configure Live Streaming + + Response: @ref ResponseGeneric + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + URL_FIELD_NUMBER: builtins.int + ENCODE_FIELD_NUMBER: builtins.int + WINDOW_SIZE_FIELD_NUMBER: builtins.int + CERT_FIELD_NUMBER: builtins.int + MINIMUM_BITRATE_FIELD_NUMBER: builtins.int + MAXIMUM_BITRATE_FIELD_NUMBER: builtins.int + STARTING_BITRATE_FIELD_NUMBER: builtins.int + LENS_FIELD_NUMBER: builtins.int + url: builtins.str + "RTMP(S) URL used for live stream" + encode: builtins.bool + "Save media to sdcard while streaming?" + window_size: global___EnumWindowSize.ValueType + "*\n Resolution to use for live stream\n\n The set of supported lenses is only available from the `live_stream_window_size_supported_array` in @ref NotifyLiveStreamStatus)\n " + cert: builtins.bytes + "Certificate for servers that require it in PEM format" + minimum_bitrate: builtins.int + "Minimum desired bitrate (may or may not be honored)" + maximum_bitrate: builtins.int + "Maximum desired bitrate (may or may not be honored)" + starting_bitrate: builtins.int + "Starting bitrate" + lens: global___EnumLens.ValueType + "*\n Lens to use for live stream\n\n The set of supported lenses is only available from the `live_stream_lens_supported_array` in @ref NotifyLiveStreamStatus)\n " + + def __init__( + self, + *, + url: builtins.str | None = ..., + encode: builtins.bool | None = ..., + window_size: global___EnumWindowSize.ValueType | None = ..., + cert: builtins.bytes | None = ..., + minimum_bitrate: builtins.int | None = ..., + maximum_bitrate: builtins.int | None = ..., + starting_bitrate: builtins.int | None = ..., + lens: global___EnumLens.ValueType | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "cert", + b"cert", + "encode", + b"encode", + "lens", + b"lens", + "maximum_bitrate", + b"maximum_bitrate", + "minimum_bitrate", + b"minimum_bitrate", + "starting_bitrate", + b"starting_bitrate", + "url", + b"url", + "window_size", + b"window_size", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "cert", + b"cert", + "encode", + b"encode", + "lens", + b"lens", + "maximum_bitrate", + b"maximum_bitrate", + "minimum_bitrate", + b"minimum_bitrate", + "starting_bitrate", + b"starting_bitrate", + "url", + b"url", + "window_size", + b"window_size", + ], + ) -> None: ... + +global___RequestSetLiveStreamMode = RequestSetLiveStreamMode diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/media_pb2.py b/demos/python/sdk_wireless_camera_control/open_gopro/proto/media_pb2.py index 05ef3d94..e9241b14 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/media_pb2.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/media_pb2.py @@ -1,23 +1,24 @@ # media_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Mon Dec 18 20:40:36 UTC 2023 +# This copyright was auto-generated on Wed Mar 27 22:05:47 UTC 2024 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder - -_sym_db = _symbol_database.Default() -from . import response_generic_pb2 as response__generic__pb2 - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n\x0bmedia.proto\x12\nopen_gopro\x1a\x16response_generic.proto"\x1d\n\x1bRequestGetLastCapturedMedia"l\n\x19ResponseLastCapturedMedia\x12-\n\x06result\x18\x01 \x01(\x0e2\x1d.open_gopro.EnumResultGeneric\x12 \n\x05media\x18\x02 \x01(\x0b2\x11.open_gopro.Media' -) -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "media_pb2", globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _REQUESTGETLASTCAPTUREDMEDIA._serialized_start = 51 - _REQUESTGETLASTCAPTUREDMEDIA._serialized_end = 80 - _RESPONSELASTCAPTUREDMEDIA._serialized_start = 82 - _RESPONSELASTCAPTUREDMEDIA._serialized_end = 190 +"""Generated protocol buffer code.""" + +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder + +_sym_db = _symbol_database.Default() +from . import response_generic_pb2 as response__generic__pb2 + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x0bmedia.proto\x12\nopen_gopro\x1a\x16response_generic.proto"\x1d\n\x1bRequestGetLastCapturedMedia"l\n\x19ResponseLastCapturedMedia\x12-\n\x06result\x18\x01 \x01(\x0e2\x1d.open_gopro.EnumResultGeneric\x12 \n\x05media\x18\x02 \x01(\x0b2\x11.open_gopro.Media' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "media_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _REQUESTGETLASTCAPTUREDMEDIA._serialized_start = 51 + _REQUESTGETLASTCAPTUREDMEDIA._serialized_end = 80 + _RESPONSELASTCAPTUREDMEDIA._serialized_start = 82 + _RESPONSELASTCAPTUREDMEDIA._serialized_end = 190 diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/media_pb2.pyi b/demos/python/sdk_wireless_camera_control/open_gopro/proto/media_pb2.pyi index 7e0584ba..845282f3 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/media_pb2.pyi +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/media_pb2.pyi @@ -1,64 +1,74 @@ -""" -@generated by mypy-protobuf. Do not edit manually! -isort:skip_file -* -Commands to query and manipulate media files -""" -import builtins -import google.protobuf.descriptor -import google.protobuf.message -from . import response_generic_pb2 -import sys - -if sys.version_info >= (3, 8): - import typing as typing_extensions -else: - import typing_extensions -DESCRIPTOR: google.protobuf.descriptor.FileDescriptor - -class RequestGetLastCapturedMedia(google.protobuf.message.Message): - """* - Get the last captured media filename - - Returns a @ref ResponseLastCapturedMedia - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - - def __init__(self) -> None: ... - -global___RequestGetLastCapturedMedia = RequestGetLastCapturedMedia - -class ResponseLastCapturedMedia(google.protobuf.message.Message): - """* - Message sent in response to a @ref RequestGetLastCapturedMedia - - This contains the complete path of the last captured media. Depending on the type of media captured, it will return: - - - Single photo / video: The single media path - - Any grouped media: The path to the first captured media in the group - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - RESULT_FIELD_NUMBER: builtins.int - MEDIA_FIELD_NUMBER: builtins.int - result: response_generic_pb2.EnumResultGeneric.ValueType - "Was the request successful?" - - @property - def media(self) -> response_generic_pb2.Media: - """* - Last captured media if result is RESULT_SUCCESS. Invalid if result is RESULT_RESOURCE_NOT_AVAILBLE. - """ - def __init__( - self, - *, - result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., - media: response_generic_pb2.Media | None = ... - ) -> None: ... - def HasField( - self, field_name: typing_extensions.Literal["media", b"media", "result", b"result"] - ) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["media", b"media", "result", b"result"]) -> None: ... - -global___ResponseLastCapturedMedia = ResponseLastCapturedMedia +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Commands to query and manipulate media files +""" + +import builtins +import google.protobuf.descriptor +import google.protobuf.message +from . import response_generic_pb2 +import sys + +if sys.version_info >= (3, 8): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +@typing_extensions.final +class RequestGetLastCapturedMedia(google.protobuf.message.Message): + """* + Get the last captured media filename + + Returns a @ref ResponseLastCapturedMedia + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__(self) -> None: ... + +global___RequestGetLastCapturedMedia = RequestGetLastCapturedMedia + +@typing_extensions.final +class ResponseLastCapturedMedia(google.protobuf.message.Message): + """* + The Last Captured Media + + Message is sent in response to a @ref RequestGetLastCapturedMedia. + + This contains the relative path of the last captured media starting from the `DCIM` directory on the SDCard. Depending + on the type of media captured, it will return: + + - The single media path for single photo/video media + - The path to the first captured media in the group for grouped media + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + RESULT_FIELD_NUMBER: builtins.int + MEDIA_FIELD_NUMBER: builtins.int + result: response_generic_pb2.EnumResultGeneric.ValueType + "Was the request successful?" + + @property + def media(self) -> response_generic_pb2.Media: + """* + Last captured media if result is RESULT_SUCCESS. Invalid if result is RESULT_RESOURCE_NOT_AVAILBLE. + """ + def __init__( + self, + *, + result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., + media: response_generic_pb2.Media | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["media", b"media", "result", b"result"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["media", b"media", "result", b"result"], + ) -> None: ... + +global___ResponseLastCapturedMedia = ResponseLastCapturedMedia diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/network_management_pb2.py b/demos/python/sdk_wireless_camera_control/open_gopro/proto/network_management_pb2.py index be49fe85..9c00171d 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/network_management_pb2.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/network_management_pb2.py @@ -1,49 +1,50 @@ # network_management_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Mon Dec 18 20:40:36 UTC 2023 +# This copyright was auto-generated on Wed Mar 27 22:05:47 UTC 2024 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder - -_sym_db = _symbol_database.Default() -from . import response_generic_pb2 as response__generic__pb2 - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n\x18network_management.proto\x12\nopen_gopro\x1a\x16response_generic.proto"R\n\x16NotifProvisioningState\x128\n\x12provisioning_state\x18\x01 \x02(\x0e2\x1c.open_gopro.EnumProvisioning"\x8d\x01\n\x12NotifStartScanning\x120\n\x0escanning_state\x18\x01 \x02(\x0e2\x18.open_gopro.EnumScanning\x12\x0f\n\x07scan_id\x18\x02 \x01(\x05\x12\x15\n\rtotal_entries\x18\x03 \x01(\x05\x12\x1d\n\x15total_configured_ssid\x18\x04 \x02(\x05"\x1e\n\x0eRequestConnect\x12\x0c\n\x04ssid\x18\x01 \x02(\t"\x93\x01\n\x11RequestConnectNew\x12\x0c\n\x04ssid\x18\x01 \x02(\t\x12\x10\n\x08password\x18\x02 \x02(\t\x12\x11\n\tstatic_ip\x18\x03 \x01(\x0c\x12\x0f\n\x07gateway\x18\x04 \x01(\x0c\x12\x0e\n\x06subnet\x18\x05 \x01(\x0c\x12\x13\n\x0bdns_primary\x18\x06 \x01(\x0c\x12\x15\n\rdns_secondary\x18\x07 \x01(\x0c"P\n\x13RequestGetApEntries\x12\x13\n\x0bstart_index\x18\x01 \x02(\x05\x12\x13\n\x0bmax_entries\x18\x02 \x02(\x05\x12\x0f\n\x07scan_id\x18\x03 \x02(\x05"\x17\n\x15RequestReleaseNetwork"\x12\n\x10RequestStartScan"\x93\x01\n\x0fResponseConnect\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric\x128\n\x12provisioning_state\x18\x02 \x02(\x0e2\x1c.open_gopro.EnumProvisioning\x12\x17\n\x0ftimeout_seconds\x18\x03 \x02(\x05"\x96\x01\n\x12ResponseConnectNew\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric\x128\n\x12provisioning_state\x18\x02 \x02(\x0e2\x1c.open_gopro.EnumProvisioning\x12\x17\n\x0ftimeout_seconds\x18\x03 \x02(\x05"\x84\x02\n\x14ResponseGetApEntries\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric\x12\x0f\n\x07scan_id\x18\x02 \x02(\x05\x12;\n\x07entries\x18\x03 \x03(\x0b2*.open_gopro.ResponseGetApEntries.ScanEntry\x1ao\n\tScanEntry\x12\x0c\n\x04ssid\x18\x01 \x02(\t\x12\x1c\n\x14signal_strength_bars\x18\x02 \x02(\x05\x12\x1c\n\x14signal_frequency_mhz\x18\x04 \x02(\x05\x12\x18\n\x10scan_entry_flags\x18\x05 \x02(\x05"x\n\x15ResponseStartScanning\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric\x120\n\x0escanning_state\x18\x02 \x02(\x0e2\x18.open_gopro.EnumScanning*\xb5\x03\n\x10EnumProvisioning\x12\x18\n\x14PROVISIONING_UNKNOWN\x10\x00\x12\x1e\n\x1aPROVISIONING_NEVER_STARTED\x10\x01\x12\x18\n\x14PROVISIONING_STARTED\x10\x02\x12"\n\x1ePROVISIONING_ABORTED_BY_SYSTEM\x10\x03\x12"\n\x1ePROVISIONING_CANCELLED_BY_USER\x10\x04\x12\x1f\n\x1bPROVISIONING_SUCCESS_NEW_AP\x10\x05\x12\x1f\n\x1bPROVISIONING_SUCCESS_OLD_AP\x10\x06\x12*\n&PROVISIONING_ERROR_FAILED_TO_ASSOCIATE\x10\x07\x12$\n PROVISIONING_ERROR_PASSWORD_AUTH\x10\x08\x12$\n PROVISIONING_ERROR_EULA_BLOCKING\x10\t\x12"\n\x1ePROVISIONING_ERROR_NO_INTERNET\x10\n\x12\'\n#PROVISIONING_ERROR_UNSUPPORTED_TYPE\x10\x0b*\xac\x01\n\x0cEnumScanning\x12\x14\n\x10SCANNING_UNKNOWN\x10\x00\x12\x1a\n\x16SCANNING_NEVER_STARTED\x10\x01\x12\x14\n\x10SCANNING_STARTED\x10\x02\x12\x1e\n\x1aSCANNING_ABORTED_BY_SYSTEM\x10\x03\x12\x1e\n\x1aSCANNING_CANCELLED_BY_USER\x10\x04\x12\x14\n\x10SCANNING_SUCCESS\x10\x05*\xb2\x01\n\x12EnumScanEntryFlags\x12\x12\n\x0eSCAN_FLAG_OPEN\x10\x00\x12\x1b\n\x17SCAN_FLAG_AUTHENTICATED\x10\x01\x12\x18\n\x14SCAN_FLAG_CONFIGURED\x10\x02\x12\x17\n\x13SCAN_FLAG_BEST_SSID\x10\x04\x12\x18\n\x14SCAN_FLAG_ASSOCIATED\x10\x08\x12\x1e\n\x1aSCAN_FLAG_UNSUPPORTED_TYPE\x10\x10' -) -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "network_management_pb2", globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _ENUMPROVISIONING._serialized_start = 1290 - _ENUMPROVISIONING._serialized_end = 1727 - _ENUMSCANNING._serialized_start = 1730 - _ENUMSCANNING._serialized_end = 1902 - _ENUMSCANENTRYFLAGS._serialized_start = 1905 - _ENUMSCANENTRYFLAGS._serialized_end = 2083 - _NOTIFPROVISIONINGSTATE._serialized_start = 64 - _NOTIFPROVISIONINGSTATE._serialized_end = 146 - _NOTIFSTARTSCANNING._serialized_start = 149 - _NOTIFSTARTSCANNING._serialized_end = 290 - _REQUESTCONNECT._serialized_start = 292 - _REQUESTCONNECT._serialized_end = 322 - _REQUESTCONNECTNEW._serialized_start = 325 - _REQUESTCONNECTNEW._serialized_end = 472 - _REQUESTGETAPENTRIES._serialized_start = 474 - _REQUESTGETAPENTRIES._serialized_end = 554 - _REQUESTRELEASENETWORK._serialized_start = 556 - _REQUESTRELEASENETWORK._serialized_end = 579 - _REQUESTSTARTSCAN._serialized_start = 581 - _REQUESTSTARTSCAN._serialized_end = 599 - _RESPONSECONNECT._serialized_start = 602 - _RESPONSECONNECT._serialized_end = 749 - _RESPONSECONNECTNEW._serialized_start = 752 - _RESPONSECONNECTNEW._serialized_end = 902 - _RESPONSEGETAPENTRIES._serialized_start = 905 - _RESPONSEGETAPENTRIES._serialized_end = 1165 - _RESPONSEGETAPENTRIES_SCANENTRY._serialized_start = 1054 - _RESPONSEGETAPENTRIES_SCANENTRY._serialized_end = 1165 - _RESPONSESTARTSCANNING._serialized_start = 1167 - _RESPONSESTARTSCANNING._serialized_end = 1287 +"""Generated protocol buffer code.""" + +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder + +_sym_db = _symbol_database.Default() +from . import response_generic_pb2 as response__generic__pb2 + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x18network_management.proto\x12\nopen_gopro\x1a\x16response_generic.proto"R\n\x16NotifProvisioningState\x128\n\x12provisioning_state\x18\x01 \x02(\x0e2\x1c.open_gopro.EnumProvisioning"\x8d\x01\n\x12NotifStartScanning\x120\n\x0escanning_state\x18\x01 \x02(\x0e2\x18.open_gopro.EnumScanning\x12\x0f\n\x07scan_id\x18\x02 \x01(\x05\x12\x15\n\rtotal_entries\x18\x03 \x01(\x05\x12\x1d\n\x15total_configured_ssid\x18\x04 \x02(\x05"\x1e\n\x0eRequestConnect\x12\x0c\n\x04ssid\x18\x01 \x02(\t"\x93\x01\n\x11RequestConnectNew\x12\x0c\n\x04ssid\x18\x01 \x02(\t\x12\x10\n\x08password\x18\x02 \x02(\t\x12\x11\n\tstatic_ip\x18\x03 \x01(\x0c\x12\x0f\n\x07gateway\x18\x04 \x01(\x0c\x12\x0e\n\x06subnet\x18\x05 \x01(\x0c\x12\x13\n\x0bdns_primary\x18\x06 \x01(\x0c\x12\x15\n\rdns_secondary\x18\x07 \x01(\x0c"P\n\x13RequestGetApEntries\x12\x13\n\x0bstart_index\x18\x01 \x02(\x05\x12\x13\n\x0bmax_entries\x18\x02 \x02(\x05\x12\x0f\n\x07scan_id\x18\x03 \x02(\x05"\x17\n\x15RequestReleaseNetwork"\x12\n\x10RequestStartScan"\x93\x01\n\x0fResponseConnect\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric\x128\n\x12provisioning_state\x18\x02 \x02(\x0e2\x1c.open_gopro.EnumProvisioning\x12\x17\n\x0ftimeout_seconds\x18\x03 \x02(\x05"\x96\x01\n\x12ResponseConnectNew\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric\x128\n\x12provisioning_state\x18\x02 \x02(\x0e2\x1c.open_gopro.EnumProvisioning\x12\x17\n\x0ftimeout_seconds\x18\x03 \x02(\x05"\x84\x02\n\x14ResponseGetApEntries\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric\x12\x0f\n\x07scan_id\x18\x02 \x02(\x05\x12;\n\x07entries\x18\x03 \x03(\x0b2*.open_gopro.ResponseGetApEntries.ScanEntry\x1ao\n\tScanEntry\x12\x0c\n\x04ssid\x18\x01 \x02(\t\x12\x1c\n\x14signal_strength_bars\x18\x02 \x02(\x05\x12\x1c\n\x14signal_frequency_mhz\x18\x04 \x02(\x05\x12\x18\n\x10scan_entry_flags\x18\x05 \x02(\x05"x\n\x15ResponseStartScanning\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric\x120\n\x0escanning_state\x18\x02 \x02(\x0e2\x18.open_gopro.EnumScanning*\xb5\x03\n\x10EnumProvisioning\x12\x18\n\x14PROVISIONING_UNKNOWN\x10\x00\x12\x1e\n\x1aPROVISIONING_NEVER_STARTED\x10\x01\x12\x18\n\x14PROVISIONING_STARTED\x10\x02\x12"\n\x1ePROVISIONING_ABORTED_BY_SYSTEM\x10\x03\x12"\n\x1ePROVISIONING_CANCELLED_BY_USER\x10\x04\x12\x1f\n\x1bPROVISIONING_SUCCESS_NEW_AP\x10\x05\x12\x1f\n\x1bPROVISIONING_SUCCESS_OLD_AP\x10\x06\x12*\n&PROVISIONING_ERROR_FAILED_TO_ASSOCIATE\x10\x07\x12$\n PROVISIONING_ERROR_PASSWORD_AUTH\x10\x08\x12$\n PROVISIONING_ERROR_EULA_BLOCKING\x10\t\x12"\n\x1ePROVISIONING_ERROR_NO_INTERNET\x10\n\x12\'\n#PROVISIONING_ERROR_UNSUPPORTED_TYPE\x10\x0b*\xac\x01\n\x0cEnumScanning\x12\x14\n\x10SCANNING_UNKNOWN\x10\x00\x12\x1a\n\x16SCANNING_NEVER_STARTED\x10\x01\x12\x14\n\x10SCANNING_STARTED\x10\x02\x12\x1e\n\x1aSCANNING_ABORTED_BY_SYSTEM\x10\x03\x12\x1e\n\x1aSCANNING_CANCELLED_BY_USER\x10\x04\x12\x14\n\x10SCANNING_SUCCESS\x10\x05*\xb2\x01\n\x12EnumScanEntryFlags\x12\x12\n\x0eSCAN_FLAG_OPEN\x10\x00\x12\x1b\n\x17SCAN_FLAG_AUTHENTICATED\x10\x01\x12\x18\n\x14SCAN_FLAG_CONFIGURED\x10\x02\x12\x17\n\x13SCAN_FLAG_BEST_SSID\x10\x04\x12\x18\n\x14SCAN_FLAG_ASSOCIATED\x10\x08\x12\x1e\n\x1aSCAN_FLAG_UNSUPPORTED_TYPE\x10\x10' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "network_management_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMPROVISIONING._serialized_start = 1290 + _ENUMPROVISIONING._serialized_end = 1727 + _ENUMSCANNING._serialized_start = 1730 + _ENUMSCANNING._serialized_end = 1902 + _ENUMSCANENTRYFLAGS._serialized_start = 1905 + _ENUMSCANENTRYFLAGS._serialized_end = 2083 + _NOTIFPROVISIONINGSTATE._serialized_start = 64 + _NOTIFPROVISIONINGSTATE._serialized_end = 146 + _NOTIFSTARTSCANNING._serialized_start = 149 + _NOTIFSTARTSCANNING._serialized_end = 290 + _REQUESTCONNECT._serialized_start = 292 + _REQUESTCONNECT._serialized_end = 322 + _REQUESTCONNECTNEW._serialized_start = 325 + _REQUESTCONNECTNEW._serialized_end = 472 + _REQUESTGETAPENTRIES._serialized_start = 474 + _REQUESTGETAPENTRIES._serialized_end = 554 + _REQUESTRELEASENETWORK._serialized_start = 556 + _REQUESTRELEASENETWORK._serialized_end = 579 + _REQUESTSTARTSCAN._serialized_start = 581 + _REQUESTSTARTSCAN._serialized_end = 599 + _RESPONSECONNECT._serialized_start = 602 + _RESPONSECONNECT._serialized_end = 749 + _RESPONSECONNECTNEW._serialized_start = 752 + _RESPONSECONNECTNEW._serialized_end = 902 + _RESPONSEGETAPENTRIES._serialized_start = 905 + _RESPONSEGETAPENTRIES._serialized_end = 1165 + _RESPONSEGETAPENTRIES_SCANENTRY._serialized_start = 1054 + _RESPONSEGETAPENTRIES_SCANENTRY._serialized_end = 1165 + _RESPONSESTARTSCANNING._serialized_start = 1167 + _RESPONSESTARTSCANNING._serialized_end = 1287 diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/network_management_pb2.pyi b/demos/python/sdk_wireless_camera_control/open_gopro/proto/network_management_pb2.pyi index 3694b6ec..1c81fec4 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/network_management_pb2.pyi +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/network_management_pb2.pyi @@ -1,571 +1,632 @@ -""" -@generated by mypy-protobuf. Do not edit manually! -isort:skip_file -* -Defines the structure of protobuf messages for network management -""" -import builtins -import collections.abc -import google.protobuf.descriptor -import google.protobuf.internal.containers -import google.protobuf.internal.enum_type_wrapper -import google.protobuf.message -from . import response_generic_pb2 -import sys -import typing - -if sys.version_info >= (3, 10): - import typing as typing_extensions -else: - import typing_extensions -DESCRIPTOR: google.protobuf.descriptor.FileDescriptor - -class _EnumProvisioning: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumProvisioningEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumProvisioning.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - PROVISIONING_UNKNOWN: _EnumProvisioning.ValueType - PROVISIONING_NEVER_STARTED: _EnumProvisioning.ValueType - PROVISIONING_STARTED: _EnumProvisioning.ValueType - PROVISIONING_ABORTED_BY_SYSTEM: _EnumProvisioning.ValueType - PROVISIONING_CANCELLED_BY_USER: _EnumProvisioning.ValueType - PROVISIONING_SUCCESS_NEW_AP: _EnumProvisioning.ValueType - PROVISIONING_SUCCESS_OLD_AP: _EnumProvisioning.ValueType - PROVISIONING_ERROR_FAILED_TO_ASSOCIATE: _EnumProvisioning.ValueType - PROVISIONING_ERROR_PASSWORD_AUTH: _EnumProvisioning.ValueType - PROVISIONING_ERROR_EULA_BLOCKING: _EnumProvisioning.ValueType - PROVISIONING_ERROR_NO_INTERNET: _EnumProvisioning.ValueType - PROVISIONING_ERROR_UNSUPPORTED_TYPE: _EnumProvisioning.ValueType - -class EnumProvisioning(_EnumProvisioning, metaclass=_EnumProvisioningEnumTypeWrapper): ... - -PROVISIONING_UNKNOWN: EnumProvisioning.ValueType -PROVISIONING_NEVER_STARTED: EnumProvisioning.ValueType -PROVISIONING_STARTED: EnumProvisioning.ValueType -PROVISIONING_ABORTED_BY_SYSTEM: EnumProvisioning.ValueType -PROVISIONING_CANCELLED_BY_USER: EnumProvisioning.ValueType -PROVISIONING_SUCCESS_NEW_AP: EnumProvisioning.ValueType -PROVISIONING_SUCCESS_OLD_AP: EnumProvisioning.ValueType -PROVISIONING_ERROR_FAILED_TO_ASSOCIATE: EnumProvisioning.ValueType -PROVISIONING_ERROR_PASSWORD_AUTH: EnumProvisioning.ValueType -PROVISIONING_ERROR_EULA_BLOCKING: EnumProvisioning.ValueType -PROVISIONING_ERROR_NO_INTERNET: EnumProvisioning.ValueType -PROVISIONING_ERROR_UNSUPPORTED_TYPE: EnumProvisioning.ValueType -global___EnumProvisioning = EnumProvisioning - -class _EnumScanning: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumScanningEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumScanning.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - SCANNING_UNKNOWN: _EnumScanning.ValueType - SCANNING_NEVER_STARTED: _EnumScanning.ValueType - SCANNING_STARTED: _EnumScanning.ValueType - SCANNING_ABORTED_BY_SYSTEM: _EnumScanning.ValueType - SCANNING_CANCELLED_BY_USER: _EnumScanning.ValueType - SCANNING_SUCCESS: _EnumScanning.ValueType - -class EnumScanning(_EnumScanning, metaclass=_EnumScanningEnumTypeWrapper): ... - -SCANNING_UNKNOWN: EnumScanning.ValueType -SCANNING_NEVER_STARTED: EnumScanning.ValueType -SCANNING_STARTED: EnumScanning.ValueType -SCANNING_ABORTED_BY_SYSTEM: EnumScanning.ValueType -SCANNING_CANCELLED_BY_USER: EnumScanning.ValueType -SCANNING_SUCCESS: EnumScanning.ValueType -global___EnumScanning = EnumScanning - -class _EnumScanEntryFlags: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumScanEntryFlagsEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumScanEntryFlags.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - SCAN_FLAG_OPEN: _EnumScanEntryFlags.ValueType - "This network does not require authentication" - SCAN_FLAG_AUTHENTICATED: _EnumScanEntryFlags.ValueType - "This network requires authentication" - SCAN_FLAG_CONFIGURED: _EnumScanEntryFlags.ValueType - "This network has been previously provisioned" - SCAN_FLAG_BEST_SSID: _EnumScanEntryFlags.ValueType - SCAN_FLAG_ASSOCIATED: _EnumScanEntryFlags.ValueType - "camera is connected to this AP" - SCAN_FLAG_UNSUPPORTED_TYPE: _EnumScanEntryFlags.ValueType - -class EnumScanEntryFlags(_EnumScanEntryFlags, metaclass=_EnumScanEntryFlagsEnumTypeWrapper): ... - -SCAN_FLAG_OPEN: EnumScanEntryFlags.ValueType -"This network does not require authentication" -SCAN_FLAG_AUTHENTICATED: EnumScanEntryFlags.ValueType -"This network requires authentication" -SCAN_FLAG_CONFIGURED: EnumScanEntryFlags.ValueType -"This network has been previously provisioned" -SCAN_FLAG_BEST_SSID: EnumScanEntryFlags.ValueType -SCAN_FLAG_ASSOCIATED: EnumScanEntryFlags.ValueType -"camera is connected to this AP" -SCAN_FLAG_UNSUPPORTED_TYPE: EnumScanEntryFlags.ValueType -global___EnumScanEntryFlags = EnumScanEntryFlags - -class NotifProvisioningState(google.protobuf.message.Message): - """ - Provision state notification - - TODO refernce where this is triggered - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - PROVISIONING_STATE_FIELD_NUMBER: builtins.int - provisioning_state: global___EnumProvisioning.ValueType - "Provisioning / connection state" - - def __init__(self, *, provisioning_state: global___EnumProvisioning.ValueType | None = ...) -> None: ... - def HasField( - self, field_name: typing_extensions.Literal["provisioning_state", b"provisioning_state"] - ) -> builtins.bool: ... - def ClearField( - self, field_name: typing_extensions.Literal["provisioning_state", b"provisioning_state"] - ) -> None: ... - -global___NotifProvisioningState = NotifProvisioningState - -class NotifStartScanning(google.protobuf.message.Message): - """ - Scanning state notification - - Triggered via @ref RequestStartScan - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - SCANNING_STATE_FIELD_NUMBER: builtins.int - SCAN_ID_FIELD_NUMBER: builtins.int - TOTAL_ENTRIES_FIELD_NUMBER: builtins.int - TOTAL_CONFIGURED_SSID_FIELD_NUMBER: builtins.int - scanning_state: global___EnumScanning.ValueType - "Scanning state" - scan_id: builtins.int - "ID associated with scan results (included if scan was successful)" - total_entries: builtins.int - "Number of APs found during scan (included if scan was successful)" - total_configured_ssid: builtins.int - "Total count of camera's provisioned SSIDs" - - def __init__( - self, - *, - scanning_state: global___EnumScanning.ValueType | None = ..., - scan_id: builtins.int | None = ..., - total_entries: builtins.int | None = ..., - total_configured_ssid: builtins.int | None = ... - ) -> None: ... - def HasField( - self, - field_name: typing_extensions.Literal[ - "scan_id", - b"scan_id", - "scanning_state", - b"scanning_state", - "total_configured_ssid", - b"total_configured_ssid", - "total_entries", - b"total_entries", - ], - ) -> builtins.bool: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "scan_id", - b"scan_id", - "scanning_state", - b"scanning_state", - "total_configured_ssid", - b"total_configured_ssid", - "total_entries", - b"total_entries", - ], - ) -> None: ... - -global___NotifStartScanning = NotifStartScanning - -class RequestConnect(google.protobuf.message.Message): - """* - Connect to (but do not authenticate with) an Access Point - - This is intended to be used to connect to a previously-connected Access Point - - Response: @ref ResponseConnect - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - SSID_FIELD_NUMBER: builtins.int - ssid: builtins.str - "AP SSID" - - def __init__(self, *, ssid: builtins.str | None = ...) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["ssid", b"ssid"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["ssid", b"ssid"]) -> None: ... - -global___RequestConnect = RequestConnect - -class RequestConnectNew(google.protobuf.message.Message): - """* - Connect to and authenticate with an Access Point - - This is only intended to be used if the AP is not previously provisioned. - - Response: @ref ResponseConnectNew sent immediately - - Notification: @ref NotifProvisioningState sent periodically as provisioning state changes - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - SSID_FIELD_NUMBER: builtins.int - PASSWORD_FIELD_NUMBER: builtins.int - STATIC_IP_FIELD_NUMBER: builtins.int - GATEWAY_FIELD_NUMBER: builtins.int - SUBNET_FIELD_NUMBER: builtins.int - DNS_PRIMARY_FIELD_NUMBER: builtins.int - DNS_SECONDARY_FIELD_NUMBER: builtins.int - ssid: builtins.str - "AP SSID" - password: builtins.str - "AP password" - static_ip: builtins.bytes - "Static IP address" - gateway: builtins.bytes - "Gateway IP address" - subnet: builtins.bytes - "Subnet mask" - dns_primary: builtins.bytes - "Primary DNS" - dns_secondary: builtins.bytes - "Secondary DNS" - - def __init__( - self, - *, - ssid: builtins.str | None = ..., - password: builtins.str | None = ..., - static_ip: builtins.bytes | None = ..., - gateway: builtins.bytes | None = ..., - subnet: builtins.bytes | None = ..., - dns_primary: builtins.bytes | None = ..., - dns_secondary: builtins.bytes | None = ... - ) -> None: ... - def HasField( - self, - field_name: typing_extensions.Literal[ - "dns_primary", - b"dns_primary", - "dns_secondary", - b"dns_secondary", - "gateway", - b"gateway", - "password", - b"password", - "ssid", - b"ssid", - "static_ip", - b"static_ip", - "subnet", - b"subnet", - ], - ) -> builtins.bool: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "dns_primary", - b"dns_primary", - "dns_secondary", - b"dns_secondary", - "gateway", - b"gateway", - "password", - b"password", - "ssid", - b"ssid", - "static_ip", - b"static_ip", - "subnet", - b"subnet", - ], - ) -> None: ... - -global___RequestConnectNew = RequestConnectNew - -class RequestGetApEntries(google.protobuf.message.Message): - """* - Get a list of Access Points found during a @ref RequestStartScan - - Response: @ref ResponseGetApEntries - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - START_INDEX_FIELD_NUMBER: builtins.int - MAX_ENTRIES_FIELD_NUMBER: builtins.int - SCAN_ID_FIELD_NUMBER: builtins.int - start_index: builtins.int - "Used for paging. 0 <= start_index < @ref ResponseGetApEntries .total_entries" - max_entries: builtins.int - "Used for paging. Value must be < @ref ResponseGetApEntries .total_entries" - scan_id: builtins.int - "ID corresponding to a set of scan results (i.e. @ref ResponseGetApEntries .scan_id)" - - def __init__( - self, - *, - start_index: builtins.int | None = ..., - max_entries: builtins.int | None = ..., - scan_id: builtins.int | None = ... - ) -> None: ... - def HasField( - self, - field_name: typing_extensions.Literal[ - "max_entries", b"max_entries", "scan_id", b"scan_id", "start_index", b"start_index" - ], - ) -> builtins.bool: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "max_entries", b"max_entries", "scan_id", b"scan_id", "start_index", b"start_index" - ], - ) -> None: ... - -global___RequestGetApEntries = RequestGetApEntries - -class RequestReleaseNetwork(google.protobuf.message.Message): - """* - Request to disconnect from current AP network - - Response: @ref ResponseGeneric - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - - def __init__(self) -> None: ... - -global___RequestReleaseNetwork = RequestReleaseNetwork - -class RequestStartScan(google.protobuf.message.Message): - """* - Start scanning for Access Points - - @note Serialization of this object is zero bytes. - - Response: @ref ResponseStartScanning are sent immediately after the camera receives this command - - Notifications: @ref NotifStartScanning are sent periodically as scanning state changes. Use to detect scan complete. - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - - def __init__(self) -> None: ... - -global___RequestStartScan = RequestStartScan - -class ResponseConnect(google.protobuf.message.Message): - """* - The status of an attempt to connect to an Access Point - - Sent as the initial response to @ref RequestConnect - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - RESULT_FIELD_NUMBER: builtins.int - PROVISIONING_STATE_FIELD_NUMBER: builtins.int - TIMEOUT_SECONDS_FIELD_NUMBER: builtins.int - result: response_generic_pb2.EnumResultGeneric.ValueType - "Generic pass/fail/error info" - provisioning_state: global___EnumProvisioning.ValueType - "Provisioning/connection state" - timeout_seconds: builtins.int - "Network connection timeout (seconds)" - - def __init__( - self, - *, - result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., - provisioning_state: global___EnumProvisioning.ValueType | None = ..., - timeout_seconds: builtins.int | None = ... - ) -> None: ... - def HasField( - self, - field_name: typing_extensions.Literal[ - "provisioning_state", b"provisioning_state", "result", b"result", "timeout_seconds", b"timeout_seconds" - ], - ) -> builtins.bool: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "provisioning_state", b"provisioning_state", "result", b"result", "timeout_seconds", b"timeout_seconds" - ], - ) -> None: ... - -global___ResponseConnect = ResponseConnect - -class ResponseConnectNew(google.protobuf.message.Message): - """* - The status of an attempt to connect to an Access Point - - Sent as the initial response to @ref RequestConnectNew - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - RESULT_FIELD_NUMBER: builtins.int - PROVISIONING_STATE_FIELD_NUMBER: builtins.int - TIMEOUT_SECONDS_FIELD_NUMBER: builtins.int - result: response_generic_pb2.EnumResultGeneric.ValueType - "Status of Connect New request" - provisioning_state: global___EnumProvisioning.ValueType - "Current provisioning state of the network" - timeout_seconds: builtins.int - "*\n number of seconds camera will wait before declaring a network connection attempt failed.\n " - - def __init__( - self, - *, - result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., - provisioning_state: global___EnumProvisioning.ValueType | None = ..., - timeout_seconds: builtins.int | None = ... - ) -> None: ... - def HasField( - self, - field_name: typing_extensions.Literal[ - "provisioning_state", b"provisioning_state", "result", b"result", "timeout_seconds", b"timeout_seconds" - ], - ) -> builtins.bool: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "provisioning_state", b"provisioning_state", "result", b"result", "timeout_seconds", b"timeout_seconds" - ], - ) -> None: ... - -global___ResponseConnectNew = ResponseConnectNew - -class ResponseGetApEntries(google.protobuf.message.Message): - """* - A list of scan entries describing a scanned Access Point - - This is sent in response to a @ref RequestGetApEntries - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - - class ScanEntry(google.protobuf.message.Message): - """The individual Scan Entry model""" - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - SSID_FIELD_NUMBER: builtins.int - SIGNAL_STRENGTH_BARS_FIELD_NUMBER: builtins.int - SIGNAL_FREQUENCY_MHZ_FIELD_NUMBER: builtins.int - SCAN_ENTRY_FLAGS_FIELD_NUMBER: builtins.int - ssid: builtins.str - "AP SSID" - signal_strength_bars: builtins.int - "Signal strength (3 bars: >-70 dBm; 2 bars: >-85 dBm; 1 bar: <=-85 dBm)" - signal_frequency_mhz: builtins.int - "Signal frequency (MHz)" - scan_entry_flags: builtins.int - "Bitmasked value from @ref EnumScanEntryFlags" - - def __init__( - self, - *, - ssid: builtins.str | None = ..., - signal_strength_bars: builtins.int | None = ..., - signal_frequency_mhz: builtins.int | None = ..., - scan_entry_flags: builtins.int | None = ... - ) -> None: ... - def HasField( - self, - field_name: typing_extensions.Literal[ - "scan_entry_flags", - b"scan_entry_flags", - "signal_frequency_mhz", - b"signal_frequency_mhz", - "signal_strength_bars", - b"signal_strength_bars", - "ssid", - b"ssid", - ], - ) -> builtins.bool: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "scan_entry_flags", - b"scan_entry_flags", - "signal_frequency_mhz", - b"signal_frequency_mhz", - "signal_strength_bars", - b"signal_strength_bars", - "ssid", - b"ssid", - ], - ) -> None: ... - RESULT_FIELD_NUMBER: builtins.int - SCAN_ID_FIELD_NUMBER: builtins.int - ENTRIES_FIELD_NUMBER: builtins.int - result: response_generic_pb2.EnumResultGeneric.ValueType - "Generic pass/fail/error info" - scan_id: builtins.int - "ID associated with this batch of results" - - @property - def entries( - self, - ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___ResponseGetApEntries.ScanEntry]: - """Array containing details about discovered APs""" - def __init__( - self, - *, - result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., - scan_id: builtins.int | None = ..., - entries: collections.abc.Iterable[global___ResponseGetApEntries.ScanEntry] | None = ... - ) -> None: ... - def HasField( - self, field_name: typing_extensions.Literal["result", b"result", "scan_id", b"scan_id"] - ) -> builtins.bool: ... - def ClearField( - self, field_name: typing_extensions.Literal["entries", b"entries", "result", b"result", "scan_id", b"scan_id"] - ) -> None: ... - -global___ResponseGetApEntries = ResponseGetApEntries - -class ResponseStartScanning(google.protobuf.message.Message): - """* - The current scanning state. - - This is the initial response to a @ref RequestStartScan - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - RESULT_FIELD_NUMBER: builtins.int - SCANNING_STATE_FIELD_NUMBER: builtins.int - result: response_generic_pb2.EnumResultGeneric.ValueType - "Generic pass/fail/error info" - scanning_state: global___EnumScanning.ValueType - "Scanning state" - - def __init__( - self, - *, - result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., - scanning_state: global___EnumScanning.ValueType | None = ... - ) -> None: ... - def HasField( - self, field_name: typing_extensions.Literal["result", b"result", "scanning_state", b"scanning_state"] - ) -> builtins.bool: ... - def ClearField( - self, field_name: typing_extensions.Literal["result", b"result", "scanning_state", b"scanning_state"] - ) -> None: ... - -global___ResponseStartScanning = ResponseStartScanning +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf messages for network management +""" + +import builtins +import collections.abc +import google.protobuf.descriptor +import google.protobuf.internal.containers +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +from . import response_generic_pb2 +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumProvisioning: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumProvisioningEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumProvisioning.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + PROVISIONING_UNKNOWN: _EnumProvisioning.ValueType + PROVISIONING_NEVER_STARTED: _EnumProvisioning.ValueType + PROVISIONING_STARTED: _EnumProvisioning.ValueType + PROVISIONING_ABORTED_BY_SYSTEM: _EnumProvisioning.ValueType + PROVISIONING_CANCELLED_BY_USER: _EnumProvisioning.ValueType + PROVISIONING_SUCCESS_NEW_AP: _EnumProvisioning.ValueType + PROVISIONING_SUCCESS_OLD_AP: _EnumProvisioning.ValueType + PROVISIONING_ERROR_FAILED_TO_ASSOCIATE: _EnumProvisioning.ValueType + PROVISIONING_ERROR_PASSWORD_AUTH: _EnumProvisioning.ValueType + PROVISIONING_ERROR_EULA_BLOCKING: _EnumProvisioning.ValueType + PROVISIONING_ERROR_NO_INTERNET: _EnumProvisioning.ValueType + PROVISIONING_ERROR_UNSUPPORTED_TYPE: _EnumProvisioning.ValueType + +class EnumProvisioning(_EnumProvisioning, metaclass=_EnumProvisioningEnumTypeWrapper): ... + +PROVISIONING_UNKNOWN: EnumProvisioning.ValueType +PROVISIONING_NEVER_STARTED: EnumProvisioning.ValueType +PROVISIONING_STARTED: EnumProvisioning.ValueType +PROVISIONING_ABORTED_BY_SYSTEM: EnumProvisioning.ValueType +PROVISIONING_CANCELLED_BY_USER: EnumProvisioning.ValueType +PROVISIONING_SUCCESS_NEW_AP: EnumProvisioning.ValueType +PROVISIONING_SUCCESS_OLD_AP: EnumProvisioning.ValueType +PROVISIONING_ERROR_FAILED_TO_ASSOCIATE: EnumProvisioning.ValueType +PROVISIONING_ERROR_PASSWORD_AUTH: EnumProvisioning.ValueType +PROVISIONING_ERROR_EULA_BLOCKING: EnumProvisioning.ValueType +PROVISIONING_ERROR_NO_INTERNET: EnumProvisioning.ValueType +PROVISIONING_ERROR_UNSUPPORTED_TYPE: EnumProvisioning.ValueType +global___EnumProvisioning = EnumProvisioning + +class _EnumScanning: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumScanningEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumScanning.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + SCANNING_UNKNOWN: _EnumScanning.ValueType + SCANNING_NEVER_STARTED: _EnumScanning.ValueType + SCANNING_STARTED: _EnumScanning.ValueType + SCANNING_ABORTED_BY_SYSTEM: _EnumScanning.ValueType + SCANNING_CANCELLED_BY_USER: _EnumScanning.ValueType + SCANNING_SUCCESS: _EnumScanning.ValueType + +class EnumScanning(_EnumScanning, metaclass=_EnumScanningEnumTypeWrapper): ... + +SCANNING_UNKNOWN: EnumScanning.ValueType +SCANNING_NEVER_STARTED: EnumScanning.ValueType +SCANNING_STARTED: EnumScanning.ValueType +SCANNING_ABORTED_BY_SYSTEM: EnumScanning.ValueType +SCANNING_CANCELLED_BY_USER: EnumScanning.ValueType +SCANNING_SUCCESS: EnumScanning.ValueType +global___EnumScanning = EnumScanning + +class _EnumScanEntryFlags: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumScanEntryFlagsEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumScanEntryFlags.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + SCAN_FLAG_OPEN: _EnumScanEntryFlags.ValueType + "This network does not require authentication" + SCAN_FLAG_AUTHENTICATED: _EnumScanEntryFlags.ValueType + "This network requires authentication" + SCAN_FLAG_CONFIGURED: _EnumScanEntryFlags.ValueType + "This network has been previously provisioned" + SCAN_FLAG_BEST_SSID: _EnumScanEntryFlags.ValueType + SCAN_FLAG_ASSOCIATED: _EnumScanEntryFlags.ValueType + "Camera is connected to this AP" + SCAN_FLAG_UNSUPPORTED_TYPE: _EnumScanEntryFlags.ValueType + +class EnumScanEntryFlags(_EnumScanEntryFlags, metaclass=_EnumScanEntryFlagsEnumTypeWrapper): ... + +SCAN_FLAG_OPEN: EnumScanEntryFlags.ValueType +"This network does not require authentication" +SCAN_FLAG_AUTHENTICATED: EnumScanEntryFlags.ValueType +"This network requires authentication" +SCAN_FLAG_CONFIGURED: EnumScanEntryFlags.ValueType +"This network has been previously provisioned" +SCAN_FLAG_BEST_SSID: EnumScanEntryFlags.ValueType +SCAN_FLAG_ASSOCIATED: EnumScanEntryFlags.ValueType +"Camera is connected to this AP" +SCAN_FLAG_UNSUPPORTED_TYPE: EnumScanEntryFlags.ValueType +global___EnumScanEntryFlags = EnumScanEntryFlags + +@typing_extensions.final +class NotifProvisioningState(google.protobuf.message.Message): + """ + Provision state notification + + Sent during provisioning triggered via @ref RequestConnect or @ref RequestConnectNew + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + PROVISIONING_STATE_FIELD_NUMBER: builtins.int + provisioning_state: global___EnumProvisioning.ValueType + "Provisioning / connection state" + + def __init__(self, *, provisioning_state: global___EnumProvisioning.ValueType | None = ...) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["provisioning_state", b"provisioning_state"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["provisioning_state", b"provisioning_state"], + ) -> None: ... + +global___NotifProvisioningState = NotifProvisioningState + +@typing_extensions.final +class NotifStartScanning(google.protobuf.message.Message): + """ + Scanning state notification + + Triggered via @ref RequestStartScan + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + SCANNING_STATE_FIELD_NUMBER: builtins.int + SCAN_ID_FIELD_NUMBER: builtins.int + TOTAL_ENTRIES_FIELD_NUMBER: builtins.int + TOTAL_CONFIGURED_SSID_FIELD_NUMBER: builtins.int + scanning_state: global___EnumScanning.ValueType + "Scanning state" + scan_id: builtins.int + "ID associated with scan results (included if scan was successful)" + total_entries: builtins.int + "Number of APs found during scan (included if scan was successful)" + total_configured_ssid: builtins.int + "Total count of camera's provisioned SSIDs" + + def __init__( + self, + *, + scanning_state: global___EnumScanning.ValueType | None = ..., + scan_id: builtins.int | None = ..., + total_entries: builtins.int | None = ..., + total_configured_ssid: builtins.int | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "scan_id", + b"scan_id", + "scanning_state", + b"scanning_state", + "total_configured_ssid", + b"total_configured_ssid", + "total_entries", + b"total_entries", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "scan_id", + b"scan_id", + "scanning_state", + b"scanning_state", + "total_configured_ssid", + b"total_configured_ssid", + "total_entries", + b"total_entries", + ], + ) -> None: ... + +global___NotifStartScanning = NotifStartScanning + +@typing_extensions.final +class RequestConnect(google.protobuf.message.Message): + """* + Connect to (but do not authenticate with) an Access Point + + This is intended to be used to connect to a previously-connected Access Point + + Response: @ref ResponseConnect + + Notification: @ref NotifProvisioningState sent periodically as provisioning state changes + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + SSID_FIELD_NUMBER: builtins.int + ssid: builtins.str + "AP SSID" + + def __init__(self, *, ssid: builtins.str | None = ...) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["ssid", b"ssid"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["ssid", b"ssid"]) -> None: ... + +global___RequestConnect = RequestConnect + +@typing_extensions.final +class RequestConnectNew(google.protobuf.message.Message): + """* + Connect to and authenticate with an Access Point + + This is only intended to be used if the AP is not previously provisioned. + + Response: @ref ResponseConnectNew sent immediately + + Notification: @ref NotifProvisioningState sent periodically as provisioning state changes + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + SSID_FIELD_NUMBER: builtins.int + PASSWORD_FIELD_NUMBER: builtins.int + STATIC_IP_FIELD_NUMBER: builtins.int + GATEWAY_FIELD_NUMBER: builtins.int + SUBNET_FIELD_NUMBER: builtins.int + DNS_PRIMARY_FIELD_NUMBER: builtins.int + DNS_SECONDARY_FIELD_NUMBER: builtins.int + ssid: builtins.str + "AP SSID" + password: builtins.str + "AP password" + static_ip: builtins.bytes + "Static IP address" + gateway: builtins.bytes + "Gateway IP address" + subnet: builtins.bytes + "Subnet mask" + dns_primary: builtins.bytes + "Primary DNS" + dns_secondary: builtins.bytes + "Secondary DNS" + + def __init__( + self, + *, + ssid: builtins.str | None = ..., + password: builtins.str | None = ..., + static_ip: builtins.bytes | None = ..., + gateway: builtins.bytes | None = ..., + subnet: builtins.bytes | None = ..., + dns_primary: builtins.bytes | None = ..., + dns_secondary: builtins.bytes | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "dns_primary", + b"dns_primary", + "dns_secondary", + b"dns_secondary", + "gateway", + b"gateway", + "password", + b"password", + "ssid", + b"ssid", + "static_ip", + b"static_ip", + "subnet", + b"subnet", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "dns_primary", + b"dns_primary", + "dns_secondary", + b"dns_secondary", + "gateway", + b"gateway", + "password", + b"password", + "ssid", + b"ssid", + "static_ip", + b"static_ip", + "subnet", + b"subnet", + ], + ) -> None: ... + +global___RequestConnectNew = RequestConnectNew + +@typing_extensions.final +class RequestGetApEntries(google.protobuf.message.Message): + """* + Get a list of Access Points found during a @ref RequestStartScan + + Response: @ref ResponseGetApEntries + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + START_INDEX_FIELD_NUMBER: builtins.int + MAX_ENTRIES_FIELD_NUMBER: builtins.int + SCAN_ID_FIELD_NUMBER: builtins.int + start_index: builtins.int + "Used for paging. 0 <= start_index < @ref ResponseGetApEntries .total_entries" + max_entries: builtins.int + "Used for paging. Value must be < @ref ResponseGetApEntries .total_entries" + scan_id: builtins.int + "ID corresponding to a set of scan results (i.e. @ref ResponseGetApEntries .scan_id)" + + def __init__( + self, + *, + start_index: builtins.int | None = ..., + max_entries: builtins.int | None = ..., + scan_id: builtins.int | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "max_entries", + b"max_entries", + "scan_id", + b"scan_id", + "start_index", + b"start_index", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "max_entries", + b"max_entries", + "scan_id", + b"scan_id", + "start_index", + b"start_index", + ], + ) -> None: ... + +global___RequestGetApEntries = RequestGetApEntries + +@typing_extensions.final +class RequestReleaseNetwork(google.protobuf.message.Message): + """* + Request to disconnect from currently-connected AP + + This drops the camera out of Station (STA) Mode and returns it to Access Point (AP) mode. + + Response: @ref ResponseGeneric + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__(self) -> None: ... + +global___RequestReleaseNetwork = RequestReleaseNetwork + +@typing_extensions.final +class RequestStartScan(google.protobuf.message.Message): + """* + Start scanning for Access Points + + @note Serialization of this object is zero bytes. + + Response: @ref ResponseStartScanning are sent immediately after the camera receives this command + + Notifications: @ref NotifStartScanning are sent periodically as scanning state changes. Use to detect scan complete. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__(self) -> None: ... + +global___RequestStartScan = RequestStartScan + +@typing_extensions.final +class ResponseConnect(google.protobuf.message.Message): + """* + The status of an attempt to connect to an Access Point + + Sent as the initial response to @ref RequestConnect + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + RESULT_FIELD_NUMBER: builtins.int + PROVISIONING_STATE_FIELD_NUMBER: builtins.int + TIMEOUT_SECONDS_FIELD_NUMBER: builtins.int + result: response_generic_pb2.EnumResultGeneric.ValueType + "Generic pass/fail/error info" + provisioning_state: global___EnumProvisioning.ValueType + "Provisioning/connection state" + timeout_seconds: builtins.int + "Network connection timeout (seconds)" + + def __init__( + self, + *, + result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., + provisioning_state: global___EnumProvisioning.ValueType | None = ..., + timeout_seconds: builtins.int | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "provisioning_state", + b"provisioning_state", + "result", + b"result", + "timeout_seconds", + b"timeout_seconds", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "provisioning_state", + b"provisioning_state", + "result", + b"result", + "timeout_seconds", + b"timeout_seconds", + ], + ) -> None: ... + +global___ResponseConnect = ResponseConnect + +@typing_extensions.final +class ResponseConnectNew(google.protobuf.message.Message): + """* + The status of an attempt to connect to an Access Point + + Sent as the initial response to @ref RequestConnectNew + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + RESULT_FIELD_NUMBER: builtins.int + PROVISIONING_STATE_FIELD_NUMBER: builtins.int + TIMEOUT_SECONDS_FIELD_NUMBER: builtins.int + result: response_generic_pb2.EnumResultGeneric.ValueType + "Status of Connect New request" + provisioning_state: global___EnumProvisioning.ValueType + "Current provisioning state of the network" + timeout_seconds: builtins.int + "*\n Number of seconds camera will wait before declaring a network connection attempt failed\n " + + def __init__( + self, + *, + result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., + provisioning_state: global___EnumProvisioning.ValueType | None = ..., + timeout_seconds: builtins.int | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "provisioning_state", + b"provisioning_state", + "result", + b"result", + "timeout_seconds", + b"timeout_seconds", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "provisioning_state", + b"provisioning_state", + "result", + b"result", + "timeout_seconds", + b"timeout_seconds", + ], + ) -> None: ... + +global___ResponseConnectNew = ResponseConnectNew + +@typing_extensions.final +class ResponseGetApEntries(google.protobuf.message.Message): + """* + A list of scan entries describing a scanned Access Point + + This is sent in response to a @ref RequestGetApEntries + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + @typing_extensions.final + class ScanEntry(google.protobuf.message.Message): + """* + An individual Scan Entry in a @ref ResponseGetApEntries response + + @note When `scan_entry_flags` contains `SCAN_FLAG_CONFIGURED`, it is an indication that this network has already been provisioned. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + SSID_FIELD_NUMBER: builtins.int + SIGNAL_STRENGTH_BARS_FIELD_NUMBER: builtins.int + SIGNAL_FREQUENCY_MHZ_FIELD_NUMBER: builtins.int + SCAN_ENTRY_FLAGS_FIELD_NUMBER: builtins.int + ssid: builtins.str + "AP SSID" + signal_strength_bars: builtins.int + "Signal strength (3 bars: >-70 dBm; 2 bars: >-85 dBm; 1 bar: <=-85 dBm)" + signal_frequency_mhz: builtins.int + "Signal frequency (MHz)" + scan_entry_flags: builtins.int + "Bitmasked value from @ref EnumScanEntryFlags" + + def __init__( + self, + *, + ssid: builtins.str | None = ..., + signal_strength_bars: builtins.int | None = ..., + signal_frequency_mhz: builtins.int | None = ..., + scan_entry_flags: builtins.int | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "scan_entry_flags", + b"scan_entry_flags", + "signal_frequency_mhz", + b"signal_frequency_mhz", + "signal_strength_bars", + b"signal_strength_bars", + "ssid", + b"ssid", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "scan_entry_flags", + b"scan_entry_flags", + "signal_frequency_mhz", + b"signal_frequency_mhz", + "signal_strength_bars", + b"signal_strength_bars", + "ssid", + b"ssid", + ], + ) -> None: ... + + RESULT_FIELD_NUMBER: builtins.int + SCAN_ID_FIELD_NUMBER: builtins.int + ENTRIES_FIELD_NUMBER: builtins.int + result: response_generic_pb2.EnumResultGeneric.ValueType + "Generic pass/fail/error info" + scan_id: builtins.int + "ID associated with this batch of results" + + @property + def entries( + self, + ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___ResponseGetApEntries.ScanEntry]: + """Array containing details about discovered APs""" + def __init__( + self, + *, + result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., + scan_id: builtins.int | None = ..., + entries: (collections.abc.Iterable[global___ResponseGetApEntries.ScanEntry] | None) = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["result", b"result", "scan_id", b"scan_id"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["entries", b"entries", "result", b"result", "scan_id", b"scan_id"], + ) -> None: ... + +global___ResponseGetApEntries = ResponseGetApEntries + +@typing_extensions.final +class ResponseStartScanning(google.protobuf.message.Message): + """* + The current scanning state. + + This is the initial response to a @ref RequestStartScan + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + RESULT_FIELD_NUMBER: builtins.int + SCANNING_STATE_FIELD_NUMBER: builtins.int + result: response_generic_pb2.EnumResultGeneric.ValueType + "Generic pass/fail/error info" + scanning_state: global___EnumScanning.ValueType + "Scanning state" + + def __init__( + self, + *, + result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., + scanning_state: global___EnumScanning.ValueType | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["result", b"result", "scanning_state", b"scanning_state"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["result", b"result", "scanning_state", b"scanning_state"], + ) -> None: ... + +global___ResponseStartScanning = ResponseStartScanning diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/preset_status_pb2.py b/demos/python/sdk_wireless_camera_control/open_gopro/proto/preset_status_pb2.py index 555abb0f..ae660544 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/preset_status_pb2.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/preset_status_pb2.py @@ -1,39 +1,40 @@ # preset_status_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Mon Dec 18 20:40:36 UTC 2023 +# This copyright was auto-generated on Wed Mar 27 22:05:47 UTC 2024 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder - -_sym_db = _symbol_database.Default() -from . import response_generic_pb2 as response__generic__pb2 - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n\x13preset_status.proto\x12\nopen_gopro\x1a\x16response_generic.proto"I\n\x12NotifyPresetStatus\x123\n\x12preset_group_array\x18\x01 \x03(\x0b2\x17.open_gopro.PresetGroup"\xaf\x02\n\x06Preset\x12\n\n\x02id\x18\x01 \x01(\x05\x12&\n\x04mode\x18\x02 \x01(\x0e2\x18.open_gopro.EnumFlatMode\x12-\n\x08title_id\x18\x03 \x01(\x0e2\x1b.open_gopro.EnumPresetTitle\x12\x14\n\x0ctitle_number\x18\x04 \x01(\x05\x12\x14\n\x0cuser_defined\x18\x05 \x01(\x08\x12(\n\x04icon\x18\x06 \x01(\x0e2\x1a.open_gopro.EnumPresetIcon\x120\n\rsetting_array\x18\x07 \x03(\x0b2\x19.open_gopro.PresetSetting\x12\x13\n\x0bis_modified\x18\x08 \x01(\x08\x12\x10\n\x08is_fixed\x18\t \x01(\x08\x12\x13\n\x0bcustom_name\x18\n \x01(\t"\x8c\x01\n\x19RequestCustomPresetUpdate\x12-\n\x08title_id\x18\x01 \x01(\x0e2\x1b.open_gopro.EnumPresetTitle\x12\x13\n\x0bcustom_name\x18\x02 \x01(\t\x12+\n\x07icon_id\x18\x03 \x01(\x0e2\x1a.open_gopro.EnumPresetIcon"\xa7\x01\n\x0bPresetGroup\x12\'\n\x02id\x18\x01 \x01(\x0e2\x1b.open_gopro.EnumPresetGroup\x12(\n\x0cpreset_array\x18\x02 \x03(\x0b2\x12.open_gopro.Preset\x12\x16\n\x0ecan_add_preset\x18\x03 \x01(\x08\x12-\n\x04icon\x18\x04 \x01(\x0e2\x1f.open_gopro.EnumPresetGroupIcon">\n\rPresetSetting\x12\n\n\x02id\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x05\x12\x12\n\nis_caption\x18\x03 \x01(\x08*\xfa\x04\n\x0cEnumFlatMode\x12\x1e\n\x11FLAT_MODE_UNKNOWN\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x12\x16\n\x12FLAT_MODE_PLAYBACK\x10\x04\x12\x13\n\x0fFLAT_MODE_SETUP\x10\x05\x12\x13\n\x0fFLAT_MODE_VIDEO\x10\x0c\x12\x1e\n\x1aFLAT_MODE_TIME_LAPSE_VIDEO\x10\r\x12\x15\n\x11FLAT_MODE_LOOPING\x10\x0f\x12\x1a\n\x16FLAT_MODE_PHOTO_SINGLE\x10\x10\x12\x13\n\x0fFLAT_MODE_PHOTO\x10\x11\x12\x19\n\x15FLAT_MODE_PHOTO_NIGHT\x10\x12\x12\x19\n\x15FLAT_MODE_PHOTO_BURST\x10\x13\x12\x1e\n\x1aFLAT_MODE_TIME_LAPSE_PHOTO\x10\x14\x12\x1f\n\x1bFLAT_MODE_NIGHT_LAPSE_PHOTO\x10\x15\x12\x1e\n\x1aFLAT_MODE_BROADCAST_RECORD\x10\x16\x12!\n\x1dFLAT_MODE_BROADCAST_BROADCAST\x10\x17\x12\x1d\n\x19FLAT_MODE_TIME_WARP_VIDEO\x10\x18\x12\x18\n\x14FLAT_MODE_LIVE_BURST\x10\x19\x12\x1f\n\x1bFLAT_MODE_NIGHT_LAPSE_VIDEO\x10\x1a\x12\x13\n\x0fFLAT_MODE_SLOMO\x10\x1b\x12\x12\n\x0eFLAT_MODE_IDLE\x10\x1c\x12\x1e\n\x1aFLAT_MODE_VIDEO_STAR_TRAIL\x10\x1d\x12"\n\x1eFLAT_MODE_VIDEO_LIGHT_PAINTING\x10\x1e\x12\x1f\n\x1bFLAT_MODE_VIDEO_LIGHT_TRAIL\x10\x1f*i\n\x0fEnumPresetGroup\x12\x1a\n\x15PRESET_GROUP_ID_VIDEO\x10\xe8\x07\x12\x1a\n\x15PRESET_GROUP_ID_PHOTO\x10\xe9\x07\x12\x1e\n\x19PRESET_GROUP_ID_TIMELAPSE\x10\xea\x07*\xbc\x02\n\x13EnumPresetGroupIcon\x12\x1e\n\x1aPRESET_GROUP_VIDEO_ICON_ID\x10\x00\x12\x1e\n\x1aPRESET_GROUP_PHOTO_ICON_ID\x10\x01\x12"\n\x1ePRESET_GROUP_TIMELAPSE_ICON_ID\x10\x02\x12\'\n#PRESET_GROUP_LONG_BAT_VIDEO_ICON_ID\x10\x03\x12(\n$PRESET_GROUP_ENDURANCE_VIDEO_ICON_ID\x10\x04\x12"\n\x1ePRESET_GROUP_MAX_VIDEO_ICON_ID\x10\x05\x12"\n\x1ePRESET_GROUP_MAX_PHOTO_ICON_ID\x10\x06\x12&\n"PRESET_GROUP_MAX_TIMELAPSE_ICON_ID\x10\x07*\xec\x10\n\x0eEnumPresetIcon\x12\x15\n\x11PRESET_ICON_VIDEO\x10\x00\x12\x18\n\x14PRESET_ICON_ACTIVITY\x10\x01\x12\x19\n\x15PRESET_ICON_CINEMATIC\x10\x02\x12\x15\n\x11PRESET_ICON_PHOTO\x10\x03\x12\x1a\n\x16PRESET_ICON_LIVE_BURST\x10\x04\x12\x15\n\x11PRESET_ICON_BURST\x10\x05\x12\x1b\n\x17PRESET_ICON_PHOTO_NIGHT\x10\x06\x12\x18\n\x14PRESET_ICON_TIMEWARP\x10\x07\x12\x19\n\x15PRESET_ICON_TIMELAPSE\x10\x08\x12\x1a\n\x16PRESET_ICON_NIGHTLAPSE\x10\t\x12\x15\n\x11PRESET_ICON_SNAIL\x10\n\x12\x17\n\x13PRESET_ICON_VIDEO_2\x10\x0b\x12\x19\n\x15PRESET_ICON_360_VIDEO\x10\x0c\x12\x17\n\x13PRESET_ICON_PHOTO_2\x10\r\x12\x18\n\x14PRESET_ICON_PANORAMA\x10\x0e\x12\x17\n\x13PRESET_ICON_BURST_2\x10\x0f\x12\x1a\n\x16PRESET_ICON_TIMEWARP_2\x10\x10\x12\x1b\n\x17PRESET_ICON_TIMELAPSE_2\x10\x11\x12\x16\n\x12PRESET_ICON_CUSTOM\x10\x12\x12\x13\n\x0fPRESET_ICON_AIR\x10\x13\x12\x14\n\x10PRESET_ICON_BIKE\x10\x14\x12\x14\n\x10PRESET_ICON_EPIC\x10\x15\x12\x16\n\x12PRESET_ICON_INDOOR\x10\x16\x12\x15\n\x11PRESET_ICON_MOTOR\x10\x17\x12\x17\n\x13PRESET_ICON_MOUNTED\x10\x18\x12\x17\n\x13PRESET_ICON_OUTDOOR\x10\x19\x12\x13\n\x0fPRESET_ICON_POV\x10\x1a\x12\x16\n\x12PRESET_ICON_SELFIE\x10\x1b\x12\x15\n\x11PRESET_ICON_SKATE\x10\x1c\x12\x14\n\x10PRESET_ICON_SNOW\x10\x1d\x12\x15\n\x11PRESET_ICON_TRAIL\x10\x1e\x12\x16\n\x12PRESET_ICON_TRAVEL\x10\x1f\x12\x15\n\x11PRESET_ICON_WATER\x10 \x12\x17\n\x13PRESET_ICON_LOOPING\x10!\x12\x15\n\x11PRESET_ICON_STARS\x10"\x12\x16\n\x12PRESET_ICON_ACTION\x10#\x12\x1a\n\x16PRESET_ICON_FOLLOW_CAM\x10$\x12\x14\n\x10PRESET_ICON_SURF\x10%\x12\x14\n\x10PRESET_ICON_CITY\x10&\x12\x15\n\x11PRESET_ICON_SHAKY\x10\'\x12\x16\n\x12PRESET_ICON_CHESTY\x10(\x12\x16\n\x12PRESET_ICON_HELMET\x10)\x12\x14\n\x10PRESET_ICON_BITE\x10*\x12\x19\n\x15PRESET_ICON_MAX_VIDEO\x107\x12\x19\n\x15PRESET_ICON_MAX_PHOTO\x108\x12\x1c\n\x18PRESET_ICON_MAX_TIMEWARP\x109\x12\x15\n\x11PRESET_ICON_BASIC\x10:\x12\x1c\n\x18PRESET_ICON_ULTRA_SLO_MO\x10;\x12"\n\x1ePRESET_ICON_STANDARD_ENDURANCE\x10<\x12"\n\x1ePRESET_ICON_ACTIVITY_ENDURANCE\x10=\x12#\n\x1fPRESET_ICON_CINEMATIC_ENDURANCE\x10>\x12\x1f\n\x1bPRESET_ICON_SLOMO_ENDURANCE\x10?\x12\x1c\n\x18PRESET_ICON_STATIONARY_1\x10@\x12\x1c\n\x18PRESET_ICON_STATIONARY_2\x10A\x12\x1c\n\x18PRESET_ICON_STATIONARY_3\x10B\x12\x1c\n\x18PRESET_ICON_STATIONARY_4\x10C\x12"\n\x1ePRESET_ICON_SIMPLE_SUPER_PHOTO\x10F\x12"\n\x1ePRESET_ICON_SIMPLE_NIGHT_PHOTO\x10G\x12%\n!PRESET_ICON_HIGHEST_QUALITY_VIDEO\x10I\x12&\n"PRESET_ICON_STANDARD_QUALITY_VIDEO\x10J\x12#\n\x1fPRESET_ICON_BASIC_QUALITY_VIDEO\x10K\x12\x1a\n\x16PRESET_ICON_STAR_TRAIL\x10L\x12\x1e\n\x1aPRESET_ICON_LIGHT_PAINTING\x10M\x12\x1b\n\x17PRESET_ICON_LIGHT_TRAIL\x10N\x12\x1a\n\x16PRESET_ICON_FULL_FRAME\x10O\x12\x1e\n\x1aPRESET_ICON_EASY_MAX_VIDEO\x10P\x12\x1e\n\x1aPRESET_ICON_EASY_MAX_PHOTO\x10Q\x12!\n\x1dPRESET_ICON_EASY_MAX_TIMEWARP\x10R\x12#\n\x1fPRESET_ICON_EASY_MAX_STAR_TRAIL\x10S\x12\'\n#PRESET_ICON_EASY_MAX_LIGHT_PAINTING\x10T\x12$\n PRESET_ICON_EASY_MAX_LIGHT_TRAIL\x10U\x12\x1e\n\x1aPRESET_ICON_MAX_STAR_TRAIL\x10Y\x12"\n\x1ePRESET_ICON_MAX_LIGHT_PAINTING\x10Z\x12\x1f\n\x1bPRESET_ICON_MAX_LIGHT_TRAIL\x10[\x12 \n\x1bPRESET_ICON_TIMELAPSE_PHOTO\x10\xe8\x07\x12!\n\x1cPRESET_ICON_NIGHTLAPSE_PHOTO\x10\xe9\x07*\xbd\x14\n\x0fEnumPresetTitle\x12\x19\n\x15PRESET_TITLE_ACTIVITY\x10\x00\x12\x19\n\x15PRESET_TITLE_STANDARD\x10\x01\x12\x1a\n\x16PRESET_TITLE_CINEMATIC\x10\x02\x12\x16\n\x12PRESET_TITLE_PHOTO\x10\x03\x12\x1b\n\x17PRESET_TITLE_LIVE_BURST\x10\x04\x12\x16\n\x12PRESET_TITLE_BURST\x10\x05\x12\x16\n\x12PRESET_TITLE_NIGHT\x10\x06\x12\x1a\n\x16PRESET_TITLE_TIME_WARP\x10\x07\x12\x1b\n\x17PRESET_TITLE_TIME_LAPSE\x10\x08\x12\x1c\n\x18PRESET_TITLE_NIGHT_LAPSE\x10\t\x12\x16\n\x12PRESET_TITLE_VIDEO\x10\n\x12\x16\n\x12PRESET_TITLE_SLOMO\x10\x0b\x12\x1a\n\x16PRESET_TITLE_360_VIDEO\x10\x0c\x12\x18\n\x14PRESET_TITLE_PHOTO_2\x10\r\x12\x19\n\x15PRESET_TITLE_PANORAMA\x10\x0e\x12\x1a\n\x16PRESET_TITLE_360_PHOTO\x10\x0f\x12\x1c\n\x18PRESET_TITLE_TIME_WARP_2\x10\x10\x12\x1e\n\x1aPRESET_TITLE_360_TIME_WARP\x10\x11\x12\x17\n\x13PRESET_TITLE_CUSTOM\x10\x12\x12\x14\n\x10PRESET_TITLE_AIR\x10\x13\x12\x15\n\x11PRESET_TITLE_BIKE\x10\x14\x12\x15\n\x11PRESET_TITLE_EPIC\x10\x15\x12\x17\n\x13PRESET_TITLE_INDOOR\x10\x16\x12\x16\n\x12PRESET_TITLE_MOTOR\x10\x17\x12\x18\n\x14PRESET_TITLE_MOUNTED\x10\x18\x12\x18\n\x14PRESET_TITLE_OUTDOOR\x10\x19\x12\x14\n\x10PRESET_TITLE_POV\x10\x1a\x12\x17\n\x13PRESET_TITLE_SELFIE\x10\x1b\x12\x16\n\x12PRESET_TITLE_SKATE\x10\x1c\x12\x15\n\x11PRESET_TITLE_SNOW\x10\x1d\x12\x16\n\x12PRESET_TITLE_TRAIL\x10\x1e\x12\x17\n\x13PRESET_TITLE_TRAVEL\x10\x1f\x12\x16\n\x12PRESET_TITLE_WATER\x10 \x12\x18\n\x14PRESET_TITLE_LOOPING\x10!\x12\x16\n\x12PRESET_TITLE_STARS\x10"\x12\x17\n\x13PRESET_TITLE_ACTION\x10#\x12\x1b\n\x17PRESET_TITLE_FOLLOW_CAM\x10$\x12\x15\n\x11PRESET_TITLE_SURF\x10%\x12\x15\n\x11PRESET_TITLE_CITY\x10&\x12\x16\n\x12PRESET_TITLE_SHAKY\x10\'\x12\x17\n\x13PRESET_TITLE_CHESTY\x10(\x12\x17\n\x13PRESET_TITLE_HELMET\x10)\x12\x15\n\x11PRESET_TITLE_BITE\x10*\x12\x1e\n\x1aPRESET_TITLE_360_TIMELAPSE\x103\x12 \n\x1cPRESET_TITLE_360_NIGHT_LAPSE\x104\x12 \n\x1cPRESET_TITLE_360_NIGHT_PHOTO\x105\x12 \n\x1cPRESET_TITLE_PANO_TIME_LAPSE\x106\x12\x1a\n\x16PRESET_TITLE_MAX_VIDEO\x107\x12\x1a\n\x16PRESET_TITLE_MAX_PHOTO\x108\x12\x1d\n\x19PRESET_TITLE_MAX_TIMEWARP\x109\x12\x16\n\x12PRESET_TITLE_BASIC\x10:\x12\x1d\n\x19PRESET_TITLE_ULTRA_SLO_MO\x10;\x12#\n\x1fPRESET_TITLE_STANDARD_ENDURANCE\x10<\x12#\n\x1fPRESET_TITLE_ACTIVITY_ENDURANCE\x10=\x12$\n PRESET_TITLE_CINEMATIC_ENDURANCE\x10>\x12 \n\x1cPRESET_TITLE_SLOMO_ENDURANCE\x10?\x12\x1d\n\x19PRESET_TITLE_STATIONARY_1\x10@\x12\x1d\n\x19PRESET_TITLE_STATIONARY_2\x10A\x12\x1d\n\x19PRESET_TITLE_STATIONARY_3\x10B\x12\x1d\n\x19PRESET_TITLE_STATIONARY_4\x10C\x12\x1d\n\x19PRESET_TITLE_SIMPLE_VIDEO\x10D\x12!\n\x1dPRESET_TITLE_SIMPLE_TIME_WARP\x10E\x12#\n\x1fPRESET_TITLE_SIMPLE_SUPER_PHOTO\x10F\x12#\n\x1fPRESET_TITLE_SIMPLE_NIGHT_PHOTO\x10G\x12\'\n#PRESET_TITLE_SIMPLE_VIDEO_ENDURANCE\x10H\x12 \n\x1cPRESET_TITLE_HIGHEST_QUALITY\x10I\x12!\n\x1dPRESET_TITLE_EXTENDED_BATTERY\x10J\x12 \n\x1cPRESET_TITLE_LONGEST_BATTERY\x10K\x12\x1b\n\x17PRESET_TITLE_STAR_TRAIL\x10L\x12\x1f\n\x1bPRESET_TITLE_LIGHT_PAINTING\x10M\x12\x1c\n\x18PRESET_TITLE_LIGHT_TRAIL\x10N\x12\x1b\n\x17PRESET_TITLE_FULL_FRAME\x10O\x12\x1f\n\x1bPRESET_TITLE_MAX_LENS_VIDEO\x10P\x12"\n\x1ePRESET_TITLE_MAX_LENS_TIMEWARP\x10Q\x12\'\n#PRESET_TITLE_STANDARD_QUALITY_VIDEO\x10R\x12$\n PRESET_TITLE_BASIC_QUALITY_VIDEO\x10S\x12\x1f\n\x1bPRESET_TITLE_EASY_MAX_VIDEO\x10T\x12\x1f\n\x1bPRESET_TITLE_EASY_MAX_PHOTO\x10U\x12"\n\x1ePRESET_TITLE_EASY_MAX_TIMEWARP\x10V\x12$\n PRESET_TITLE_EASY_MAX_STAR_TRAIL\x10W\x12(\n$PRESET_TITLE_EASY_MAX_LIGHT_PAINTING\x10X\x12%\n!PRESET_TITLE_EASY_MAX_LIGHT_TRAIL\x10Y\x12\x1f\n\x1bPRESET_TITLE_MAX_STAR_TRAIL\x10Z\x12#\n\x1fPRESET_TITLE_MAX_LIGHT_PAINTING\x10[\x12 \n\x1cPRESET_TITLE_MAX_LIGHT_TRAIL\x10\\\x12&\n"PRESET_TITLE_HIGHEST_QUALITY_VIDEO\x10]\x12)\n%PRESET_TITLE_USER_DEFINED_CUSTOM_NAME\x10^' -) -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "preset_status_pb2", globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _ENUMFLATMODE._serialized_start = 818 - _ENUMFLATMODE._serialized_end = 1452 - _ENUMPRESETGROUP._serialized_start = 1454 - _ENUMPRESETGROUP._serialized_end = 1559 - _ENUMPRESETGROUPICON._serialized_start = 1562 - _ENUMPRESETGROUPICON._serialized_end = 1878 - _ENUMPRESETICON._serialized_start = 1881 - _ENUMPRESETICON._serialized_end = 4037 - _ENUMPRESETTITLE._serialized_start = 4040 - _ENUMPRESETTITLE._serialized_end = 6661 - _NOTIFYPRESETSTATUS._serialized_start = 59 - _NOTIFYPRESETSTATUS._serialized_end = 132 - _PRESET._serialized_start = 135 - _PRESET._serialized_end = 438 - _REQUESTCUSTOMPRESETUPDATE._serialized_start = 441 - _REQUESTCUSTOMPRESETUPDATE._serialized_end = 581 - _PRESETGROUP._serialized_start = 584 - _PRESETGROUP._serialized_end = 751 - _PRESETSETTING._serialized_start = 753 - _PRESETSETTING._serialized_end = 815 +"""Generated protocol buffer code.""" + +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder + +_sym_db = _symbol_database.Default() +from . import response_generic_pb2 as response__generic__pb2 + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x13preset_status.proto\x12\nopen_gopro\x1a\x16response_generic.proto"I\n\x12NotifyPresetStatus\x123\n\x12preset_group_array\x18\x01 \x03(\x0b2\x17.open_gopro.PresetGroup"\xaf\x02\n\x06Preset\x12\n\n\x02id\x18\x01 \x01(\x05\x12&\n\x04mode\x18\x02 \x01(\x0e2\x18.open_gopro.EnumFlatMode\x12-\n\x08title_id\x18\x03 \x01(\x0e2\x1b.open_gopro.EnumPresetTitle\x12\x14\n\x0ctitle_number\x18\x04 \x01(\x05\x12\x14\n\x0cuser_defined\x18\x05 \x01(\x08\x12(\n\x04icon\x18\x06 \x01(\x0e2\x1a.open_gopro.EnumPresetIcon\x120\n\rsetting_array\x18\x07 \x03(\x0b2\x19.open_gopro.PresetSetting\x12\x13\n\x0bis_modified\x18\x08 \x01(\x08\x12\x10\n\x08is_fixed\x18\t \x01(\x08\x12\x13\n\x0bcustom_name\x18\n \x01(\t"\x8c\x01\n\x19RequestCustomPresetUpdate\x12-\n\x08title_id\x18\x01 \x01(\x0e2\x1b.open_gopro.EnumPresetTitle\x12\x13\n\x0bcustom_name\x18\x02 \x01(\t\x12+\n\x07icon_id\x18\x03 \x01(\x0e2\x1a.open_gopro.EnumPresetIcon"\xa7\x01\n\x0bPresetGroup\x12\'\n\x02id\x18\x01 \x01(\x0e2\x1b.open_gopro.EnumPresetGroup\x12(\n\x0cpreset_array\x18\x02 \x03(\x0b2\x12.open_gopro.Preset\x12\x16\n\x0ecan_add_preset\x18\x03 \x01(\x08\x12-\n\x04icon\x18\x04 \x01(\x0e2\x1f.open_gopro.EnumPresetGroupIcon">\n\rPresetSetting\x12\n\n\x02id\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x05\x12\x12\n\nis_caption\x18\x03 \x01(\x08*\x9b\x05\n\x0cEnumFlatMode\x12\x1e\n\x11FLAT_MODE_UNKNOWN\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x12\x16\n\x12FLAT_MODE_PLAYBACK\x10\x04\x12\x13\n\x0fFLAT_MODE_SETUP\x10\x05\x12\x13\n\x0fFLAT_MODE_VIDEO\x10\x0c\x12\x1e\n\x1aFLAT_MODE_TIME_LAPSE_VIDEO\x10\r\x12\x15\n\x11FLAT_MODE_LOOPING\x10\x0f\x12\x1a\n\x16FLAT_MODE_PHOTO_SINGLE\x10\x10\x12\x13\n\x0fFLAT_MODE_PHOTO\x10\x11\x12\x19\n\x15FLAT_MODE_PHOTO_NIGHT\x10\x12\x12\x19\n\x15FLAT_MODE_PHOTO_BURST\x10\x13\x12\x1e\n\x1aFLAT_MODE_TIME_LAPSE_PHOTO\x10\x14\x12\x1f\n\x1bFLAT_MODE_NIGHT_LAPSE_PHOTO\x10\x15\x12\x1e\n\x1aFLAT_MODE_BROADCAST_RECORD\x10\x16\x12!\n\x1dFLAT_MODE_BROADCAST_BROADCAST\x10\x17\x12\x1d\n\x19FLAT_MODE_TIME_WARP_VIDEO\x10\x18\x12\x18\n\x14FLAT_MODE_LIVE_BURST\x10\x19\x12\x1f\n\x1bFLAT_MODE_NIGHT_LAPSE_VIDEO\x10\x1a\x12\x13\n\x0fFLAT_MODE_SLOMO\x10\x1b\x12\x12\n\x0eFLAT_MODE_IDLE\x10\x1c\x12\x1e\n\x1aFLAT_MODE_VIDEO_STAR_TRAIL\x10\x1d\x12"\n\x1eFLAT_MODE_VIDEO_LIGHT_PAINTING\x10\x1e\x12\x1f\n\x1bFLAT_MODE_VIDEO_LIGHT_TRAIL\x10\x1f\x12\x1f\n\x1bFLAT_MODE_VIDEO_BURST_SLOMO\x10 *i\n\x0fEnumPresetGroup\x12\x1a\n\x15PRESET_GROUP_ID_VIDEO\x10\xe8\x07\x12\x1a\n\x15PRESET_GROUP_ID_PHOTO\x10\xe9\x07\x12\x1e\n\x19PRESET_GROUP_ID_TIMELAPSE\x10\xea\x07*\xbc\x02\n\x13EnumPresetGroupIcon\x12\x1e\n\x1aPRESET_GROUP_VIDEO_ICON_ID\x10\x00\x12\x1e\n\x1aPRESET_GROUP_PHOTO_ICON_ID\x10\x01\x12"\n\x1ePRESET_GROUP_TIMELAPSE_ICON_ID\x10\x02\x12\'\n#PRESET_GROUP_LONG_BAT_VIDEO_ICON_ID\x10\x03\x12(\n$PRESET_GROUP_ENDURANCE_VIDEO_ICON_ID\x10\x04\x12"\n\x1ePRESET_GROUP_MAX_VIDEO_ICON_ID\x10\x05\x12"\n\x1ePRESET_GROUP_MAX_PHOTO_ICON_ID\x10\x06\x12&\n"PRESET_GROUP_MAX_TIMELAPSE_ICON_ID\x10\x07*\xc1\r\n\x0eEnumPresetIcon\x12\x15\n\x11PRESET_ICON_VIDEO\x10\x00\x12\x18\n\x14PRESET_ICON_ACTIVITY\x10\x01\x12\x19\n\x15PRESET_ICON_CINEMATIC\x10\x02\x12\x15\n\x11PRESET_ICON_PHOTO\x10\x03\x12\x1a\n\x16PRESET_ICON_LIVE_BURST\x10\x04\x12\x15\n\x11PRESET_ICON_BURST\x10\x05\x12\x1b\n\x17PRESET_ICON_PHOTO_NIGHT\x10\x06\x12\x18\n\x14PRESET_ICON_TIMEWARP\x10\x07\x12\x19\n\x15PRESET_ICON_TIMELAPSE\x10\x08\x12\x1a\n\x16PRESET_ICON_NIGHTLAPSE\x10\t\x12\x15\n\x11PRESET_ICON_SNAIL\x10\n\x12\x17\n\x13PRESET_ICON_VIDEO_2\x10\x0b\x12\x17\n\x13PRESET_ICON_PHOTO_2\x10\r\x12\x18\n\x14PRESET_ICON_PANORAMA\x10\x0e\x12\x17\n\x13PRESET_ICON_BURST_2\x10\x0f\x12\x1a\n\x16PRESET_ICON_TIMEWARP_2\x10\x10\x12\x1b\n\x17PRESET_ICON_TIMELAPSE_2\x10\x11\x12\x16\n\x12PRESET_ICON_CUSTOM\x10\x12\x12\x13\n\x0fPRESET_ICON_AIR\x10\x13\x12\x14\n\x10PRESET_ICON_BIKE\x10\x14\x12\x14\n\x10PRESET_ICON_EPIC\x10\x15\x12\x16\n\x12PRESET_ICON_INDOOR\x10\x16\x12\x15\n\x11PRESET_ICON_MOTOR\x10\x17\x12\x17\n\x13PRESET_ICON_MOUNTED\x10\x18\x12\x17\n\x13PRESET_ICON_OUTDOOR\x10\x19\x12\x13\n\x0fPRESET_ICON_POV\x10\x1a\x12\x16\n\x12PRESET_ICON_SELFIE\x10\x1b\x12\x15\n\x11PRESET_ICON_SKATE\x10\x1c\x12\x14\n\x10PRESET_ICON_SNOW\x10\x1d\x12\x15\n\x11PRESET_ICON_TRAIL\x10\x1e\x12\x16\n\x12PRESET_ICON_TRAVEL\x10\x1f\x12\x15\n\x11PRESET_ICON_WATER\x10 \x12\x17\n\x13PRESET_ICON_LOOPING\x10!\x12\x15\n\x11PRESET_ICON_STARS\x10"\x12\x16\n\x12PRESET_ICON_ACTION\x10#\x12\x1a\n\x16PRESET_ICON_FOLLOW_CAM\x10$\x12\x14\n\x10PRESET_ICON_SURF\x10%\x12\x14\n\x10PRESET_ICON_CITY\x10&\x12\x15\n\x11PRESET_ICON_SHAKY\x10\'\x12\x16\n\x12PRESET_ICON_CHESTY\x10(\x12\x16\n\x12PRESET_ICON_HELMET\x10)\x12\x14\n\x10PRESET_ICON_BITE\x10*\x12\x15\n\x11PRESET_ICON_BASIC\x10:\x12\x1c\n\x18PRESET_ICON_ULTRA_SLO_MO\x10;\x12"\n\x1ePRESET_ICON_STANDARD_ENDURANCE\x10<\x12"\n\x1ePRESET_ICON_ACTIVITY_ENDURANCE\x10=\x12#\n\x1fPRESET_ICON_CINEMATIC_ENDURANCE\x10>\x12\x1f\n\x1bPRESET_ICON_SLOMO_ENDURANCE\x10?\x12\x1c\n\x18PRESET_ICON_STATIONARY_1\x10@\x12\x1c\n\x18PRESET_ICON_STATIONARY_2\x10A\x12\x1c\n\x18PRESET_ICON_STATIONARY_3\x10B\x12\x1c\n\x18PRESET_ICON_STATIONARY_4\x10C\x12"\n\x1ePRESET_ICON_SIMPLE_SUPER_PHOTO\x10F\x12"\n\x1ePRESET_ICON_SIMPLE_NIGHT_PHOTO\x10G\x12%\n!PRESET_ICON_HIGHEST_QUALITY_VIDEO\x10I\x12&\n"PRESET_ICON_STANDARD_QUALITY_VIDEO\x10J\x12#\n\x1fPRESET_ICON_BASIC_QUALITY_VIDEO\x10K\x12\x1a\n\x16PRESET_ICON_STAR_TRAIL\x10L\x12\x1e\n\x1aPRESET_ICON_LIGHT_PAINTING\x10M\x12\x1b\n\x17PRESET_ICON_LIGHT_TRAIL\x10N\x12\x1a\n\x16PRESET_ICON_FULL_FRAME\x10O\x12 \n\x1bPRESET_ICON_TIMELAPSE_PHOTO\x10\xe8\x07\x12!\n\x1cPRESET_ICON_NIGHTLAPSE_PHOTO\x10\xe9\x07*\xfe\x0e\n\x0fEnumPresetTitle\x12\x19\n\x15PRESET_TITLE_ACTIVITY\x10\x00\x12\x19\n\x15PRESET_TITLE_STANDARD\x10\x01\x12\x1a\n\x16PRESET_TITLE_CINEMATIC\x10\x02\x12\x16\n\x12PRESET_TITLE_PHOTO\x10\x03\x12\x1b\n\x17PRESET_TITLE_LIVE_BURST\x10\x04\x12\x16\n\x12PRESET_TITLE_BURST\x10\x05\x12\x16\n\x12PRESET_TITLE_NIGHT\x10\x06\x12\x1a\n\x16PRESET_TITLE_TIME_WARP\x10\x07\x12\x1b\n\x17PRESET_TITLE_TIME_LAPSE\x10\x08\x12\x1c\n\x18PRESET_TITLE_NIGHT_LAPSE\x10\t\x12\x16\n\x12PRESET_TITLE_VIDEO\x10\n\x12\x16\n\x12PRESET_TITLE_SLOMO\x10\x0b\x12\x18\n\x14PRESET_TITLE_PHOTO_2\x10\r\x12\x19\n\x15PRESET_TITLE_PANORAMA\x10\x0e\x12\x1c\n\x18PRESET_TITLE_TIME_WARP_2\x10\x10\x12\x17\n\x13PRESET_TITLE_CUSTOM\x10\x12\x12\x14\n\x10PRESET_TITLE_AIR\x10\x13\x12\x15\n\x11PRESET_TITLE_BIKE\x10\x14\x12\x15\n\x11PRESET_TITLE_EPIC\x10\x15\x12\x17\n\x13PRESET_TITLE_INDOOR\x10\x16\x12\x16\n\x12PRESET_TITLE_MOTOR\x10\x17\x12\x18\n\x14PRESET_TITLE_MOUNTED\x10\x18\x12\x18\n\x14PRESET_TITLE_OUTDOOR\x10\x19\x12\x14\n\x10PRESET_TITLE_POV\x10\x1a\x12\x17\n\x13PRESET_TITLE_SELFIE\x10\x1b\x12\x16\n\x12PRESET_TITLE_SKATE\x10\x1c\x12\x15\n\x11PRESET_TITLE_SNOW\x10\x1d\x12\x16\n\x12PRESET_TITLE_TRAIL\x10\x1e\x12\x17\n\x13PRESET_TITLE_TRAVEL\x10\x1f\x12\x16\n\x12PRESET_TITLE_WATER\x10 \x12\x18\n\x14PRESET_TITLE_LOOPING\x10!\x12\x16\n\x12PRESET_TITLE_STARS\x10"\x12\x17\n\x13PRESET_TITLE_ACTION\x10#\x12\x1b\n\x17PRESET_TITLE_FOLLOW_CAM\x10$\x12\x15\n\x11PRESET_TITLE_SURF\x10%\x12\x15\n\x11PRESET_TITLE_CITY\x10&\x12\x16\n\x12PRESET_TITLE_SHAKY\x10\'\x12\x17\n\x13PRESET_TITLE_CHESTY\x10(\x12\x17\n\x13PRESET_TITLE_HELMET\x10)\x12\x15\n\x11PRESET_TITLE_BITE\x10*\x12\x16\n\x12PRESET_TITLE_BASIC\x10:\x12\x1d\n\x19PRESET_TITLE_ULTRA_SLO_MO\x10;\x12#\n\x1fPRESET_TITLE_STANDARD_ENDURANCE\x10<\x12#\n\x1fPRESET_TITLE_ACTIVITY_ENDURANCE\x10=\x12$\n PRESET_TITLE_CINEMATIC_ENDURANCE\x10>\x12 \n\x1cPRESET_TITLE_SLOMO_ENDURANCE\x10?\x12\x1d\n\x19PRESET_TITLE_STATIONARY_1\x10@\x12\x1d\n\x19PRESET_TITLE_STATIONARY_2\x10A\x12\x1d\n\x19PRESET_TITLE_STATIONARY_3\x10B\x12\x1d\n\x19PRESET_TITLE_STATIONARY_4\x10C\x12\x1d\n\x19PRESET_TITLE_SIMPLE_VIDEO\x10D\x12!\n\x1dPRESET_TITLE_SIMPLE_TIME_WARP\x10E\x12#\n\x1fPRESET_TITLE_SIMPLE_SUPER_PHOTO\x10F\x12#\n\x1fPRESET_TITLE_SIMPLE_NIGHT_PHOTO\x10G\x12\'\n#PRESET_TITLE_SIMPLE_VIDEO_ENDURANCE\x10H\x12 \n\x1cPRESET_TITLE_HIGHEST_QUALITY\x10I\x12!\n\x1dPRESET_TITLE_EXTENDED_BATTERY\x10J\x12 \n\x1cPRESET_TITLE_LONGEST_BATTERY\x10K\x12\x1b\n\x17PRESET_TITLE_STAR_TRAIL\x10L\x12\x1f\n\x1bPRESET_TITLE_LIGHT_PAINTING\x10M\x12\x1c\n\x18PRESET_TITLE_LIGHT_TRAIL\x10N\x12\x1b\n\x17PRESET_TITLE_FULL_FRAME\x10O\x12\'\n#PRESET_TITLE_STANDARD_QUALITY_VIDEO\x10R\x12$\n PRESET_TITLE_BASIC_QUALITY_VIDEO\x10S\x12&\n"PRESET_TITLE_HIGHEST_QUALITY_VIDEO\x10]\x12)\n%PRESET_TITLE_USER_DEFINED_CUSTOM_NAME\x10^' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "preset_status_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMFLATMODE._serialized_start = 818 + _ENUMFLATMODE._serialized_end = 1485 + _ENUMPRESETGROUP._serialized_start = 1487 + _ENUMPRESETGROUP._serialized_end = 1592 + _ENUMPRESETGROUPICON._serialized_start = 1595 + _ENUMPRESETGROUPICON._serialized_end = 1911 + _ENUMPRESETICON._serialized_start = 1914 + _ENUMPRESETICON._serialized_end = 3643 + _ENUMPRESETTITLE._serialized_start = 3646 + _ENUMPRESETTITLE._serialized_end = 5564 + _NOTIFYPRESETSTATUS._serialized_start = 59 + _NOTIFYPRESETSTATUS._serialized_end = 132 + _PRESET._serialized_start = 135 + _PRESET._serialized_end = 438 + _REQUESTCUSTOMPRESETUPDATE._serialized_start = 441 + _REQUESTCUSTOMPRESETUPDATE._serialized_end = 581 + _PRESETGROUP._serialized_start = 584 + _PRESETGROUP._serialized_end = 751 + _PRESETSETTING._serialized_start = 753 + _PRESETSETTING._serialized_end = 815 diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/preset_status_pb2.pyi b/demos/python/sdk_wireless_camera_control/open_gopro/proto/preset_status_pb2.pyi index 4f5035dd..d5145f88 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/preset_status_pb2.pyi +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/preset_status_pb2.pyi @@ -1,740 +1,701 @@ -""" -@generated by mypy-protobuf. Do not edit manually! -isort:skip_file -* -Defines the structure of protobuf message received from camera containing preset status -""" -import builtins -import collections.abc -import google.protobuf.descriptor -import google.protobuf.internal.containers -import google.protobuf.internal.enum_type_wrapper -import google.protobuf.message -import sys -import typing - -if sys.version_info >= (3, 10): - import typing as typing_extensions -else: - import typing_extensions -DESCRIPTOR: google.protobuf.descriptor.FileDescriptor - -class _EnumFlatMode: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumFlatModeEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumFlatMode.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - FLAT_MODE_UNKNOWN: _EnumFlatMode.ValueType - FLAT_MODE_PLAYBACK: _EnumFlatMode.ValueType - FLAT_MODE_SETUP: _EnumFlatMode.ValueType - FLAT_MODE_VIDEO: _EnumFlatMode.ValueType - FLAT_MODE_TIME_LAPSE_VIDEO: _EnumFlatMode.ValueType - FLAT_MODE_LOOPING: _EnumFlatMode.ValueType - FLAT_MODE_PHOTO_SINGLE: _EnumFlatMode.ValueType - FLAT_MODE_PHOTO: _EnumFlatMode.ValueType - FLAT_MODE_PHOTO_NIGHT: _EnumFlatMode.ValueType - FLAT_MODE_PHOTO_BURST: _EnumFlatMode.ValueType - FLAT_MODE_TIME_LAPSE_PHOTO: _EnumFlatMode.ValueType - FLAT_MODE_NIGHT_LAPSE_PHOTO: _EnumFlatMode.ValueType - FLAT_MODE_BROADCAST_RECORD: _EnumFlatMode.ValueType - FLAT_MODE_BROADCAST_BROADCAST: _EnumFlatMode.ValueType - FLAT_MODE_TIME_WARP_VIDEO: _EnumFlatMode.ValueType - FLAT_MODE_LIVE_BURST: _EnumFlatMode.ValueType - FLAT_MODE_NIGHT_LAPSE_VIDEO: _EnumFlatMode.ValueType - FLAT_MODE_SLOMO: _EnumFlatMode.ValueType - FLAT_MODE_IDLE: _EnumFlatMode.ValueType - FLAT_MODE_VIDEO_STAR_TRAIL: _EnumFlatMode.ValueType - FLAT_MODE_VIDEO_LIGHT_PAINTING: _EnumFlatMode.ValueType - FLAT_MODE_VIDEO_LIGHT_TRAIL: _EnumFlatMode.ValueType - -class EnumFlatMode(_EnumFlatMode, metaclass=_EnumFlatModeEnumTypeWrapper): ... - -FLAT_MODE_UNKNOWN: EnumFlatMode.ValueType -FLAT_MODE_PLAYBACK: EnumFlatMode.ValueType -FLAT_MODE_SETUP: EnumFlatMode.ValueType -FLAT_MODE_VIDEO: EnumFlatMode.ValueType -FLAT_MODE_TIME_LAPSE_VIDEO: EnumFlatMode.ValueType -FLAT_MODE_LOOPING: EnumFlatMode.ValueType -FLAT_MODE_PHOTO_SINGLE: EnumFlatMode.ValueType -FLAT_MODE_PHOTO: EnumFlatMode.ValueType -FLAT_MODE_PHOTO_NIGHT: EnumFlatMode.ValueType -FLAT_MODE_PHOTO_BURST: EnumFlatMode.ValueType -FLAT_MODE_TIME_LAPSE_PHOTO: EnumFlatMode.ValueType -FLAT_MODE_NIGHT_LAPSE_PHOTO: EnumFlatMode.ValueType -FLAT_MODE_BROADCAST_RECORD: EnumFlatMode.ValueType -FLAT_MODE_BROADCAST_BROADCAST: EnumFlatMode.ValueType -FLAT_MODE_TIME_WARP_VIDEO: EnumFlatMode.ValueType -FLAT_MODE_LIVE_BURST: EnumFlatMode.ValueType -FLAT_MODE_NIGHT_LAPSE_VIDEO: EnumFlatMode.ValueType -FLAT_MODE_SLOMO: EnumFlatMode.ValueType -FLAT_MODE_IDLE: EnumFlatMode.ValueType -FLAT_MODE_VIDEO_STAR_TRAIL: EnumFlatMode.ValueType -FLAT_MODE_VIDEO_LIGHT_PAINTING: EnumFlatMode.ValueType -FLAT_MODE_VIDEO_LIGHT_TRAIL: EnumFlatMode.ValueType -global___EnumFlatMode = EnumFlatMode - -class _EnumPresetGroup: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumPresetGroupEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumPresetGroup.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - PRESET_GROUP_ID_VIDEO: _EnumPresetGroup.ValueType - PRESET_GROUP_ID_PHOTO: _EnumPresetGroup.ValueType - PRESET_GROUP_ID_TIMELAPSE: _EnumPresetGroup.ValueType - -class EnumPresetGroup(_EnumPresetGroup, metaclass=_EnumPresetGroupEnumTypeWrapper): ... - -PRESET_GROUP_ID_VIDEO: EnumPresetGroup.ValueType -PRESET_GROUP_ID_PHOTO: EnumPresetGroup.ValueType -PRESET_GROUP_ID_TIMELAPSE: EnumPresetGroup.ValueType -global___EnumPresetGroup = EnumPresetGroup - -class _EnumPresetGroupIcon: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumPresetGroupIconEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumPresetGroupIcon.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - PRESET_GROUP_VIDEO_ICON_ID: _EnumPresetGroupIcon.ValueType - PRESET_GROUP_PHOTO_ICON_ID: _EnumPresetGroupIcon.ValueType - PRESET_GROUP_TIMELAPSE_ICON_ID: _EnumPresetGroupIcon.ValueType - PRESET_GROUP_LONG_BAT_VIDEO_ICON_ID: _EnumPresetGroupIcon.ValueType - PRESET_GROUP_ENDURANCE_VIDEO_ICON_ID: _EnumPresetGroupIcon.ValueType - PRESET_GROUP_MAX_VIDEO_ICON_ID: _EnumPresetGroupIcon.ValueType - PRESET_GROUP_MAX_PHOTO_ICON_ID: _EnumPresetGroupIcon.ValueType - PRESET_GROUP_MAX_TIMELAPSE_ICON_ID: _EnumPresetGroupIcon.ValueType - -class EnumPresetGroupIcon(_EnumPresetGroupIcon, metaclass=_EnumPresetGroupIconEnumTypeWrapper): ... - -PRESET_GROUP_VIDEO_ICON_ID: EnumPresetGroupIcon.ValueType -PRESET_GROUP_PHOTO_ICON_ID: EnumPresetGroupIcon.ValueType -PRESET_GROUP_TIMELAPSE_ICON_ID: EnumPresetGroupIcon.ValueType -PRESET_GROUP_LONG_BAT_VIDEO_ICON_ID: EnumPresetGroupIcon.ValueType -PRESET_GROUP_ENDURANCE_VIDEO_ICON_ID: EnumPresetGroupIcon.ValueType -PRESET_GROUP_MAX_VIDEO_ICON_ID: EnumPresetGroupIcon.ValueType -PRESET_GROUP_MAX_PHOTO_ICON_ID: EnumPresetGroupIcon.ValueType -PRESET_GROUP_MAX_TIMELAPSE_ICON_ID: EnumPresetGroupIcon.ValueType -global___EnumPresetGroupIcon = EnumPresetGroupIcon - -class _EnumPresetIcon: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumPresetIconEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumPresetIcon.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - PRESET_ICON_VIDEO: _EnumPresetIcon.ValueType - PRESET_ICON_ACTIVITY: _EnumPresetIcon.ValueType - PRESET_ICON_CINEMATIC: _EnumPresetIcon.ValueType - PRESET_ICON_PHOTO: _EnumPresetIcon.ValueType - PRESET_ICON_LIVE_BURST: _EnumPresetIcon.ValueType - PRESET_ICON_BURST: _EnumPresetIcon.ValueType - PRESET_ICON_PHOTO_NIGHT: _EnumPresetIcon.ValueType - PRESET_ICON_TIMEWARP: _EnumPresetIcon.ValueType - PRESET_ICON_TIMELAPSE: _EnumPresetIcon.ValueType - PRESET_ICON_NIGHTLAPSE: _EnumPresetIcon.ValueType - PRESET_ICON_SNAIL: _EnumPresetIcon.ValueType - PRESET_ICON_VIDEO_2: _EnumPresetIcon.ValueType - PRESET_ICON_360_VIDEO: _EnumPresetIcon.ValueType - PRESET_ICON_PHOTO_2: _EnumPresetIcon.ValueType - PRESET_ICON_PANORAMA: _EnumPresetIcon.ValueType - PRESET_ICON_BURST_2: _EnumPresetIcon.ValueType - PRESET_ICON_TIMEWARP_2: _EnumPresetIcon.ValueType - PRESET_ICON_TIMELAPSE_2: _EnumPresetIcon.ValueType - PRESET_ICON_CUSTOM: _EnumPresetIcon.ValueType - PRESET_ICON_AIR: _EnumPresetIcon.ValueType - PRESET_ICON_BIKE: _EnumPresetIcon.ValueType - PRESET_ICON_EPIC: _EnumPresetIcon.ValueType - PRESET_ICON_INDOOR: _EnumPresetIcon.ValueType - PRESET_ICON_MOTOR: _EnumPresetIcon.ValueType - PRESET_ICON_MOUNTED: _EnumPresetIcon.ValueType - PRESET_ICON_OUTDOOR: _EnumPresetIcon.ValueType - PRESET_ICON_POV: _EnumPresetIcon.ValueType - PRESET_ICON_SELFIE: _EnumPresetIcon.ValueType - PRESET_ICON_SKATE: _EnumPresetIcon.ValueType - PRESET_ICON_SNOW: _EnumPresetIcon.ValueType - PRESET_ICON_TRAIL: _EnumPresetIcon.ValueType - PRESET_ICON_TRAVEL: _EnumPresetIcon.ValueType - PRESET_ICON_WATER: _EnumPresetIcon.ValueType - PRESET_ICON_LOOPING: _EnumPresetIcon.ValueType - PRESET_ICON_STARS: _EnumPresetIcon.ValueType - "*\n New custom icon (34 - 42)added for HERO 12\n " - PRESET_ICON_ACTION: _EnumPresetIcon.ValueType - PRESET_ICON_FOLLOW_CAM: _EnumPresetIcon.ValueType - PRESET_ICON_SURF: _EnumPresetIcon.ValueType - PRESET_ICON_CITY: _EnumPresetIcon.ValueType - PRESET_ICON_SHAKY: _EnumPresetIcon.ValueType - PRESET_ICON_CHESTY: _EnumPresetIcon.ValueType - PRESET_ICON_HELMET: _EnumPresetIcon.ValueType - PRESET_ICON_BITE: _EnumPresetIcon.ValueType - PRESET_ICON_MAX_VIDEO: _EnumPresetIcon.ValueType - "*\n Reserved 43 - 50 for Custom presets. Add icons below for new presets starting from 51\n " - PRESET_ICON_MAX_PHOTO: _EnumPresetIcon.ValueType - PRESET_ICON_MAX_TIMEWARP: _EnumPresetIcon.ValueType - PRESET_ICON_BASIC: _EnumPresetIcon.ValueType - PRESET_ICON_ULTRA_SLO_MO: _EnumPresetIcon.ValueType - PRESET_ICON_STANDARD_ENDURANCE: _EnumPresetIcon.ValueType - PRESET_ICON_ACTIVITY_ENDURANCE: _EnumPresetIcon.ValueType - PRESET_ICON_CINEMATIC_ENDURANCE: _EnumPresetIcon.ValueType - PRESET_ICON_SLOMO_ENDURANCE: _EnumPresetIcon.ValueType - PRESET_ICON_STATIONARY_1: _EnumPresetIcon.ValueType - PRESET_ICON_STATIONARY_2: _EnumPresetIcon.ValueType - PRESET_ICON_STATIONARY_3: _EnumPresetIcon.ValueType - PRESET_ICON_STATIONARY_4: _EnumPresetIcon.ValueType - PRESET_ICON_SIMPLE_SUPER_PHOTO: _EnumPresetIcon.ValueType - PRESET_ICON_SIMPLE_NIGHT_PHOTO: _EnumPresetIcon.ValueType - PRESET_ICON_HIGHEST_QUALITY_VIDEO: _EnumPresetIcon.ValueType - PRESET_ICON_STANDARD_QUALITY_VIDEO: _EnumPresetIcon.ValueType - PRESET_ICON_BASIC_QUALITY_VIDEO: _EnumPresetIcon.ValueType - PRESET_ICON_STAR_TRAIL: _EnumPresetIcon.ValueType - PRESET_ICON_LIGHT_PAINTING: _EnumPresetIcon.ValueType - PRESET_ICON_LIGHT_TRAIL: _EnumPresetIcon.ValueType - PRESET_ICON_FULL_FRAME: _EnumPresetIcon.ValueType - PRESET_ICON_EASY_MAX_VIDEO: _EnumPresetIcon.ValueType - PRESET_ICON_EASY_MAX_PHOTO: _EnumPresetIcon.ValueType - PRESET_ICON_EASY_MAX_TIMEWARP: _EnumPresetIcon.ValueType - PRESET_ICON_EASY_MAX_STAR_TRAIL: _EnumPresetIcon.ValueType - PRESET_ICON_EASY_MAX_LIGHT_PAINTING: _EnumPresetIcon.ValueType - PRESET_ICON_EASY_MAX_LIGHT_TRAIL: _EnumPresetIcon.ValueType - PRESET_ICON_MAX_STAR_TRAIL: _EnumPresetIcon.ValueType - PRESET_ICON_MAX_LIGHT_PAINTING: _EnumPresetIcon.ValueType - PRESET_ICON_MAX_LIGHT_TRAIL: _EnumPresetIcon.ValueType - PRESET_ICON_TIMELAPSE_PHOTO: _EnumPresetIcon.ValueType - PRESET_ICON_NIGHTLAPSE_PHOTO: _EnumPresetIcon.ValueType - -class EnumPresetIcon(_EnumPresetIcon, metaclass=_EnumPresetIconEnumTypeWrapper): ... - -PRESET_ICON_VIDEO: EnumPresetIcon.ValueType -PRESET_ICON_ACTIVITY: EnumPresetIcon.ValueType -PRESET_ICON_CINEMATIC: EnumPresetIcon.ValueType -PRESET_ICON_PHOTO: EnumPresetIcon.ValueType -PRESET_ICON_LIVE_BURST: EnumPresetIcon.ValueType -PRESET_ICON_BURST: EnumPresetIcon.ValueType -PRESET_ICON_PHOTO_NIGHT: EnumPresetIcon.ValueType -PRESET_ICON_TIMEWARP: EnumPresetIcon.ValueType -PRESET_ICON_TIMELAPSE: EnumPresetIcon.ValueType -PRESET_ICON_NIGHTLAPSE: EnumPresetIcon.ValueType -PRESET_ICON_SNAIL: EnumPresetIcon.ValueType -PRESET_ICON_VIDEO_2: EnumPresetIcon.ValueType -PRESET_ICON_360_VIDEO: EnumPresetIcon.ValueType -PRESET_ICON_PHOTO_2: EnumPresetIcon.ValueType -PRESET_ICON_PANORAMA: EnumPresetIcon.ValueType -PRESET_ICON_BURST_2: EnumPresetIcon.ValueType -PRESET_ICON_TIMEWARP_2: EnumPresetIcon.ValueType -PRESET_ICON_TIMELAPSE_2: EnumPresetIcon.ValueType -PRESET_ICON_CUSTOM: EnumPresetIcon.ValueType -PRESET_ICON_AIR: EnumPresetIcon.ValueType -PRESET_ICON_BIKE: EnumPresetIcon.ValueType -PRESET_ICON_EPIC: EnumPresetIcon.ValueType -PRESET_ICON_INDOOR: EnumPresetIcon.ValueType -PRESET_ICON_MOTOR: EnumPresetIcon.ValueType -PRESET_ICON_MOUNTED: EnumPresetIcon.ValueType -PRESET_ICON_OUTDOOR: EnumPresetIcon.ValueType -PRESET_ICON_POV: EnumPresetIcon.ValueType -PRESET_ICON_SELFIE: EnumPresetIcon.ValueType -PRESET_ICON_SKATE: EnumPresetIcon.ValueType -PRESET_ICON_SNOW: EnumPresetIcon.ValueType -PRESET_ICON_TRAIL: EnumPresetIcon.ValueType -PRESET_ICON_TRAVEL: EnumPresetIcon.ValueType -PRESET_ICON_WATER: EnumPresetIcon.ValueType -PRESET_ICON_LOOPING: EnumPresetIcon.ValueType -PRESET_ICON_STARS: EnumPresetIcon.ValueType -"*\nNew custom icon (34 - 42)added for HERO 12\n" -PRESET_ICON_ACTION: EnumPresetIcon.ValueType -PRESET_ICON_FOLLOW_CAM: EnumPresetIcon.ValueType -PRESET_ICON_SURF: EnumPresetIcon.ValueType -PRESET_ICON_CITY: EnumPresetIcon.ValueType -PRESET_ICON_SHAKY: EnumPresetIcon.ValueType -PRESET_ICON_CHESTY: EnumPresetIcon.ValueType -PRESET_ICON_HELMET: EnumPresetIcon.ValueType -PRESET_ICON_BITE: EnumPresetIcon.ValueType -PRESET_ICON_MAX_VIDEO: EnumPresetIcon.ValueType -"*\nReserved 43 - 50 for Custom presets. Add icons below for new presets starting from 51\n" -PRESET_ICON_MAX_PHOTO: EnumPresetIcon.ValueType -PRESET_ICON_MAX_TIMEWARP: EnumPresetIcon.ValueType -PRESET_ICON_BASIC: EnumPresetIcon.ValueType -PRESET_ICON_ULTRA_SLO_MO: EnumPresetIcon.ValueType -PRESET_ICON_STANDARD_ENDURANCE: EnumPresetIcon.ValueType -PRESET_ICON_ACTIVITY_ENDURANCE: EnumPresetIcon.ValueType -PRESET_ICON_CINEMATIC_ENDURANCE: EnumPresetIcon.ValueType -PRESET_ICON_SLOMO_ENDURANCE: EnumPresetIcon.ValueType -PRESET_ICON_STATIONARY_1: EnumPresetIcon.ValueType -PRESET_ICON_STATIONARY_2: EnumPresetIcon.ValueType -PRESET_ICON_STATIONARY_3: EnumPresetIcon.ValueType -PRESET_ICON_STATIONARY_4: EnumPresetIcon.ValueType -PRESET_ICON_SIMPLE_SUPER_PHOTO: EnumPresetIcon.ValueType -PRESET_ICON_SIMPLE_NIGHT_PHOTO: EnumPresetIcon.ValueType -PRESET_ICON_HIGHEST_QUALITY_VIDEO: EnumPresetIcon.ValueType -PRESET_ICON_STANDARD_QUALITY_VIDEO: EnumPresetIcon.ValueType -PRESET_ICON_BASIC_QUALITY_VIDEO: EnumPresetIcon.ValueType -PRESET_ICON_STAR_TRAIL: EnumPresetIcon.ValueType -PRESET_ICON_LIGHT_PAINTING: EnumPresetIcon.ValueType -PRESET_ICON_LIGHT_TRAIL: EnumPresetIcon.ValueType -PRESET_ICON_FULL_FRAME: EnumPresetIcon.ValueType -PRESET_ICON_EASY_MAX_VIDEO: EnumPresetIcon.ValueType -PRESET_ICON_EASY_MAX_PHOTO: EnumPresetIcon.ValueType -PRESET_ICON_EASY_MAX_TIMEWARP: EnumPresetIcon.ValueType -PRESET_ICON_EASY_MAX_STAR_TRAIL: EnumPresetIcon.ValueType -PRESET_ICON_EASY_MAX_LIGHT_PAINTING: EnumPresetIcon.ValueType -PRESET_ICON_EASY_MAX_LIGHT_TRAIL: EnumPresetIcon.ValueType -PRESET_ICON_MAX_STAR_TRAIL: EnumPresetIcon.ValueType -PRESET_ICON_MAX_LIGHT_PAINTING: EnumPresetIcon.ValueType -PRESET_ICON_MAX_LIGHT_TRAIL: EnumPresetIcon.ValueType -PRESET_ICON_TIMELAPSE_PHOTO: EnumPresetIcon.ValueType -PRESET_ICON_NIGHTLAPSE_PHOTO: EnumPresetIcon.ValueType -global___EnumPresetIcon = EnumPresetIcon - -class _EnumPresetTitle: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumPresetTitleEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumPresetTitle.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - PRESET_TITLE_ACTIVITY: _EnumPresetTitle.ValueType - PRESET_TITLE_STANDARD: _EnumPresetTitle.ValueType - PRESET_TITLE_CINEMATIC: _EnumPresetTitle.ValueType - PRESET_TITLE_PHOTO: _EnumPresetTitle.ValueType - PRESET_TITLE_LIVE_BURST: _EnumPresetTitle.ValueType - PRESET_TITLE_BURST: _EnumPresetTitle.ValueType - PRESET_TITLE_NIGHT: _EnumPresetTitle.ValueType - PRESET_TITLE_TIME_WARP: _EnumPresetTitle.ValueType - PRESET_TITLE_TIME_LAPSE: _EnumPresetTitle.ValueType - PRESET_TITLE_NIGHT_LAPSE: _EnumPresetTitle.ValueType - PRESET_TITLE_VIDEO: _EnumPresetTitle.ValueType - PRESET_TITLE_SLOMO: _EnumPresetTitle.ValueType - PRESET_TITLE_360_VIDEO: _EnumPresetTitle.ValueType - PRESET_TITLE_PHOTO_2: _EnumPresetTitle.ValueType - PRESET_TITLE_PANORAMA: _EnumPresetTitle.ValueType - PRESET_TITLE_360_PHOTO: _EnumPresetTitle.ValueType - PRESET_TITLE_TIME_WARP_2: _EnumPresetTitle.ValueType - PRESET_TITLE_360_TIME_WARP: _EnumPresetTitle.ValueType - PRESET_TITLE_CUSTOM: _EnumPresetTitle.ValueType - PRESET_TITLE_AIR: _EnumPresetTitle.ValueType - PRESET_TITLE_BIKE: _EnumPresetTitle.ValueType - PRESET_TITLE_EPIC: _EnumPresetTitle.ValueType - PRESET_TITLE_INDOOR: _EnumPresetTitle.ValueType - PRESET_TITLE_MOTOR: _EnumPresetTitle.ValueType - PRESET_TITLE_MOUNTED: _EnumPresetTitle.ValueType - PRESET_TITLE_OUTDOOR: _EnumPresetTitle.ValueType - PRESET_TITLE_POV: _EnumPresetTitle.ValueType - PRESET_TITLE_SELFIE: _EnumPresetTitle.ValueType - PRESET_TITLE_SKATE: _EnumPresetTitle.ValueType - PRESET_TITLE_SNOW: _EnumPresetTitle.ValueType - PRESET_TITLE_TRAIL: _EnumPresetTitle.ValueType - PRESET_TITLE_TRAVEL: _EnumPresetTitle.ValueType - PRESET_TITLE_WATER: _EnumPresetTitle.ValueType - PRESET_TITLE_LOOPING: _EnumPresetTitle.ValueType - PRESET_TITLE_STARS: _EnumPresetTitle.ValueType - "*\n New custom names (34 - 42)added for HERO 12\n " - PRESET_TITLE_ACTION: _EnumPresetTitle.ValueType - PRESET_TITLE_FOLLOW_CAM: _EnumPresetTitle.ValueType - PRESET_TITLE_SURF: _EnumPresetTitle.ValueType - PRESET_TITLE_CITY: _EnumPresetTitle.ValueType - PRESET_TITLE_SHAKY: _EnumPresetTitle.ValueType - PRESET_TITLE_CHESTY: _EnumPresetTitle.ValueType - PRESET_TITLE_HELMET: _EnumPresetTitle.ValueType - PRESET_TITLE_BITE: _EnumPresetTitle.ValueType - PRESET_TITLE_360_TIMELAPSE: _EnumPresetTitle.ValueType - "*\n Reserved 43 - 50 for custom presets.\n " - PRESET_TITLE_360_NIGHT_LAPSE: _EnumPresetTitle.ValueType - PRESET_TITLE_360_NIGHT_PHOTO: _EnumPresetTitle.ValueType - PRESET_TITLE_PANO_TIME_LAPSE: _EnumPresetTitle.ValueType - PRESET_TITLE_MAX_VIDEO: _EnumPresetTitle.ValueType - PRESET_TITLE_MAX_PHOTO: _EnumPresetTitle.ValueType - PRESET_TITLE_MAX_TIMEWARP: _EnumPresetTitle.ValueType - PRESET_TITLE_BASIC: _EnumPresetTitle.ValueType - PRESET_TITLE_ULTRA_SLO_MO: _EnumPresetTitle.ValueType - PRESET_TITLE_STANDARD_ENDURANCE: _EnumPresetTitle.ValueType - PRESET_TITLE_ACTIVITY_ENDURANCE: _EnumPresetTitle.ValueType - PRESET_TITLE_CINEMATIC_ENDURANCE: _EnumPresetTitle.ValueType - PRESET_TITLE_SLOMO_ENDURANCE: _EnumPresetTitle.ValueType - PRESET_TITLE_STATIONARY_1: _EnumPresetTitle.ValueType - PRESET_TITLE_STATIONARY_2: _EnumPresetTitle.ValueType - PRESET_TITLE_STATIONARY_3: _EnumPresetTitle.ValueType - PRESET_TITLE_STATIONARY_4: _EnumPresetTitle.ValueType - PRESET_TITLE_SIMPLE_VIDEO: _EnumPresetTitle.ValueType - PRESET_TITLE_SIMPLE_TIME_WARP: _EnumPresetTitle.ValueType - PRESET_TITLE_SIMPLE_SUPER_PHOTO: _EnumPresetTitle.ValueType - PRESET_TITLE_SIMPLE_NIGHT_PHOTO: _EnumPresetTitle.ValueType - PRESET_TITLE_SIMPLE_VIDEO_ENDURANCE: _EnumPresetTitle.ValueType - PRESET_TITLE_HIGHEST_QUALITY: _EnumPresetTitle.ValueType - PRESET_TITLE_EXTENDED_BATTERY: _EnumPresetTitle.ValueType - PRESET_TITLE_LONGEST_BATTERY: _EnumPresetTitle.ValueType - PRESET_TITLE_STAR_TRAIL: _EnumPresetTitle.ValueType - PRESET_TITLE_LIGHT_PAINTING: _EnumPresetTitle.ValueType - PRESET_TITLE_LIGHT_TRAIL: _EnumPresetTitle.ValueType - PRESET_TITLE_FULL_FRAME: _EnumPresetTitle.ValueType - PRESET_TITLE_MAX_LENS_VIDEO: _EnumPresetTitle.ValueType - PRESET_TITLE_MAX_LENS_TIMEWARP: _EnumPresetTitle.ValueType - PRESET_TITLE_STANDARD_QUALITY_VIDEO: _EnumPresetTitle.ValueType - PRESET_TITLE_BASIC_QUALITY_VIDEO: _EnumPresetTitle.ValueType - PRESET_TITLE_EASY_MAX_VIDEO: _EnumPresetTitle.ValueType - PRESET_TITLE_EASY_MAX_PHOTO: _EnumPresetTitle.ValueType - PRESET_TITLE_EASY_MAX_TIMEWARP: _EnumPresetTitle.ValueType - PRESET_TITLE_EASY_MAX_STAR_TRAIL: _EnumPresetTitle.ValueType - PRESET_TITLE_EASY_MAX_LIGHT_PAINTING: _EnumPresetTitle.ValueType - PRESET_TITLE_EASY_MAX_LIGHT_TRAIL: _EnumPresetTitle.ValueType - PRESET_TITLE_MAX_STAR_TRAIL: _EnumPresetTitle.ValueType - PRESET_TITLE_MAX_LIGHT_PAINTING: _EnumPresetTitle.ValueType - PRESET_TITLE_MAX_LIGHT_TRAIL: _EnumPresetTitle.ValueType - PRESET_TITLE_HIGHEST_QUALITY_VIDEO: _EnumPresetTitle.ValueType - PRESET_TITLE_USER_DEFINED_CUSTOM_NAME: _EnumPresetTitle.ValueType - -class EnumPresetTitle(_EnumPresetTitle, metaclass=_EnumPresetTitleEnumTypeWrapper): ... - -PRESET_TITLE_ACTIVITY: EnumPresetTitle.ValueType -PRESET_TITLE_STANDARD: EnumPresetTitle.ValueType -PRESET_TITLE_CINEMATIC: EnumPresetTitle.ValueType -PRESET_TITLE_PHOTO: EnumPresetTitle.ValueType -PRESET_TITLE_LIVE_BURST: EnumPresetTitle.ValueType -PRESET_TITLE_BURST: EnumPresetTitle.ValueType -PRESET_TITLE_NIGHT: EnumPresetTitle.ValueType -PRESET_TITLE_TIME_WARP: EnumPresetTitle.ValueType -PRESET_TITLE_TIME_LAPSE: EnumPresetTitle.ValueType -PRESET_TITLE_NIGHT_LAPSE: EnumPresetTitle.ValueType -PRESET_TITLE_VIDEO: EnumPresetTitle.ValueType -PRESET_TITLE_SLOMO: EnumPresetTitle.ValueType -PRESET_TITLE_360_VIDEO: EnumPresetTitle.ValueType -PRESET_TITLE_PHOTO_2: EnumPresetTitle.ValueType -PRESET_TITLE_PANORAMA: EnumPresetTitle.ValueType -PRESET_TITLE_360_PHOTO: EnumPresetTitle.ValueType -PRESET_TITLE_TIME_WARP_2: EnumPresetTitle.ValueType -PRESET_TITLE_360_TIME_WARP: EnumPresetTitle.ValueType -PRESET_TITLE_CUSTOM: EnumPresetTitle.ValueType -PRESET_TITLE_AIR: EnumPresetTitle.ValueType -PRESET_TITLE_BIKE: EnumPresetTitle.ValueType -PRESET_TITLE_EPIC: EnumPresetTitle.ValueType -PRESET_TITLE_INDOOR: EnumPresetTitle.ValueType -PRESET_TITLE_MOTOR: EnumPresetTitle.ValueType -PRESET_TITLE_MOUNTED: EnumPresetTitle.ValueType -PRESET_TITLE_OUTDOOR: EnumPresetTitle.ValueType -PRESET_TITLE_POV: EnumPresetTitle.ValueType -PRESET_TITLE_SELFIE: EnumPresetTitle.ValueType -PRESET_TITLE_SKATE: EnumPresetTitle.ValueType -PRESET_TITLE_SNOW: EnumPresetTitle.ValueType -PRESET_TITLE_TRAIL: EnumPresetTitle.ValueType -PRESET_TITLE_TRAVEL: EnumPresetTitle.ValueType -PRESET_TITLE_WATER: EnumPresetTitle.ValueType -PRESET_TITLE_LOOPING: EnumPresetTitle.ValueType -PRESET_TITLE_STARS: EnumPresetTitle.ValueType -"*\nNew custom names (34 - 42)added for HERO 12\n" -PRESET_TITLE_ACTION: EnumPresetTitle.ValueType -PRESET_TITLE_FOLLOW_CAM: EnumPresetTitle.ValueType -PRESET_TITLE_SURF: EnumPresetTitle.ValueType -PRESET_TITLE_CITY: EnumPresetTitle.ValueType -PRESET_TITLE_SHAKY: EnumPresetTitle.ValueType -PRESET_TITLE_CHESTY: EnumPresetTitle.ValueType -PRESET_TITLE_HELMET: EnumPresetTitle.ValueType -PRESET_TITLE_BITE: EnumPresetTitle.ValueType -PRESET_TITLE_360_TIMELAPSE: EnumPresetTitle.ValueType -"*\nReserved 43 - 50 for custom presets.\n" -PRESET_TITLE_360_NIGHT_LAPSE: EnumPresetTitle.ValueType -PRESET_TITLE_360_NIGHT_PHOTO: EnumPresetTitle.ValueType -PRESET_TITLE_PANO_TIME_LAPSE: EnumPresetTitle.ValueType -PRESET_TITLE_MAX_VIDEO: EnumPresetTitle.ValueType -PRESET_TITLE_MAX_PHOTO: EnumPresetTitle.ValueType -PRESET_TITLE_MAX_TIMEWARP: EnumPresetTitle.ValueType -PRESET_TITLE_BASIC: EnumPresetTitle.ValueType -PRESET_TITLE_ULTRA_SLO_MO: EnumPresetTitle.ValueType -PRESET_TITLE_STANDARD_ENDURANCE: EnumPresetTitle.ValueType -PRESET_TITLE_ACTIVITY_ENDURANCE: EnumPresetTitle.ValueType -PRESET_TITLE_CINEMATIC_ENDURANCE: EnumPresetTitle.ValueType -PRESET_TITLE_SLOMO_ENDURANCE: EnumPresetTitle.ValueType -PRESET_TITLE_STATIONARY_1: EnumPresetTitle.ValueType -PRESET_TITLE_STATIONARY_2: EnumPresetTitle.ValueType -PRESET_TITLE_STATIONARY_3: EnumPresetTitle.ValueType -PRESET_TITLE_STATIONARY_4: EnumPresetTitle.ValueType -PRESET_TITLE_SIMPLE_VIDEO: EnumPresetTitle.ValueType -PRESET_TITLE_SIMPLE_TIME_WARP: EnumPresetTitle.ValueType -PRESET_TITLE_SIMPLE_SUPER_PHOTO: EnumPresetTitle.ValueType -PRESET_TITLE_SIMPLE_NIGHT_PHOTO: EnumPresetTitle.ValueType -PRESET_TITLE_SIMPLE_VIDEO_ENDURANCE: EnumPresetTitle.ValueType -PRESET_TITLE_HIGHEST_QUALITY: EnumPresetTitle.ValueType -PRESET_TITLE_EXTENDED_BATTERY: EnumPresetTitle.ValueType -PRESET_TITLE_LONGEST_BATTERY: EnumPresetTitle.ValueType -PRESET_TITLE_STAR_TRAIL: EnumPresetTitle.ValueType -PRESET_TITLE_LIGHT_PAINTING: EnumPresetTitle.ValueType -PRESET_TITLE_LIGHT_TRAIL: EnumPresetTitle.ValueType -PRESET_TITLE_FULL_FRAME: EnumPresetTitle.ValueType -PRESET_TITLE_MAX_LENS_VIDEO: EnumPresetTitle.ValueType -PRESET_TITLE_MAX_LENS_TIMEWARP: EnumPresetTitle.ValueType -PRESET_TITLE_STANDARD_QUALITY_VIDEO: EnumPresetTitle.ValueType -PRESET_TITLE_BASIC_QUALITY_VIDEO: EnumPresetTitle.ValueType -PRESET_TITLE_EASY_MAX_VIDEO: EnumPresetTitle.ValueType -PRESET_TITLE_EASY_MAX_PHOTO: EnumPresetTitle.ValueType -PRESET_TITLE_EASY_MAX_TIMEWARP: EnumPresetTitle.ValueType -PRESET_TITLE_EASY_MAX_STAR_TRAIL: EnumPresetTitle.ValueType -PRESET_TITLE_EASY_MAX_LIGHT_PAINTING: EnumPresetTitle.ValueType -PRESET_TITLE_EASY_MAX_LIGHT_TRAIL: EnumPresetTitle.ValueType -PRESET_TITLE_MAX_STAR_TRAIL: EnumPresetTitle.ValueType -PRESET_TITLE_MAX_LIGHT_PAINTING: EnumPresetTitle.ValueType -PRESET_TITLE_MAX_LIGHT_TRAIL: EnumPresetTitle.ValueType -PRESET_TITLE_HIGHEST_QUALITY_VIDEO: EnumPresetTitle.ValueType -PRESET_TITLE_USER_DEFINED_CUSTOM_NAME: EnumPresetTitle.ValueType -global___EnumPresetTitle = EnumPresetTitle - -class NotifyPresetStatus(google.protobuf.message.Message): - """* - Current Preset status - - Sent either: - - synchronously via initial response to @ref RequestGetPresetStatus - - asynchronously when Preset change if registered in @rev RequestGetPresetStatus - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - PRESET_GROUP_ARRAY_FIELD_NUMBER: builtins.int - - @property - def preset_group_array( - self, - ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___PresetGroup]: - """Array of currently available Preset Groups""" - def __init__(self, *, preset_group_array: collections.abc.Iterable[global___PresetGroup] | None = ...) -> None: ... - def ClearField( - self, field_name: typing_extensions.Literal["preset_group_array", b"preset_group_array"] - ) -> None: ... - -global___NotifyPresetStatus = NotifyPresetStatus - -class Preset(google.protobuf.message.Message): - """* - An individual preset. - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - ID_FIELD_NUMBER: builtins.int - MODE_FIELD_NUMBER: builtins.int - TITLE_ID_FIELD_NUMBER: builtins.int - TITLE_NUMBER_FIELD_NUMBER: builtins.int - USER_DEFINED_FIELD_NUMBER: builtins.int - ICON_FIELD_NUMBER: builtins.int - SETTING_ARRAY_FIELD_NUMBER: builtins.int - IS_MODIFIED_FIELD_NUMBER: builtins.int - IS_FIXED_FIELD_NUMBER: builtins.int - CUSTOM_NAME_FIELD_NUMBER: builtins.int - id: builtins.int - "Preset ID" - mode: global___EnumFlatMode.ValueType - "Preset flatmode ID" - title_id: global___EnumPresetTitle.ValueType - "Preset Title ID" - title_number: builtins.int - "Preset Title Number (e.g. 1/2/3 in Custom1, Custom2, Custom3)" - user_defined: builtins.bool - "Is the Preset custom/user-defined?" - icon: global___EnumPresetIcon.ValueType - "Preset Icon ID" - - @property - def setting_array( - self, - ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___PresetSetting]: - """Array of settings associated with this Preset""" - is_modified: builtins.bool - "Has Preset been modified from factory defaults? (False for user-defined Presets)" - is_fixed: builtins.bool - "Is this Preset mutable?" - custom_name: builtins.str - "Custom string name given to this preset via @ref RequestCustomPresetUpdate" - - def __init__( - self, - *, - id: builtins.int | None = ..., - mode: global___EnumFlatMode.ValueType | None = ..., - title_id: global___EnumPresetTitle.ValueType | None = ..., - title_number: builtins.int | None = ..., - user_defined: builtins.bool | None = ..., - icon: global___EnumPresetIcon.ValueType | None = ..., - setting_array: collections.abc.Iterable[global___PresetSetting] | None = ..., - is_modified: builtins.bool | None = ..., - is_fixed: builtins.bool | None = ..., - custom_name: builtins.str | None = ... - ) -> None: ... - def HasField( - self, - field_name: typing_extensions.Literal[ - "custom_name", - b"custom_name", - "icon", - b"icon", - "id", - b"id", - "is_fixed", - b"is_fixed", - "is_modified", - b"is_modified", - "mode", - b"mode", - "title_id", - b"title_id", - "title_number", - b"title_number", - "user_defined", - b"user_defined", - ], - ) -> builtins.bool: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "custom_name", - b"custom_name", - "icon", - b"icon", - "id", - b"id", - "is_fixed", - b"is_fixed", - "is_modified", - b"is_modified", - "mode", - b"mode", - "setting_array", - b"setting_array", - "title_id", - b"title_id", - "title_number", - b"title_number", - "user_defined", - b"user_defined", - ], - ) -> None: ... - -global___Preset = Preset - -class RequestCustomPresetUpdate(google.protobuf.message.Message): - """* - Request to update the active custom preset - - This only operates on the currently active Preset and will fail if the current - Preset is not custom. - - The use cases are: - - 1. Update the Custom Preset Icon - - `icon_id` is always optional and can always be passed - - and / or - - 2. Update the Custom Preset Title to a... - - **Factory Preset Title**: Set `title_id` to a non-94 value - - **Custom Preset Name**: Set `title_id` to 94 and specify a `custom_name` - * - Preset Title ID - - The range of acceptable custom title ID's can be found in the initial @ref NotifyPresetStatus response - to @ref RequestGetPresetStatus - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - TITLE_ID_FIELD_NUMBER: builtins.int - CUSTOM_NAME_FIELD_NUMBER: builtins.int - ICON_ID_FIELD_NUMBER: builtins.int - title_id: global___EnumPresetTitle.ValueType - custom_name: builtins.str - "utf-8 encoded target custom preset name" - icon_id: global___EnumPresetIcon.ValueType - "*\n Preset Icon ID\n\n The range of acceptable custom icon ID's can be found in the initial @ref NotifyPresetStatus response to\n @ref RequestGetPresetStatus\n " - - def __init__( - self, - *, - title_id: global___EnumPresetTitle.ValueType | None = ..., - custom_name: builtins.str | None = ..., - icon_id: global___EnumPresetIcon.ValueType | None = ... - ) -> None: ... - def HasField( - self, - field_name: typing_extensions.Literal[ - "custom_name", b"custom_name", "icon_id", b"icon_id", "title_id", b"title_id" - ], - ) -> builtins.bool: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "custom_name", b"custom_name", "icon_id", b"icon_id", "title_id", b"title_id" - ], - ) -> None: ... - -global___RequestCustomPresetUpdate = RequestCustomPresetUpdate - -class PresetGroup(google.protobuf.message.Message): - """ - Preset Group meta information and contained Presets - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - ID_FIELD_NUMBER: builtins.int - PRESET_ARRAY_FIELD_NUMBER: builtins.int - CAN_ADD_PRESET_FIELD_NUMBER: builtins.int - ICON_FIELD_NUMBER: builtins.int - id: global___EnumPresetGroup.ValueType - "Preset Group ID" - - @property - def preset_array(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Preset]: - """Array of Presets contained in this Preset Group""" - can_add_preset: builtins.bool - "Is there room in the group to add additional Presets?" - icon: global___EnumPresetGroupIcon.ValueType - "The icon to display for this preset group" - - def __init__( - self, - *, - id: global___EnumPresetGroup.ValueType | None = ..., - preset_array: collections.abc.Iterable[global___Preset] | None = ..., - can_add_preset: builtins.bool | None = ..., - icon: global___EnumPresetGroupIcon.ValueType | None = ... - ) -> None: ... - def HasField( - self, field_name: typing_extensions.Literal["can_add_preset", b"can_add_preset", "icon", b"icon", "id", b"id"] - ) -> builtins.bool: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "can_add_preset", b"can_add_preset", "icon", b"icon", "id", b"id", "preset_array", b"preset_array" - ], - ) -> None: ... - -global___PresetGroup = PresetGroup - -class PresetSetting(google.protobuf.message.Message): - """* - Setting representation that comprises a @ref Preset - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - ID_FIELD_NUMBER: builtins.int - VALUE_FIELD_NUMBER: builtins.int - IS_CAPTION_FIELD_NUMBER: builtins.int - id: builtins.int - "Setting ID" - value: builtins.int - "Setting value" - is_caption: builtins.bool - 'Does this setting appear on the Preset "pill" in the camera UI?' - - def __init__( - self, *, id: builtins.int | None = ..., value: builtins.int | None = ..., is_caption: builtins.bool | None = ... - ) -> None: ... - def HasField( - self, field_name: typing_extensions.Literal["id", b"id", "is_caption", b"is_caption", "value", b"value"] - ) -> builtins.bool: ... - def ClearField( - self, field_name: typing_extensions.Literal["id", b"id", "is_caption", b"is_caption", "value", b"value"] - ) -> None: ... - -global___PresetSetting = PresetSetting +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf message received from camera containing preset status +""" + +import builtins +import collections.abc +import google.protobuf.descriptor +import google.protobuf.internal.containers +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumFlatMode: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumFlatModeEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumFlatMode.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + FLAT_MODE_UNKNOWN: _EnumFlatMode.ValueType + FLAT_MODE_PLAYBACK: _EnumFlatMode.ValueType + FLAT_MODE_SETUP: _EnumFlatMode.ValueType + FLAT_MODE_VIDEO: _EnumFlatMode.ValueType + FLAT_MODE_TIME_LAPSE_VIDEO: _EnumFlatMode.ValueType + FLAT_MODE_LOOPING: _EnumFlatMode.ValueType + FLAT_MODE_PHOTO_SINGLE: _EnumFlatMode.ValueType + FLAT_MODE_PHOTO: _EnumFlatMode.ValueType + FLAT_MODE_PHOTO_NIGHT: _EnumFlatMode.ValueType + FLAT_MODE_PHOTO_BURST: _EnumFlatMode.ValueType + FLAT_MODE_TIME_LAPSE_PHOTO: _EnumFlatMode.ValueType + FLAT_MODE_NIGHT_LAPSE_PHOTO: _EnumFlatMode.ValueType + FLAT_MODE_BROADCAST_RECORD: _EnumFlatMode.ValueType + FLAT_MODE_BROADCAST_BROADCAST: _EnumFlatMode.ValueType + FLAT_MODE_TIME_WARP_VIDEO: _EnumFlatMode.ValueType + FLAT_MODE_LIVE_BURST: _EnumFlatMode.ValueType + FLAT_MODE_NIGHT_LAPSE_VIDEO: _EnumFlatMode.ValueType + FLAT_MODE_SLOMO: _EnumFlatMode.ValueType + FLAT_MODE_IDLE: _EnumFlatMode.ValueType + FLAT_MODE_VIDEO_STAR_TRAIL: _EnumFlatMode.ValueType + FLAT_MODE_VIDEO_LIGHT_PAINTING: _EnumFlatMode.ValueType + FLAT_MODE_VIDEO_LIGHT_TRAIL: _EnumFlatMode.ValueType + FLAT_MODE_VIDEO_BURST_SLOMO: _EnumFlatMode.ValueType + +class EnumFlatMode(_EnumFlatMode, metaclass=_EnumFlatModeEnumTypeWrapper): ... + +FLAT_MODE_UNKNOWN: EnumFlatMode.ValueType +FLAT_MODE_PLAYBACK: EnumFlatMode.ValueType +FLAT_MODE_SETUP: EnumFlatMode.ValueType +FLAT_MODE_VIDEO: EnumFlatMode.ValueType +FLAT_MODE_TIME_LAPSE_VIDEO: EnumFlatMode.ValueType +FLAT_MODE_LOOPING: EnumFlatMode.ValueType +FLAT_MODE_PHOTO_SINGLE: EnumFlatMode.ValueType +FLAT_MODE_PHOTO: EnumFlatMode.ValueType +FLAT_MODE_PHOTO_NIGHT: EnumFlatMode.ValueType +FLAT_MODE_PHOTO_BURST: EnumFlatMode.ValueType +FLAT_MODE_TIME_LAPSE_PHOTO: EnumFlatMode.ValueType +FLAT_MODE_NIGHT_LAPSE_PHOTO: EnumFlatMode.ValueType +FLAT_MODE_BROADCAST_RECORD: EnumFlatMode.ValueType +FLAT_MODE_BROADCAST_BROADCAST: EnumFlatMode.ValueType +FLAT_MODE_TIME_WARP_VIDEO: EnumFlatMode.ValueType +FLAT_MODE_LIVE_BURST: EnumFlatMode.ValueType +FLAT_MODE_NIGHT_LAPSE_VIDEO: EnumFlatMode.ValueType +FLAT_MODE_SLOMO: EnumFlatMode.ValueType +FLAT_MODE_IDLE: EnumFlatMode.ValueType +FLAT_MODE_VIDEO_STAR_TRAIL: EnumFlatMode.ValueType +FLAT_MODE_VIDEO_LIGHT_PAINTING: EnumFlatMode.ValueType +FLAT_MODE_VIDEO_LIGHT_TRAIL: EnumFlatMode.ValueType +FLAT_MODE_VIDEO_BURST_SLOMO: EnumFlatMode.ValueType +global___EnumFlatMode = EnumFlatMode + +class _EnumPresetGroup: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumPresetGroupEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumPresetGroup.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + PRESET_GROUP_ID_VIDEO: _EnumPresetGroup.ValueType + PRESET_GROUP_ID_PHOTO: _EnumPresetGroup.ValueType + PRESET_GROUP_ID_TIMELAPSE: _EnumPresetGroup.ValueType + +class EnumPresetGroup(_EnumPresetGroup, metaclass=_EnumPresetGroupEnumTypeWrapper): ... + +PRESET_GROUP_ID_VIDEO: EnumPresetGroup.ValueType +PRESET_GROUP_ID_PHOTO: EnumPresetGroup.ValueType +PRESET_GROUP_ID_TIMELAPSE: EnumPresetGroup.ValueType +global___EnumPresetGroup = EnumPresetGroup + +class _EnumPresetGroupIcon: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumPresetGroupIconEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumPresetGroupIcon.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + PRESET_GROUP_VIDEO_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_PHOTO_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_TIMELAPSE_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_LONG_BAT_VIDEO_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_ENDURANCE_VIDEO_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_MAX_VIDEO_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_MAX_PHOTO_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_MAX_TIMELAPSE_ICON_ID: _EnumPresetGroupIcon.ValueType + +class EnumPresetGroupIcon(_EnumPresetGroupIcon, metaclass=_EnumPresetGroupIconEnumTypeWrapper): ... + +PRESET_GROUP_VIDEO_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_PHOTO_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_TIMELAPSE_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_LONG_BAT_VIDEO_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_ENDURANCE_VIDEO_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_MAX_VIDEO_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_MAX_PHOTO_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_MAX_TIMELAPSE_ICON_ID: EnumPresetGroupIcon.ValueType +global___EnumPresetGroupIcon = EnumPresetGroupIcon + +class _EnumPresetIcon: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumPresetIconEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumPresetIcon.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + PRESET_ICON_VIDEO: _EnumPresetIcon.ValueType + PRESET_ICON_ACTIVITY: _EnumPresetIcon.ValueType + PRESET_ICON_CINEMATIC: _EnumPresetIcon.ValueType + PRESET_ICON_PHOTO: _EnumPresetIcon.ValueType + PRESET_ICON_LIVE_BURST: _EnumPresetIcon.ValueType + PRESET_ICON_BURST: _EnumPresetIcon.ValueType + PRESET_ICON_PHOTO_NIGHT: _EnumPresetIcon.ValueType + PRESET_ICON_TIMEWARP: _EnumPresetIcon.ValueType + PRESET_ICON_TIMELAPSE: _EnumPresetIcon.ValueType + PRESET_ICON_NIGHTLAPSE: _EnumPresetIcon.ValueType + PRESET_ICON_SNAIL: _EnumPresetIcon.ValueType + PRESET_ICON_VIDEO_2: _EnumPresetIcon.ValueType + PRESET_ICON_PHOTO_2: _EnumPresetIcon.ValueType + PRESET_ICON_PANORAMA: _EnumPresetIcon.ValueType + PRESET_ICON_BURST_2: _EnumPresetIcon.ValueType + PRESET_ICON_TIMEWARP_2: _EnumPresetIcon.ValueType + PRESET_ICON_TIMELAPSE_2: _EnumPresetIcon.ValueType + PRESET_ICON_CUSTOM: _EnumPresetIcon.ValueType + PRESET_ICON_AIR: _EnumPresetIcon.ValueType + PRESET_ICON_BIKE: _EnumPresetIcon.ValueType + PRESET_ICON_EPIC: _EnumPresetIcon.ValueType + PRESET_ICON_INDOOR: _EnumPresetIcon.ValueType + PRESET_ICON_MOTOR: _EnumPresetIcon.ValueType + PRESET_ICON_MOUNTED: _EnumPresetIcon.ValueType + PRESET_ICON_OUTDOOR: _EnumPresetIcon.ValueType + PRESET_ICON_POV: _EnumPresetIcon.ValueType + PRESET_ICON_SELFIE: _EnumPresetIcon.ValueType + PRESET_ICON_SKATE: _EnumPresetIcon.ValueType + PRESET_ICON_SNOW: _EnumPresetIcon.ValueType + PRESET_ICON_TRAIL: _EnumPresetIcon.ValueType + PRESET_ICON_TRAVEL: _EnumPresetIcon.ValueType + PRESET_ICON_WATER: _EnumPresetIcon.ValueType + PRESET_ICON_LOOPING: _EnumPresetIcon.ValueType + PRESET_ICON_STARS: _EnumPresetIcon.ValueType + PRESET_ICON_ACTION: _EnumPresetIcon.ValueType + PRESET_ICON_FOLLOW_CAM: _EnumPresetIcon.ValueType + PRESET_ICON_SURF: _EnumPresetIcon.ValueType + PRESET_ICON_CITY: _EnumPresetIcon.ValueType + PRESET_ICON_SHAKY: _EnumPresetIcon.ValueType + PRESET_ICON_CHESTY: _EnumPresetIcon.ValueType + PRESET_ICON_HELMET: _EnumPresetIcon.ValueType + PRESET_ICON_BITE: _EnumPresetIcon.ValueType + PRESET_ICON_BASIC: _EnumPresetIcon.ValueType + PRESET_ICON_ULTRA_SLO_MO: _EnumPresetIcon.ValueType + PRESET_ICON_STANDARD_ENDURANCE: _EnumPresetIcon.ValueType + PRESET_ICON_ACTIVITY_ENDURANCE: _EnumPresetIcon.ValueType + PRESET_ICON_CINEMATIC_ENDURANCE: _EnumPresetIcon.ValueType + PRESET_ICON_SLOMO_ENDURANCE: _EnumPresetIcon.ValueType + PRESET_ICON_STATIONARY_1: _EnumPresetIcon.ValueType + PRESET_ICON_STATIONARY_2: _EnumPresetIcon.ValueType + PRESET_ICON_STATIONARY_3: _EnumPresetIcon.ValueType + PRESET_ICON_STATIONARY_4: _EnumPresetIcon.ValueType + PRESET_ICON_SIMPLE_SUPER_PHOTO: _EnumPresetIcon.ValueType + PRESET_ICON_SIMPLE_NIGHT_PHOTO: _EnumPresetIcon.ValueType + PRESET_ICON_HIGHEST_QUALITY_VIDEO: _EnumPresetIcon.ValueType + PRESET_ICON_STANDARD_QUALITY_VIDEO: _EnumPresetIcon.ValueType + PRESET_ICON_BASIC_QUALITY_VIDEO: _EnumPresetIcon.ValueType + PRESET_ICON_STAR_TRAIL: _EnumPresetIcon.ValueType + PRESET_ICON_LIGHT_PAINTING: _EnumPresetIcon.ValueType + PRESET_ICON_LIGHT_TRAIL: _EnumPresetIcon.ValueType + PRESET_ICON_FULL_FRAME: _EnumPresetIcon.ValueType + PRESET_ICON_TIMELAPSE_PHOTO: _EnumPresetIcon.ValueType + PRESET_ICON_NIGHTLAPSE_PHOTO: _EnumPresetIcon.ValueType + +class EnumPresetIcon(_EnumPresetIcon, metaclass=_EnumPresetIconEnumTypeWrapper): ... + +PRESET_ICON_VIDEO: EnumPresetIcon.ValueType +PRESET_ICON_ACTIVITY: EnumPresetIcon.ValueType +PRESET_ICON_CINEMATIC: EnumPresetIcon.ValueType +PRESET_ICON_PHOTO: EnumPresetIcon.ValueType +PRESET_ICON_LIVE_BURST: EnumPresetIcon.ValueType +PRESET_ICON_BURST: EnumPresetIcon.ValueType +PRESET_ICON_PHOTO_NIGHT: EnumPresetIcon.ValueType +PRESET_ICON_TIMEWARP: EnumPresetIcon.ValueType +PRESET_ICON_TIMELAPSE: EnumPresetIcon.ValueType +PRESET_ICON_NIGHTLAPSE: EnumPresetIcon.ValueType +PRESET_ICON_SNAIL: EnumPresetIcon.ValueType +PRESET_ICON_VIDEO_2: EnumPresetIcon.ValueType +PRESET_ICON_PHOTO_2: EnumPresetIcon.ValueType +PRESET_ICON_PANORAMA: EnumPresetIcon.ValueType +PRESET_ICON_BURST_2: EnumPresetIcon.ValueType +PRESET_ICON_TIMEWARP_2: EnumPresetIcon.ValueType +PRESET_ICON_TIMELAPSE_2: EnumPresetIcon.ValueType +PRESET_ICON_CUSTOM: EnumPresetIcon.ValueType +PRESET_ICON_AIR: EnumPresetIcon.ValueType +PRESET_ICON_BIKE: EnumPresetIcon.ValueType +PRESET_ICON_EPIC: EnumPresetIcon.ValueType +PRESET_ICON_INDOOR: EnumPresetIcon.ValueType +PRESET_ICON_MOTOR: EnumPresetIcon.ValueType +PRESET_ICON_MOUNTED: EnumPresetIcon.ValueType +PRESET_ICON_OUTDOOR: EnumPresetIcon.ValueType +PRESET_ICON_POV: EnumPresetIcon.ValueType +PRESET_ICON_SELFIE: EnumPresetIcon.ValueType +PRESET_ICON_SKATE: EnumPresetIcon.ValueType +PRESET_ICON_SNOW: EnumPresetIcon.ValueType +PRESET_ICON_TRAIL: EnumPresetIcon.ValueType +PRESET_ICON_TRAVEL: EnumPresetIcon.ValueType +PRESET_ICON_WATER: EnumPresetIcon.ValueType +PRESET_ICON_LOOPING: EnumPresetIcon.ValueType +PRESET_ICON_STARS: EnumPresetIcon.ValueType +PRESET_ICON_ACTION: EnumPresetIcon.ValueType +PRESET_ICON_FOLLOW_CAM: EnumPresetIcon.ValueType +PRESET_ICON_SURF: EnumPresetIcon.ValueType +PRESET_ICON_CITY: EnumPresetIcon.ValueType +PRESET_ICON_SHAKY: EnumPresetIcon.ValueType +PRESET_ICON_CHESTY: EnumPresetIcon.ValueType +PRESET_ICON_HELMET: EnumPresetIcon.ValueType +PRESET_ICON_BITE: EnumPresetIcon.ValueType +PRESET_ICON_BASIC: EnumPresetIcon.ValueType +PRESET_ICON_ULTRA_SLO_MO: EnumPresetIcon.ValueType +PRESET_ICON_STANDARD_ENDURANCE: EnumPresetIcon.ValueType +PRESET_ICON_ACTIVITY_ENDURANCE: EnumPresetIcon.ValueType +PRESET_ICON_CINEMATIC_ENDURANCE: EnumPresetIcon.ValueType +PRESET_ICON_SLOMO_ENDURANCE: EnumPresetIcon.ValueType +PRESET_ICON_STATIONARY_1: EnumPresetIcon.ValueType +PRESET_ICON_STATIONARY_2: EnumPresetIcon.ValueType +PRESET_ICON_STATIONARY_3: EnumPresetIcon.ValueType +PRESET_ICON_STATIONARY_4: EnumPresetIcon.ValueType +PRESET_ICON_SIMPLE_SUPER_PHOTO: EnumPresetIcon.ValueType +PRESET_ICON_SIMPLE_NIGHT_PHOTO: EnumPresetIcon.ValueType +PRESET_ICON_HIGHEST_QUALITY_VIDEO: EnumPresetIcon.ValueType +PRESET_ICON_STANDARD_QUALITY_VIDEO: EnumPresetIcon.ValueType +PRESET_ICON_BASIC_QUALITY_VIDEO: EnumPresetIcon.ValueType +PRESET_ICON_STAR_TRAIL: EnumPresetIcon.ValueType +PRESET_ICON_LIGHT_PAINTING: EnumPresetIcon.ValueType +PRESET_ICON_LIGHT_TRAIL: EnumPresetIcon.ValueType +PRESET_ICON_FULL_FRAME: EnumPresetIcon.ValueType +PRESET_ICON_TIMELAPSE_PHOTO: EnumPresetIcon.ValueType +PRESET_ICON_NIGHTLAPSE_PHOTO: EnumPresetIcon.ValueType +global___EnumPresetIcon = EnumPresetIcon + +class _EnumPresetTitle: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumPresetTitleEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumPresetTitle.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + PRESET_TITLE_ACTIVITY: _EnumPresetTitle.ValueType + PRESET_TITLE_STANDARD: _EnumPresetTitle.ValueType + PRESET_TITLE_CINEMATIC: _EnumPresetTitle.ValueType + PRESET_TITLE_PHOTO: _EnumPresetTitle.ValueType + PRESET_TITLE_LIVE_BURST: _EnumPresetTitle.ValueType + PRESET_TITLE_BURST: _EnumPresetTitle.ValueType + PRESET_TITLE_NIGHT: _EnumPresetTitle.ValueType + PRESET_TITLE_TIME_WARP: _EnumPresetTitle.ValueType + PRESET_TITLE_TIME_LAPSE: _EnumPresetTitle.ValueType + PRESET_TITLE_NIGHT_LAPSE: _EnumPresetTitle.ValueType + PRESET_TITLE_VIDEO: _EnumPresetTitle.ValueType + PRESET_TITLE_SLOMO: _EnumPresetTitle.ValueType + PRESET_TITLE_PHOTO_2: _EnumPresetTitle.ValueType + PRESET_TITLE_PANORAMA: _EnumPresetTitle.ValueType + PRESET_TITLE_TIME_WARP_2: _EnumPresetTitle.ValueType + PRESET_TITLE_CUSTOM: _EnumPresetTitle.ValueType + PRESET_TITLE_AIR: _EnumPresetTitle.ValueType + PRESET_TITLE_BIKE: _EnumPresetTitle.ValueType + PRESET_TITLE_EPIC: _EnumPresetTitle.ValueType + PRESET_TITLE_INDOOR: _EnumPresetTitle.ValueType + PRESET_TITLE_MOTOR: _EnumPresetTitle.ValueType + PRESET_TITLE_MOUNTED: _EnumPresetTitle.ValueType + PRESET_TITLE_OUTDOOR: _EnumPresetTitle.ValueType + PRESET_TITLE_POV: _EnumPresetTitle.ValueType + PRESET_TITLE_SELFIE: _EnumPresetTitle.ValueType + PRESET_TITLE_SKATE: _EnumPresetTitle.ValueType + PRESET_TITLE_SNOW: _EnumPresetTitle.ValueType + PRESET_TITLE_TRAIL: _EnumPresetTitle.ValueType + PRESET_TITLE_TRAVEL: _EnumPresetTitle.ValueType + PRESET_TITLE_WATER: _EnumPresetTitle.ValueType + PRESET_TITLE_LOOPING: _EnumPresetTitle.ValueType + PRESET_TITLE_STARS: _EnumPresetTitle.ValueType + PRESET_TITLE_ACTION: _EnumPresetTitle.ValueType + PRESET_TITLE_FOLLOW_CAM: _EnumPresetTitle.ValueType + PRESET_TITLE_SURF: _EnumPresetTitle.ValueType + PRESET_TITLE_CITY: _EnumPresetTitle.ValueType + PRESET_TITLE_SHAKY: _EnumPresetTitle.ValueType + PRESET_TITLE_CHESTY: _EnumPresetTitle.ValueType + PRESET_TITLE_HELMET: _EnumPresetTitle.ValueType + PRESET_TITLE_BITE: _EnumPresetTitle.ValueType + PRESET_TITLE_BASIC: _EnumPresetTitle.ValueType + PRESET_TITLE_ULTRA_SLO_MO: _EnumPresetTitle.ValueType + PRESET_TITLE_STANDARD_ENDURANCE: _EnumPresetTitle.ValueType + PRESET_TITLE_ACTIVITY_ENDURANCE: _EnumPresetTitle.ValueType + PRESET_TITLE_CINEMATIC_ENDURANCE: _EnumPresetTitle.ValueType + PRESET_TITLE_SLOMO_ENDURANCE: _EnumPresetTitle.ValueType + PRESET_TITLE_STATIONARY_1: _EnumPresetTitle.ValueType + PRESET_TITLE_STATIONARY_2: _EnumPresetTitle.ValueType + PRESET_TITLE_STATIONARY_3: _EnumPresetTitle.ValueType + PRESET_TITLE_STATIONARY_4: _EnumPresetTitle.ValueType + PRESET_TITLE_SIMPLE_VIDEO: _EnumPresetTitle.ValueType + PRESET_TITLE_SIMPLE_TIME_WARP: _EnumPresetTitle.ValueType + PRESET_TITLE_SIMPLE_SUPER_PHOTO: _EnumPresetTitle.ValueType + PRESET_TITLE_SIMPLE_NIGHT_PHOTO: _EnumPresetTitle.ValueType + PRESET_TITLE_SIMPLE_VIDEO_ENDURANCE: _EnumPresetTitle.ValueType + PRESET_TITLE_HIGHEST_QUALITY: _EnumPresetTitle.ValueType + PRESET_TITLE_EXTENDED_BATTERY: _EnumPresetTitle.ValueType + PRESET_TITLE_LONGEST_BATTERY: _EnumPresetTitle.ValueType + PRESET_TITLE_STAR_TRAIL: _EnumPresetTitle.ValueType + PRESET_TITLE_LIGHT_PAINTING: _EnumPresetTitle.ValueType + PRESET_TITLE_LIGHT_TRAIL: _EnumPresetTitle.ValueType + PRESET_TITLE_FULL_FRAME: _EnumPresetTitle.ValueType + PRESET_TITLE_STANDARD_QUALITY_VIDEO: _EnumPresetTitle.ValueType + PRESET_TITLE_BASIC_QUALITY_VIDEO: _EnumPresetTitle.ValueType + PRESET_TITLE_HIGHEST_QUALITY_VIDEO: _EnumPresetTitle.ValueType + PRESET_TITLE_USER_DEFINED_CUSTOM_NAME: _EnumPresetTitle.ValueType + +class EnumPresetTitle(_EnumPresetTitle, metaclass=_EnumPresetTitleEnumTypeWrapper): ... + +PRESET_TITLE_ACTIVITY: EnumPresetTitle.ValueType +PRESET_TITLE_STANDARD: EnumPresetTitle.ValueType +PRESET_TITLE_CINEMATIC: EnumPresetTitle.ValueType +PRESET_TITLE_PHOTO: EnumPresetTitle.ValueType +PRESET_TITLE_LIVE_BURST: EnumPresetTitle.ValueType +PRESET_TITLE_BURST: EnumPresetTitle.ValueType +PRESET_TITLE_NIGHT: EnumPresetTitle.ValueType +PRESET_TITLE_TIME_WARP: EnumPresetTitle.ValueType +PRESET_TITLE_TIME_LAPSE: EnumPresetTitle.ValueType +PRESET_TITLE_NIGHT_LAPSE: EnumPresetTitle.ValueType +PRESET_TITLE_VIDEO: EnumPresetTitle.ValueType +PRESET_TITLE_SLOMO: EnumPresetTitle.ValueType +PRESET_TITLE_PHOTO_2: EnumPresetTitle.ValueType +PRESET_TITLE_PANORAMA: EnumPresetTitle.ValueType +PRESET_TITLE_TIME_WARP_2: EnumPresetTitle.ValueType +PRESET_TITLE_CUSTOM: EnumPresetTitle.ValueType +PRESET_TITLE_AIR: EnumPresetTitle.ValueType +PRESET_TITLE_BIKE: EnumPresetTitle.ValueType +PRESET_TITLE_EPIC: EnumPresetTitle.ValueType +PRESET_TITLE_INDOOR: EnumPresetTitle.ValueType +PRESET_TITLE_MOTOR: EnumPresetTitle.ValueType +PRESET_TITLE_MOUNTED: EnumPresetTitle.ValueType +PRESET_TITLE_OUTDOOR: EnumPresetTitle.ValueType +PRESET_TITLE_POV: EnumPresetTitle.ValueType +PRESET_TITLE_SELFIE: EnumPresetTitle.ValueType +PRESET_TITLE_SKATE: EnumPresetTitle.ValueType +PRESET_TITLE_SNOW: EnumPresetTitle.ValueType +PRESET_TITLE_TRAIL: EnumPresetTitle.ValueType +PRESET_TITLE_TRAVEL: EnumPresetTitle.ValueType +PRESET_TITLE_WATER: EnumPresetTitle.ValueType +PRESET_TITLE_LOOPING: EnumPresetTitle.ValueType +PRESET_TITLE_STARS: EnumPresetTitle.ValueType +PRESET_TITLE_ACTION: EnumPresetTitle.ValueType +PRESET_TITLE_FOLLOW_CAM: EnumPresetTitle.ValueType +PRESET_TITLE_SURF: EnumPresetTitle.ValueType +PRESET_TITLE_CITY: EnumPresetTitle.ValueType +PRESET_TITLE_SHAKY: EnumPresetTitle.ValueType +PRESET_TITLE_CHESTY: EnumPresetTitle.ValueType +PRESET_TITLE_HELMET: EnumPresetTitle.ValueType +PRESET_TITLE_BITE: EnumPresetTitle.ValueType +PRESET_TITLE_BASIC: EnumPresetTitle.ValueType +PRESET_TITLE_ULTRA_SLO_MO: EnumPresetTitle.ValueType +PRESET_TITLE_STANDARD_ENDURANCE: EnumPresetTitle.ValueType +PRESET_TITLE_ACTIVITY_ENDURANCE: EnumPresetTitle.ValueType +PRESET_TITLE_CINEMATIC_ENDURANCE: EnumPresetTitle.ValueType +PRESET_TITLE_SLOMO_ENDURANCE: EnumPresetTitle.ValueType +PRESET_TITLE_STATIONARY_1: EnumPresetTitle.ValueType +PRESET_TITLE_STATIONARY_2: EnumPresetTitle.ValueType +PRESET_TITLE_STATIONARY_3: EnumPresetTitle.ValueType +PRESET_TITLE_STATIONARY_4: EnumPresetTitle.ValueType +PRESET_TITLE_SIMPLE_VIDEO: EnumPresetTitle.ValueType +PRESET_TITLE_SIMPLE_TIME_WARP: EnumPresetTitle.ValueType +PRESET_TITLE_SIMPLE_SUPER_PHOTO: EnumPresetTitle.ValueType +PRESET_TITLE_SIMPLE_NIGHT_PHOTO: EnumPresetTitle.ValueType +PRESET_TITLE_SIMPLE_VIDEO_ENDURANCE: EnumPresetTitle.ValueType +PRESET_TITLE_HIGHEST_QUALITY: EnumPresetTitle.ValueType +PRESET_TITLE_EXTENDED_BATTERY: EnumPresetTitle.ValueType +PRESET_TITLE_LONGEST_BATTERY: EnumPresetTitle.ValueType +PRESET_TITLE_STAR_TRAIL: EnumPresetTitle.ValueType +PRESET_TITLE_LIGHT_PAINTING: EnumPresetTitle.ValueType +PRESET_TITLE_LIGHT_TRAIL: EnumPresetTitle.ValueType +PRESET_TITLE_FULL_FRAME: EnumPresetTitle.ValueType +PRESET_TITLE_STANDARD_QUALITY_VIDEO: EnumPresetTitle.ValueType +PRESET_TITLE_BASIC_QUALITY_VIDEO: EnumPresetTitle.ValueType +PRESET_TITLE_HIGHEST_QUALITY_VIDEO: EnumPresetTitle.ValueType +PRESET_TITLE_USER_DEFINED_CUSTOM_NAME: EnumPresetTitle.ValueType +global___EnumPresetTitle = EnumPresetTitle + +@typing_extensions.final +class NotifyPresetStatus(google.protobuf.message.Message): + """* + Current Preset status + + Sent either: + + - Synchronously via initial response to @ref RequestGetPresetStatus + - Asynchronously when Preset change if registered in @ref RequestGetPresetStatus + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + PRESET_GROUP_ARRAY_FIELD_NUMBER: builtins.int + + @property + def preset_group_array( + self, + ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___PresetGroup]: + """List of currently available Preset Groups""" + def __init__(self, *, preset_group_array: collections.abc.Iterable[global___PresetGroup] | None = ...) -> None: ... + def ClearField( + self, + field_name: typing_extensions.Literal["preset_group_array", b"preset_group_array"], + ) -> None: ... + +global___NotifyPresetStatus = NotifyPresetStatus + +@typing_extensions.final +class Preset(google.protobuf.message.Message): + """* + An individual preset. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + ID_FIELD_NUMBER: builtins.int + MODE_FIELD_NUMBER: builtins.int + TITLE_ID_FIELD_NUMBER: builtins.int + TITLE_NUMBER_FIELD_NUMBER: builtins.int + USER_DEFINED_FIELD_NUMBER: builtins.int + ICON_FIELD_NUMBER: builtins.int + SETTING_ARRAY_FIELD_NUMBER: builtins.int + IS_MODIFIED_FIELD_NUMBER: builtins.int + IS_FIXED_FIELD_NUMBER: builtins.int + CUSTOM_NAME_FIELD_NUMBER: builtins.int + id: builtins.int + "Preset ID" + mode: global___EnumFlatMode.ValueType + "Preset flatmode ID" + title_id: global___EnumPresetTitle.ValueType + "Preset Title ID" + title_number: builtins.int + "Preset Title Number (e.g. 1/2/3 in Custom1, Custom2, Custom3)" + user_defined: builtins.bool + "Is the Preset custom/user-defined?" + icon: global___EnumPresetIcon.ValueType + "Preset Icon ID" + + @property + def setting_array( + self, + ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___PresetSetting]: + """Array of settings associated with this Preset""" + is_modified: builtins.bool + "Has Preset been modified from factory defaults? (False for user-defined Presets)" + is_fixed: builtins.bool + "Is this Preset mutable?" + custom_name: builtins.str + "Custom string name given to this preset via @ref RequestCustomPresetUpdate" + + def __init__( + self, + *, + id: builtins.int | None = ..., + mode: global___EnumFlatMode.ValueType | None = ..., + title_id: global___EnumPresetTitle.ValueType | None = ..., + title_number: builtins.int | None = ..., + user_defined: builtins.bool | None = ..., + icon: global___EnumPresetIcon.ValueType | None = ..., + setting_array: collections.abc.Iterable[global___PresetSetting] | None = ..., + is_modified: builtins.bool | None = ..., + is_fixed: builtins.bool | None = ..., + custom_name: builtins.str | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "custom_name", + b"custom_name", + "icon", + b"icon", + "id", + b"id", + "is_fixed", + b"is_fixed", + "is_modified", + b"is_modified", + "mode", + b"mode", + "title_id", + b"title_id", + "title_number", + b"title_number", + "user_defined", + b"user_defined", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "custom_name", + b"custom_name", + "icon", + b"icon", + "id", + b"id", + "is_fixed", + b"is_fixed", + "is_modified", + b"is_modified", + "mode", + b"mode", + "setting_array", + b"setting_array", + "title_id", + b"title_id", + "title_number", + b"title_number", + "user_defined", + b"user_defined", + ], + ) -> None: ... + +global___Preset = Preset + +@typing_extensions.final +class RequestCustomPresetUpdate(google.protobuf.message.Message): + """* + Request to Update the Title and / or Icon of the Active Custom Preset + + This only operates on the currently active Preset and will fail if the current + Preset is not custom. + + The use cases are: + + 1. Update the Custom Preset Icon + + - `icon_id` is always optional and can always be passed + + and / or + + 2. Update the Custom Preset Title to a... + + - **Factory Preset Title**: Set `title_id` to a non-PRESET_TITLE_USER_DEFINED_CUSTOM_NAME (94) value + - **Custom Preset Name**: Set `title_id` to PRESET_TITLE_USER_DEFINED_CUSTOM_NAME (94) and specify a `custom_name` + + Returns a @ref ResponseGeneric with the status of the preset update request. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + TITLE_ID_FIELD_NUMBER: builtins.int + CUSTOM_NAME_FIELD_NUMBER: builtins.int + ICON_ID_FIELD_NUMBER: builtins.int + title_id: global___EnumPresetTitle.ValueType + "*\n Preset Title ID\n\n The range of acceptable custom title ID's can be found in the initial @ref NotifyPresetStatus response\n to @ref RequestGetPresetStatus\n " + custom_name: builtins.str + "*\n UTF-8 encoded custom preset name\n\n The name must obey the following:\n\n - Custom titles must be between 1 and 16 characters (inclusive)\n - No special characters outside of the following languages: English, French, Italian, German,\n Spanish, Portuguese, Swedish, Russian\n " + icon_id: global___EnumPresetIcon.ValueType + "*\n Preset Icon ID\n\n The range of acceptable custom icon ID's can be found in the initial @ref NotifyPresetStatus response to\n @ref RequestGetPresetStatus\n " + + def __init__( + self, + *, + title_id: global___EnumPresetTitle.ValueType | None = ..., + custom_name: builtins.str | None = ..., + icon_id: global___EnumPresetIcon.ValueType | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "custom_name", + b"custom_name", + "icon_id", + b"icon_id", + "title_id", + b"title_id", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "custom_name", + b"custom_name", + "icon_id", + b"icon_id", + "title_id", + b"title_id", + ], + ) -> None: ... + +global___RequestCustomPresetUpdate = RequestCustomPresetUpdate + +@typing_extensions.final +class PresetGroup(google.protobuf.message.Message): + """ + Preset Group meta information and contained Presets + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + ID_FIELD_NUMBER: builtins.int + PRESET_ARRAY_FIELD_NUMBER: builtins.int + CAN_ADD_PRESET_FIELD_NUMBER: builtins.int + ICON_FIELD_NUMBER: builtins.int + id: global___EnumPresetGroup.ValueType + "Preset Group ID" + + @property + def preset_array( + self, + ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Preset]: + """Array of Presets contained in this Preset Group""" + can_add_preset: builtins.bool + "Is there room in the group to add additional Presets?" + icon: global___EnumPresetGroupIcon.ValueType + "The icon to display for this preset group" + + def __init__( + self, + *, + id: global___EnumPresetGroup.ValueType | None = ..., + preset_array: collections.abc.Iterable[global___Preset] | None = ..., + can_add_preset: builtins.bool | None = ..., + icon: global___EnumPresetGroupIcon.ValueType | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["can_add_preset", b"can_add_preset", "icon", b"icon", "id", b"id"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "can_add_preset", + b"can_add_preset", + "icon", + b"icon", + "id", + b"id", + "preset_array", + b"preset_array", + ], + ) -> None: ... + +global___PresetGroup = PresetGroup + +@typing_extensions.final +class PresetSetting(google.protobuf.message.Message): + """* + Setting representation that comprises a @ref Preset + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + ID_FIELD_NUMBER: builtins.int + VALUE_FIELD_NUMBER: builtins.int + IS_CAPTION_FIELD_NUMBER: builtins.int + id: builtins.int + "Setting ID" + value: builtins.int + "Setting value" + is_caption: builtins.bool + 'Does this setting appear on the Preset "pill" in the camera UI?' + + def __init__( + self, *, id: builtins.int | None = ..., value: builtins.int | None = ..., is_caption: builtins.bool | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["id", b"id", "is_caption", b"is_caption", "value", b"value"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["id", b"id", "is_caption", b"is_caption", "value", b"value"], + ) -> None: ... + +global___PresetSetting = PresetSetting diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/request_get_preset_status_pb2.py b/demos/python/sdk_wireless_camera_control/open_gopro/proto/request_get_preset_status_pb2.py index 318a73d8..91f1f5b8 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/request_get_preset_status_pb2.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/request_get_preset_status_pb2.py @@ -1,21 +1,22 @@ # request_get_preset_status_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Mon Dec 18 20:40:36 UTC 2023 +# This copyright was auto-generated on Wed Mar 27 22:05:47 UTC 2024 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder - -_sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n\x1frequest_get_preset_status.proto\x12\nopen_gopro"\xa6\x01\n\x16RequestGetPresetStatus\x12D\n\x16register_preset_status\x18\x01 \x03(\x0e2$.open_gopro.EnumRegisterPresetStatus\x12F\n\x18unregister_preset_status\x18\x02 \x03(\x0e2$.open_gopro.EnumRegisterPresetStatus*l\n\x18EnumRegisterPresetStatus\x12!\n\x1dREGISTER_PRESET_STATUS_PRESET\x10\x01\x12-\n)REGISTER_PRESET_STATUS_PRESET_GROUP_ARRAY\x10\x02' -) -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "request_get_preset_status_pb2", globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _ENUMREGISTERPRESETSTATUS._serialized_start = 216 - _ENUMREGISTERPRESETSTATUS._serialized_end = 324 - _REQUESTGETPRESETSTATUS._serialized_start = 48 - _REQUESTGETPRESETSTATUS._serialized_end = 214 +"""Generated protocol buffer code.""" + +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder + +_sym_db = _symbol_database.Default() +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x1frequest_get_preset_status.proto\x12\nopen_gopro"\xa6\x01\n\x16RequestGetPresetStatus\x12D\n\x16register_preset_status\x18\x01 \x03(\x0e2$.open_gopro.EnumRegisterPresetStatus\x12F\n\x18unregister_preset_status\x18\x02 \x03(\x0e2$.open_gopro.EnumRegisterPresetStatus*l\n\x18EnumRegisterPresetStatus\x12!\n\x1dREGISTER_PRESET_STATUS_PRESET\x10\x01\x12-\n)REGISTER_PRESET_STATUS_PRESET_GROUP_ARRAY\x10\x02' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "request_get_preset_status_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMREGISTERPRESETSTATUS._serialized_start = 216 + _ENUMREGISTERPRESETSTATUS._serialized_end = 324 + _REQUESTGETPRESETSTATUS._serialized_start = 48 + _REQUESTGETPRESETSTATUS._serialized_end = 214 diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/request_get_preset_status_pb2.pyi b/demos/python/sdk_wireless_camera_control/open_gopro/proto/request_get_preset_status_pb2.pyi index 8a5d9f05..ef0a0092 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/request_get_preset_status_pb2.pyi +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/request_get_preset_status_pb2.pyi @@ -1,79 +1,91 @@ -""" -@generated by mypy-protobuf. Do not edit manually! -isort:skip_file -* -Defines the structure of protobuf messages for obtaining preset status -""" -import builtins -import collections.abc -import google.protobuf.descriptor -import google.protobuf.internal.containers -import google.protobuf.internal.enum_type_wrapper -import google.protobuf.message -import sys -import typing - -if sys.version_info >= (3, 10): - import typing as typing_extensions -else: - import typing_extensions -DESCRIPTOR: google.protobuf.descriptor.FileDescriptor - -class _EnumRegisterPresetStatus: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumRegisterPresetStatusEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumRegisterPresetStatus.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - REGISTER_PRESET_STATUS_PRESET: _EnumRegisterPresetStatus.ValueType - "Send notification when properties of a preset change" - REGISTER_PRESET_STATUS_PRESET_GROUP_ARRAY: _EnumRegisterPresetStatus.ValueType - "Send notification when properties of a preset group change" - -class EnumRegisterPresetStatus(_EnumRegisterPresetStatus, metaclass=_EnumRegisterPresetStatusEnumTypeWrapper): ... - -REGISTER_PRESET_STATUS_PRESET: EnumRegisterPresetStatus.ValueType -"Send notification when properties of a preset change" -REGISTER_PRESET_STATUS_PRESET_GROUP_ARRAY: EnumRegisterPresetStatus.ValueType -"Send notification when properties of a preset group change" -global___EnumRegisterPresetStatus = EnumRegisterPresetStatus - -class RequestGetPresetStatus(google.protobuf.message.Message): - """* - Get preset status (and optionally register to be notified when it changes) - - Response: @ref NotifyPresetStatus sent immediately - - Notification: @ref NotifyPresetStatus sent periodically as preset status changes, if registered. - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - REGISTER_PRESET_STATUS_FIELD_NUMBER: builtins.int - UNREGISTER_PRESET_STATUS_FIELD_NUMBER: builtins.int - - @property - def register_preset_status( - self, - ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___EnumRegisterPresetStatus.ValueType]: - """Array of Preset statuses to be notified about""" - @property - def unregister_preset_status( - self, - ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___EnumRegisterPresetStatus.ValueType]: - """Array of Preset statuses to stop being notified about""" - def __init__( - self, - *, - register_preset_status: collections.abc.Iterable[global___EnumRegisterPresetStatus.ValueType] | None = ..., - unregister_preset_status: collections.abc.Iterable[global___EnumRegisterPresetStatus.ValueType] | None = ... - ) -> None: ... - def ClearField( - self, - field_name: typing_extensions.Literal[ - "register_preset_status", b"register_preset_status", "unregister_preset_status", b"unregister_preset_status" - ], - ) -> None: ... - -global___RequestGetPresetStatus = RequestGetPresetStatus +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf messages for obtaining preset status +""" + +import builtins +import collections.abc +import google.protobuf.descriptor +import google.protobuf.internal.containers +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumRegisterPresetStatus: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumRegisterPresetStatusEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumRegisterPresetStatus.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + REGISTER_PRESET_STATUS_PRESET: _EnumRegisterPresetStatus.ValueType + "Send notification when properties of a preset change" + REGISTER_PRESET_STATUS_PRESET_GROUP_ARRAY: _EnumRegisterPresetStatus.ValueType + "Send notification when properties of a preset group change" + +class EnumRegisterPresetStatus(_EnumRegisterPresetStatus, metaclass=_EnumRegisterPresetStatusEnumTypeWrapper): ... + +REGISTER_PRESET_STATUS_PRESET: EnumRegisterPresetStatus.ValueType +"Send notification when properties of a preset change" +REGISTER_PRESET_STATUS_PRESET_GROUP_ARRAY: EnumRegisterPresetStatus.ValueType +"Send notification when properties of a preset group change" +global___EnumRegisterPresetStatus = EnumRegisterPresetStatus + +@typing_extensions.final +class RequestGetPresetStatus(google.protobuf.message.Message): + """* + Get the set of currently available presets and optionally register to be notified when it changes. + + Response: @ref NotifyPresetStatus sent immediately + + Notification: @ref NotifyPresetStatus sent periodically as preset status changes, if registered. + + The preset status changes when: + + - A client changes one of a preset's captioned settings via the API + - The user exits from a preset's settings UI on the camera (e.g. long-press the preset pill and then press the back arrow) + - The user creates/deletes/reorders a preset within a group + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + REGISTER_PRESET_STATUS_FIELD_NUMBER: builtins.int + UNREGISTER_PRESET_STATUS_FIELD_NUMBER: builtins.int + + @property + def register_preset_status( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___EnumRegisterPresetStatus.ValueType]: + """Array of Preset statuses to be notified about""" + @property + def unregister_preset_status( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___EnumRegisterPresetStatus.ValueType]: + """Array of Preset statuses to stop being notified about""" + def __init__( + self, + *, + register_preset_status: (collections.abc.Iterable[global___EnumRegisterPresetStatus.ValueType] | None) = ..., + unregister_preset_status: (collections.abc.Iterable[global___EnumRegisterPresetStatus.ValueType] | None) = ... + ) -> None: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "register_preset_status", + b"register_preset_status", + "unregister_preset_status", + b"unregister_preset_status", + ], + ) -> None: ... + +global___RequestGetPresetStatus = RequestGetPresetStatus diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/response_generic_pb2.py b/demos/python/sdk_wireless_camera_control/open_gopro/proto/response_generic_pb2.py index b2e9890d..fd295a47 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/response_generic_pb2.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/response_generic_pb2.py @@ -1,23 +1,24 @@ # response_generic_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Mon Dec 18 20:40:36 UTC 2023 +# This copyright was auto-generated on Wed Mar 27 22:05:48 UTC 2024 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder - -_sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n\x16response_generic.proto\x12\nopen_gopro"@\n\x0fResponseGeneric\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric"%\n\x05Media\x12\x0e\n\x06folder\x18\x01 \x01(\t\x12\x0c\n\x04file\x18\x02 \x01(\t*\xcf\x01\n\x11EnumResultGeneric\x12\x12\n\x0eRESULT_UNKNOWN\x10\x00\x12\x12\n\x0eRESULT_SUCCESS\x10\x01\x12\x15\n\x11RESULT_ILL_FORMED\x10\x02\x12\x18\n\x14RESULT_NOT_SUPPORTED\x10\x03\x12!\n\x1dRESULT_ARGUMENT_OUT_OF_BOUNDS\x10\x04\x12\x1b\n\x17RESULT_ARGUMENT_INVALID\x10\x05\x12!\n\x1dRESULT_RESOURCE_NOT_AVAILABLE\x10\x06' -) -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "response_generic_pb2", globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _ENUMRESULTGENERIC._serialized_start = 144 - _ENUMRESULTGENERIC._serialized_end = 351 - _RESPONSEGENERIC._serialized_start = 38 - _RESPONSEGENERIC._serialized_end = 102 - _MEDIA._serialized_start = 104 - _MEDIA._serialized_end = 141 +"""Generated protocol buffer code.""" + +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder + +_sym_db = _symbol_database.Default() +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x16response_generic.proto\x12\nopen_gopro"@\n\x0fResponseGeneric\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric"%\n\x05Media\x12\x0e\n\x06folder\x18\x01 \x01(\t\x12\x0c\n\x04file\x18\x02 \x01(\t*\xcf\x01\n\x11EnumResultGeneric\x12\x12\n\x0eRESULT_UNKNOWN\x10\x00\x12\x12\n\x0eRESULT_SUCCESS\x10\x01\x12\x15\n\x11RESULT_ILL_FORMED\x10\x02\x12\x18\n\x14RESULT_NOT_SUPPORTED\x10\x03\x12!\n\x1dRESULT_ARGUMENT_OUT_OF_BOUNDS\x10\x04\x12\x1b\n\x17RESULT_ARGUMENT_INVALID\x10\x05\x12!\n\x1dRESULT_RESOURCE_NOT_AVAILABLE\x10\x06' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "response_generic_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMRESULTGENERIC._serialized_start = 144 + _ENUMRESULTGENERIC._serialized_end = 351 + _RESPONSEGENERIC._serialized_start = 38 + _RESPONSEGENERIC._serialized_end = 102 + _MEDIA._serialized_start = 104 + _MEDIA._serialized_end = 141 diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/response_generic_pb2.pyi b/demos/python/sdk_wireless_camera_control/open_gopro/proto/response_generic_pb2.pyi index eed7c045..85655c36 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/response_generic_pb2.pyi +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/response_generic_pb2.pyi @@ -1,84 +1,90 @@ -""" -@generated by mypy-protobuf. Do not edit manually! -isort:skip_file -* -Defines the structure of protobuf message containing generic response to a command -""" -import builtins -import google.protobuf.descriptor -import google.protobuf.internal.enum_type_wrapper -import google.protobuf.message -import sys -import typing - -if sys.version_info >= (3, 10): - import typing as typing_extensions -else: - import typing_extensions -DESCRIPTOR: google.protobuf.descriptor.FileDescriptor - -class _EnumResultGeneric: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumResultGenericEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumResultGeneric.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - RESULT_UNKNOWN: _EnumResultGeneric.ValueType - RESULT_SUCCESS: _EnumResultGeneric.ValueType - RESULT_ILL_FORMED: _EnumResultGeneric.ValueType - RESULT_NOT_SUPPORTED: _EnumResultGeneric.ValueType - RESULT_ARGUMENT_OUT_OF_BOUNDS: _EnumResultGeneric.ValueType - RESULT_ARGUMENT_INVALID: _EnumResultGeneric.ValueType - RESULT_RESOURCE_NOT_AVAILABLE: _EnumResultGeneric.ValueType - -class EnumResultGeneric(_EnumResultGeneric, metaclass=_EnumResultGenericEnumTypeWrapper): ... - -RESULT_UNKNOWN: EnumResultGeneric.ValueType -RESULT_SUCCESS: EnumResultGeneric.ValueType -RESULT_ILL_FORMED: EnumResultGeneric.ValueType -RESULT_NOT_SUPPORTED: EnumResultGeneric.ValueType -RESULT_ARGUMENT_OUT_OF_BOUNDS: EnumResultGeneric.ValueType -RESULT_ARGUMENT_INVALID: EnumResultGeneric.ValueType -RESULT_RESOURCE_NOT_AVAILABLE: EnumResultGeneric.ValueType -global___EnumResultGeneric = EnumResultGeneric - -class ResponseGeneric(google.protobuf.message.Message): - """ - Generic Response used across most response / notification messages - - @ref EnumResultGeneric - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - RESULT_FIELD_NUMBER: builtins.int - result: global___EnumResultGeneric.ValueType - "Generic pass/fail/error info" - - def __init__(self, *, result: global___EnumResultGeneric.ValueType | None = ...) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["result", b"result"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["result", b"result"]) -> None: ... - -global___ResponseGeneric = ResponseGeneric - -class Media(google.protobuf.message.Message): - """* - A reusable model to represent a media file - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - FOLDER_FIELD_NUMBER: builtins.int - FILE_FIELD_NUMBER: builtins.int - folder: builtins.str - "Directory that the media is contained in" - file: builtins.str - "Filename of media" - - def __init__(self, *, folder: builtins.str | None = ..., file: builtins.str | None = ...) -> None: ... - def HasField( - self, field_name: typing_extensions.Literal["file", b"file", "folder", b"folder"] - ) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["file", b"file", "folder", b"folder"]) -> None: ... - -global___Media = Media +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf message containing generic response to a command +""" + +import builtins +import google.protobuf.descriptor +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumResultGeneric: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumResultGenericEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumResultGeneric.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + RESULT_UNKNOWN: _EnumResultGeneric.ValueType + RESULT_SUCCESS: _EnumResultGeneric.ValueType + RESULT_ILL_FORMED: _EnumResultGeneric.ValueType + RESULT_NOT_SUPPORTED: _EnumResultGeneric.ValueType + RESULT_ARGUMENT_OUT_OF_BOUNDS: _EnumResultGeneric.ValueType + RESULT_ARGUMENT_INVALID: _EnumResultGeneric.ValueType + RESULT_RESOURCE_NOT_AVAILABLE: _EnumResultGeneric.ValueType + +class EnumResultGeneric(_EnumResultGeneric, metaclass=_EnumResultGenericEnumTypeWrapper): ... + +RESULT_UNKNOWN: EnumResultGeneric.ValueType +RESULT_SUCCESS: EnumResultGeneric.ValueType +RESULT_ILL_FORMED: EnumResultGeneric.ValueType +RESULT_NOT_SUPPORTED: EnumResultGeneric.ValueType +RESULT_ARGUMENT_OUT_OF_BOUNDS: EnumResultGeneric.ValueType +RESULT_ARGUMENT_INVALID: EnumResultGeneric.ValueType +RESULT_RESOURCE_NOT_AVAILABLE: EnumResultGeneric.ValueType +global___EnumResultGeneric = EnumResultGeneric + +@typing_extensions.final +class ResponseGeneric(google.protobuf.message.Message): + """ + Generic Response used across many response / notification messages + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + RESULT_FIELD_NUMBER: builtins.int + result: global___EnumResultGeneric.ValueType + "Generic pass/fail/error info" + + def __init__(self, *, result: global___EnumResultGeneric.ValueType | None = ...) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["result", b"result"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["result", b"result"]) -> None: ... + +global___ResponseGeneric = ResponseGeneric + +@typing_extensions.final +class Media(google.protobuf.message.Message): + """* + A common model to represent a media file + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + FOLDER_FIELD_NUMBER: builtins.int + FILE_FIELD_NUMBER: builtins.int + folder: builtins.str + "Directory in which the media is contained" + file: builtins.str + "Filename of media" + + def __init__(self, *, folder: builtins.str | None = ..., file: builtins.str | None = ...) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["file", b"file", "folder", b"folder"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["file", b"file", "folder", b"folder"], + ) -> None: ... + +global___Media = Media diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/set_camera_control_status_pb2.py b/demos/python/sdk_wireless_camera_control/open_gopro/proto/set_camera_control_status_pb2.py index ee279177..1430451c 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/set_camera_control_status_pb2.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/set_camera_control_status_pb2.py @@ -1,21 +1,22 @@ # set_camera_control_status_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Mon Dec 18 20:40:36 UTC 2023 +# This copyright was auto-generated on Wed Mar 27 22:05:47 UTC 2024 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder - -_sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n\x1fset_camera_control_status.proto\x12\nopen_gopro"c\n\x1dRequestSetCameraControlStatus\x12B\n\x15camera_control_status\x18\x01 \x02(\x0e2#.open_gopro.EnumCameraControlStatus*[\n\x17EnumCameraControlStatus\x12\x0f\n\x0bCAMERA_IDLE\x10\x00\x12\x12\n\x0eCAMERA_CONTROL\x10\x01\x12\x1b\n\x17CAMERA_EXTERNAL_CONTROL\x10\x02' -) -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "set_camera_control_status_pb2", globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _ENUMCAMERACONTROLSTATUS._serialized_start = 148 - _ENUMCAMERACONTROLSTATUS._serialized_end = 239 - _REQUESTSETCAMERACONTROLSTATUS._serialized_start = 47 - _REQUESTSETCAMERACONTROLSTATUS._serialized_end = 146 +"""Generated protocol buffer code.""" + +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder + +_sym_db = _symbol_database.Default() +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x1fset_camera_control_status.proto\x12\nopen_gopro"c\n\x1dRequestSetCameraControlStatus\x12B\n\x15camera_control_status\x18\x01 \x02(\x0e2#.open_gopro.EnumCameraControlStatus*[\n\x17EnumCameraControlStatus\x12\x0f\n\x0bCAMERA_IDLE\x10\x00\x12\x12\n\x0eCAMERA_CONTROL\x10\x01\x12\x1b\n\x17CAMERA_EXTERNAL_CONTROL\x10\x02' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "set_camera_control_status_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMCAMERACONTROLSTATUS._serialized_start = 148 + _ENUMCAMERACONTROLSTATUS._serialized_end = 239 + _REQUESTSETCAMERACONTROLSTATUS._serialized_start = 47 + _REQUESTSETCAMERACONTROLSTATUS._serialized_end = 146 diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/set_camera_control_status_pb2.pyi b/demos/python/sdk_wireless_camera_control/open_gopro/proto/set_camera_control_status_pb2.pyi index 125b2005..37b27336 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/set_camera_control_status_pb2.pyi +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/set_camera_control_status_pb2.pyi @@ -1,61 +1,74 @@ -""" -@generated by mypy-protobuf. Do not edit manually! -isort:skip_file -* -Defines the structure of protobuf messages for setting camera control status -""" -import builtins -import google.protobuf.descriptor -import google.protobuf.internal.enum_type_wrapper -import google.protobuf.message -import sys -import typing - -if sys.version_info >= (3, 10): - import typing as typing_extensions -else: - import typing_extensions -DESCRIPTOR: google.protobuf.descriptor.FileDescriptor - -class _EnumCameraControlStatus: - ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType - -class _EnumCameraControlStatusEnumTypeWrapper( - google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumCameraControlStatus.ValueType], builtins.type -): - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor - CAMERA_IDLE: _EnumCameraControlStatus.ValueType - CAMERA_CONTROL: _EnumCameraControlStatus.ValueType - "Can only be set by camera, not by app or third party" - CAMERA_EXTERNAL_CONTROL: _EnumCameraControlStatus.ValueType - -class EnumCameraControlStatus(_EnumCameraControlStatus, metaclass=_EnumCameraControlStatusEnumTypeWrapper): ... - -CAMERA_IDLE: EnumCameraControlStatus.ValueType -CAMERA_CONTROL: EnumCameraControlStatus.ValueType -"Can only be set by camera, not by app or third party" -CAMERA_EXTERNAL_CONTROL: EnumCameraControlStatus.ValueType -global___EnumCameraControlStatus = EnumCameraControlStatus - -class RequestSetCameraControlStatus(google.protobuf.message.Message): - """* - Set Camera Control Status (as part of Global Behaviors feature) - - Response: @ref ResponseGeneric - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - CAMERA_CONTROL_STATUS_FIELD_NUMBER: builtins.int - camera_control_status: global___EnumCameraControlStatus.ValueType - "Declare who is taking control of the camera" - - def __init__(self, *, camera_control_status: global___EnumCameraControlStatus.ValueType | None = ...) -> None: ... - def HasField( - self, field_name: typing_extensions.Literal["camera_control_status", b"camera_control_status"] - ) -> builtins.bool: ... - def ClearField( - self, field_name: typing_extensions.Literal["camera_control_status", b"camera_control_status"] - ) -> None: ... - -global___RequestSetCameraControlStatus = RequestSetCameraControlStatus +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf messages for setting camera control status +""" + +import builtins +import google.protobuf.descriptor +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumCameraControlStatus: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumCameraControlStatusEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumCameraControlStatus.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + CAMERA_IDLE: _EnumCameraControlStatus.ValueType + CAMERA_CONTROL: _EnumCameraControlStatus.ValueType + "Can only be set by camera, not by app or third party" + CAMERA_EXTERNAL_CONTROL: _EnumCameraControlStatus.ValueType + +class EnumCameraControlStatus(_EnumCameraControlStatus, metaclass=_EnumCameraControlStatusEnumTypeWrapper): ... + +CAMERA_IDLE: EnumCameraControlStatus.ValueType +CAMERA_CONTROL: EnumCameraControlStatus.ValueType +"Can only be set by camera, not by app or third party" +CAMERA_EXTERNAL_CONTROL: EnumCameraControlStatus.ValueType +global___EnumCameraControlStatus = EnumCameraControlStatus + +@typing_extensions.final +class RequestSetCameraControlStatus(google.protobuf.message.Message): + """* + Set Camera Control Status (as part of Global Behaviors feature) + + This command is used to tell the camera that the app (i.e. External Control) wishes to claim control of the camera. + This causes the camera to immediately exit most contextual menus and return to the idle screen. Any interaction with + the camera's physical buttons will cause the camera to reclaim control and update control status accordingly. If the + user returns the camera UI to the idle screen, the camera updates control status to Idle. + + The entity currently claiming control of the camera is advertised in camera status 114. Information about whether the + camera is in a contextual menu or not is advertised in camera status 63. + + Response: @ref ResponseGeneric + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + CAMERA_CONTROL_STATUS_FIELD_NUMBER: builtins.int + camera_control_status: global___EnumCameraControlStatus.ValueType + "Declare who is taking control of the camera" + + def __init__(self, *, camera_control_status: global___EnumCameraControlStatus.ValueType | None = ...) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["camera_control_status", b"camera_control_status"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["camera_control_status", b"camera_control_status"], + ) -> None: ... + +global___RequestSetCameraControlStatus = RequestSetCameraControlStatus diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/turbo_transfer_pb2.py b/demos/python/sdk_wireless_camera_control/open_gopro/proto/turbo_transfer_pb2.py index 8ce4f006..565e1e72 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/turbo_transfer_pb2.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/turbo_transfer_pb2.py @@ -1,19 +1,20 @@ # turbo_transfer_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Mon Dec 18 20:40:36 UTC 2023 +# This copyright was auto-generated on Wed Mar 27 22:05:47 UTC 2024 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder - -_sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b"\n\x14turbo_transfer.proto\x12\nopen_gopro\"'\n\x15RequestSetTurboActive\x12\x0e\n\x06active\x18\x01 \x02(\x08" -) -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "turbo_transfer_pb2", globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _REQUESTSETTURBOACTIVE._serialized_start = 36 - _REQUESTSETTURBOACTIVE._serialized_end = 75 +"""Generated protocol buffer code.""" + +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder + +_sym_db = _symbol_database.Default() +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b"\n\x14turbo_transfer.proto\x12\nopen_gopro\"'\n\x15RequestSetTurboActive\x12\x0e\n\x06active\x18\x01 \x02(\x08" +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "turbo_transfer_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _REQUESTSETTURBOACTIVE._serialized_start = 36 + _REQUESTSETTURBOACTIVE._serialized_end = 75 diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/proto/turbo_transfer_pb2.pyi b/demos/python/sdk_wireless_camera_control/open_gopro/proto/turbo_transfer_pb2.pyi index cd34eb19..0c79e66a 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/proto/turbo_transfer_pb2.pyi +++ b/demos/python/sdk_wireless_camera_control/open_gopro/proto/turbo_transfer_pb2.pyi @@ -1,34 +1,36 @@ -""" -@generated by mypy-protobuf. Do not edit manually! -isort:skip_file -* -Defines the structure of protobuf messages for enabling and disabling Turbo Transfer feature -""" -import builtins -import google.protobuf.descriptor -import google.protobuf.message -import sys - -if sys.version_info >= (3, 8): - import typing as typing_extensions -else: - import typing_extensions -DESCRIPTOR: google.protobuf.descriptor.FileDescriptor - -class RequestSetTurboActive(google.protobuf.message.Message): - """* - Enable/disable display of "Transferring Media" UI - - Response: @ref ResponseGeneric - """ - - DESCRIPTOR: google.protobuf.descriptor.Descriptor - ACTIVE_FIELD_NUMBER: builtins.int - active: builtins.bool - "Enable or disable Turbo Transfer feature" - - def __init__(self, *, active: builtins.bool | None = ...) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["active", b"active"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["active", b"active"]) -> None: ... - -global___RequestSetTurboActive = RequestSetTurboActive +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf messages for enabling and disabling Turbo Transfer feature +""" + +import builtins +import google.protobuf.descriptor +import google.protobuf.message +import sys + +if sys.version_info >= (3, 8): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +@typing_extensions.final +class RequestSetTurboActive(google.protobuf.message.Message): + """* + Enable/disable display of "Transferring Media" UI + + Response: @ref ResponseGeneric + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + ACTIVE_FIELD_NUMBER: builtins.int + active: builtins.bool + "Enable or disable Turbo Transfer feature" + + def __init__(self, *, active: builtins.bool | None = ...) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["active", b"active"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["active", b"active"]) -> None: ... + +global___RequestSetTurboActive = RequestSetTurboActive diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/types.py b/demos/python/sdk_wireless_camera_control/open_gopro/types.py index dadaa14b..97df1aae 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/types.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/types.py @@ -36,3 +36,5 @@ UpdateType = Union[SettingId, StatusId, ActionId] UpdateCb = Callable[[UpdateType, Any], Coroutine[Any, Any, None]] + +IdType = Union[SettingId, StatusId, ActionId, CmdId, BleUUID, str] diff --git a/demos/python/sdk_wireless_camera_control/open_gopro/util.py b/demos/python/sdk_wireless_camera_control/open_gopro/util.py index 4a370883..1d16bb16 100644 --- a/demos/python/sdk_wireless_camera_control/open_gopro/util.py +++ b/demos/python/sdk_wireless_camera_control/open_gopro/util.py @@ -98,7 +98,7 @@ def pretty_print(obj: Any, stringify_all: bool = True, should_quote: bool = True obj (Any): object to recurse through stringify_all (bool): At the end of each recursion, should the element be turned into a string? For example, should an int be turned into a str? Defaults to True. - should_quote (bool): _description_. Defaults to True. + should_quote (bool): Should each element be surrounded in quotes?. Defaults to True. Returns: str: pretty-printed string @@ -301,7 +301,7 @@ async def ainput(string: str, printer: Callable = sys.stdout.write) -> str: Returns: str: Input read from console """ - await asyncio.get_event_loop().run_in_executor(None, lambda s=string: printer(s + " ")) + await asyncio.get_event_loop().run_in_executor(None, lambda s=string: printer(s + " ")) # type: ignore return await asyncio.get_event_loop().run_in_executor(None, sys.stdin.readline) @@ -319,4 +319,6 @@ def get_current_dst_aware_time() -> tuple[datetime, int, bool]: except AttributeError: is_dst = False offset = now.utcoffset().total_seconds() / 60 # type: ignore + if is_dst: + offset += 60 return (now, int(offset), is_dst) diff --git a/demos/python/sdk_wireless_camera_control/poetry.lock b/demos/python/sdk_wireless_camera_control/poetry.lock index 59bab35e..b0ec87a9 100644 --- a/demos/python/sdk_wireless_camera_control/poetry.lock +++ b/demos/python/sdk_wireless_camera_control/poetry.lock @@ -2,14 +2,14 @@ [[package]] name = "alabaster" -version = "0.7.13" -description = "A configurable sidebar-enabled Sphinx theme" +version = "0.7.16" +description = "A light, configurable Sphinx theme" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" files = [ - {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, - {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, + {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, + {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, ] [[package]] @@ -58,14 +58,14 @@ files = [ [[package]] name = "autodoc-pydantic" -version = "2.0.1" +version = "2.1.0" description = "Seamlessly integrate pydantic models in your Sphinx documentation." category = "dev" optional = false -python-versions = ">=3.7.1,<4.0.0" +python-versions = ">=3.8,<4.0.0" files = [ - {file = "autodoc_pydantic-2.0.1-py3-none-any.whl", hash = "sha256:d3c302fdb6d37edb5b721f0f540252fa79cea7018bc1a9a85bf70f33a68b0ce4"}, - {file = "autodoc_pydantic-2.0.1.tar.gz", hash = "sha256:7a125a4ff18e4903e27be71e4ddb3269380860eacab4a584d6cc2e212fa96991"}, + {file = "autodoc_pydantic-2.1.0-py3-none-any.whl", hash = "sha256:9f1f82ee3667589dfa08b21697be8bbd80b15110e838cd765bb1bf3ce1b0ea8f"}, + {file = "autodoc_pydantic-2.1.0.tar.gz", hash = "sha256:3cf1b973e2f5ff0fbbe9b951c11827b5e32d3409e238f7f5782359426ab8d360"}, ] [package.dependencies] @@ -81,14 +81,14 @@ test = ["coverage (>=7,<8)", "pytest (>=7,<8)"] [[package]] name = "babel" -version = "2.13.1" +version = "2.14.0" description = "Internationalization utilities" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "Babel-2.13.1-py3-none-any.whl", hash = "sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed"}, - {file = "Babel-2.13.1.tar.gz", hash = "sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900"}, + {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, + {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, ] [package.extras] @@ -174,14 +174,14 @@ files = [ [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] [[package]] @@ -451,62 +451,63 @@ files = [ [[package]] name = "dbus-fast" -version = "2.20.0" +version = "2.21.1" description = "A faster version of dbus-next" category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "dbus_fast-2.20.0-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:ecf22e22434bdd61bfb8b544eb58f5032b23dda5a7fc233afa1d3c9c3241f0a8"}, - {file = "dbus_fast-2.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed70f4c1fe23c47a59d81c8fd8830c65307a1f089cc92949004df4c65c69f155"}, - {file = "dbus_fast-2.20.0-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:9963180456586d0e1b58075e0439a34ed8e9ee4266b35f76f3db6ffc1af17e27"}, - {file = "dbus_fast-2.20.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:eafbf4f0ac86fd959f86bbdf910bf64406b35315781014ef4a1cd2bb43985346"}, - {file = "dbus_fast-2.20.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bb668e2039e15f0e5af14bee7de8c8c082e3b292ed2ce2ceb3168c7068ff2856"}, - {file = "dbus_fast-2.20.0-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:3f7966f835da1d8a77c55a7336313bd97e7f722b316f760077c55c1e9533b0cd"}, - {file = "dbus_fast-2.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff856cbb1508bcf6735ed1e3c04de1def6c400720765141d2470e39c8fd6f13"}, - {file = "dbus_fast-2.20.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7a1da4ed9880046403ddedb7b941fd981872fc883dc9925bbf269b551f12120d"}, - {file = "dbus_fast-2.20.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9084ded47761a43b2252879c6ebaddb7e3cf89377cbdc981de7e8ba87c845239"}, - {file = "dbus_fast-2.20.0-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:d4b91b98cc1849f7d062d563d320594377b099ea9de53ebb789bf9fd6a0eeab4"}, - {file = "dbus_fast-2.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8ab58ef76575e6e00cf1c1f5747b24ce19e35d4966f1c5c3732cea2c3ed5e9"}, - {file = "dbus_fast-2.20.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1909addfad23d400d6f77c3665778a96003e32a1cddd1964de605d0ca400d829"}, - {file = "dbus_fast-2.20.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e591b218d4f327df29a89a922f199bbefb6f892ddc9b96aff21c05c15c0e5dc8"}, - {file = "dbus_fast-2.20.0-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:f55f75ac3891c161daeabdb37d8a3407098482fe54013342a340cdd58f2be091"}, - {file = "dbus_fast-2.20.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d317dba76e904f75146ce0c5f219dae44e8060767b3adf78c94557bbcbea2cbe"}, - {file = "dbus_fast-2.20.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:88126343024f280c1fadd6599ac4cd7046ed550ddc942811dc3d290830cffd51"}, - {file = "dbus_fast-2.20.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ecc07860e3014607a5293e1b87294148f96b1cc508f6496b27e40f64079ebb7a"}, - {file = "dbus_fast-2.20.0-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:e9cdf34f81320b36ce7f2b8c46169632730d9cdcafc52b55cada95096fce3457"}, - {file = "dbus_fast-2.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e40ad43412f92373e4c74bb76d2129a7f0c38a1d883adcfc08f168535f7e7846"}, - {file = "dbus_fast-2.20.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4a5fdebcd8f79d417693536d3ed08bb5842917d373fbc3e9685feecd001accd7"}, - {file = "dbus_fast-2.20.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b134d40688ca7f27ab38bec99194e2551c82fc01f583f44ae66129c3d15db8a7"}, - {file = "dbus_fast-2.20.0-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:fdd4ece2c856e44b5fe9dec354ce5d8930f7ae9bb4b96b3a195157621fea6322"}, - {file = "dbus_fast-2.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e609309d5503a5eab91a7b0cef9dd158c3d8786ac38643a962e99a69d5eb7a66"}, - {file = "dbus_fast-2.20.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8fd806bf4676a28b2323d8529d51f86fec5a9d32923d53ba522a4c2bc3d55857"}, - {file = "dbus_fast-2.20.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8526ff5b27b7c689d97fe8a29e97d3cb7298419b4cb63ed9029331d08d423c55"}, - {file = "dbus_fast-2.20.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:562868206d774080c4131b124a407350ffb5d2b89442048350b83b5084f4e0e1"}, - {file = "dbus_fast-2.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707fc61b4f2de83c8f574061fdaf0ac6fc28b402f451951cf0a1ead11bfcac71"}, - {file = "dbus_fast-2.20.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:4a13c7856459e849202165fd9e1adda8169107a591b083b95842c15b9e772be4"}, - {file = "dbus_fast-2.20.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca1aba69c1dd694399124efbc6ce15930e4697a95d527f16b614100f1f1055a2"}, - {file = "dbus_fast-2.20.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:9817bd32d7734766b073bb08525b9560b0b9501c68c43cc91d43684a2829ad86"}, - {file = "dbus_fast-2.20.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bed226cccedee0c94b292e27fd1c7d24987d36b5ac1cde021031f9c77a76a423"}, - {file = "dbus_fast-2.20.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c11a2b4addb965e09a2d8d666265455f4a7e48916b7c6f43629b828de6682425"}, - {file = "dbus_fast-2.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88367c2a849234f134b9c98fdb16dc84d5ba9703fe995c67f7306900bfa13896"}, - {file = "dbus_fast-2.20.0.tar.gz", hash = "sha256:a38e837c5a8d0a1745ec8390f68ff57986ed2167b0aa2e4a79738a51dd6dfcc3"}, + {file = "dbus_fast-2.21.1-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:b04b88be594dad81b33f6770283eed2125763632515c5112f8aa30f259cd334c"}, + {file = "dbus_fast-2.21.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7333896544a4d0a3d708bd092f8c05eb3599dc2b34ae6e4c4b44d04d5514b0ec"}, + {file = "dbus_fast-2.21.1-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:4591e0962c272d42d305ab3fb8889f13d47255e412fd3b9839620836662c91fe"}, + {file = "dbus_fast-2.21.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:52641305461660c8969c6bb12364206a108c5c9e014c9220c70b99c4f48b6750"}, + {file = "dbus_fast-2.21.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:237db4ab0b90e5284ea7659264630d693273cdbda323a40368f320869bf6470f"}, + {file = "dbus_fast-2.21.1-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:999fed45cb391126107b804be0e344e75556fceaee4cc30a0ca06d77309bdf3c"}, + {file = "dbus_fast-2.21.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2309b9cafba799e9d343fdfdd5ae46276adf3929fef60f296f23b97ed1aa2f6"}, + {file = "dbus_fast-2.21.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b7d1f35218549762e52a782c0b548e0681332beee773d3dfffe2efc38b2ee960"}, + {file = "dbus_fast-2.21.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47aa28520fe274414b655c74cbe2e91d8b76e22f40cd41a758bb6975e526827b"}, + {file = "dbus_fast-2.21.1-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:0ff6c72bcd6539d798015bda33c7ce35c7de76276b9bd45e48db13672713521a"}, + {file = "dbus_fast-2.21.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36d8cd43b3799e766158f1bb0b27cc4eef685fd892417b0382b7fdfdd94f1e6c"}, + {file = "dbus_fast-2.21.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d4da8d58064f0a3dd07bfc283ba912b9d5a4cb38f1c0fcd9ecb2b9d43111243c"}, + {file = "dbus_fast-2.21.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:66e160f496ac79248feb09a0acf4aab5d139d823330cbd9377f6e19ae007330a"}, + {file = "dbus_fast-2.21.1-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:670b5c4d78c9c2d25e7ba650d212d98bf24d40292f91fe4e2f3ad4f80dc6d7e5"}, + {file = "dbus_fast-2.21.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15d62adfab7c6f4a491085f53f9634d24745ca5a2772549945b7e2de27c0d534"}, + {file = "dbus_fast-2.21.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:54e8771e31ee1deb01feef2475c12123cab770c371ecc97af98eb6ca10a2858e"}, + {file = "dbus_fast-2.21.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2db4d0d60a891a8b20a4c6de68a088efe73b29ab4a5949fe6aad2713c131e174"}, + {file = "dbus_fast-2.21.1-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:65e76b20099c33352d5e7734a219982858873cf66fe510951d9bd27cb690190f"}, + {file = "dbus_fast-2.21.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:927f294b1dc7cea9372ef8c7c46ebeb5c7e6c1c7345358f952e7499bdbdf7eb4"}, + {file = "dbus_fast-2.21.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9e9a43ea42b8a9f2c62ca50ce05582de7b4f1f7eb27091f904578c29124af246"}, + {file = "dbus_fast-2.21.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:78c84ecf19459571784fd6a8ad8b3e9006cf96c3282e8220bc49098866ef4cc7"}, + {file = "dbus_fast-2.21.1-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a5b3895ea12c4e636dfaacf75fa5bd1e8450b2ffb97507520991eaf1989d102e"}, + {file = "dbus_fast-2.21.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85be33bb04e918833ac6f28f68f83a1e83425eb6e08b9c482cc3318820dfd55f"}, + {file = "dbus_fast-2.21.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:13ab6a0f64d345cb42c489239962261f724bd441458bef245b39828ed94ea6f4"}, + {file = "dbus_fast-2.21.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c585e7a94bb723a70b4966677b882be8bda324cc41bd129765e3ceab428889bb"}, + {file = "dbus_fast-2.21.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:62331ee3871f6881f517ca65ae185fb2462a0bf2fe78acc4a4d621fc4da08396"}, + {file = "dbus_fast-2.21.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbfd6892fa092cbd6f52edcb24797af62fba8baa50995db856b0a342184c850d"}, + {file = "dbus_fast-2.21.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a999e35628988ad4f81af36192cd592b8fd1e72e1bbc76a64d80808e6f4b9540"}, + {file = "dbus_fast-2.21.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9cae9a6b9bb54f3f89424fdd960b60ac53239b9e5d4a5d9a598d222fbf8d3173"}, + {file = "dbus_fast-2.21.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:39a3f3662391b49553bf9d9d2e9a6cb31e0d7d337557ee0c0be5c558a3c7d230"}, + {file = "dbus_fast-2.21.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffc2b6beb212d0d231816dcb7bd8bcdafccd04750ba8f5e915f40ad312f5adf2"}, + {file = "dbus_fast-2.21.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c938eb7130067ca3b74b248ee376228776d8f013a206ae78e6fc644c9db0f4f5"}, + {file = "dbus_fast-2.21.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fae9609d972f0c2b72017796a8140b8a6fb842426f0aed4f43f0fa7d780a16f"}, + {file = "dbus_fast-2.21.1.tar.gz", hash = "sha256:87b852d2005f1d59399ca51c5f3538f28a4742d739d7abe82b7ae8d01d8a5d02"}, ] [[package]] name = "dill" -version = "0.3.7" +version = "0.3.8" description = "serialize all of Python" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"}, - {file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"}, + {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, + {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, ] [package.extras] graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "docutils" @@ -573,23 +574,23 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.0" +version = "7.1.0" description = "Read metadata from Python packages" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.0-py3-none-any.whl", hash = "sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67"}, - {file = "importlib_metadata-7.0.0.tar.gz", hash = "sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7"}, + {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, + {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "iniconfig" @@ -605,32 +606,29 @@ files = [ [[package]] name = "isort" -version = "5.12.0" +version = "5.13.2" description = "A Python utility / library to sort Python imports." category = "dev" optional = false python-versions = ">=3.8.0" files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, ] [package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] +colors = ["colorama (>=0.4.6)"] [[package]] name = "jinja2" -version = "3.1.2" +version = "3.1.3" description = "A very fast and expressive template engine." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, ] [package.dependencies] @@ -641,108 +639,119 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "lazy-object-proxy" -version = "1.9.0" +version = "1.10.0" description = "A fast and thorough lazy object proxy." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, + {file = "lazy-object-proxy-1.10.0.tar.gz", hash = "sha256:78247b6d45f43a52ef35c25b5581459e85117225408a4128a3daf8bf9648ac69"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:855e068b0358ab916454464a884779c7ffa312b8925c6f7401e952dcf3b89977"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab7004cf2e59f7c2e4345604a3e6ea0d92ac44e1c2375527d56492014e690c3"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc0d2fc424e54c70c4bc06787e4072c4f3b1aa2f897dfdc34ce1013cf3ceef05"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e2adb09778797da09d2b5ebdbceebf7dd32e2c96f79da9052b2e87b6ea495895"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1f711e2c6dcd4edd372cf5dec5c5a30d23bba06ee012093267b3376c079ec83"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-win32.whl", hash = "sha256:76a095cfe6045c7d0ca77db9934e8f7b71b14645f0094ffcd842349ada5c5fb9"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:b4f87d4ed9064b2628da63830986c3d2dca7501e6018347798313fcf028e2fd4"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fec03caabbc6b59ea4a638bee5fce7117be8e99a4103d9d5ad77f15d6f81020c"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c83f957782cbbe8136bee26416686a6ae998c7b6191711a04da776dc9e47d4"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009e6bb1f1935a62889ddc8541514b6a9e1fcf302667dcb049a0be5c8f613e56"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75fc59fc450050b1b3c203c35020bc41bd2695ed692a392924c6ce180c6f1dc9"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:782e2c9b2aab1708ffb07d4bf377d12901d7a1d99e5e410d648d892f8967ab1f"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-win32.whl", hash = "sha256:edb45bb8278574710e68a6b021599a10ce730d156e5b254941754a9cc0b17d03"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:e271058822765ad5e3bca7f05f2ace0de58a3f4e62045a8c90a0dfd2f8ad8cc6"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e98c8af98d5707dcdecc9ab0863c0ea6e88545d42ca7c3feffb6b4d1e370c7ba"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:952c81d415b9b80ea261d2372d2a4a2332a3890c2b83e0535f263ddfe43f0d43"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80b39d3a151309efc8cc48675918891b865bdf742a8616a337cb0090791a0de9"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e221060b701e2aa2ea991542900dd13907a5c90fa80e199dbf5a03359019e7a3"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92f09ff65ecff3108e56526f9e2481b8116c0b9e1425325e13245abfd79bdb1b"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-win32.whl", hash = "sha256:3ad54b9ddbe20ae9f7c1b29e52f123120772b06dbb18ec6be9101369d63a4074"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:127a789c75151db6af398b8972178afe6bda7d6f68730c057fbbc2e96b08d282"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9e4ed0518a14dd26092614412936920ad081a424bdcb54cc13349a8e2c6d106a"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ad9e6ed739285919aa9661a5bbed0aaf410aa60231373c5579c6b4801bd883c"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fc0a92c02fa1ca1e84fc60fa258458e5bf89d90a1ddaeb8ed9cc3147f417255"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0aefc7591920bbd360d57ea03c995cebc204b424524a5bd78406f6e1b8b2a5d8"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5faf03a7d8942bb4476e3b62fd0f4cf94eaf4618e304a19865abf89a35c0bbee"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-win32.whl", hash = "sha256:e333e2324307a7b5d86adfa835bb500ee70bfcd1447384a822e96495796b0ca4"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:cb73507defd385b7705c599a94474b1d5222a508e502553ef94114a143ec6696"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:366c32fe5355ef5fc8a232c5436f4cc66e9d3e8967c01fb2e6302fd6627e3d94"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2297f08f08a2bb0d32a4265e98a006643cd7233fb7983032bd61ac7a02956b3b"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18dd842b49456aaa9a7cf535b04ca4571a302ff72ed8740d06b5adcd41fe0757"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:217138197c170a2a74ca0e05bddcd5f1796c735c37d0eee33e43259b192aa424"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a3a87cf1e133e5b1994144c12ca4aa3d9698517fe1e2ca82977781b16955658"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-win32.whl", hash = "sha256:30b339b2a743c5288405aa79a69e706a06e02958eab31859f7f3c04980853b70"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:a899b10e17743683b293a729d3a11f2f399e8a90c73b089e29f5d0fe3509f0dd"}, + {file = "lazy_object_proxy-1.10.0-pp310.pp311.pp312.pp38.pp39-none-any.whl", hash = "sha256:80fa48bd89c8f2f456fc0765c11c23bf5af827febacd2f523ca5bc1893fcc09d"}, ] [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] @@ -759,39 +768,39 @@ files = [ [[package]] name = "mypy" -version = "1.7.1" +version = "1.9.0" description = "Optional static typing for Python" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"}, - {file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"}, - {file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"}, - {file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"}, - {file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"}, - {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"}, - {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"}, - {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"}, - {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"}, - {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"}, - {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"}, - {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"}, - {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"}, - {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"}, - {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"}, - {file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"}, - {file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"}, - {file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"}, - {file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"}, - {file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"}, - {file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"}, - {file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"}, - {file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"}, - {file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"}, - {file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"}, - {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"}, - {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"}, + {file = "mypy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8a67616990062232ee4c3952f41c779afac41405806042a8126fe96e098419f"}, + {file = "mypy-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d357423fa57a489e8c47b7c85dfb96698caba13d66e086b412298a1a0ea3b0ed"}, + {file = "mypy-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c87c15aed320de9b438ae7b00c1ac91cd393c1b854c2ce538e2a72d55df150"}, + {file = "mypy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:48533cdd345c3c2e5ef48ba3b0d3880b257b423e7995dada04248725c6f77374"}, + {file = "mypy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:4d3dbd346cfec7cb98e6cbb6e0f3c23618af826316188d587d1c1bc34f0ede03"}, + {file = "mypy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:653265f9a2784db65bfca694d1edd23093ce49740b2244cde583aeb134c008f3"}, + {file = "mypy-1.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a3c007ff3ee90f69cf0a15cbcdf0995749569b86b6d2f327af01fd1b8aee9dc"}, + {file = "mypy-1.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2418488264eb41f69cc64a69a745fad4a8f86649af4b1041a4c64ee61fc61129"}, + {file = "mypy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:68edad3dc7d70f2f17ae4c6c1b9471a56138ca22722487eebacfd1eb5321d612"}, + {file = "mypy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:85ca5fcc24f0b4aeedc1d02f93707bccc04733f21d41c88334c5482219b1ccb3"}, + {file = "mypy-1.9.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aceb1db093b04db5cd390821464504111b8ec3e351eb85afd1433490163d60cd"}, + {file = "mypy-1.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0235391f1c6f6ce487b23b9dbd1327b4ec33bb93934aa986efe8a9563d9349e6"}, + {file = "mypy-1.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d5ddc13421ba3e2e082a6c2d74c2ddb3979c39b582dacd53dd5d9431237185"}, + {file = "mypy-1.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:190da1ee69b427d7efa8aa0d5e5ccd67a4fb04038c380237a0d96829cb157913"}, + {file = "mypy-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe28657de3bfec596bbeef01cb219833ad9d38dd5393fc649f4b366840baefe6"}, + {file = "mypy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e54396d70be04b34f31d2edf3362c1edd023246c82f1730bbf8768c28db5361b"}, + {file = "mypy-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5e6061f44f2313b94f920e91b204ec600982961e07a17e0f6cd83371cb23f5c2"}, + {file = "mypy-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a10926e5473c5fc3da8abb04119a1f5811a236dc3a38d92015cb1e6ba4cb9e"}, + {file = "mypy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b685154e22e4e9199fc95f298661deea28aaede5ae16ccc8cbb1045e716b3e04"}, + {file = "mypy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d741d3fc7c4da608764073089e5f58ef6352bedc223ff58f2f038c2c4698a89"}, + {file = "mypy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:587ce887f75dd9700252a3abbc9c97bbe165a4a630597845c61279cf32dfbf02"}, + {file = "mypy-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f88566144752999351725ac623471661c9d1cd8caa0134ff98cceeea181789f4"}, + {file = "mypy-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61758fabd58ce4b0720ae1e2fea5cfd4431591d6d590b197775329264f86311d"}, + {file = "mypy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e49499be624dead83927e70c756970a0bc8240e9f769389cdf5714b0784ca6bf"}, + {file = "mypy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:571741dc4194b4f82d344b15e8837e8c5fcc462d66d076748142327626a1b6e9"}, + {file = "mypy-1.9.0-py3-none-any.whl", hash = "sha256:a260627a570559181a9ea5de61ac6297aa5af202f06fd7ab093ce74e7181e43e"}, + {file = "mypy-1.9.0.tar.gz", hash = "sha256:3cc5da0127e6a478cddd906068496a97a7618a21ce9b54bde5bf7e539c7af974"}, ] [package.dependencies] @@ -817,83 +826,67 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] -[[package]] -name = "mypy-protobuf" -version = "3.3.0" -description = "Generate mypy stub files from protobuf specs" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "mypy-protobuf-3.3.0.tar.gz", hash = "sha256:24f3b0aecb06656e983f58e07c732a90577b9d7af3e1066fc2b663bbf0370248"}, - {file = "mypy_protobuf-3.3.0-py3-none-any.whl", hash = "sha256:15604f6943b16c05db646903261e3b3e775cf7f7990b7c37b03d043a907b650d"}, -] - -[package.dependencies] -protobuf = ">=3.19.4" -types-protobuf = ">=3.19.12" - [[package]] name = "numpy" -version = "1.26.2" +version = "1.26.4" description = "Fundamental package for array computing in Python" category = "main" optional = true python-versions = ">=3.9" files = [ - {file = "numpy-1.26.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3703fc9258a4a122d17043e57b35e5ef1c5a5837c3db8be396c82e04c1cf9b0f"}, - {file = "numpy-1.26.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc392fdcbd21d4be6ae1bb4475a03ce3b025cd49a9be5345d76d7585aea69440"}, - {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36340109af8da8805d8851ef1d74761b3b88e81a9bd80b290bbfed61bd2b4f75"}, - {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc008217145b3d77abd3e4d5ef586e3bdfba8fe17940769f8aa09b99e856c00"}, - {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ced40d4e9e18242f70dd02d739e44698df3dcb010d31f495ff00a31ef6014fe"}, - {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b272d4cecc32c9e19911891446b72e986157e6a1809b7b56518b4f3755267523"}, - {file = "numpy-1.26.2-cp310-cp310-win32.whl", hash = "sha256:22f8fc02fdbc829e7a8c578dd8d2e15a9074b630d4da29cda483337e300e3ee9"}, - {file = "numpy-1.26.2-cp310-cp310-win_amd64.whl", hash = "sha256:26c9d33f8e8b846d5a65dd068c14e04018d05533b348d9eaeef6c1bd787f9919"}, - {file = "numpy-1.26.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b96e7b9c624ef3ae2ae0e04fa9b460f6b9f17ad8b4bec6d7756510f1f6c0c841"}, - {file = "numpy-1.26.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa18428111fb9a591d7a9cc1b48150097ba6a7e8299fb56bdf574df650e7d1f1"}, - {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06fa1ed84aa60ea6ef9f91ba57b5ed963c3729534e6e54055fc151fad0423f0a"}, - {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca5482c3dbdd051bcd1fce8034603d6ebfc125a7bd59f55b40d8f5d246832b"}, - {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:854ab91a2906ef29dc3925a064fcd365c7b4da743f84b123002f6139bcb3f8a7"}, - {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f43740ab089277d403aa07567be138fc2a89d4d9892d113b76153e0e412409f8"}, - {file = "numpy-1.26.2-cp311-cp311-win32.whl", hash = "sha256:a2bbc29fcb1771cd7b7425f98b05307776a6baf43035d3b80c4b0f29e9545186"}, - {file = "numpy-1.26.2-cp311-cp311-win_amd64.whl", hash = "sha256:2b3fca8a5b00184828d12b073af4d0fc5fdd94b1632c2477526f6bd7842d700d"}, - {file = "numpy-1.26.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a4cd6ed4a339c21f1d1b0fdf13426cb3b284555c27ac2f156dfdaaa7e16bfab0"}, - {file = "numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d5244aabd6ed7f312268b9247be47343a654ebea52a60f002dc70c769048e75"}, - {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3cdb4d9c70e6b8c0814239ead47da00934666f668426fc6e94cce869e13fd7"}, - {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa317b2325f7aa0a9471663e6093c210cb2ae9c0ad824732b307d2c51983d5b6"}, - {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:174a8880739c16c925799c018f3f55b8130c1f7c8e75ab0a6fa9d41cab092fd6"}, - {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f79b231bf5c16b1f39c7f4875e1ded36abee1591e98742b05d8a0fb55d8a3eec"}, - {file = "numpy-1.26.2-cp312-cp312-win32.whl", hash = "sha256:4a06263321dfd3598cacb252f51e521a8cb4b6df471bb12a7ee5cbab20ea9167"}, - {file = "numpy-1.26.2-cp312-cp312-win_amd64.whl", hash = "sha256:b04f5dc6b3efdaab541f7857351aac359e6ae3c126e2edb376929bd3b7f92d7e"}, - {file = "numpy-1.26.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4eb8df4bf8d3d90d091e0146f6c28492b0be84da3e409ebef54349f71ed271ef"}, - {file = "numpy-1.26.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a13860fdcd95de7cf58bd6f8bc5a5ef81c0b0625eb2c9a783948847abbef2c2"}, - {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64308ebc366a8ed63fd0bf426b6a9468060962f1a4339ab1074c228fa6ade8e3"}, - {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baf8aab04a2c0e859da118f0b38617e5ee65d75b83795055fb66c0d5e9e9b818"}, - {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d73a3abcac238250091b11caef9ad12413dab01669511779bc9b29261dd50210"}, - {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b361d369fc7e5e1714cf827b731ca32bff8d411212fccd29ad98ad622449cc36"}, - {file = "numpy-1.26.2-cp39-cp39-win32.whl", hash = "sha256:bd3f0091e845164a20bd5a326860c840fe2af79fa12e0469a12768a3ec578d80"}, - {file = "numpy-1.26.2-cp39-cp39-win_amd64.whl", hash = "sha256:2beef57fb031dcc0dc8fa4fe297a742027b954949cabb52a2a376c144e5e6060"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1cc3d5029a30fb5f06704ad6b23b35e11309491c999838c31f124fee32107c79"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94cc3c222bb9fb5a12e334d0479b97bb2df446fbe622b470928f5284ffca3f8d"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe6b44fb8fcdf7eda4ef4461b97b3f63c466b27ab151bec2366db8b197387841"}, - {file = "numpy-1.26.2.tar.gz", hash = "sha256:f65738447676ab5777f11e6bbbdb8ce11b785e105f690bc45966574816b6d3ea"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] name = "opencv-python" -version = "4.8.1.78" +version = "4.9.0.80" description = "Wrapper package for OpenCV python bindings." category = "main" optional = true python-versions = ">=3.6" files = [ - {file = "opencv-python-4.8.1.78.tar.gz", hash = "sha256:cc7adbbcd1112877a39274106cb2752e04984bc01a031162952e97450d6117f6"}, - {file = "opencv_python-4.8.1.78-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:91d5f6f5209dc2635d496f6b8ca6573ecdad051a09e6b5de4c399b8e673c60da"}, - {file = "opencv_python-4.8.1.78-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:bc31f47e05447da8b3089faa0a07ffe80e114c91ce0b171e6424f9badbd1c5cd"}, - {file = "opencv_python-4.8.1.78-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9814beca408d3a0eca1bae7e3e5be68b07c17ecceb392b94170881216e09b319"}, - {file = "opencv_python-4.8.1.78-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c406bdb41eb21ea51b4e90dfbc989c002786c3f601c236a99c59a54670a394"}, - {file = "opencv_python-4.8.1.78-cp37-abi3-win32.whl", hash = "sha256:a7aac3900fbacf55b551e7b53626c3dad4c71ce85643645c43e91fcb19045e47"}, - {file = "opencv_python-4.8.1.78-cp37-abi3-win_amd64.whl", hash = "sha256:b983197f97cfa6fcb74e1da1802c7497a6f94ed561aba6980f1f33123f904956"}, + {file = "opencv-python-4.9.0.80.tar.gz", hash = "sha256:1a9f0e6267de3a1a1db0c54213d022c7c8b5b9ca4b580e80bdc58516c922c9e1"}, + {file = "opencv_python-4.9.0.80-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:7e5f7aa4486651a6ebfa8ed4b594b65bd2d2f41beeb4241a3e4b1b85acbbbadb"}, + {file = "opencv_python-4.9.0.80-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:71dfb9555ccccdd77305fc3dcca5897fbf0cf28b297c51ee55e079c065d812a3"}, + {file = "opencv_python-4.9.0.80-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b34a52e9da36dda8c151c6394aed602e4b17fa041df0b9f5b93ae10b0fcca2a"}, + {file = "opencv_python-4.9.0.80-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4088cab82b66a3b37ffc452976b14a3c599269c247895ae9ceb4066d8188a57"}, + {file = "opencv_python-4.9.0.80-cp37-abi3-win32.whl", hash = "sha256:dcf000c36dd1651118a2462257e3a9e76db789a78432e1f303c7bac54f63ef6c"}, + {file = "opencv_python-4.9.0.80-cp37-abi3-win_amd64.whl", hash = "sha256:3f16f08e02b2a2da44259c7cc712e779eff1dd8b55fdb0323e8cab09548086c0"}, ] [package.dependencies] @@ -901,10 +894,10 @@ numpy = [ {version = ">=1.21.0", markers = "python_version <= \"3.9\" and platform_system == \"Darwin\" and platform_machine == \"arm64\""}, {version = ">=1.21.2", markers = "python_version >= \"3.10\""}, {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\""}, + {version = ">=1.23.5", markers = "python_version >= \"3.11\""}, {version = ">=1.19.3", markers = "python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\" or python_version >= \"3.9\""}, {version = ">=1.17.0", markers = "python_version >= \"3.7\""}, {version = ">=1.17.3", markers = "python_version >= \"3.8\""}, - {version = ">=1.23.5", markers = "python_version >= \"3.11\""}, ] [[package]] @@ -936,14 +929,14 @@ files = [ [[package]] name = "pathspec" -version = "0.11.2" +version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] [[package]] @@ -1043,30 +1036,30 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "platformdirs" -version = "4.1.0" +version = "4.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] [[package]] name = "pluggy" -version = "1.3.0" +version = "1.4.0" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, ] [package.extras] @@ -1075,14 +1068,14 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "poethepoet" -version = "0.24.4" +version = "0.25.0" description = "A task runner that works well with poetry." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "poethepoet-0.24.4-py3-none-any.whl", hash = "sha256:fb4ea35d7f40fe2081ea917d2e4102e2310fda2cde78974050ca83896e229075"}, - {file = "poethepoet-0.24.4.tar.gz", hash = "sha256:ff4220843a87c888cbcb5312c8905214701d0af60ac7271795baa8369b428fef"}, + {file = "poethepoet-0.25.0-py3-none-any.whl", hash = "sha256:42c0fd654f23e1b7c67aa8aa395c72e15eb275034bd5105171003daf679c1470"}, + {file = "poethepoet-0.25.0.tar.gz", hash = "sha256:ca8f1d8475aa10d2ceeb26331d2626fc4a6b51df1e7e70d3d0d6481a984faab6"}, ] [package.dependencies] @@ -1124,25 +1117,6 @@ files = [ {file = "protobuf-3.20.3.tar.gz", hash = "sha256:2e3427429c9cffebf259491be0af70189607f365c2f41c7c3764af6f337105f2"}, ] -[[package]] -name = "protoletariat" -version = "3.2.19" -description = "Python protocol buffers for the rest of us" -category = "dev" -optional = false -python-versions = ">=3.8,<4.0" -files = [ - {file = "protoletariat-3.2.19-py3-none-any.whl", hash = "sha256:4bed510011cb352b26998008167a5a7ae697fb49d76fe4848bffa27856feab35"}, - {file = "protoletariat-3.2.19.tar.gz", hash = "sha256:3c23aa88bcceadde5a589bf0c1dd91e08636309e5b3d115ddebb38f5b1873d53"}, -] - -[package.dependencies] -click = ">=8,<9" -protobuf = ">=3.19.1,<5" - -[package.extras] -grpcio-tools = ["grpcio-tools (>=1.42.0,<2)"] - [[package]] name = "ptyprocess" version = "0.7.0" @@ -1169,19 +1143,19 @@ files = [ [[package]] name = "pydantic" -version = "2.5.2" +version = "2.6.4" description = "Data validation using Python type hints" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic-2.5.2-py3-none-any.whl", hash = "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0"}, - {file = "pydantic-2.5.2.tar.gz", hash = "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd"}, + {file = "pydantic-2.6.4-py3-none-any.whl", hash = "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5"}, + {file = "pydantic-2.6.4.tar.gz", hash = "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.14.5" +pydantic-core = "2.16.3" typing-extensions = ">=4.6.1" [package.extras] @@ -1189,117 +1163,91 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.14.5" +version = "2.16.3" description = "" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.14.5-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd"}, - {file = "pydantic_core-2.14.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66"}, - {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997"}, - {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093"}, - {file = "pydantic_core-2.14.5-cp310-none-win32.whl", hash = "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720"}, - {file = "pydantic_core-2.14.5-cp310-none-win_amd64.whl", hash = "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b"}, - {file = "pydantic_core-2.14.5-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459"}, - {file = "pydantic_core-2.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4"}, - {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada"}, - {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda"}, - {file = "pydantic_core-2.14.5-cp311-none-win32.whl", hash = "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651"}, - {file = "pydantic_core-2.14.5-cp311-none-win_amd64.whl", hash = "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077"}, - {file = "pydantic_core-2.14.5-cp311-none-win_arm64.whl", hash = "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf"}, - {file = "pydantic_core-2.14.5-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093"}, - {file = "pydantic_core-2.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e"}, - {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69"}, - {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d"}, - {file = "pydantic_core-2.14.5-cp312-none-win32.whl", hash = "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260"}, - {file = "pydantic_core-2.14.5-cp312-none-win_amd64.whl", hash = "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36"}, - {file = "pydantic_core-2.14.5-cp312-none-win_arm64.whl", hash = "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325"}, - {file = "pydantic_core-2.14.5-cp37-none-win32.whl", hash = "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405"}, - {file = "pydantic_core-2.14.5-cp37-none-win_amd64.whl", hash = "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588"}, - {file = "pydantic_core-2.14.5-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf"}, - {file = "pydantic_core-2.14.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b"}, - {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec"}, - {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124"}, - {file = "pydantic_core-2.14.5-cp38-none-win32.whl", hash = "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867"}, - {file = "pydantic_core-2.14.5-cp38-none-win_amd64.whl", hash = "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d"}, - {file = "pydantic_core-2.14.5-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7"}, - {file = "pydantic_core-2.14.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955"}, - {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5"}, - {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209"}, - {file = "pydantic_core-2.14.5-cp39-none-win32.whl", hash = "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6"}, - {file = "pydantic_core-2.14.5-cp39-none-win_amd64.whl", hash = "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3"}, - {file = "pydantic_core-2.14.5.tar.gz", hash = "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, + {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, + {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, + {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, + {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, + {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, + {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, + {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, + {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, + {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, + {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, + {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, + {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, + {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, ] [package.dependencies] @@ -1307,20 +1255,24 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.1.0" +version = "2.2.1" description = "Settings management using Pydantic" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.1.0-py3-none-any.whl", hash = "sha256:7621c0cb5d90d1140d2f0ef557bdf03573aac7035948109adf2574770b77605a"}, - {file = "pydantic_settings-2.1.0.tar.gz", hash = "sha256:26b1492e0a24755626ac5e6d715e9077ab7ad4fb5f19a8b7ed7011d52f36141c"}, + {file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"}, + {file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"}, ] [package.dependencies] pydantic = ">=2.3.0" python-dotenv = ">=0.21.0" +[package.extras] +toml = ["tomli (>=2.0.1)"] +yaml = ["pyyaml (>=6.0.1)"] + [[package]] name = "pydocstyle" version = "6.3.0" @@ -1466,14 +1418,14 @@ pyobjc-core = ">=9.2" [[package]] name = "pyparsing" -version = "3.1.1" +version = "3.1.2" description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "main" optional = false python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, - {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, + {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, + {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, ] [package.extras] @@ -1481,14 +1433,14 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -1558,14 +1510,14 @@ pytest-metadata = "*" [[package]] name = "pytest-metadata" -version = "3.0.0" +version = "3.1.1" description = "pytest plugin for test session metadata" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest_metadata-3.0.0-py3-none-any.whl", hash = "sha256:a17b1e40080401dc23177599208c52228df463db191c1a573ccdffacd885e190"}, - {file = "pytest_metadata-3.0.0.tar.gz", hash = "sha256:769a9c65d2884bd583bc626b0ace77ad15dbe02dd91a9106d47fd46d9c2569ca"}, + {file = "pytest_metadata-3.1.1-py3-none-any.whl", hash = "sha256:c8e0844db684ee1c798cfa38908d20d67d0463ecb6137c72e91f418558dd5f4b"}, + {file = "pytest_metadata-3.1.1.tar.gz", hash = "sha256:d2a29b0355fbc03f168aa96d41ff88b1a3b44a3b02acbe491801c98a048017c8"}, ] [package.dependencies] @@ -1576,29 +1528,29 @@ test = ["black (>=22.1.0)", "flake8 (>=4.0.1)", "pre-commit (>=2.17.0)", "tox (> [[package]] name = "pytest-timeout" -version = "2.2.0" +version = "2.3.1" description = "pytest plugin to abort hanging tests" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-timeout-2.2.0.tar.gz", hash = "sha256:3b0b95dabf3cb50bac9ef5ca912fa0cfc286526af17afc806824df20c2f72c90"}, - {file = "pytest_timeout-2.2.0-py3-none-any.whl", hash = "sha256:bde531e096466f49398a59f2dde76fa78429a09a12411466f88a07213e220de2"}, + {file = "pytest-timeout-2.3.1.tar.gz", hash = "sha256:12397729125c6ecbdaca01035b9e5239d4db97352320af155b3f5de1ba5165d9"}, + {file = "pytest_timeout-2.3.1-py3-none-any.whl", hash = "sha256:68188cb703edfc6a18fad98dc25a3c61e9f24d644b0b70f33af545219fc7813e"}, ] [package.dependencies] -pytest = ">=5.0.0" +pytest = ">=7.0.0" [[package]] name = "python-dotenv" -version = "1.0.0" +version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, - {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, + {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, + {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, ] [package.extras] @@ -1606,14 +1558,14 @@ cli = ["click (>=5.0)"] [[package]] name = "pytz" -version = "2023.3.post1" +version = "2024.1" description = "World timezone definitions, modern and historical" category = "main" optional = false python-versions = "*" files = [ - {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, - {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] [[package]] @@ -1640,23 +1592,21 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-mock" -version = "1.11.0" +version = "1.12.1" description = "Mock out responses from the requests package" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.5" files = [ - {file = "requests-mock-1.11.0.tar.gz", hash = "sha256:ef10b572b489a5f28e09b708697208c4a3b2b89ef80a9f01584340ea357ec3c4"}, - {file = "requests_mock-1.11.0-py2.py3-none-any.whl", hash = "sha256:f7fae383f228633f6bececebdab236c478ace2284d6292c6e7e2867b9ab74d15"}, + {file = "requests-mock-1.12.1.tar.gz", hash = "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401"}, + {file = "requests_mock-1.12.1-py2.py3-none-any.whl", hash = "sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563"}, ] [package.dependencies] -requests = ">=2.3,<3" -six = "*" +requests = ">=2.22,<3" [package.extras] fixture = ["fixtures"] -test = ["fixtures", "mock", "purl", "pytest", "requests-futures", "sphinx", "testtools"] [[package]] name = "rich" @@ -1677,18 +1627,6 @@ pygments = ">=2.6.0,<3.0.0" [package.extras] jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - [[package]] name = "snowballstemmer" version = "2.2.0" @@ -1759,59 +1697,53 @@ dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.7" +version = "1.0.8" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" category = "dev" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_applehelp-1.0.7-py3-none-any.whl", hash = "sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d"}, - {file = "sphinxcontrib_applehelp-1.0.7.tar.gz", hash = "sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa"}, + {file = "sphinxcontrib_applehelp-1.0.8-py3-none-any.whl", hash = "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4"}, + {file = "sphinxcontrib_applehelp-1.0.8.tar.gz", hash = "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-devhelp" -version = "1.0.5" +version = "1.0.6" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" category = "dev" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_devhelp-1.0.5-py3-none-any.whl", hash = "sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f"}, - {file = "sphinxcontrib_devhelp-1.0.5.tar.gz", hash = "sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212"}, + {file = "sphinxcontrib_devhelp-1.0.6-py3-none-any.whl", hash = "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f"}, + {file = "sphinxcontrib_devhelp-1.0.6.tar.gz", hash = "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "2.0.4" +version = "2.0.5" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" category = "dev" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_htmlhelp-2.0.4-py3-none-any.whl", hash = "sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9"}, - {file = "sphinxcontrib_htmlhelp-2.0.4.tar.gz", hash = "sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a"}, + {file = "sphinxcontrib_htmlhelp-2.0.5-py3-none-any.whl", hash = "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04"}, + {file = "sphinxcontrib_htmlhelp-2.0.5.tar.gz", hash = "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] [[package]] @@ -1846,55 +1778,52 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" -version = "1.0.6" +version = "1.0.7" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" category = "dev" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_qthelp-1.0.6-py3-none-any.whl", hash = "sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4"}, - {file = "sphinxcontrib_qthelp-1.0.6.tar.gz", hash = "sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d"}, + {file = "sphinxcontrib_qthelp-1.0.7-py3-none-any.whl", hash = "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182"}, + {file = "sphinxcontrib_qthelp-1.0.7.tar.gz", hash = "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.9" +version = "1.1.10" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" category = "dev" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_serializinghtml-1.1.9-py3-none-any.whl", hash = "sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1"}, - {file = "sphinxcontrib_serializinghtml-1.1.9.tar.gz", hash = "sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54"}, + {file = "sphinxcontrib_serializinghtml-1.1.10-py3-none-any.whl", hash = "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7"}, + {file = "sphinxcontrib_serializinghtml-1.1.10.tar.gz", hash = "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxemoji" -version = "0.2.0" +version = "0.3.1" description = "An extension to use emoji codes in your Sphinx documentation" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.9" files = [ - {file = "sphinxemoji-0.2.0.tar.gz", hash = "sha256:27861d1dd7c6570f5e63020dac9a687263f7481f6d5d6409eb31ecebcc804e4c"}, + {file = "sphinxemoji-0.3.1-py3-none-any.whl", hash = "sha256:dae483695f8d1e90a28a6e9bbccc08d256202afcc1d0fbd33b51b3b4352d439e"}, + {file = "sphinxemoji-0.3.1.tar.gz", hash = "sha256:23ecff1f1e765393e49083b45386b7da81ced97c9a18a1dfd191460a97da3b11"}, ] [package.dependencies] -sphinx = ">=1.8" +sphinx = ">=5.0" [[package]] name = "tomli" @@ -1910,14 +1839,14 @@ files = [ [[package]] name = "tomlkit" -version = "0.12.3" +version = "0.12.4" description = "Style preserving TOML library" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, - {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, + {file = "tomlkit-0.12.4-py3-none-any.whl", hash = "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b"}, + {file = "tomlkit-0.12.4.tar.gz", hash = "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3"}, ] [[package]] @@ -1933,38 +1862,38 @@ files = [ [[package]] name = "types-protobuf" -version = "4.24.0.4" +version = "4.24.0.20240408" description = "Typing stubs for protobuf" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "types-protobuf-4.24.0.4.tar.gz", hash = "sha256:57ab42cb171dfdba2c74bb5b50c250478538cc3c5ed95b8b368929ad0c9f90a5"}, - {file = "types_protobuf-4.24.0.4-py3-none-any.whl", hash = "sha256:131ab7d0cbc9e444bc89c994141327dcce7bcaeded72b1acb72a94827eb9c7af"}, + {file = "types-protobuf-4.24.0.20240408.tar.gz", hash = "sha256:c03a44357b03c233c8c5864ce3e07dd9c766a00497d271496923f7ae3cb9e1de"}, + {file = "types_protobuf-4.24.0.20240408-py3-none-any.whl", hash = "sha256:9b87cd279378693071247227f52e89738af7c8d6f06dbdd749b0cf473c4916ce"}, ] [[package]] name = "types-pytz" -version = "2023.3.1.1" +version = "2024.1.0.20240203" description = "Typing stubs for pytz" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "types-pytz-2023.3.1.1.tar.gz", hash = "sha256:cc23d0192cd49c8f6bba44ee0c81e4586a8f30204970fc0894d209a6b08dab9a"}, - {file = "types_pytz-2023.3.1.1-py3-none-any.whl", hash = "sha256:1999a123a3dc0e39a2ef6d19f3f8584211de9e6a77fe7a0259f04a524e90a5cf"}, + {file = "types-pytz-2024.1.0.20240203.tar.gz", hash = "sha256:c93751ee20dfc6e054a0148f8f5227b9a00b79c90a4d3c9f464711a73179c89e"}, + {file = "types_pytz-2024.1.0.20240203-py3-none-any.whl", hash = "sha256:9679eef0365db3af91ef7722c199dbb75ee5c1b67e3c4dd7bfbeb1b8a71c21a3"}, ] [[package]] name = "types-requests" -version = "2.31.0.10" +version = "2.31.0.20240406" description = "Typing stubs for requests" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "types-requests-2.31.0.10.tar.gz", hash = "sha256:dc5852a76f1eaf60eafa81a2e50aefa3d1f015c34cf0cba130930866b1b22a92"}, - {file = "types_requests-2.31.0.10-py3-none-any.whl", hash = "sha256:b32b9a86beffa876c0c3ac99a4cd3b8b51e973fb8e3bd4e0a6bb32c7efad80fc"}, + {file = "types-requests-2.31.0.20240406.tar.gz", hash = "sha256:4428df33c5503945c74b3f42e82b181e86ec7b724620419a2966e2de604ce1a1"}, + {file = "types_requests-2.31.0.20240406-py3-none-any.whl", hash = "sha256:6216cdac377c6b9a040ac1c0404f7284bd13199c0e1bb235f4324627e8898cf5"}, ] [package.dependencies] @@ -1987,26 +1916,26 @@ types-pytz = "*" [[package]] name = "typing-extensions" -version = "4.8.0" +version = "4.11.0" description = "Backported and Experimental Type Hints for Python 3.8+" category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, ] [[package]] name = "tzdata" -version = "2023.3" +version = "2024.1" description = "Provider of IANA time zone data" category = "main" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, - {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] [[package]] @@ -2029,18 +1958,19 @@ devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3) [[package]] name = "urllib3" -version = "2.1.0" +version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, - {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -2126,63 +2056,14 @@ files = [ [[package]] name = "zeroconf" -version = "0.128.0" +version = "0.132.0" description = "A pure python implementation of multicast DNS service discovery" category = "main" optional = false -python-versions = ">=3.7,<4.0" +python-versions = "<4.0,>=3.8" files = [ - {file = "zeroconf-0.128.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:95b4a196126162938b132a6baa46b8e0d7198252aab2e04744b3782ccc35be05"}, - {file = "zeroconf-0.128.0-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:23c40f972019643665a16f96d2874e649593efac633542b39cd705d23fc52508"}, - {file = "zeroconf-0.128.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b37b8bcc0510a16f1e045422cf7f062e9d6a2f599777614e11f157f11f85879"}, - {file = "zeroconf-0.128.0-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:10bcbc0789581a9dd7a60aa8f2e6c7ce6d8c574c004bbabd1b8a87f80cdc89ee"}, - {file = "zeroconf-0.128.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:81db09373f2283b9ed23a8de569ecbc6735822f317e4fa77793b7b368e8443b6"}, - {file = "zeroconf-0.128.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a044f04dfc01655f85934db860649295a7958808fed8641ef2e2af8d0546c1a4"}, - {file = "zeroconf-0.128.0-cp310-cp310-win32.whl", hash = "sha256:a9fe274dda792d89ee644fe18e050f92bff2634717c85dec775707896f0f9856"}, - {file = "zeroconf-0.128.0-cp310-cp310-win_amd64.whl", hash = "sha256:b69e4b12332f60feea49a14e3aa7b92a31d21d52de6ebe67de4fa1f183705029"}, - {file = "zeroconf-0.128.0-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:9035d647039cdf679e664d5ddb0277e3219131e22e29643b79d5f16324e99261"}, - {file = "zeroconf-0.128.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9084e621ea4dffe551f46dfcfc41f2e8854b4642e59aebae383ce0f4c7185254"}, - {file = "zeroconf-0.128.0-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:7340863fd214d025f5a27eb0d6fef7310aca42f7f031922ba21086fea5872e3a"}, - {file = "zeroconf-0.128.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e8cda1be369c587a25d6a8f5db5d0e1ae3d163c9ff1236719e1def0bd52c0e4"}, - {file = "zeroconf-0.128.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3d5dc5f2d1613466c61627bb137613009452cf3be864b1344c1af9c1c0e39bb5"}, - {file = "zeroconf-0.128.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7906a820d54a18a8ee77940eea56e365bd770fc8c4f83d740f7f0c6087ec3c3e"}, - {file = "zeroconf-0.128.0-cp311-cp311-win32.whl", hash = "sha256:002cdec84b3a4c55dc877af0c7b99e0d8bdb3c92d9f294dd48b1f4b4eab2c893"}, - {file = "zeroconf-0.128.0-cp311-cp311-win_amd64.whl", hash = "sha256:367f0d1e8ad789c39c385f153b1ff0c924fbdf9983eb65579be67e74585b6b0b"}, - {file = "zeroconf-0.128.0-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:600d84ee75ad7a5e41b69f8f650af6d8551cb0ee9d67708aff0bee1ece8f3686"}, - {file = "zeroconf-0.128.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77b5cc3466c9bf09b88b123b68c3ca0fbc1af78dcbb001c2d684bf7440fdc1cb"}, - {file = "zeroconf-0.128.0-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:7d1b42e2067b9d1323a9626de5f31087ba3d7bcb8770cf82b65bf448fc1ff87a"}, - {file = "zeroconf-0.128.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96edbde95d81de2c618479338b34791abf4fa1e4bcf48fc669b05afa181fd3ea"}, - {file = "zeroconf-0.128.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9bb825df621fb70a82d59807e046876f85770457feb17e76118e91a4ceb58868"}, - {file = "zeroconf-0.128.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:774f6f4c4cdf87c7a09a55dbad8c7755a737e84ca8a0e1c2ef360c9ed6b49333"}, - {file = "zeroconf-0.128.0-cp312-cp312-win32.whl", hash = "sha256:4d891fc5fc2f8739934c3afb6ed667dda639daf76051e56d5b8d843bcb0e43e3"}, - {file = "zeroconf-0.128.0-cp312-cp312-win_amd64.whl", hash = "sha256:0f62e7842e874aa8dd2c3fd35319594a6a2e02e470c79be67eac6b85760cfa57"}, - {file = "zeroconf-0.128.0-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:eb500b4eb00b694214a68c229c6845cc66b7ab50e43648ee15d649775107bd5c"}, - {file = "zeroconf-0.128.0-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:548ad39fe7f30b2181dde26aff4dc1711226dd72719496c71c73f9f26e92ce0e"}, - {file = "zeroconf-0.128.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba341df450470895a69403d64636ceb309cf5c56f525d62e396818e3c71a78a0"}, - {file = "zeroconf-0.128.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:173a66bf776407cf5eb2d17a3d1fd1343ce078e5126019383d230be0769be0d8"}, - {file = "zeroconf-0.128.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fb33cf2ce028c94146876453044672f12f5f834fb1a76b9aaca46e316c3fdc81"}, - {file = "zeroconf-0.128.0-cp38-cp38-win32.whl", hash = "sha256:58853c89c8f533d53ba02fc94fa30b249da46ae19a557a987cd36d89095ffbc2"}, - {file = "zeroconf-0.128.0-cp38-cp38-win_amd64.whl", hash = "sha256:5966882787be03cb51442b8a8725a6c11c3b0e406aff75fb68c5307c504d1958"}, - {file = "zeroconf-0.128.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:03dcb14a1b377bcb9da90866c4d72291101b4dc8ea15ecdde7d448b298bb41aa"}, - {file = "zeroconf-0.128.0-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:156001fb366170d99cc735093b0eaba6b1cc113df5388b1016acb1630a7ef2ff"}, - {file = "zeroconf-0.128.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5f09fa3a56393932f67ee12416cad3c70297bd1a66b70024fb9a7f63d97a215"}, - {file = "zeroconf-0.128.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6c5f4fbb5ba36f40d0968b3c7ec7ec13bbbb3bb09217bb70682cf48322803d57"}, - {file = "zeroconf-0.128.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1854ea933b3821172a371868f34cf94f9033f9f52e8523e08aa140bce00633f4"}, - {file = "zeroconf-0.128.0-cp39-cp39-win32.whl", hash = "sha256:eae387ff5ba80b66678653b00598b613859c7c4fc4ee8a38b1cc7a83cc1c7b91"}, - {file = "zeroconf-0.128.0-cp39-cp39-win_amd64.whl", hash = "sha256:a8a99fea808f3f3a67ec516386408603e9b95b700794bfeabfdaff3d52227e67"}, - {file = "zeroconf-0.128.0-pp310-pypy310_pp73-macosx_11_0_x86_64.whl", hash = "sha256:eca9d64becb1ecb5ae9af58243aa03b813b64c750fe9eba18b6fa641cb685eb7"}, - {file = "zeroconf-0.128.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:20eb9d0948a4cf92ff33cbfb2b6883cc995b449b4ef4c97cd2697b366ed62abc"}, - {file = "zeroconf-0.128.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2839f7374bbf3e07db19be51d6f64ab222071d70c4e20541d179550f6fde6e79"}, - {file = "zeroconf-0.128.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2713afa28747a4e58a6995b1df24cba1215ed03ce77cd5efbca39262fff4d593"}, - {file = "zeroconf-0.128.0-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:836ef8149f135d4c17d1745cd3774d531984063e173dfc77a12ef1e3ed509b3f"}, - {file = "zeroconf-0.128.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:4b3f35deac8fc38ec9a4413fdf6d0fce8872e6320d0580120233661e7988e3b6"}, - {file = "zeroconf-0.128.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96be7af467fddd964794733ba2442608ce381bd4574f46b72e603b0834765cd7"}, - {file = "zeroconf-0.128.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:24d8f54e37e49691d834a20641a82adcbc2f601d1eca1bc86eb9f045f12aa379"}, - {file = "zeroconf-0.128.0-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:5f4a70c129858c956fa28310aafa12776ebb093dea9c7d09b9d759aea02087e7"}, - {file = "zeroconf-0.128.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:9b76bbbba4b1ba2d28aa0813e260b6bf7e9374a584902c75e60dac6a449a2926"}, - {file = "zeroconf-0.128.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0efddd1518e394cb97660eb63b97675761a83013701d528eb31b9175c535c7ee"}, - {file = "zeroconf-0.128.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c37f5f9379527d06b7e165792b916b122f8192bd9d91e8e9ab52344f3722c4e2"}, - {file = "zeroconf-0.128.0.tar.gz", hash = "sha256:f27877647f2afdf02f365d38d912bef0966783fb25fe0fba287f025969cf7349"}, + {file = "zeroconf-0.132.0-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:fb0a91b58b10d3a31b8324b2a8548e59c547a5c37055344c12d929f86c063d4e"}, + {file = "zeroconf-0.132.0.tar.gz", hash = "sha256:e2dddb9b8e6a9de3c43f943d8547300e6bd49b2043fd719ae830cfe0f2908a5c"}, ] [package.dependencies] @@ -2191,19 +2072,19 @@ ifaddr = ">=0.1.7" [[package]] name = "zipp" -version = "3.17.0" +version = "3.18.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, + {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [extras] gui = ["opencv-python", "Pillow"] @@ -2211,4 +2092,4 @@ gui = ["opencv-python", "Pillow"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "ee2cd93dd3871ec789b46a5fed7f46ccc66a127c69953cf70cb87bdbc1c9b562" +content-hash = "f2e9d2dd78a4da02ab1f6e1f1f0c487756c9cf1332e08c0a33ae2e3ea58966cf" diff --git a/demos/python/sdk_wireless_camera_control/pyproject.toml b/demos/python/sdk_wireless_camera_control/pyproject.toml index 362c7731..9790f02c 100644 --- a/demos/python/sdk_wireless_camera_control/pyproject.toml +++ b/demos/python/sdk_wireless_camera_control/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "open_gopro" -version = "0.15.1" +version = "0.16.0" description = "Open GoPro API and Examples" authors = ["Tim Camise "] readme = "README.md" @@ -71,7 +71,6 @@ types-requests = "*" types-attrs = "*" types-pytz = "*" types-tzlocal = "*" -mypy-protobuf = "*" construct-typing = "*" sphinx = "^5" sphinx-rtd-theme = "^1" @@ -82,69 +81,69 @@ poethepoet = "^0" autodoc-pydantic = "^2" pytest-timeout = "^2" isort = "*" -protoletariat = "^3" +types-protobuf = "^4" [tool.poe.tasks.tests] cmd = "pytest tests --cov-fail-under=70" help = "Run unit tests" -[tool.poe.tasks.types] +[tool.poe.tasks._types] cmd = "mypy open_gopro" help = "Check types" -[tool.poe.tasks.lint] +[tool.poe.tasks._pylint] cmd = "pylint open_gopro" help = "Run pylint" -[tool.poe.tasks.format_code] +[tool.poe.tasks._format_code] cmd = "black open_gopro tests noxfile.py docs/conf.py" help = "Apply black formatting to source code" -[tool.poe.tasks.sort_imports] +[tool.poe.tasks._sort_imports] cmd = "isort open_gopro tests" help = "Sort imports with isort" [tool.poe.tasks.format] -sequence = ["format_code", "sort_imports"] +sequence = ["_format_code", "_sort_imports"] help = "Format code and sort imports" -[tool.poe.tasks.pydocstyle] +[tool.poe.tasks.lint] +sequence = ["format", "_types", "_pylint"] +help = "Perform all static code analysis" + +[tool.poe.tasks._pydocstyle] cmd = "pydocstyle --config pyproject.toml -v open_gopro" help = "check docstrings style" -[tool.poe.tasks.darglint] +[tool.poe.tasks._darglint] cmd = "darglint -v 2 open_gopro" help = "validate docstrings" [tool.poe.tasks.docstrings] -sequence = ["pydocstyle", "darglint"] +sequence = ["_pydocstyle", "_darglint"] help = "Format, check types, lint, check docstrings, and run unit tests" [tool.poe.tasks.sphinx] cmd = "sphinx-build -W --keep-going -a -E -b html docs docs/build" help = "Build sphinx documentation." -[tool.poe.tasks.coverage] +[tool.poe.tasks._coverage] cmd = "coverage-badge -f -o docs/_static/coverage.svg" help = "update coverage badge" -[tool.poe.tasks.protobuf] -cmd = "bash ./tools/build_protos.sh" -help = "generate protobuf source from .proto (assumes protoc >= 3.20.1 available)" - -[tool.poe.tasks.clean_artifacts] +[tool.poe.tasks._clean_artifacts] cmd = "rm -rf **/__pycache__ *.csv *.mp4 *.jpg *.log .mypy_cache .nox" help = "Clean testing artifacts and pycache" -[tool.poe.tasks.clean_tests] +[tool.poe.tasks._clean_tests] cmd = "rm -rf .reports && rm -rf .pytest_cache" help = "Clean test reports" -[tool.poe.tasks.clean_docs] +[tool.poe.tasks._clean_docs] cmd = "rm -f docs/modules.rst && rm -rf docs/build" help = "Clean built docs output" -[tool.poe.tasks.clean_build] +[tool.poe.tasks._clean_build] cmd = "rm -rf dist" help = "Clean module build output" @@ -153,11 +152,11 @@ sequence = ["docstrings", "sphinx"] help = "Validate docstrings and build docs" [tool.poe.tasks.clean] -sequence = ["clean_artifacts", "clean_tests", "clean_docs", "clean_build"] +sequence = ["_clean_artifacts", "_clean_tests", "_clean_docs", "_clean_build"] help = "Clean everything" [tool.poe.tasks.all] -sequence = ["format", "types", "lint", "tests", "docs"] +sequence = ["format", "lint", "tests", "docs"] help = "Format, check types, lint, check docstrings, and run unit tests" [tool.mypy] @@ -217,6 +216,7 @@ ignore = ["tests", "proto"] [tool.pylint.'MESSAGES CONTROL'] disable = [ + "use-maxsplit-arg", "unnecessary-lambda", "unnecessary-lambda-assignment", "too-many-ancestors", diff --git a/demos/python/sdk_wireless_camera_control/tests/conftest.py b/demos/python/sdk_wireless_camera_control/tests/conftest.py index 10738c98..36105af0 100644 --- a/demos/python/sdk_wireless_camera_control/tests/conftest.py +++ b/demos/python/sdk_wireless_camera_control/tests/conftest.py @@ -6,7 +6,7 @@ import asyncio import logging import re -from dataclasses import dataclass +from dataclasses import dataclass, field from pathlib import Path from typing import Any, Generic, Optional, Pattern @@ -37,8 +37,14 @@ ) from open_gopro.ble.adapters.bleak_wrapper import BleakWrapperController from open_gopro.ble.services import CharProps -from open_gopro.communicator_interface import GoProBle, GoProWifi -from open_gopro.constants import CmdId, ErrorCode, GoProUUIDs, StatusId +from open_gopro.communicator_interface import ( + BleMessage, + GoProBle, + GoProWifi, + HttpMessage, + MessageRules, +) +from open_gopro.constants import CmdId, GoProUUIDs, StatusId from open_gopro.exceptions import ConnectFailed, FailedToFindDevice from open_gopro.gopro_base import GoProBase from open_gopro.logger import set_logging_level, setup_logging @@ -193,7 +199,7 @@ def disconnection_handler(_) -> None: print("Entered test disconnect callback") -def notification_handler(handle: int, data: bytearray) -> None: +async def notification_handler(handle: int, data: bytearray) -> None: print("Entered test notification callback") @@ -222,12 +228,14 @@ def unregister_update(self, callback: types.UpdateCb, update: types.UpdateType = return async def _send_ble_message( - self, uuid: BleUUID, data: bytearray, response_id: types.ResponseType, **kwargs - ) -> dict: - return dict(uuid=uuid, packet=data) + self, message: BleMessage, rules: MessageRules = MessageRules(), **kwargs: Any + ) -> GoProResp: + return dict(uuid=message._uuid, packet=message._build_data(**kwargs)) - async def _read_characteristic(self, uuid: BleUUID) -> dict: - return dict(uuid=uuid) + async def _read_ble_characteristic( + self, message: BleMessage, rules: MessageRules = MessageRules(), **kwargs: Any + ) -> GoProResp: + return dict(uuid=message._uuid) @property def ble_command(self) -> BleCommands: @@ -287,6 +295,7 @@ async def mock_wifi_client(): @dataclass class MockWifiResponse: url: str + body: dict[str, Any] = field(default_factory=dict) class MockWifiCommunicator(GoProWifi): @@ -296,8 +305,20 @@ def __init__(self, test_version: str): super().__init__(MockWifiController()) self._api = api_versions[test_version](self) - async def _http_get(self, url: str, _=None, **kwargs): - return MockWifiResponse(url) + async def _get_json( + self, message: HttpMessage, *, timeout: int = 0, rules: MessageRules = MessageRules(), **kwargs + ) -> GoProResp: + return MockWifiResponse(message.build_url(**kwargs), message.build_body(**kwargs)) + + async def _get_stream( + self, message: HttpMessage, *, timeout: int = 0, rules: MessageRules = MessageRules(), **kwargs + ) -> GoProResp: + return MockWifiResponse(message.build_url(path=kwargs["camera_file"])), kwargs["local_file"] + + async def _put_json( + self, message: HttpMessage, *, timeout: int = 0, rules: MessageRules = MessageRules(), **kwargs + ) -> GoProResp: + return MockWifiResponse(message.build_url(**kwargs), message.build_body(**kwargs)) async def _stream_to_file(self, url: str, file: Path): return url, file @@ -391,23 +412,22 @@ async def _open_ble(self, timeout: int, retries: int) -> None: self._ble._gatt_table.handle2uuid = self._mock_uuid async def _send_ble_message( - self, - uuid: BleUUID, - data: bytearray, - response_id: types.ResponseType, - response_data: list[bytearray] = None, - response_uuid: BleUUID = None, - **kwargs + self, message: BleMessage, rules: MessageRules = MessageRules(), **kwargs: Any ) -> GoProResp: - if response_uuid is None: - return mock_good_response - else: + if response_data := kwargs.get("response_data"): self._test_response_data = response_data - self._test_response_uuid = response_uuid + self._test_response_uuid = message._uuid global _test_response_id - _test_response_id = response_id + _test_response_id = message._identifier self._ble.write = self._mock_write - return await super()._send_ble_message(uuid, data, response_id) + return await super()._send_ble_message(message, **kwargs) + else: + return mock_good_response + + async def _read_ble_characteristic( + self, message: BleMessage, rules: MessageRules = MessageRules(), **kwargs: Any + ) -> GoProResp: + raise NotImplementedError async def _mock_version(self) -> DataPatch: return DataPatch("2.0") @@ -423,8 +443,9 @@ def _mock_uuid(self, _) -> BleUUID: async def _mock_write(self, uuid: str, data: bytearray) -> None: assert self._test_response_data is not None - for packet in self._test_response_data: - self._notification_handler(0, packet) + self._notification_handler(0, self._test_response_data) + # for packet in self._test_response_data: + # self._notification_handler(0, packet) @property def is_ble_connected(self) -> bool: @@ -441,7 +462,6 @@ def close(self) -> None: _test_response_id = CmdId.SET_SHUTTER -# TODO use mocking library instead of doing this manually? @pytest.fixture(params=versions) async def mock_wireless_gopro_basic(request): test_client = MockWirelessGoPro(request.param) diff --git a/demos/python/sdk_wireless_camera_control/tests/test_ble_commands.py b/demos/python/sdk_wireless_camera_control/tests/test_ble_commands.py index b1e946ad..285a8293 100644 --- a/demos/python/sdk_wireless_camera_control/tests/test_ble_commands.py +++ b/demos/python/sdk_wireless_camera_control/tests/test_ble_commands.py @@ -1,32 +1,25 @@ # test_ble_commands.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). # This copyright was auto-generated on Wed, Sep 1, 2021 5:05:54 PM -import inspect -import logging -from typing import cast import pytest from construct import Int32ub -from open_gopro import Params, proto -from open_gopro.communicator_interface import GoProBle -from open_gopro.constants import CmdId, GoProUUIDs, QueryCmdId, SettingId, StatusId +from open_gopro import Params +from open_gopro.constants import GoProUUIDs, SettingId from open_gopro.gopro_base import GoProBase -from tests.conftest import MockBleCommunicator @pytest.mark.asyncio async def test_write_command_correct_uuid_cmd_id(mock_ble_communicator: GoProBase): response = await mock_ble_communicator.ble_command.set_shutter(shutter=Params.Toggle.ENABLE) - response = cast(dict, response) assert response["uuid"] == GoProUUIDs.CQ_COMMAND - assert response["packet"][0] == CmdId.SET_SHUTTER.value + assert response["packet"] == bytearray([1, 1, 1]) @pytest.mark.asyncio async def test_write_command_correct_parameter_data(mock_ble_communicator: GoProBase): response = await mock_ble_communicator.ble_command.load_preset(preset=5) - response = cast(dict, response) assert response["uuid"] == GoProUUIDs.CQ_COMMAND assert Int32ub.parse(response["packet"][-4:]) == 5 @@ -34,5 +27,17 @@ async def test_write_command_correct_parameter_data(mock_ble_communicator: GoPro @pytest.mark.asyncio async def test_read_command_correct_uuid(mock_ble_communicator: GoProBase): response = await mock_ble_communicator.ble_command.get_wifi_ssid() - response = cast(dict, response) assert response["uuid"] == GoProUUIDs.WAP_SSID + + +@pytest.mark.asyncio +async def test_ble_setting(mock_ble_communicator: GoProBase): + response = await mock_ble_communicator.ble_setting.led.set(Params.LED.BLE_KEEP_ALIVE) + assert response["uuid"] == GoProUUIDs.CQ_SETTINGS + assert response["packet"] == bytearray([SettingId.LED, 1, Params.LED.BLE_KEEP_ALIVE]) + + +@pytest.mark.asyncio +async def test_fastpass_shutter(mock_ble_communicator: GoProBase): + response = await mock_ble_communicator.ble_command.set_shutter(shutter=Params.Toggle.ENABLE) + assert response["uuid"] == GoProUUIDs.CQ_COMMAND diff --git a/demos/python/sdk_wireless_camera_control/tests/test_http_commands.py b/demos/python/sdk_wireless_camera_control/tests/test_http_commands.py index 6f10c44f..c712313d 100644 --- a/demos/python/sdk_wireless_camera_control/tests/test_http_commands.py +++ b/demos/python/sdk_wireless_camera_control/tests/test_http_commands.py @@ -7,12 +7,27 @@ import pytest -from open_gopro import Params +from open_gopro import Params, proto from open_gopro.gopro_base import GoProBase camera_file = "100GOPRO/XXX.mp4" +@pytest.mark.asyncio +async def test_put_with_body_args(mock_wifi_communicator: GoProBase): + response = await mock_wifi_communicator.http_command.update_custom_preset( + custom_name="Custom Name", + icon_id=proto.EnumPresetIcon.PRESET_ICON_ACTION, + title_id=proto.EnumPresetTitle.PRESET_TITLE_ACTION, + ) + assert response.url == "gopro/camera/presets/update_custom" + assert response.body == { + "custom_name": "Custom Name", + "icon_id": proto.EnumPresetIcon.PRESET_ICON_ACTION, + "title_id": proto.EnumPresetTitle.PRESET_TITLE_ACTION, + } + + @pytest.mark.asyncio async def test_get_with_no_params(mock_wifi_communicator: GoProBase): response = await mock_wifi_communicator.http_command.get_media_list() @@ -34,16 +49,18 @@ async def test_get_with_params(mock_wifi_communicator: GoProBase): @pytest.mark.asyncio async def test_get_binary(mock_wifi_communicator: GoProBase): - url, file = await mock_wifi_communicator.http_command.get_gpmf_data(camera_file=camera_file) - assert url == f"gopro/media/gpmf?path={camera_file}" + response, file = await mock_wifi_communicator.http_command.get_gpmf_data(camera_file=camera_file) + assert response.url == f"gopro/media/gpmf?path={camera_file}" assert file == Path("XXX.mp4") @pytest.mark.asyncio async def test_get_binary_with_component(mock_wifi_communicator: GoProBase): - url, file = await mock_wifi_communicator.http_command.download_file(camera_file=camera_file) - assert url == f"videos/DCIM/{camera_file}" - assert file == Path("XXX.mp4") + response, file = await mock_wifi_communicator.http_command.download_file( + camera_file=camera_file, local_file=Path("cheese.mp4") + ) + assert response.url == f"videos/DCIM/{camera_file}" + assert file == Path("cheese.mp4") @pytest.mark.asyncio diff --git a/demos/python/sdk_wireless_camera_control/tests/test_logging.py b/demos/python/sdk_wireless_camera_control/tests/test_logging.py new file mode 100644 index 00000000..880ba861 --- /dev/null +++ b/demos/python/sdk_wireless_camera_control/tests/test_logging.py @@ -0,0 +1,248 @@ +# test_logging.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +from typing import Generic, TypeVar + +import construct +import pytest + +from open_gopro import GoProResp +from open_gopro.api.builders import ( + BleProtoCommand, + BleReadCommand, + BleSettingFacade, + BleStatusFacade, + BleWriteCommand, + HttpSetting, +) +from open_gopro.communicator_interface import HttpMessage, Message +from open_gopro.constants import ( + ActionId, + CmdId, + ErrorCode, + FeatureId, + GoProUUIDs, + QueryCmdId, + SettingId, + StatusId, +) + +dummy_kwargs = {"first": 1, "second": 2} + + +def assert_kwargs(message: dict): + assert message.pop("first") == 1 + assert message.pop("second") == 2 + + +@pytest.mark.asyncio +async def test_ble_read_command(): + message = BleReadCommand(uuid=GoProUUIDs.ACC_APPEARANCE, parser=None) + d = message._as_dict(**dummy_kwargs) + assert d.pop("id") == GoProUUIDs.ACC_APPEARANCE + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.ACC_APPEARANCE + assert_kwargs(d) + assert not d + + +@pytest.mark.asyncio +async def test_ble_write_command(): + message = BleWriteCommand(uuid=GoProUUIDs.ACC_APPEARANCE, cmd=CmdId.GET_CAMERA_CAPABILITIES) + d = message._as_dict(**dummy_kwargs) + assert d.pop("id") == CmdId.GET_CAMERA_CAPABILITIES + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.ACC_APPEARANCE + assert_kwargs(d) + assert not d + + +@pytest.mark.asyncio +async def test_ble_proto_command(): + message = BleProtoCommand( + uuid=GoProUUIDs.ACC_APPEARANCE, + feature_id=FeatureId.COMMAND, + action_id=ActionId.GET_AP_ENTRIES, + response_action_id=ActionId.GET_AP_ENTRIES_RSP, + request_proto=None, + response_proto=None, + parser=None, + ) + d = message._as_dict(**dummy_kwargs) + assert d.pop("id") == ActionId.GET_AP_ENTRIES + assert d.pop("feature_id") == FeatureId.COMMAND + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.ACC_APPEARANCE + assert_kwargs(d) + assert not d + + +T = TypeVar("T", bound=Message) + + +class MockCommunicator(Generic[T]): + def __init__(self) -> None: + self.message: T + + async def _send_ble_message(self, message: T) -> GoProResp: + self.message = message + return GoProResp( + protocol=GoProResp.Protocol.BLE, status=ErrorCode.SUCCESS, data=bytes(), identifier=message._identifier + ) + + async def _get_json(self, message, **kwargs) -> GoProResp: + self.message = message + return GoProResp(protocol=GoProResp.Protocol.BLE, status=ErrorCode.SUCCESS, data=bytes(), identifier="unknown") + + def register_update(self, *args, **kwargs): + ... + + def unregister_update(self, *args, **kwargs): + ... + + +@pytest.mark.asyncio +async def test_ble_setting(): + class Communicator(MockCommunicator[BleSettingFacade.BleSettingMessageBase]): + ... + + communicator = Communicator() + message = BleSettingFacade( + communicator=communicator, identifier=SettingId.ADDON_MAX_LENS_MOD, parser_builder=construct.Flag + ) + + # Set Setting Value + await message.set(bytes()) + d = communicator.message._as_dict(**dummy_kwargs) + assert d.pop("id") == SettingId.ADDON_MAX_LENS_MOD + assert d.pop("setting_id") == SettingId.ADDON_MAX_LENS_MOD + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.CQ_SETTINGS + assert_kwargs(d) + assert not d + + # Get Setting Value + await message.get_value() + d = communicator.message._as_dict(**dummy_kwargs) + assert d.pop("id") == QueryCmdId.GET_SETTING_VAL + assert d.pop("setting_id") == SettingId.ADDON_MAX_LENS_MOD + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.CQ_QUERY + assert_kwargs(d) + assert not d + + # Get Setting Capabilities Values + await message.get_capabilities_values() + d = communicator.message._as_dict(**dummy_kwargs) + assert d.pop("id") == QueryCmdId.GET_CAPABILITIES_VAL + assert d.pop("setting_id") == SettingId.ADDON_MAX_LENS_MOD + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.CQ_QUERY + assert_kwargs(d) + assert not d + + # Register value updates + await message.register_value_update(None) + d = communicator.message._as_dict(**dummy_kwargs) + assert d.pop("id") == QueryCmdId.REG_SETTING_VAL_UPDATE + assert d.pop("setting_id") == SettingId.ADDON_MAX_LENS_MOD + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.CQ_QUERY + assert_kwargs(d) + assert not d + + # Unregister value updates + await message.unregister_value_update(None) + d = communicator.message._as_dict(**dummy_kwargs) + assert d.pop("id") == QueryCmdId.UNREG_SETTING_VAL_UPDATE + assert d.pop("setting_id") == SettingId.ADDON_MAX_LENS_MOD + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.CQ_QUERY + assert_kwargs(d) + assert not d + + # Register capability updates + await message.register_capability_update(None) + d = communicator.message._as_dict(**dummy_kwargs) + assert d.pop("id") == QueryCmdId.REG_CAPABILITIES_UPDATE + assert d.pop("setting_id") == SettingId.ADDON_MAX_LENS_MOD + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.CQ_QUERY + assert_kwargs(d) + assert not d + + # Unregister capability updates + await message.unregister_capability_update(None) + d = communicator.message._as_dict(**dummy_kwargs) + assert d.pop("id") == QueryCmdId.UNREG_CAPABILITIES_UPDATE + assert d.pop("setting_id") == SettingId.ADDON_MAX_LENS_MOD + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.CQ_QUERY + assert_kwargs(d) + assert not d + + +@pytest.mark.asyncio +async def test_ble_status(): + class Communicator(MockCommunicator[BleStatusFacade.BleStatusMessageBase]): + ... + + communicator = Communicator() + message = BleStatusFacade(communicator=communicator, identifier=StatusId.ACC_MIC_STAT, parser=construct.Flag) + + # Get Status Value + await message.get_value() + d = communicator.message._as_dict(**dummy_kwargs) + assert d.pop("id") == QueryCmdId.GET_STATUS_VAL + assert d.pop("status_id") == StatusId.ACC_MIC_STAT + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.CQ_QUERY + assert_kwargs(d) + assert not d + + # Register value updates + await message.register_value_update(None) + d = communicator.message._as_dict(**dummy_kwargs) + assert d.pop("id") == QueryCmdId.REG_STATUS_VAL_UPDATE + assert d.pop("status_id") == StatusId.ACC_MIC_STAT + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.CQ_QUERY + assert_kwargs(d) + assert not d + + # Unregister value updates + await message.unregister_value_update(None) + d = communicator.message._as_dict(**dummy_kwargs) + assert d.pop("id") == QueryCmdId.UNREG_STATUS_VAL_UPDATE + assert d.pop("status_id") == StatusId.ACC_MIC_STAT + assert d.pop("protocol") == GoProResp.Protocol.BLE + assert d.pop("uuid") == GoProUUIDs.CQ_QUERY + assert_kwargs(d) + assert not d + + +@pytest.mark.asyncio +async def test_http_command(): + message = HttpMessage("endpoint", identifier=None) + d = message._as_dict(**dummy_kwargs) + assert d.pop("id") == "Endpoint" + assert d.pop("protocol") == GoProResp.Protocol.HTTP + assert d.pop("endpoint") == "endpoint" + assert_kwargs(d) + assert not d + + +@pytest.mark.asyncio +async def test_http_setting(): + class Communicator(MockCommunicator[HttpMessage]): + ... + + communicator = Communicator() + message = HttpSetting(communicator=communicator, identifier=SettingId.ADDON_MAX_LENS_MOD) + await message.set(1) + d = communicator.message._as_dict(**dummy_kwargs) + assert d.pop("id") == SettingId.ADDON_MAX_LENS_MOD + assert d.pop("protocol") == GoProResp.Protocol.HTTP + assert d.pop("endpoint") == r"gopro/camera/setting?setting={setting}&option={option}" + assert_kwargs(d) + assert not d diff --git a/demos/python/sdk_wireless_camera_control/tests/test_parsers.py b/demos/python/sdk_wireless_camera_control/tests/test_parsers.py index 188c92f5..9d144e59 100644 --- a/demos/python/sdk_wireless_camera_control/tests/test_parsers.py +++ b/demos/python/sdk_wireless_camera_control/tests/test_parsers.py @@ -1,13 +1,11 @@ # test_parsers.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). # This copyright was auto-generated on Mon Jul 31 17:04:06 UTC 2023 -from typing import cast - from open_gopro.api.ble_commands import BleCommands from open_gopro.api.parsers import ByteParserBuilders from open_gopro.communicator_interface import GoProBle from open_gopro.constants import CmdId -from open_gopro.models.response import GlobalParsers +from open_gopro.models.response import BleRespBuilder, GlobalParsers from open_gopro.parser_interface import Parser from open_gopro.proto import EnumResultGeneric, ResponseGetApEntries diff --git a/demos/python/sdk_wireless_camera_control/tests/test_wireless_gopro.py b/demos/python/sdk_wireless_camera_control/tests/test_wireless_gopro.py index b56269fc..81f303b8 100644 --- a/demos/python/sdk_wireless_camera_control/tests/test_wireless_gopro.py +++ b/demos/python/sdk_wireless_camera_control/tests/test_wireless_gopro.py @@ -13,6 +13,7 @@ import requests import requests_mock +from open_gopro.communicator_interface import HttpMessage from open_gopro.constants import SettingId, StatusId from open_gopro.exceptions import GoProNotOpened, ResponseTimeout from open_gopro.gopro_wireless import Params, WirelessGoPro, types @@ -67,58 +68,58 @@ async def test_gopro_open(mock_wireless_gopro_basic: WirelessGoPro): @pytest.mark.asyncio async def test_http_get(mock_wireless_gopro_basic: WirelessGoPro, monkeypatch): - endpoint = "gopro/camera/stream/start" + message = HttpMessage("gopro/camera/stream/start", None) session = requests.Session() adapter = requests_mock.Adapter() - session.mount(mock_wireless_gopro_basic._base_url + endpoint, adapter) - adapter.register_uri("GET", mock_wireless_gopro_basic._base_url + endpoint, json="{}") + session.mount(mock_wireless_gopro_basic._base_url + message._endpoint, adapter) + adapter.register_uri("GET", mock_wireless_gopro_basic._base_url + message._endpoint, json="{}") monkeypatch.setattr("open_gopro.gopro_base.requests.get", session.get) - response = await mock_wireless_gopro_basic._http_get(endpoint) + response = await mock_wireless_gopro_basic._get_json(message) assert response.ok @pytest.mark.asyncio async def test_http_file(mock_wireless_gopro_basic: WirelessGoPro, monkeypatch): + message = HttpMessage("videos/DCIM/100GOPRO/dummy.MP4", None) out_file = Path("test.mp4") - endpoint = "videos/DCIM/100GOPRO/dummy.MP4" session = requests.Session() adapter = requests_mock.Adapter() - session.mount(mock_wireless_gopro_basic._base_url + endpoint, adapter) - adapter.register_uri("GET", mock_wireless_gopro_basic._base_url + endpoint, text="BINARY DATA") + session.mount(mock_wireless_gopro_basic._base_url + message._endpoint, adapter) + adapter.register_uri("GET", mock_wireless_gopro_basic._base_url + message._endpoint, text="BINARY DATA") monkeypatch.setattr("open_gopro.gopro_base.requests.get", session.get) - await mock_wireless_gopro_basic._stream_to_file(endpoint, out_file) + await mock_wireless_gopro_basic._get_stream(message, camera_file=out_file, local_file=out_file) assert out_file.exists() @pytest.mark.asyncio async def test_http_response_timeout(mock_wireless_gopro_basic: WirelessGoPro, monkeypatch): with pytest.raises(ResponseTimeout): - endpoint = "gopro/camera/stream/start" + message = HttpMessage("gopro/camera/stream/start", None) session = requests.Session() adapter = requests_mock.Adapter() - session.mount(mock_wireless_gopro_basic._base_url + endpoint, adapter) + session.mount(mock_wireless_gopro_basic._base_url + message._endpoint, adapter) adapter.register_uri( - "GET", mock_wireless_gopro_basic._base_url + endpoint, exc=requests.exceptions.ConnectTimeout + "GET", mock_wireless_gopro_basic._base_url + message._endpoint, exc=requests.exceptions.ConnectTimeout ) monkeypatch.setattr("open_gopro.gopro_base.requests.get", session.get) - await mock_wireless_gopro_basic._http_get(endpoint, timeout=1) + await mock_wireless_gopro_basic._get_json(message, timeout=1) @pytest.mark.asyncio async def test_http_response_error(mock_wireless_gopro_basic: WirelessGoPro, monkeypatch): - endpoint = "gopro/camera/stream/start" + message = HttpMessage("gopro/camera/stream/start", None) session = requests.Session() adapter = requests_mock.Adapter() - session.mount(mock_wireless_gopro_basic._base_url + endpoint, adapter) + session.mount(mock_wireless_gopro_basic._base_url + message._endpoint, adapter) adapter.register_uri( "GET", - mock_wireless_gopro_basic._base_url + endpoint, + mock_wireless_gopro_basic._base_url + message._endpoint, status_code=403, reason="something bad happened", json="{}", ) monkeypatch.setattr("open_gopro.gopro_base.requests.get", session.get) - response = await mock_wireless_gopro_basic._http_get(endpoint) + response = await mock_wireless_gopro_basic._get_json(message) assert not response.ok diff --git a/demos/python/sdk_wireless_camera_control/tools/build_protos.sh b/demos/python/sdk_wireless_camera_control/tools/build_protos.sh deleted file mode 100755 index 8e20751d..00000000 --- a/demos/python/sdk_wireless_camera_control/tools/build_protos.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -# build_protos.sh/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Wed Jul 6 19:59:53 UTC 2022 - - -CWD=$(pwd) -PROTO_SRC_DIR=$CWD/../../../protobuf -PROTO_OUT_DIR=$CWD/open_gopro/proto - -# Clean all current protobuf files and stubs -rm -f $PROTO_OUT_DIR/*pb2.py* >/dev/null 2>&1 - -echo -echo "Building protobuf python files and stubs from .proto source files..." -pushd $PROTO_SRC_DIR -protoc --include_imports --descriptor_set_out=$CWD/descriptors --python_out=$PROTO_OUT_DIR --mypy_out=$PROTO_OUT_DIR * -popd - -echo -echo "Converting relative imports to absolute..." -poetry run protol -o ./open_gopro/proto/ --in-place raw descriptors -rm descriptors - -# Format generated files -echo -echo "Formatting..." -poetry run black open_gopro/proto diff --git a/demos/python/tutorial/.python-version b/demos/python/tutorial/.python-version index 0f57b2b6..1d44b9e0 100644 --- a/demos/python/tutorial/.python-version +++ b/demos/python/tutorial/.python-version @@ -1 +1 @@ -3.10.8 +3.11.4 diff --git a/demos/python/tutorial/README.md b/demos/python/tutorial/README.md index 0e450726..9ede5dcc 100644 --- a/demos/python/tutorial/README.md +++ b/demos/python/tutorial/README.md @@ -8,10 +8,10 @@ If you are a user of the tutorials, please visit the above link. Developer's of ## Development Environment Setup -With Python >= 3.8 and < 3.11, perform: +With Python >= 3.9 and < 3.12, perform: ``` -pip install -r requirements-dev.txt +poetry install ``` ## Tutorial Documentation @@ -29,7 +29,7 @@ shall be tested as detailed below. There should be no static typing or linting errors as checked via: ``` -make lint +poetry run poe lint ``` ## Testing @@ -39,7 +39,7 @@ Each script shall be tested via pytest by adding a case to the `tests/testtutori Tests can be run via: ``` -make tests +poetry run poe tests ``` -After running th tests, test logs and a summary test report can be found in the `reports` folder. \ No newline at end of file +After running the tests, test logs and a summary test report can be found in the `.reports` folder. \ No newline at end of file diff --git a/demos/python/tutorial/poetry.lock b/demos/python/tutorial/poetry.lock index 40545c9c..2a8bc8e0 100644 --- a/demos/python/tutorial/poetry.lock +++ b/demos/python/tutorial/poetry.lock @@ -15,7 +15,10 @@ files = [ [package.dependencies] lazy-object-proxy = ">=1.4.0" typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} -wrapt = {version = ">=1.11,<2", markers = "python_version < \"3.11\""} +wrapt = [ + {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, + {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, +] [[package]] name = "async-timeout" @@ -31,30 +34,34 @@ files = [ [[package]] name = "black" -version = "23.11.0" +version = "24.3.0" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "black-23.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911"}, - {file = "black-23.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f"}, - {file = "black-23.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394"}, - {file = "black-23.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f"}, - {file = "black-23.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479"}, - {file = "black-23.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244"}, - {file = "black-23.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221"}, - {file = "black-23.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5"}, - {file = "black-23.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187"}, - {file = "black-23.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6"}, - {file = "black-23.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b"}, - {file = "black-23.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142"}, - {file = "black-23.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055"}, - {file = "black-23.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4"}, - {file = "black-23.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06"}, - {file = "black-23.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07"}, - {file = "black-23.11.0-py3-none-any.whl", hash = "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e"}, - {file = "black-23.11.0.tar.gz", hash = "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05"}, + {file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"}, + {file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"}, + {file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"}, + {file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"}, + {file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"}, + {file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"}, + {file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"}, + {file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"}, + {file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"}, + {file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"}, + {file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"}, + {file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"}, + {file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"}, + {file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"}, + {file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"}, + {file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"}, + {file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"}, + {file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"}, + {file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"}, + {file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"}, + {file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"}, + {file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"}, ] [package.dependencies] @@ -68,7 +75,7 @@ typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] @@ -116,14 +123,14 @@ files = [ [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] [[package]] @@ -321,62 +328,63 @@ toml = ["tomli"] [[package]] name = "dbus-fast" -version = "2.20.0" +version = "2.21.1" description = "A faster version of dbus-next" category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "dbus_fast-2.20.0-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:ecf22e22434bdd61bfb8b544eb58f5032b23dda5a7fc233afa1d3c9c3241f0a8"}, - {file = "dbus_fast-2.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed70f4c1fe23c47a59d81c8fd8830c65307a1f089cc92949004df4c65c69f155"}, - {file = "dbus_fast-2.20.0-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:9963180456586d0e1b58075e0439a34ed8e9ee4266b35f76f3db6ffc1af17e27"}, - {file = "dbus_fast-2.20.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:eafbf4f0ac86fd959f86bbdf910bf64406b35315781014ef4a1cd2bb43985346"}, - {file = "dbus_fast-2.20.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bb668e2039e15f0e5af14bee7de8c8c082e3b292ed2ce2ceb3168c7068ff2856"}, - {file = "dbus_fast-2.20.0-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:3f7966f835da1d8a77c55a7336313bd97e7f722b316f760077c55c1e9533b0cd"}, - {file = "dbus_fast-2.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff856cbb1508bcf6735ed1e3c04de1def6c400720765141d2470e39c8fd6f13"}, - {file = "dbus_fast-2.20.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7a1da4ed9880046403ddedb7b941fd981872fc883dc9925bbf269b551f12120d"}, - {file = "dbus_fast-2.20.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9084ded47761a43b2252879c6ebaddb7e3cf89377cbdc981de7e8ba87c845239"}, - {file = "dbus_fast-2.20.0-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:d4b91b98cc1849f7d062d563d320594377b099ea9de53ebb789bf9fd6a0eeab4"}, - {file = "dbus_fast-2.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8ab58ef76575e6e00cf1c1f5747b24ce19e35d4966f1c5c3732cea2c3ed5e9"}, - {file = "dbus_fast-2.20.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1909addfad23d400d6f77c3665778a96003e32a1cddd1964de605d0ca400d829"}, - {file = "dbus_fast-2.20.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e591b218d4f327df29a89a922f199bbefb6f892ddc9b96aff21c05c15c0e5dc8"}, - {file = "dbus_fast-2.20.0-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:f55f75ac3891c161daeabdb37d8a3407098482fe54013342a340cdd58f2be091"}, - {file = "dbus_fast-2.20.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d317dba76e904f75146ce0c5f219dae44e8060767b3adf78c94557bbcbea2cbe"}, - {file = "dbus_fast-2.20.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:88126343024f280c1fadd6599ac4cd7046ed550ddc942811dc3d290830cffd51"}, - {file = "dbus_fast-2.20.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ecc07860e3014607a5293e1b87294148f96b1cc508f6496b27e40f64079ebb7a"}, - {file = "dbus_fast-2.20.0-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:e9cdf34f81320b36ce7f2b8c46169632730d9cdcafc52b55cada95096fce3457"}, - {file = "dbus_fast-2.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e40ad43412f92373e4c74bb76d2129a7f0c38a1d883adcfc08f168535f7e7846"}, - {file = "dbus_fast-2.20.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4a5fdebcd8f79d417693536d3ed08bb5842917d373fbc3e9685feecd001accd7"}, - {file = "dbus_fast-2.20.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b134d40688ca7f27ab38bec99194e2551c82fc01f583f44ae66129c3d15db8a7"}, - {file = "dbus_fast-2.20.0-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:fdd4ece2c856e44b5fe9dec354ce5d8930f7ae9bb4b96b3a195157621fea6322"}, - {file = "dbus_fast-2.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e609309d5503a5eab91a7b0cef9dd158c3d8786ac38643a962e99a69d5eb7a66"}, - {file = "dbus_fast-2.20.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8fd806bf4676a28b2323d8529d51f86fec5a9d32923d53ba522a4c2bc3d55857"}, - {file = "dbus_fast-2.20.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8526ff5b27b7c689d97fe8a29e97d3cb7298419b4cb63ed9029331d08d423c55"}, - {file = "dbus_fast-2.20.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:562868206d774080c4131b124a407350ffb5d2b89442048350b83b5084f4e0e1"}, - {file = "dbus_fast-2.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707fc61b4f2de83c8f574061fdaf0ac6fc28b402f451951cf0a1ead11bfcac71"}, - {file = "dbus_fast-2.20.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:4a13c7856459e849202165fd9e1adda8169107a591b083b95842c15b9e772be4"}, - {file = "dbus_fast-2.20.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca1aba69c1dd694399124efbc6ce15930e4697a95d527f16b614100f1f1055a2"}, - {file = "dbus_fast-2.20.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:9817bd32d7734766b073bb08525b9560b0b9501c68c43cc91d43684a2829ad86"}, - {file = "dbus_fast-2.20.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bed226cccedee0c94b292e27fd1c7d24987d36b5ac1cde021031f9c77a76a423"}, - {file = "dbus_fast-2.20.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c11a2b4addb965e09a2d8d666265455f4a7e48916b7c6f43629b828de6682425"}, - {file = "dbus_fast-2.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88367c2a849234f134b9c98fdb16dc84d5ba9703fe995c67f7306900bfa13896"}, - {file = "dbus_fast-2.20.0.tar.gz", hash = "sha256:a38e837c5a8d0a1745ec8390f68ff57986ed2167b0aa2e4a79738a51dd6dfcc3"}, + {file = "dbus_fast-2.21.1-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:b04b88be594dad81b33f6770283eed2125763632515c5112f8aa30f259cd334c"}, + {file = "dbus_fast-2.21.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7333896544a4d0a3d708bd092f8c05eb3599dc2b34ae6e4c4b44d04d5514b0ec"}, + {file = "dbus_fast-2.21.1-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:4591e0962c272d42d305ab3fb8889f13d47255e412fd3b9839620836662c91fe"}, + {file = "dbus_fast-2.21.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:52641305461660c8969c6bb12364206a108c5c9e014c9220c70b99c4f48b6750"}, + {file = "dbus_fast-2.21.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:237db4ab0b90e5284ea7659264630d693273cdbda323a40368f320869bf6470f"}, + {file = "dbus_fast-2.21.1-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:999fed45cb391126107b804be0e344e75556fceaee4cc30a0ca06d77309bdf3c"}, + {file = "dbus_fast-2.21.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2309b9cafba799e9d343fdfdd5ae46276adf3929fef60f296f23b97ed1aa2f6"}, + {file = "dbus_fast-2.21.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b7d1f35218549762e52a782c0b548e0681332beee773d3dfffe2efc38b2ee960"}, + {file = "dbus_fast-2.21.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47aa28520fe274414b655c74cbe2e91d8b76e22f40cd41a758bb6975e526827b"}, + {file = "dbus_fast-2.21.1-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:0ff6c72bcd6539d798015bda33c7ce35c7de76276b9bd45e48db13672713521a"}, + {file = "dbus_fast-2.21.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36d8cd43b3799e766158f1bb0b27cc4eef685fd892417b0382b7fdfdd94f1e6c"}, + {file = "dbus_fast-2.21.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d4da8d58064f0a3dd07bfc283ba912b9d5a4cb38f1c0fcd9ecb2b9d43111243c"}, + {file = "dbus_fast-2.21.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:66e160f496ac79248feb09a0acf4aab5d139d823330cbd9377f6e19ae007330a"}, + {file = "dbus_fast-2.21.1-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:670b5c4d78c9c2d25e7ba650d212d98bf24d40292f91fe4e2f3ad4f80dc6d7e5"}, + {file = "dbus_fast-2.21.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15d62adfab7c6f4a491085f53f9634d24745ca5a2772549945b7e2de27c0d534"}, + {file = "dbus_fast-2.21.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:54e8771e31ee1deb01feef2475c12123cab770c371ecc97af98eb6ca10a2858e"}, + {file = "dbus_fast-2.21.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2db4d0d60a891a8b20a4c6de68a088efe73b29ab4a5949fe6aad2713c131e174"}, + {file = "dbus_fast-2.21.1-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:65e76b20099c33352d5e7734a219982858873cf66fe510951d9bd27cb690190f"}, + {file = "dbus_fast-2.21.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:927f294b1dc7cea9372ef8c7c46ebeb5c7e6c1c7345358f952e7499bdbdf7eb4"}, + {file = "dbus_fast-2.21.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9e9a43ea42b8a9f2c62ca50ce05582de7b4f1f7eb27091f904578c29124af246"}, + {file = "dbus_fast-2.21.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:78c84ecf19459571784fd6a8ad8b3e9006cf96c3282e8220bc49098866ef4cc7"}, + {file = "dbus_fast-2.21.1-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a5b3895ea12c4e636dfaacf75fa5bd1e8450b2ffb97507520991eaf1989d102e"}, + {file = "dbus_fast-2.21.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85be33bb04e918833ac6f28f68f83a1e83425eb6e08b9c482cc3318820dfd55f"}, + {file = "dbus_fast-2.21.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:13ab6a0f64d345cb42c489239962261f724bd441458bef245b39828ed94ea6f4"}, + {file = "dbus_fast-2.21.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c585e7a94bb723a70b4966677b882be8bda324cc41bd129765e3ceab428889bb"}, + {file = "dbus_fast-2.21.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:62331ee3871f6881f517ca65ae185fb2462a0bf2fe78acc4a4d621fc4da08396"}, + {file = "dbus_fast-2.21.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbfd6892fa092cbd6f52edcb24797af62fba8baa50995db856b0a342184c850d"}, + {file = "dbus_fast-2.21.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a999e35628988ad4f81af36192cd592b8fd1e72e1bbc76a64d80808e6f4b9540"}, + {file = "dbus_fast-2.21.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9cae9a6b9bb54f3f89424fdd960b60ac53239b9e5d4a5d9a598d222fbf8d3173"}, + {file = "dbus_fast-2.21.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:39a3f3662391b49553bf9d9d2e9a6cb31e0d7d337557ee0c0be5c558a3c7d230"}, + {file = "dbus_fast-2.21.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffc2b6beb212d0d231816dcb7bd8bcdafccd04750ba8f5e915f40ad312f5adf2"}, + {file = "dbus_fast-2.21.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c938eb7130067ca3b74b248ee376228776d8f013a206ae78e6fc644c9db0f4f5"}, + {file = "dbus_fast-2.21.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fae9609d972f0c2b72017796a8140b8a6fb842426f0aed4f43f0fa7d780a16f"}, + {file = "dbus_fast-2.21.1.tar.gz", hash = "sha256:87b852d2005f1d59399ca51c5f3538f28a4742d739d7abe82b7ae8d01d8a5d02"}, ] [[package]] name = "dill" -version = "0.3.7" +version = "0.3.8" description = "serialize all of Python" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"}, - {file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"}, + {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, + {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, ] [package.extras] graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "exceptiongroup" @@ -419,66 +427,64 @@ files = [ [[package]] name = "isort" -version = "5.12.0" +version = "5.13.2" description = "A Python utility / library to sort Python imports." category = "dev" optional = false python-versions = ">=3.8.0" files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, ] [package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] +colors = ["colorama (>=0.4.6)"] [[package]] name = "lazy-object-proxy" -version = "1.9.0" +version = "1.10.0" description = "A fast and thorough lazy object proxy." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, + {file = "lazy-object-proxy-1.10.0.tar.gz", hash = "sha256:78247b6d45f43a52ef35c25b5581459e85117225408a4128a3daf8bf9648ac69"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:855e068b0358ab916454464a884779c7ffa312b8925c6f7401e952dcf3b89977"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab7004cf2e59f7c2e4345604a3e6ea0d92ac44e1c2375527d56492014e690c3"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc0d2fc424e54c70c4bc06787e4072c4f3b1aa2f897dfdc34ce1013cf3ceef05"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e2adb09778797da09d2b5ebdbceebf7dd32e2c96f79da9052b2e87b6ea495895"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1f711e2c6dcd4edd372cf5dec5c5a30d23bba06ee012093267b3376c079ec83"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-win32.whl", hash = "sha256:76a095cfe6045c7d0ca77db9934e8f7b71b14645f0094ffcd842349ada5c5fb9"}, + {file = "lazy_object_proxy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:b4f87d4ed9064b2628da63830986c3d2dca7501e6018347798313fcf028e2fd4"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fec03caabbc6b59ea4a638bee5fce7117be8e99a4103d9d5ad77f15d6f81020c"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c83f957782cbbe8136bee26416686a6ae998c7b6191711a04da776dc9e47d4"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009e6bb1f1935a62889ddc8541514b6a9e1fcf302667dcb049a0be5c8f613e56"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75fc59fc450050b1b3c203c35020bc41bd2695ed692a392924c6ce180c6f1dc9"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:782e2c9b2aab1708ffb07d4bf377d12901d7a1d99e5e410d648d892f8967ab1f"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-win32.whl", hash = "sha256:edb45bb8278574710e68a6b021599a10ce730d156e5b254941754a9cc0b17d03"}, + {file = "lazy_object_proxy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:e271058822765ad5e3bca7f05f2ace0de58a3f4e62045a8c90a0dfd2f8ad8cc6"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e98c8af98d5707dcdecc9ab0863c0ea6e88545d42ca7c3feffb6b4d1e370c7ba"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:952c81d415b9b80ea261d2372d2a4a2332a3890c2b83e0535f263ddfe43f0d43"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80b39d3a151309efc8cc48675918891b865bdf742a8616a337cb0090791a0de9"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e221060b701e2aa2ea991542900dd13907a5c90fa80e199dbf5a03359019e7a3"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92f09ff65ecff3108e56526f9e2481b8116c0b9e1425325e13245abfd79bdb1b"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-win32.whl", hash = "sha256:3ad54b9ddbe20ae9f7c1b29e52f123120772b06dbb18ec6be9101369d63a4074"}, + {file = "lazy_object_proxy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:127a789c75151db6af398b8972178afe6bda7d6f68730c057fbbc2e96b08d282"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9e4ed0518a14dd26092614412936920ad081a424bdcb54cc13349a8e2c6d106a"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ad9e6ed739285919aa9661a5bbed0aaf410aa60231373c5579c6b4801bd883c"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fc0a92c02fa1ca1e84fc60fa258458e5bf89d90a1ddaeb8ed9cc3147f417255"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0aefc7591920bbd360d57ea03c995cebc204b424524a5bd78406f6e1b8b2a5d8"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5faf03a7d8942bb4476e3b62fd0f4cf94eaf4618e304a19865abf89a35c0bbee"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-win32.whl", hash = "sha256:e333e2324307a7b5d86adfa835bb500ee70bfcd1447384a822e96495796b0ca4"}, + {file = "lazy_object_proxy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:cb73507defd385b7705c599a94474b1d5222a508e502553ef94114a143ec6696"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:366c32fe5355ef5fc8a232c5436f4cc66e9d3e8967c01fb2e6302fd6627e3d94"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2297f08f08a2bb0d32a4265e98a006643cd7233fb7983032bd61ac7a02956b3b"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18dd842b49456aaa9a7cf535b04ca4571a302ff72ed8740d06b5adcd41fe0757"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:217138197c170a2a74ca0e05bddcd5f1796c735c37d0eee33e43259b192aa424"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a3a87cf1e133e5b1994144c12ca4aa3d9698517fe1e2ca82977781b16955658"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-win32.whl", hash = "sha256:30b339b2a743c5288405aa79a69e706a06e02958eab31859f7f3c04980853b70"}, + {file = "lazy_object_proxy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:a899b10e17743683b293a729d3a11f2f399e8a90c73b089e29f5d0fe3509f0dd"}, + {file = "lazy_object_proxy-1.10.0-pp310.pp311.pp312.pp38.pp39-none-any.whl", hash = "sha256:80fa48bd89c8f2f456fc0765c11c23bf5af827febacd2f523ca5bc1893fcc09d"}, ] [[package]] @@ -532,39 +538,39 @@ files = [ [[package]] name = "mypy" -version = "1.7.1" +version = "1.9.0" description = "Optional static typing for Python" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"}, - {file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"}, - {file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"}, - {file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"}, - {file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"}, - {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"}, - {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"}, - {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"}, - {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"}, - {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"}, - {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"}, - {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"}, - {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"}, - {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"}, - {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"}, - {file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"}, - {file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"}, - {file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"}, - {file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"}, - {file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"}, - {file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"}, - {file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"}, - {file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"}, - {file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"}, - {file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"}, - {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"}, - {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"}, + {file = "mypy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8a67616990062232ee4c3952f41c779afac41405806042a8126fe96e098419f"}, + {file = "mypy-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d357423fa57a489e8c47b7c85dfb96698caba13d66e086b412298a1a0ea3b0ed"}, + {file = "mypy-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c87c15aed320de9b438ae7b00c1ac91cd393c1b854c2ce538e2a72d55df150"}, + {file = "mypy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:48533cdd345c3c2e5ef48ba3b0d3880b257b423e7995dada04248725c6f77374"}, + {file = "mypy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:4d3dbd346cfec7cb98e6cbb6e0f3c23618af826316188d587d1c1bc34f0ede03"}, + {file = "mypy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:653265f9a2784db65bfca694d1edd23093ce49740b2244cde583aeb134c008f3"}, + {file = "mypy-1.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a3c007ff3ee90f69cf0a15cbcdf0995749569b86b6d2f327af01fd1b8aee9dc"}, + {file = "mypy-1.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2418488264eb41f69cc64a69a745fad4a8f86649af4b1041a4c64ee61fc61129"}, + {file = "mypy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:68edad3dc7d70f2f17ae4c6c1b9471a56138ca22722487eebacfd1eb5321d612"}, + {file = "mypy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:85ca5fcc24f0b4aeedc1d02f93707bccc04733f21d41c88334c5482219b1ccb3"}, + {file = "mypy-1.9.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aceb1db093b04db5cd390821464504111b8ec3e351eb85afd1433490163d60cd"}, + {file = "mypy-1.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0235391f1c6f6ce487b23b9dbd1327b4ec33bb93934aa986efe8a9563d9349e6"}, + {file = "mypy-1.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d5ddc13421ba3e2e082a6c2d74c2ddb3979c39b582dacd53dd5d9431237185"}, + {file = "mypy-1.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:190da1ee69b427d7efa8aa0d5e5ccd67a4fb04038c380237a0d96829cb157913"}, + {file = "mypy-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe28657de3bfec596bbeef01cb219833ad9d38dd5393fc649f4b366840baefe6"}, + {file = "mypy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e54396d70be04b34f31d2edf3362c1edd023246c82f1730bbf8768c28db5361b"}, + {file = "mypy-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5e6061f44f2313b94f920e91b204ec600982961e07a17e0f6cd83371cb23f5c2"}, + {file = "mypy-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a10926e5473c5fc3da8abb04119a1f5811a236dc3a38d92015cb1e6ba4cb9e"}, + {file = "mypy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b685154e22e4e9199fc95f298661deea28aaede5ae16ccc8cbb1045e716b3e04"}, + {file = "mypy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d741d3fc7c4da608764073089e5f58ef6352bedc223ff58f2f038c2c4698a89"}, + {file = "mypy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:587ce887f75dd9700252a3abbc9c97bbe165a4a630597845c61279cf32dfbf02"}, + {file = "mypy-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f88566144752999351725ac623471661c9d1cd8caa0134ff98cceeea181789f4"}, + {file = "mypy-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61758fabd58ce4b0720ae1e2fea5cfd4431591d6d590b197775329264f86311d"}, + {file = "mypy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e49499be624dead83927e70c756970a0bc8240e9f769389cdf5714b0784ca6bf"}, + {file = "mypy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:571741dc4194b4f82d344b15e8837e8c5fcc462d66d076748142327626a1b6e9"}, + {file = "mypy-1.9.0-py3-none-any.whl", hash = "sha256:a260627a570559181a9ea5de61ac6297aa5af202f06fd7ab093ce74e7181e43e"}, + {file = "mypy-1.9.0.tar.gz", hash = "sha256:3cc5da0127e6a478cddd906068496a97a7618a21ce9b54bde5bf7e539c7af974"}, ] [package.dependencies] @@ -590,16 +596,32 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] +[[package]] +name = "mypy-protobuf" +version = "3.6.0" +description = "Generate mypy stub files from protobuf specs" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-protobuf-3.6.0.tar.gz", hash = "sha256:02f242eb3409f66889f2b1a3aa58356ec4d909cdd0f93115622e9e70366eca3c"}, + {file = "mypy_protobuf-3.6.0-py3-none-any.whl", hash = "sha256:56176e4d569070e7350ea620262478b49b7efceba4103d468448f1d21492fd6c"}, +] + +[package.dependencies] +protobuf = ">=4.25.3" +types-protobuf = ">=4.24" + [[package]] name = "packaging" -version = "23.2" +version = "24.0" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] [[package]] @@ -616,42 +638,42 @@ files = [ [[package]] name = "pathspec" -version = "0.11.2" +version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] [[package]] name = "platformdirs" -version = "4.1.0" +version = "4.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] [[package]] name = "pluggy" -version = "1.3.0" +version = "1.4.0" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, ] [package.extras] @@ -660,14 +682,14 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "poethepoet" -version = "0.24.4" +version = "0.25.0" description = "A task runner that works well with poetry." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "poethepoet-0.24.4-py3-none-any.whl", hash = "sha256:fb4ea35d7f40fe2081ea917d2e4102e2310fda2cde78974050ca83896e229075"}, - {file = "poethepoet-0.24.4.tar.gz", hash = "sha256:ff4220843a87c888cbcb5312c8905214701d0af60ac7271795baa8369b428fef"}, + {file = "poethepoet-0.25.0-py3-none-any.whl", hash = "sha256:42c0fd654f23e1b7c67aa8aa395c72e15eb275034bd5105171003daf679c1470"}, + {file = "poethepoet-0.25.0.tar.gz", hash = "sha256:ca8f1d8475aa10d2ceeb26331d2626fc4a6b51df1e7e70d3d0d6481a984faab6"}, ] [package.dependencies] @@ -677,6 +699,46 @@ tomli = ">=1.2.2" [package.extras] poetry-plugin = ["poetry (>=1.0,<2.0)"] +[[package]] +name = "protobuf" +version = "4.25.3" +description = "" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, + {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, + {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, + {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"}, + {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"}, + {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, + {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, + {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, + {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, +] + +[[package]] +name = "protoletariat" +version = "3.2.19" +description = "Python protocol buffers for the rest of us" +category = "dev" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "protoletariat-3.2.19-py3-none-any.whl", hash = "sha256:4bed510011cb352b26998008167a5a7ae697fb49d76fe4848bffa27856feab35"}, + {file = "protoletariat-3.2.19.tar.gz", hash = "sha256:3c23aa88bcceadde5a589bf0c1dd91e08636309e5b3d115ddebb38f5b1873d53"}, +] + +[package.dependencies] +click = ">=8,<9" +protobuf = ">=3.19.1,<5" + +[package.extras] +grpcio-tools = ["grpcio-tools (>=1.42.0,<2)"] + [[package]] name = "py" version = "1.11.0" @@ -720,7 +782,10 @@ files = [ [package.dependencies] astroid = ">=2.15.8,<=2.17.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -dill = {version = ">=0.2", markers = "python_version < \"3.11\""} +dill = [ + {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, +] isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" @@ -812,14 +877,14 @@ pyobjc-core = ">=9.2" [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -835,18 +900,18 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.23.2" +version = "0.23.6" description = "Pytest support for asyncio" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.2.tar.gz", hash = "sha256:c16052382554c7b22d48782ab3438d5b10f8cf7a4bdcae7f0f67f097d95beecc"}, - {file = "pytest_asyncio-0.23.2-py3-none-any.whl", hash = "sha256:ea9021364e32d58f0be43b91c6233fb8d2224ccef2398d6837559e587682808f"}, + {file = "pytest-asyncio-0.23.6.tar.gz", hash = "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f"}, + {file = "pytest_asyncio-0.23.6-py3-none-any.whl", hash = "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a"}, ] [package.dependencies] -pytest = ">=7.0.0" +pytest = ">=7.0.0,<9" [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] @@ -890,14 +955,14 @@ pytest-metadata = "*" [[package]] name = "pytest-metadata" -version = "3.0.0" +version = "3.1.1" description = "pytest plugin for test session metadata" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest_metadata-3.0.0-py3-none-any.whl", hash = "sha256:a17b1e40080401dc23177599208c52228df463db191c1a573ccdffacd885e190"}, - {file = "pytest_metadata-3.0.0.tar.gz", hash = "sha256:769a9c65d2884bd583bc626b0ace77ad15dbe02dd91a9106d47fd46d9c2569ca"}, + {file = "pytest_metadata-3.1.1-py3-none-any.whl", hash = "sha256:c8e0844db684ee1c798cfa38908d20d67d0463ecb6137c72e91f418558dd5f4b"}, + {file = "pytest_metadata-3.1.1.tar.gz", hash = "sha256:d2a29b0355fbc03f168aa96d41ff88b1a3b44a3b02acbe491801c98a048017c8"}, ] [package.dependencies] @@ -906,6 +971,18 @@ pytest = ">=7.0.0" [package.extras] test = ["black (>=22.1.0)", "flake8 (>=4.0.1)", "pre-commit (>=2.17.0)", "tox (>=3.24.5)"] +[[package]] +name = "pytz" +version = "2024.1" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, +] + [[package]] name = "requests" version = "2.31.0" @@ -930,20 +1007,19 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rich" -version = "13.7.0" +version = "13.7.1" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" category = "main" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, - {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, ] [package.dependencies] markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" -typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] @@ -962,26 +1038,50 @@ files = [ [[package]] name = "tomlkit" -version = "0.12.3" +version = "0.12.4" description = "Style preserving TOML library" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, - {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, + {file = "tomlkit-0.12.4-py3-none-any.whl", hash = "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b"}, + {file = "tomlkit-0.12.4.tar.gz", hash = "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3"}, +] + +[[package]] +name = "types-protobuf" +version = "4.24.0.20240408" +description = "Typing stubs for protobuf" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-protobuf-4.24.0.20240408.tar.gz", hash = "sha256:c03a44357b03c233c8c5864ce3e07dd9c766a00497d271496923f7ae3cb9e1de"}, + {file = "types_protobuf-4.24.0.20240408-py3-none-any.whl", hash = "sha256:9b87cd279378693071247227f52e89738af7c8d6f06dbdd749b0cf473c4916ce"}, +] + +[[package]] +name = "types-pytz" +version = "2024.1.0.20240203" +description = "Typing stubs for pytz" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-pytz-2024.1.0.20240203.tar.gz", hash = "sha256:c93751ee20dfc6e054a0148f8f5227b9a00b79c90a4d3c9f464711a73179c89e"}, + {file = "types_pytz-2024.1.0.20240203-py3-none-any.whl", hash = "sha256:9679eef0365db3af91ef7722c199dbb75ee5c1b67e3c4dd7bfbeb1b8a71c21a3"}, ] [[package]] name = "types-requests" -version = "2.31.0.10" +version = "2.31.0.20240406" description = "Typing stubs for requests" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "types-requests-2.31.0.10.tar.gz", hash = "sha256:dc5852a76f1eaf60eafa81a2e50aefa3d1f015c34cf0cba130930866b1b22a92"}, - {file = "types_requests-2.31.0.10-py3-none-any.whl", hash = "sha256:b32b9a86beffa876c0c3ac99a4cd3b8b51e973fb8e3bd4e0a6bb32c7efad80fc"}, + {file = "types-requests-2.31.0.20240406.tar.gz", hash = "sha256:4428df33c5503945c74b3f42e82b181e86ec7b724620419a2966e2de604ce1a1"}, + {file = "types_requests-2.31.0.20240406-py3-none-any.whl", hash = "sha256:6216cdac377c6b9a040ac1c0404f7284bd13199c0e1bb235f4324627e8898cf5"}, ] [package.dependencies] @@ -989,30 +1089,61 @@ urllib3 = ">=2" [[package]] name = "typing-extensions" -version = "4.8.0" +version = "4.11.0" description = "Backported and Experimental Type Hints for Python 3.8+" category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, +] + +[[package]] +name = "tzdata" +version = "2024.1" +description = "Provider of IANA time zone data" +category = "main" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, +] + +[[package]] +name = "tzlocal" +version = "5.2" +description = "tzinfo object for the local timezone" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"}, + {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"}, ] +[package.dependencies] +tzdata = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] + [[package]] name = "urllib3" -version = "2.1.0" +version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, - {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -1098,5 +1229,5 @@ files = [ [metadata] lock-version = "2.0" -python-versions = ">=3.8,<3.11" -content-hash = "56ab342d644d11266f452ce4f3ae66ee054b4366839ea554cb3b94d79828edf6" +python-versions = ">=3.9,<3.12" +content-hash = "d7f680ddab9cf52fa424bcb3a374e4782acbf42221405e834dc40d3675670a6a" diff --git a/demos/python/tutorial/pyproject.toml b/demos/python/tutorial/pyproject.toml index 9c5d2e21..2385318b 100644 --- a/demos/python/tutorial/pyproject.toml +++ b/demos/python/tutorial/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "open-gopro-tutorials" -version = "0.2.0" +version = "0.3.0" description = "Open GoPro Python Tutorials" authors = ["Tim Camise "] license = "MIT" @@ -18,20 +18,25 @@ classifiers = [ "Operating System :: MacOS :: MacOS X", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ] [tool.poetry.dependencies] -python = ">=3.8,<3.11" +python = ">=3.9,<3.12" bleak = "0.21.1" requests = "^2" rich = "^13" +pytz = "^2024.1" +tzlocal = "^5.2" +mypy-protobuf = "*" [tool.poetry.group.dev.dependencies] +types-pytz = "^2024.1.0.20240203" poethepoet = "^0" black = "*" +isort = "*" mypy = "*" pytest = "^7" pytest-asyncio = "^0" @@ -40,6 +45,7 @@ pytest-cov = "^4" coverage = { extras = ["toml"], version = "^6" } pylint = "^2" types-requests = "*" +protoletariat = "^3" [build-system] requires = ["poetry-core"] @@ -47,39 +53,47 @@ build-backend = "poetry.core.masonry.api" [tool.poe.tasks.tests] cmd = "pytest tests --cov-fail-under=60" -help = "Run end-to-end tests" +help = "Run end-to-end tests. Requires ssid=${SSID} and password=${ssid} args to connect to AP" -[tool.poe.tasks.types] +[tool.poe.tasks._types] cmd = "mypy tutorial_modules" help = "Check types" -[tool.poe.tasks.lint] -cmd = "pylint --no-docstring-rgx=main tutorial_modules" +[tool.poe.tasks._pylint] +cmd = "pylint --no-docstring-rgx=main|_ tutorial_modules" help = "Run pylint" +[tool.poe.tasks._sort_imports] +cmd = "isort open_gopro tests" +help = "Sort imports with isort" + [tool.poe.tasks.format] cmd = "black tutorial_modules tests" help = "Apply black formatting to source code" -[tool.poe.tasks.clean_artifacts] +[tool.poe.tasks._clean_artifacts] cmd = "rm -rf **/__pycache__ *.csv *.mp4 *.jpg *.log .mypy_cache .nox" help = "Clean testing artifacts and pycache" -[tool.poe.tasks.clean_tests] +[tool.poe.tasks._clean_tests] cmd = "rm -rf .reports && rm -rf .pytest_cache" help = "Clean test reports" -[tool.poe.tasks.clean_build] +[tool.poe.tasks._clean_build] cmd = "rm -rf dist" help = "Clean module build output" [tool.poe.tasks.clean] -sequence = ["clean_artifacts", "clean_tests", "clean_build"] +sequence = ["_clean_artifacts", "_clean_tests", "_clean_build"] help = "Clean everything" -[tool.poe.tasks.all] -sequence = ["format", "types", "lint", "tests"] -help = "Format, check types, lint, check docstrings, and run end-to-end tests" +[tool.poe.tasks.protobuf] +cmd = "bash ../../../tools/build_python_protos.sh tutorial_modules" +help = "generate protobuf source from .proto (assumes protoc >= 3.20.1 available)" + +[tool.poe.tasks.lint] +sequence = ["format", "_sort_imports", "_types", "_pylint",] +help = "Format, check types, lint, and check docstrings" [tool.mypy] ignore_missing_imports = true @@ -126,7 +140,6 @@ directory = ".reports/coverage" exclude_lines = ["raise NotImplementedError"] [tool.pylint.'MASTER'] -extension-pkg-whitelist = "cv2" # TODO this isn't working load-plugins = "pylint.extensions.docparams" accept-no-param-doc = "yes" accept-no-return-doc = "yes" @@ -165,8 +178,11 @@ disable = [ ] [tool.pylint.'FORMAT'] -max-line-length = 160 +max-line-length = 300 # Handled by black [tool.black] -line-length = 111 +line-length = 120 exclude = ".venv" + +[tool.isort] +profile = "black" diff --git a/demos/python/tutorial/tests/conftest.py b/demos/python/tutorial/tests/conftest.py index cd065bdd..6788e510 100644 --- a/demos/python/tutorial/tests/conftest.py +++ b/demos/python/tutorial/tests/conftest.py @@ -7,6 +7,12 @@ import pytest + +def pytest_addoption(parser): + parser.addoption("--ssid", action="store", required=True) + parser.addoption("--password", action="store", required=True) + + ############################################################################################################## # Log Management ############################################################################################################## @@ -15,7 +21,7 @@ @pytest.fixture(scope="class", autouse=True) def manage_logs(request): log_file = Path(request.node.name + ".log") - request.config.pluginmanager.get_plugin("logging-plugin").set_log_path(Path("reports") / "logs" / log_file) + request.config.pluginmanager.get_plugin("logging-plugin").set_log_path(Path(".reports") / "logs" / log_file) @pytest.fixture(scope="function", autouse=True) diff --git a/demos/python/tutorial/tests/test_tutorials.py b/demos/python/tutorial/tests/test_tutorials.py index 66ff099f..7a828644 100644 --- a/demos/python/tutorial/tests/test_tutorials.py +++ b/demos/python/tutorial/tests/test_tutorials.py @@ -4,20 +4,25 @@ # Simply run each demo for some naive sanity checking import time +from pathlib import Path import pytest from tutorial_modules.tutorial_1_connect_ble.ble_connect import main as ble_connect -from tutorial_modules.tutorial_2_send_ble_commands.ble_command_load_group import main as ble_command_load_group -from tutorial_modules.tutorial_2_send_ble_commands.ble_command_set_fps import main as ble_command_set_fps +from tutorial_modules.tutorial_2_send_ble_commands.ble_command_load_group import ( + main as ble_command_load_group, +) +from tutorial_modules.tutorial_2_send_ble_commands.ble_command_set_fps import ( + main as ble_command_set_fps, +) from tutorial_modules.tutorial_2_send_ble_commands.ble_command_set_resolution import ( main as ble_command_set_resolution, ) from tutorial_modules.tutorial_2_send_ble_commands.ble_command_set_shutter import ( main as ble_command_set_shutter, ) -from tutorial_modules.tutorial_3_parse_ble_tlv_responses.ble_command_get_state import ( - main as ble_command_get_state, +from tutorial_modules.tutorial_3_parse_ble_tlv_responses.ble_command_get_hardware_info import ( + main as ble_get_hardware_info, ) from tutorial_modules.tutorial_3_parse_ble_tlv_responses.ble_command_get_version import ( main as ble_command_get_version, @@ -31,35 +36,45 @@ from tutorial_modules.tutorial_4_ble_queries.ble_query_register_resolution_value_updates import ( main as ble_query_register_resolution_value_updates, ) -from tutorial_modules.tutorial_5_connect_wifi.wifi_enable import main as wifi_enable -from tutorial_modules.tutorial_6_send_wifi_commands.wifi_command_get_media_list import ( +from tutorial_modules.tutorial_5_ble_protobuf.set_turbo_mode import ( + main as set_turbo_mode, +) +from tutorial_modules.tutorial_6_connect_wifi.connect_as_sta import main as connect_sta +from tutorial_modules.tutorial_6_connect_wifi.enable_wifi_ap import main as wifi_enable +from tutorial_modules.tutorial_7_send_wifi_commands.wifi_command_get_media_list import ( main as wifi_command_get_media_list, ) -from tutorial_modules.tutorial_6_send_wifi_commands.wifi_command_get_state import ( +from tutorial_modules.tutorial_7_send_wifi_commands.wifi_command_get_state import ( main as wifi_command_get_state, ) -from tutorial_modules.tutorial_6_send_wifi_commands.wifi_command_load_group import ( +from tutorial_modules.tutorial_7_send_wifi_commands.wifi_command_load_group import ( main as wifi_command_load_group, ) -from tutorial_modules.tutorial_6_send_wifi_commands.wifi_command_preview_stream import ( +from tutorial_modules.tutorial_7_send_wifi_commands.wifi_command_preview_stream import ( main as wifi_command_preview_stream, ) -from tutorial_modules.tutorial_6_send_wifi_commands.wifi_command_set_resolution import ( +from tutorial_modules.tutorial_7_send_wifi_commands.wifi_command_set_resolution import ( main as wifi_command_set_resolution, ) -from tutorial_modules.tutorial_6_send_wifi_commands.wifi_command_set_shutter import ( +from tutorial_modules.tutorial_7_send_wifi_commands.wifi_command_set_shutter import ( main as wifi_command_set_shutter, ) -from tutorial_modules.tutorial_7_camera_media_list.wifi_media_download_file import ( +from tutorial_modules.tutorial_8_camera_media_list.wifi_media_download_file import ( main as wifi_media_download_file, ) -from tutorial_modules.tutorial_7_camera_media_list.wifi_media_get_gpmf import main as wifi_media_get_gpmf -from tutorial_modules.tutorial_7_camera_media_list.wifi_media_get_screennail import ( +from tutorial_modules.tutorial_8_camera_media_list.wifi_media_get_gpmf import ( + main as wifi_media_get_gpmf, +) +from tutorial_modules.tutorial_8_camera_media_list.wifi_media_get_screennail import ( main as wifi_media_get_screennail, ) -from tutorial_modules.tutorial_7_camera_media_list.wifi_media_get_thumbnail import ( +from tutorial_modules.tutorial_8_camera_media_list.wifi_media_get_thumbnail import ( main as wifi_media_get_thumbnail, ) +from tutorial_modules.tutorial_9_cohn.communicate_via_cohn import ( + main as communicate_via_cohn, +) +from tutorial_modules.tutorial_9_cohn.provision_cohn import main as provision_cohn @pytest.fixture(scope="module") @@ -80,28 +95,28 @@ class TestTutorial2SendBleCommands: async def test_ble_command_load_group(self): await ble_command_load_group(None) - @pytest.mark.asyncio - async def test_ble_command_set_fps(self): - await ble_command_set_fps(None) - @pytest.mark.asyncio async def test_ble_command_set_resolution(self): await ble_command_set_resolution(None) + @pytest.mark.asyncio + async def test_ble_command_set_fps(self): + await ble_command_set_fps(None) + @pytest.mark.asyncio async def test_ble_command_set_shutter(self): await ble_command_set_shutter(None) class TestTutorial3ParseBleTlvResponses: - @pytest.mark.asyncio - async def test_ble_command_get_state(self): - await ble_command_get_state(None) - @pytest.mark.asyncio async def test_ble_command_get_version(self): await ble_command_get_version(None) + @pytest.mark.asyncio + async def test_ble_get_hardware_info(self): + await ble_get_hardware_info(None) + class TestTutorial4BleQueries: @pytest.mark.asyncio @@ -123,7 +138,27 @@ async def test_wifi_enable(self): await wifi_enable(None, timeout=1) -class TestTutorial6SendWifiCommands: +class TestTutorial6BleProtobuf: + @pytest.mark.asyncio + async def test_set_turbo_mode(self): + await set_turbo_mode(None) + + +class TestTutorial9Cohn: + @pytest.mark.asyncio + async def test_connect_sta(self, pytestconfig): + await connect_sta(pytestconfig.getoption("ssid"), pytestconfig.getoption("password"), None) + + @pytest.mark.asyncio + async def test_cohn(self, pytestconfig): + credentials = await provision_cohn( + pytestconfig.getoption("ssid"), pytestconfig.getoption("password"), None, Path("cohn.crt") + ) + assert credentials + await communicate_via_cohn(credentials.ip_address, credentials.username, credentials.password, Path("cohn.crt")) + + +class TestTutorial7SendWifiCommands: def test_wifi_command_get_media_list(self, connect_wifi): wifi_command_get_media_list() @@ -144,7 +179,7 @@ def test_wifi_command_set_shutter(self, connect_wifi): time.sleep(2) # wait for camera to be ready -class TestTutorial7CameraMediaList: +class TestTutorial8CameraMediaList: def test_wifi_media_download_file(self, connect_wifi): wifi_media_download_file() diff --git a/demos/python/tutorial/tutorial_modules/__init__.py b/demos/python/tutorial/tutorial_modules/__init__.py index f262bc0a..01f65f95 100644 --- a/demos/python/tutorial/tutorial_modules/__init__.py +++ b/demos/python/tutorial/tutorial_modules/__init__.py @@ -3,7 +3,7 @@ # pylint: disable=wrong-import-position -from typing import Callable +from typing import Awaitable, Callable, Any import logging from bleak.backends.characteristic import BleakGATTCharacteristic @@ -17,7 +17,7 @@ sh.setFormatter(stream_formatter) sh.setLevel(logging.DEBUG) logger.addHandler(sh) -logger.setLevel(logging.INFO) +logger.setLevel(logging.DEBUG) bleak_logger = logging.getLogger("bleak") bleak_logger.setLevel(logging.WARNING) @@ -28,9 +28,15 @@ GOPRO_BASE_UUID = "b5f9{}-aa8d-11e3-9046-0002a5d5c51b" GOPRO_BASE_URL = "http://10.5.5.9:8080" -noti_handler_T = Callable[[BleakGATTCharacteristic, bytearray], None] +noti_handler_T = Callable[[BleakGATTCharacteristic, bytearray], Awaitable[None]] from tutorial_modules.tutorial_1_connect_ble.ble_connect import connect_ble -from tutorial_modules.tutorial_3_parse_ble_tlv_responses.ble_command_get_state import Response -from tutorial_modules.tutorial_5_connect_wifi.wifi_enable import enable_wifi -from tutorial_modules.tutorial_6_send_wifi_commands.wifi_command_get_media_list import get_media_list +from tutorial_modules.tutorial_2_send_ble_commands.ble_command_set_shutter import GoProUuid +from tutorial_modules.tutorial_3_parse_ble_tlv_responses.ble_command_get_hardware_info import Response, TlvResponse +from tutorial_modules.tutorial_4_ble_queries.ble_query_poll_resolution_value import QueryResponse, Resolution +from tutorial_modules.tutorial_6_connect_wifi.enable_wifi_ap import enable_wifi +from tutorial_modules.tutorial_7_send_wifi_commands.wifi_command_get_media_list import get_media_list +from tutorial_modules.tutorial_5_ble_protobuf import proto +from tutorial_modules.tutorial_5_ble_protobuf.set_turbo_mode import ProtobufResponse +from tutorial_modules.tutorial_5_ble_protobuf.decipher_response import ResponseManager +from tutorial_modules.tutorial_6_connect_wifi.connect_as_sta import connect_to_access_point diff --git a/demos/python/tutorial/tutorial_modules/tutorial_1_connect_ble/ble_connect.py b/demos/python/tutorial/tutorial_modules/tutorial_1_connect_ble/ble_connect.py index 5abf9e7e..292635a0 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_1_connect_ble/ble_connect.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_1_connect_ble/ble_connect.py @@ -5,7 +5,7 @@ import sys import asyncio import argparse -from typing import Dict, Any, List, Optional +from typing import Any from bleak import BleakScanner, BleakClient from bleak.backends.device import BLEDevice as BleakDevice @@ -13,7 +13,7 @@ from tutorial_modules import logger, noti_handler_T -def exception_handler(loop: asyncio.AbstractEventLoop, context: Dict[str, Any]) -> None: +def exception_handler(loop: asyncio.AbstractEventLoop, context: dict[str, Any]) -> None: """Catch exceptions from non-main thread Args: @@ -25,7 +25,7 @@ def exception_handler(loop: asyncio.AbstractEventLoop, context: Dict[str, Any]) logger.critical("This is unexpected and unrecoverable.") -async def connect_ble(notification_handler: noti_handler_T, identifier: Optional[str] = None) -> BleakClient: +async def connect_ble(notification_handler: noti_handler_T, identifier: str | None = None) -> BleakClient: """Connect to a GoPro, then pair, and enable notifications If identifier is None, the first discovered GoPro will be connected to. @@ -49,7 +49,7 @@ async def connect_ble(notification_handler: noti_handler_T, identifier: Optional for retry in range(RETRIES): try: # Map of discovered devices indexed by name - devices: Dict[str, BleakDevice] = {} + devices: dict[str, BleakDevice] = {} # Scan for devices logger.info("Scanning for bluetooth devices...") @@ -62,17 +62,17 @@ def _scan_callback(device: BleakDevice, _: Any) -> None: devices[device.name] = device # Scan until we find devices - matched_devices: List[BleakDevice] = [] + matched_devices: list[BleakDevice] = [] while len(matched_devices) == 0: # Now get list of connectable advertisements for device in await BleakScanner.discover(timeout=5, detection_callback=_scan_callback): - if device.name != "Unknown" and device.name is not None: + if device.name and device.name != "Unknown": devices[device.name] = device # Log every device we discovered for d in devices: logger.info(f"\tDiscovered: {d}") # Now look for our matching device(s) - token = re.compile(r"GoPro [A-Z0-9]{4}" if identifier is None else f"GoPro {identifier}") + token = re.compile(identifier or r"GoPro [A-Z0-9]{4}") matched_devices = [device for name, device in devices.items() if token.match(name)] logger.info(f"Found {len(matched_devices)} matching devices.") @@ -101,6 +101,7 @@ def _scan_callback(device: BleakDevice, _: Any) -> None: logger.info(f"Enabling notification on char {char.uuid}") await client.start_notify(char, notification_handler) logger.info("Done enabling notifications") + logger.info("BLE Connection is ready for communication.") return client except Exception as exc: # pylint: disable=broad-exception-caught @@ -110,9 +111,8 @@ def _scan_callback(device: BleakDevice, _: Any) -> None: raise RuntimeError(f"Couldn't establish BLE connection after {RETRIES} retries") -async def main(identifier: Optional[str]) -> None: - def dummy_notification_handler(*_: Any) -> None: - ... +async def main(identifier: str | None) -> None: + async def dummy_notification_handler(*_: Any) -> None: ... client = await connect_ble(dummy_notification_handler, identifier) await client.disconnect() diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_connect_wifi/__init__.py b/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/__init__.py similarity index 58% rename from demos/python/tutorial/tutorial_modules/tutorial_5_connect_wifi/__init__.py rename to demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/__init__.py index 005ca0cb..e3af0028 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_5_connect_wifi/__init__.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/__init__.py @@ -1,2 +1,2 @@ # __init__.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Wed, Sep 1, 2021 5:06:01 PM +# This copyright was auto-generated on Thu Apr 4 21:50:02 UTC 2024 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_load_group.py b/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_load_group.py index 8d864905..fff08620 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_load_group.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_load_group.py @@ -4,30 +4,26 @@ import sys import asyncio import argparse -from typing import Optional from bleak import BleakClient from bleak.backends.characteristic import BleakGATTCharacteristic -from tutorial_modules import GOPRO_BASE_UUID, connect_ble, logger, noti_handler_T +from tutorial_modules import connect_ble, logger, GoProUuid -async def main(identifier: Optional[str]) -> None: +async def main(identifier: str | None) -> None: # Synchronization event to wait until notification response is received event = asyncio.Event() - - # UUIDs to write to and receive responses from - COMMAND_REQ_UUID = GOPRO_BASE_UUID.format("0072") - COMMAND_RSP_UUID = GOPRO_BASE_UUID.format("0073") - response_uuid = COMMAND_RSP_UUID - client: BleakClient + request_uuid = GoProUuid.COMMAND_REQ_UUID + response_uuid = GoProUuid.COMMAND_RSP_UUID - def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}') + async def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + logger.info(f'Received response at {uuid}: {data.hex(":")}') # If this is the correct handle and the status is success, the command was a success - if client.services.characteristics[characteristic.handle].uuid == response_uuid and data[2] == 0x00: + if uuid is response_uuid and data[2] == 0x00: logger.info("Command sent successfully") # Anything else is unexpected. This shouldn't happen else: @@ -40,16 +36,16 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - # Write to command request BleUUID to load the video preset group logger.info("Loading the video preset group...") + request = bytes([0x04, 0x3E, 0x02, 0x03, 0xE8]) + logger.debug(f"Sending to {request_uuid}: {request.hex(':')}") event.clear() - await client.write_gatt_char(COMMAND_REQ_UUID, bytearray([0x04, 0x3E, 0x02, 0x03, 0xE8]), response=True) + await client.write_gatt_char(request_uuid.value, request, response=True) await event.wait() # Wait to receive the notification response await client.disconnect() if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Connect to a GoPro camera, then change the Preset Group to Video." - ) + parser = argparse.ArgumentParser(description="Connect to a GoPro camera, then change the Preset Group to Video.") parser.add_argument( "-i", "--identifier", @@ -61,7 +57,7 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - try: asyncio.run(main(args.identifier)) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught logger.error(e) sys.exit(-1) else: diff --git a/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_set_fps.py b/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_set_fps.py index cee7e0d1..03cd8d20 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_set_fps.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_set_fps.py @@ -4,31 +4,28 @@ import sys import asyncio import argparse -from typing import Optional -from binascii import hexlify from bleak import BleakClient from bleak.backends.characteristic import BleakGATTCharacteristic -from tutorial_modules import GOPRO_BASE_UUID, connect_ble, logger +from tutorial_modules import connect_ble, logger, GoProUuid -async def main(identifier: Optional[str]) -> None: +async def main(identifier: str | None) -> None: # Synchronization event to wait until notification response is received event = asyncio.Event() - # UUIDs to write to and receive responses from - SETTINGS_REQ_UUID = GOPRO_BASE_UUID.format("0074") - SETTINGS_RSP_UUID = GOPRO_BASE_UUID.format("0075") - response_uuid = SETTINGS_RSP_UUID + request_uuid = GoProUuid.SETTINGS_REQ_UUID + response_uuid = GoProUuid.SETTINGS_RSP_UUID client: BleakClient - def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}') + async def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + logger.info(f'Received response at {uuid}: {data.hex(":")}') # If this is the correct handle and the status is success, the command was a success - if client.services.characteristics[characteristic.handle].uuid == response_uuid and data[2] == 0x00: + if uuid is response_uuid and data[2] == 0x00: logger.info("Command sent successfully") # Anything else is unexpected. This shouldn't happen else: @@ -41,16 +38,16 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - # Write to command request BleUUID to change the fps to 240 logger.info("Setting the fps to 240") + request = bytes([0x03, 0x03, 0x01, 0x00]) + logger.debug(f"Writing to {request_uuid}: {request.hex(':')}") event.clear() - await client.write_gatt_char(SETTINGS_REQ_UUID, bytearray([0x03, 0x03, 0x01, 0x00]), response=True) + await client.write_gatt_char(request_uuid.value, request, response=True) await event.wait() # Wait to receive the notification response await client.disconnect() if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Connect to a GoPro camera, then attempt to change the fps to 240." - ) + parser = argparse.ArgumentParser(description="Connect to a GoPro camera, then attempt to change the fps to 240.") parser.add_argument( "-i", "--identifier", @@ -62,7 +59,7 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - try: asyncio.run(main(args.identifier)) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught logger.error(e) sys.exit(-1) else: diff --git a/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_set_resolution.py b/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_set_resolution.py index 98157f25..c9030ab3 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_set_resolution.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_set_resolution.py @@ -4,31 +4,27 @@ import sys import asyncio import argparse -from typing import Optional -from binascii import hexlify from bleak import BleakClient from bleak.backends.characteristic import BleakGATTCharacteristic -from tutorial_modules import GOPRO_BASE_UUID, connect_ble, logger +from tutorial_modules import GoProUuid, connect_ble, logger -async def main(identifier: Optional[str]) -> None: +async def main(identifier: str | None) -> None: # Synchronization event to wait until notification response is received event = asyncio.Event() - - # UUIDs to write to and receive responses from - SETTINGS_REQ_UUID = GOPRO_BASE_UUID.format("0074") - SETTINGS_RSP_UUID = GOPRO_BASE_UUID.format("0075") - response_uuid = SETTINGS_RSP_UUID + response_uuid = GoProUuid.SETTINGS_RSP_UUID + request_uuid = GoProUuid.SETTINGS_REQ_UUID client: BleakClient - def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}') + async def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + logger.info(f'Received response at {uuid}: {data.hex(":")}') # If this is the correct handle and the status is success, the command was a success - if client.services.characteristics[characteristic.handle].uuid == response_uuid and data[2] == 0x00: + if uuid == response_uuid and data[2] == 0x00: logger.info("Command sent successfully") # Anything else is unexpected. This shouldn't happen else: @@ -41,16 +37,16 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - # Write to command request BleUUID to change the video resolution to 1080 logger.info("Setting the video resolution to 1080") + request = bytes([0x03, 0x02, 0x01, 0x09]) + logger.debug(f"Writing to {request_uuid}: {request.hex(':')}") event.clear() - await client.write_gatt_char(SETTINGS_REQ_UUID, bytearray([0x03, 0x02, 0x01, 0x09]), response=True) + await client.write_gatt_char(request_uuid.value, request, response=True) await event.wait() # Wait to receive the notification response await client.disconnect() if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Connect to a GoPro camera, then change the resolution to 1080." - ) + parser = argparse.ArgumentParser(description="Connect to a GoPro camera, then change the resolution to 1080.") parser.add_argument( "-i", "--identifier", @@ -62,7 +58,7 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - try: asyncio.run(main(args.identifier)) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught logger.error(e) sys.exit(-1) else: diff --git a/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_set_shutter.py b/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_set_shutter.py index 6c984e2a..006fd939 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_set_shutter.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/ble_command_set_shutter.py @@ -1,11 +1,12 @@ # ble_command_set_shutter.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). # This copyright was auto-generated on Wed, Sep 1, 2021 5:05:58 PM +from __future__ import annotations import sys -import time +import enum import asyncio import argparse -from typing import Optional +from typing import Callable, TypeVar from bleak import BleakClient from bleak.backends.characteristic import BleakGATTCharacteristic @@ -13,22 +14,52 @@ from tutorial_modules import GOPRO_BASE_UUID, connect_ble, logger -async def main(identifier: Optional[str]) -> None: - # Synchronization event to wait until notification response is received - event = asyncio.Event() +T = TypeVar("T") + + +class GoProUuid(str, enum.Enum): + """UUIDs to write to and receive responses from""" - # UUIDs to write to and receive responses from COMMAND_REQ_UUID = GOPRO_BASE_UUID.format("0072") COMMAND_RSP_UUID = GOPRO_BASE_UUID.format("0073") - response_uuid = COMMAND_RSP_UUID + SETTINGS_REQ_UUID = GOPRO_BASE_UUID.format("0074") + SETTINGS_RSP_UUID = GOPRO_BASE_UUID.format("0075") + CONTROL_QUERY_SERVICE_UUID = "0000fea6-0000-1000-8000-00805f9b34fb" + INTERNAL_UUID = "00002a19-0000-1000-8000-00805f9b34fb" + QUERY_REQ_UUID = GOPRO_BASE_UUID.format("0076") + QUERY_RSP_UUID = GOPRO_BASE_UUID.format("0077") + WIFI_AP_SSID_UUID = GOPRO_BASE_UUID.format("0002") + WIFI_AP_PASSWORD_UUID = GOPRO_BASE_UUID.format("0003") + NETWORK_MANAGEMENT_REQ_UUID = GOPRO_BASE_UUID.format("0091") + NETWORK_MANAGEMENT_RSP_UUID = GOPRO_BASE_UUID.format("0092") + + @classmethod + def dict_by_uuid(cls, value_creator: Callable[[GoProUuid], T]) -> dict[GoProUuid, T]: + """Build a dict where the keys are each UUID defined here and the values are built from the input value_creator. + + Args: + value_creator (Callable[[GoProUuid], T]): callable to create the values from each UUID + + Returns: + dict[GoProUuid, T]: uuid-to-value mapping. + """ + return {uuid: value_creator(uuid) for uuid in cls} + + +async def main(identifier: str | None) -> None: + # Synchronization event to wait until notification response is received + event = asyncio.Event() + request_uuid = GoProUuid.COMMAND_REQ_UUID + response_uuid = GoProUuid.COMMAND_RSP_UUID client: BleakClient - def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}') + async def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + logger.info(f'Received response at {uuid}: {data.hex(":")}') # If this is the correct handle and the status is success, the command was a success - if client.services.characteristics[characteristic.handle].uuid == response_uuid and data[2] == 0x00: + if uuid is response_uuid and data[2] == 0x00: logger.info("Command sent successfully") # Anything else is unexpected. This shouldn't happen else: @@ -42,14 +73,18 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - # Write to command request BleUUID to turn the shutter on logger.info("Setting the shutter on") event.clear() - await client.write_gatt_char(COMMAND_REQ_UUID, bytearray([3, 1, 1, 1]), response=True) + request = bytes([3, 1, 1, 1]) + logger.debug(f"Writing to {request_uuid}: {request.hex(':')}") + await client.write_gatt_char(request_uuid.value, request, response=True) await event.wait() # Wait to receive the notification response - time.sleep(2) # If we're recording, let's wait 2 seconds (i.e. take a 2 second video) + await asyncio.sleep(2) # If we're recording, let's wait 2 seconds (i.e. take a 2 second video) # Write to command request BleUUID to turn the shutter off logger.info("Setting the shutter off") - # event.clear() - await client.write_gatt_char(COMMAND_REQ_UUID, bytearray([3, 1, 1, 0]), response=True) + request = bytes([3, 1, 1, 0]) + logger.debug(f"Writing to {request_uuid}: {request.hex(':')}") + event.clear() + await client.write_gatt_char(request_uuid.value, request, response=True) await event.wait() # Wait to receive the notification response await client.disconnect() @@ -69,7 +104,7 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - try: asyncio.run(main(args.identifier)) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught logger.error(e) sys.exit(-1) else: diff --git a/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/__init__.py b/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/__init__.py new file mode 100644 index 00000000..e3af0028 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/__init__.py @@ -0,0 +1,2 @@ +# __init__.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Thu Apr 4 21:50:02 UTC 2024 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/ble_command_get_hardware_info.py b/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/ble_command_get_hardware_info.py new file mode 100644 index 00000000..8a870e7b --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/ble_command_get_hardware_info.py @@ -0,0 +1,238 @@ +# ble_command_get_state.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed, Sep 1, 2021 5:05:59 PM + +from __future__ import annotations +import sys +import json +import enum +import asyncio +import argparse +from typing import TypeVar +from dataclasses import dataclass, asdict + +from bleak import BleakClient +from bleak.backends.characteristic import BleakGATTCharacteristic + +from tutorial_modules import GoProUuid, connect_ble, logger + +T = TypeVar("T", bound="Response") + + +class Response: + """The base class to encapsulate all BLE Responses + + Args: + uuid (GoProUuid): UUID that this response was received on. + """ + + def __init__(self, uuid: GoProUuid) -> None: + """Constructor""" + self.bytes_remaining = 0 + self.uuid = uuid + self.raw_bytes = bytearray() + + @classmethod + def from_received_response(cls: type[T], received_response: Response) -> T: + """Build a new response from a received response. + + Can be used by subclasses for essentially casting into their derived type. + + Args: + cls (type[T]): type of response to build + received_response (Response): received response to build from + + Returns: + T: built response. + """ + response = cls(received_response.uuid) + response.bytes_remaining = 0 + response.raw_bytes = received_response.raw_bytes + return response + + @property + def is_received(self) -> bool: + """Have all of the bytes identified by the length header been received? + + Returns: + bool: True if received, False otherwise. + """ + return len(self.raw_bytes) > 0 and self.bytes_remaining == 0 + + def accumulate(self, data: bytes) -> None: + """Accumulate a current packet in to the received response. + + Args: + data (bytes): bytes to accumulate. + """ + CONT_MASK = 0b10000000 + HDR_MASK = 0b01100000 + GEN_LEN_MASK = 0b00011111 + EXT_13_BYTE0_MASK = 0b00011111 + + class Header(enum.Enum): + """Header Type Identifiers""" + + GENERAL = 0b00 + EXT_13 = 0b01 + EXT_16 = 0b10 + RESERVED = 0b11 + + buf = bytearray(data) + if buf[0] & CONT_MASK: + buf.pop(0) + else: + # This is a new packet so start with an empty byte array + self.raw_bytes = bytearray() + hdr = Header((buf[0] & HDR_MASK) >> 5) + if hdr is Header.GENERAL: + self.bytes_remaining = buf[0] & GEN_LEN_MASK + buf = buf[1:] + elif hdr is Header.EXT_13: + self.bytes_remaining = ((buf[0] & EXT_13_BYTE0_MASK) << 8) + buf[1] + buf = buf[2:] + elif hdr is Header.EXT_16: + self.bytes_remaining = (buf[1] << 8) + buf[2] + buf = buf[3:] + + # Append payload to buffer and update remaining / complete + self.raw_bytes.extend(buf) + self.bytes_remaining -= len(buf) + logger.debug(f"{self.bytes_remaining=}") + + +class TlvResponse(Response): + """A Type Length Value TLV Response. + + TLV response all have an ID, status, and payload. + """ + + def __init__(self, uuid: GoProUuid) -> None: + super().__init__(uuid) + self.id: int + self.status: int + self.payload: bytes + + def parse(self) -> None: + """Extract the ID, status, and payload""" + self.id = self.raw_bytes[0] + self.status = self.raw_bytes[1] + self.payload = bytes(self.raw_bytes[2:]) + + +@dataclass +class HardwareInfo: + """The meaningful values from a hardware info response""" + + model_number: int + model_name: str + firmware_version: str + serial_number: str + ap_ssid: str + ap_mac_address: str + + def __str__(self) -> str: + return json.dumps(asdict(self), indent=4) + + @classmethod + def from_bytes(cls, data: bytes) -> HardwareInfo: + """Parse and build from a raw hardware info response bytestream + + Args: + data (bytes): bytestream to parse + + Returns: + HardwareInfo: Parsed response. + """ + buf = bytearray(data) + # Get model number + model_num_length = buf.pop(0) + model = int.from_bytes(buf[:model_num_length], "big", signed=False) + buf = buf[model_num_length:] + # Get model name + model_name_length = buf.pop(0) + model_name = (buf[:model_name_length]).decode() + buf = buf[model_name_length:] + # Advance past deprecated bytes + deprecated_length = buf.pop(0) + buf = buf[deprecated_length:] + # Get firmware version + firmware_length = buf.pop(0) + firmware = (buf[:firmware_length]).decode() + buf = buf[firmware_length:] + # Get serial number + serial_length = buf.pop(0) + serial = (buf[:serial_length]).decode() + buf = buf[serial_length:] + # Get AP SSID + ssid_length = buf.pop(0) + ssid = (buf[:ssid_length]).decode() + buf = buf[ssid_length:] + # Get MAC address + mac_length = buf.pop(0) + mac = (buf[:mac_length]).decode() + buf = buf[mac_length:] + + return cls(model, model_name, firmware, serial, ssid, mac) + + +async def main(identifier: str | None) -> None: + client: BleakClient + responses_by_uuid = GoProUuid.dict_by_uuid(TlvResponse) + received_responses: asyncio.Queue[TlvResponse] = asyncio.Queue() + + request_uuid = GoProUuid.COMMAND_REQ_UUID + response_uuid = GoProUuid.COMMAND_RSP_UUID + + async def tlv_notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + logger.info(f'Received response at {uuid}: {data.hex(":")}') + + response = responses_by_uuid[uuid] + response.accumulate(data) + + if response.is_received: + # If this is the correct handle, enqueue it for processing + if uuid is response_uuid: + logger.info("Received the get hardware info response") + await received_responses.put(response) + # Anything else is unexpected. This shouldn't happen + else: + logger.error("Unexpected response") + # Reset the per-UUID response + responses_by_uuid[uuid] = TlvResponse(uuid) + + client = await connect_ble(tlv_notification_handler, identifier) + + # Write to command request BleUUID to get the hardware info + logger.info("Getting the camera's hardware info...") + request = bytearray([0x01, 0x3C]) + logger.debug(f"Writing to {request_uuid}: {request.hex(':')}") + await client.write_gatt_char(request_uuid.value, request, response=True) + response = await received_responses.get() + # Parse TLV headers and Payload + response.parse() + # Now parse payload into human readable object + hardware_info = HardwareInfo.from_bytes(response.payload) + logger.info(f"Parsed hardware info: {hardware_info}") + + await client.disconnect() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Connect to a GoPro camera via BLE, then get its hardware info.") + parser.add_argument( + "-i", + "--identifier", + type=str, + help="Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to", + default=None, + ) + args = parser.parse_args() + + try: + asyncio.run(main(args.identifier)) + except Exception as e: # pylint: disable=broad-exception-caught + logger.error(e) + sys.exit(-1) + else: + sys.exit(0) diff --git a/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/ble_command_get_state.py b/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/ble_command_get_state.py deleted file mode 100644 index 17251b96..00000000 --- a/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/ble_command_get_state.py +++ /dev/null @@ -1,157 +0,0 @@ -# ble_command_get_state.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). -# This copyright was auto-generated on Wed, Sep 1, 2021 5:05:59 PM - -import sys -import json -import enum -import asyncio -import argparse -from binascii import hexlify -from typing import Dict, Optional - -from bleak import BleakClient -from bleak.backends.characteristic import BleakGATTCharacteristic - -from tutorial_modules import GOPRO_BASE_UUID, connect_ble, logger - - -class Response: - def __init__(self) -> None: - self.bytes_remaining = 0 - self.bytes = bytearray() - self.data: Dict[int, bytes] = {} - self.id: int - self.status: int - - def __str__(self) -> str: - return json.dumps(self.data, indent=4, default=lambda x: x.hex(":")) - - @property - def is_received(self) -> bool: - return len(self.bytes) > 0 and self.bytes_remaining == 0 - - def accumulate(self, data: bytes) -> None: - CONT_MASK = 0b10000000 - HDR_MASK = 0b01100000 - GEN_LEN_MASK = 0b00011111 - EXT_13_BYTE0_MASK = 0b00011111 - - class Header(enum.Enum): - GENERAL = 0b00 - EXT_13 = 0b01 - EXT_16 = 0b10 - RESERVED = 0b11 - - buf = bytearray(data) - if buf[0] & CONT_MASK: - buf.pop(0) - else: - # This is a new packet so start with an empty byte array - self.bytes = bytearray() - hdr = Header((buf[0] & HDR_MASK) >> 5) - if hdr is Header.GENERAL: - self.bytes_remaining = buf[0] & GEN_LEN_MASK - buf = buf[1:] - elif hdr is Header.EXT_13: - self.bytes_remaining = ((buf[0] & EXT_13_BYTE0_MASK) << 8) + buf[1] - buf = buf[2:] - elif hdr is Header.EXT_16: - self.bytes_remaining = (buf[1] << 8) + buf[2] - buf = buf[3:] - - # Append payload to buffer and update remaining / complete - self.bytes.extend(buf) - self.bytes_remaining -= len(buf) - logger.info(f"{self.bytes_remaining=}") - - def parse(self) -> None: - self.id = self.bytes[0] - self.status = self.bytes[1] - buf = self.bytes[2:] - while len(buf) > 0: - # Get ID and Length - param_id = buf[0] - param_len = buf[1] - buf = buf[2:] - # Get the value - value = buf[:param_len] - - # Store in dict for later access - self.data[param_id] = value - - # Advance the buffer - buf = buf[param_len:] - - -async def main(identifier: Optional[str]) -> None: - # Synchronization event to wait until notification response is received - event = asyncio.Event() - - # UUIDs to write to and receive responses from - QUERY_REQ_UUID = GOPRO_BASE_UUID.format("0076") - QUERY_RSP_UUID = GOPRO_BASE_UUID.format("0077") - response_uuid = QUERY_RSP_UUID - - client: BleakClient - response = Response() - - def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}') - - response.accumulate(data) - - if response.is_received: - response.parse() - - # If this is the correct handle and the status is success, the command was a success - if ( - client.services.characteristics[characteristic.handle].uuid == response_uuid - and response.status == 0 - ): - logger.info("Successfully received the response") - # Anything else is unexpected. This shouldn't happen - else: - logger.error("Unexpected response") - - # Notify writer that procedure is complete - event.set() - - client = await connect_ble(notification_handler, identifier) - - # Write to command request BleUUID to put the camera to sleep - logger.info("Getting the camera's settings...") - event.clear() - await client.write_gatt_char(QUERY_REQ_UUID, bytearray([0x01, 0x12]), response=True) - await event.wait() # Wait to receive the notification response - logger.info(f"Received settings\n: {response}") - - # Write to command request BleUUID to put the camera to sleep - logger.info("Getting the camera's statuses...") - event.clear() - await client.write_gatt_char(QUERY_REQ_UUID, bytearray([0x01, 0x13]), response=True) - await event.wait() # Wait to receive the notification response - logger.info(f"Received statuses\n: {response}") - - await client.disconnect() - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Connect to a GoPro camera via BLE, then get its statuses and settings." - ) - parser.add_argument( - "-i", - "--identifier", - type=str, - help="Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to", - default=None, - ) - args = parser.parse_args() - - try: - asyncio.run(main(args.identifier)) - except Exception as e: - logger.error(e) - sys.exit(-1) - else: - sys.exit(0) diff --git a/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/ble_command_get_version.py b/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/ble_command_get_version.py index ed46bb9f..400168d3 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/ble_command_get_version.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/ble_command_get_version.py @@ -4,47 +4,46 @@ import sys import asyncio import argparse -from typing import Dict, Optional from bleak import BleakClient from bleak.backends.characteristic import BleakGATTCharacteristic -from tutorial_modules import GOPRO_BASE_UUID, connect_ble, logger +from tutorial_modules import GoProUuid, connect_ble, logger -async def main(identifier: Optional[str]) -> None: +async def main(identifier: str | None) -> None: # Synchronization event to wait until notification response is received event = asyncio.Event() - # UUIDs to write to and receive responses from - COMMAND_REQ_UUID = GOPRO_BASE_UUID.format("0072") - COMMAND_RSP_UUID = GOPRO_BASE_UUID.format("0073") - response_uuid = COMMAND_RSP_UUID - client: BleakClient - def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}') + request_uuid = GoProUuid.COMMAND_REQ_UUID + response_uuid = GoProUuid.COMMAND_RSP_UUID + + async def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + logger.info(f'Received response {uuid}: {data.hex(":")}') # If this is the correct handle and the status is success, the command was a success - if client.services.characteristics[characteristic.handle].uuid == response_uuid: - # First byte is the length for this command. + if uuid is response_uuid: + # First byte is the length of this response. length = data[0] # Second byte is the ID command_id = data[1] # Third byte is the status status = data[2] - index = 3 - params = [] - # Remaining bytes are individual values of (length...length bytes) - while index <= length: - param_len = data[index] - index += 1 - params.append(data[index : index + param_len]) - index += param_len - major, minor = params - - logger.info(f"Received a response to {command_id=} with {status=}") + # The remainder is the payload + payload = data[3 : length + 1] + logger.info(f"Received a response to {command_id=} with {status=}, payload={payload.hex(':')}") + + # Now parse the payload from the response documentation + major_length = payload[0] + payload.pop(0) + major = payload[:major_length] + payload.pop(major_length) + minor_length = payload[0] + payload.pop(0) + minor = payload[:minor_length] logger.info(f"The version is Open GoPro {major[0]}.{minor[0]}") # Anything else is unexpected. This shouldn't happen @@ -59,16 +58,15 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - # Write to command request BleUUID to get the Open GoPro Version logger.info("Getting the Open GoPro version...") event.clear() - await client.write_gatt_char(COMMAND_REQ_UUID, bytearray([0x01, 0x51]), response=True) + request = bytes([0x01, 0x51]) + logger.debug(f"Writing to {request_uuid}: {request.hex(':')}") + await client.write_gatt_char(request_uuid.value, request, response=True) await event.wait() # Wait to receive the notification response - await client.disconnect() if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Connect to a GoPro camera via BLE, then get the Open GoPro version." - ) + parser = argparse.ArgumentParser(description="Connect to a GoPro camera via BLE, then get the Open GoPro version.") parser.add_argument( "-i", "--identifier", @@ -80,7 +78,7 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - try: asyncio.run(main(args.identifier)) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught logger.error(e) sys.exit(-1) else: diff --git a/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/__init__.py b/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/__init__.py new file mode 100644 index 00000000..e3af0028 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/__init__.py @@ -0,0 +1,2 @@ +# __init__.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Thu Apr 4 21:50:02 UTC 2024 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/ble_query_poll_multiple_setting_values.py b/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/ble_query_poll_multiple_setting_values.py index bc2b6c6a..4c69192e 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/ble_query_poll_multiple_setting_values.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/ble_query_poll_multiple_setting_values.py @@ -5,29 +5,17 @@ import enum import asyncio import argparse -from typing import Optional from bleak import BleakClient from bleak.backends.characteristic import BleakGATTCharacteristic -from tutorial_modules import GOPRO_BASE_UUID, connect_ble, Response - -from tutorial_modules import logger - - -# Note these may change based on the Open GoPro version! -class Resolution(enum.Enum): - RES_4K = 1 - RES_2_7K = 4 - RES_2_7K_4_3 = 6 - RES_1440 = 7 - RES_1080 = 9 - RES_4K_4_3 = 18 - RES_5K = 24 +from tutorial_modules import GoProUuid, connect_ble, QueryResponse, logger, Resolution # Note these may change based on the Open GoPro version! class FPS(enum.Enum): + """Common Frames-per-second values""" + FPS_240 = 0 FPS_120 = 1 FPS_100 = 2 @@ -40,6 +28,8 @@ class FPS(enum.Enum): # Note these may change based on the Open GoPro version! class VideoFOV(enum.Enum): + """Common Video Field of View values""" + FOV_WIDE = 0 FOV_NARROW = 2 FOV_SUPERVIEW = 3 @@ -48,67 +38,50 @@ class VideoFOV(enum.Enum): FOV_LINEAR_HORIZON_LEVELING = 8 -resolution: Resolution -fps: FPS -video_fov: VideoFOV - - -async def main(identifier: Optional[str]) -> None: - # Synchronization event to wait until notification response is received - event = asyncio.Event() - - # UUIDs to write to and receive responses from - QUERY_REQ_UUID = GOPRO_BASE_UUID.format("0076") - QUERY_RSP_UUID = GOPRO_BASE_UUID.format("0077") - SETTINGS_REQ_UUID = GOPRO_BASE_UUID.format("0074") - SETTINGS_RSP_UUID = GOPRO_BASE_UUID.format("0075") - +async def main(identifier: str | None) -> None: RESOLUTION_ID = 2 FPS_ID = 3 FOV_ID = 121 client: BleakClient - response = Response() + responses_by_uuid = GoProUuid.dict_by_uuid(value_creator=QueryResponse) + received_responses: asyncio.Queue[QueryResponse] = asyncio.Queue() - def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}') + query_request_uuid = GoProUuid.QUERY_REQ_UUID + query_response_uuid = GoProUuid.QUERY_RSP_UUID + async def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + logger.info(f'Received response at {uuid}: {data.hex(":")}') + + response = responses_by_uuid[uuid] response.accumulate(data) # Notify the writer if we have received the entire response if response.is_received: - response.parse() - - # If this is query response, it must contain a resolution value - if client.services.characteristics[characteristic.handle].uuid == QUERY_RSP_UUID: - global resolution - global fps - global video_fov - resolution = Resolution(response.data[RESOLUTION_ID][0]) - fps = FPS(response.data[FPS_ID][0]) - video_fov = VideoFOV(response.data[FOV_ID][0]) - # If this is a setting response, it will just show the status - elif client.services.characteristics[characteristic.handle].uuid == SETTINGS_RSP_UUID: - logger.info("Command sent successfully") + # If this is query response, enqueue it + if uuid is query_response_uuid: + logger.info("Received the Query Response") + await received_responses.put(response) # Anything else is unexpected. This shouldn't happen else: logger.error("Unexpected response") - - # Notify writer that the procedure is complete - event.set() + # Reset the per-uuuid response + responses_by_uuid[uuid] = QueryResponse(uuid) client = await connect_ble(notification_handler, identifier) # Write to query BleUUID to poll the current resolution, fps, and fov - logger.info("Getting the current resolution, fps, and fov,") - event.clear() - await client.write_gatt_char( - QUERY_REQ_UUID, bytearray([0x04, 0x12, RESOLUTION_ID, FPS_ID, FOV_ID]), response=True - ) - await event.wait() # Wait to receive the notification response - logger.info(f"Resolution is currently {resolution}") - logger.info(f"Video FOV is currently {video_fov}") - logger.info(f"FPS is currently {fps}") + logger.info("Getting the current resolution, fps, and fov.") + request = bytes([0x04, 0x12, RESOLUTION_ID, FPS_ID, FOV_ID]) + logger.debug(f"Writing to {query_request_uuid}: {request.hex(':')}") + await client.write_gatt_char(query_request_uuid.value, request, response=True) + response = await received_responses.get() # Wait to receive the notification response + # Parse Query headers and query items + response.parse() + logger.info(f"Resolution is currently {Resolution(response.data[RESOLUTION_ID][0])}") + logger.info(f"Video FOV is currently {VideoFOV(response.data[FOV_ID][0])}") + logger.info(f"FPS is currently {FPS(response.data[FPS_ID][0])}") await client.disconnect() @@ -128,7 +101,7 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - try: asyncio.run(main(args.identifier)) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught logger.error(e) sys.exit(-1) else: diff --git a/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/ble_query_poll_resolution_value.py b/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/ble_query_poll_resolution_value.py index 0e48088a..b559ffea 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/ble_query_poll_resolution_value.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/ble_query_poll_resolution_value.py @@ -5,92 +5,131 @@ import enum import asyncio import argparse -from typing import Optional from bleak import BleakClient from bleak.backends.characteristic import BleakGATTCharacteristic -from tutorial_modules import GOPRO_BASE_UUID, connect_ble, Response +from tutorial_modules import GoProUuid, connect_ble, TlvResponse from tutorial_modules import logger +# Note these may change based on the Open GoPro version! class Resolution(enum.Enum): + """Common Resolution Values""" + RES_4K = 1 RES_2_7K = 4 RES_2_7K_4_3 = 6 + RES_1440 = 7 RES_1080 = 9 RES_4K_4_3 = 18 RES_5K = 24 -resolution: Resolution +class QueryResponse(TlvResponse): + """A TLV Response to a Query Operation. + + Args: + uuid (GoProUuid): _description_ + """ + def __init__(self, uuid: GoProUuid) -> None: + """Constructor""" + super().__init__(uuid) + self.data: dict[int, bytes] = {} -async def main(identifier: Optional[str]) -> None: - # Synchronization event to wait until notification response is received - event = asyncio.Event() + def parse(self) -> None: + """Perform common TLV parsing. Then also parse all Query elements into the data property""" + super().parse() + buf = bytearray(self.payload) + while len(buf) > 0: + # Get ID and Length of query parameter + param_id = buf[0] + param_len = buf[1] + buf = buf[2:] + # Get the value + value = buf[:param_len] + # Store in dict for later access + self.data[param_id] = bytes(value) - # UUIDs to write to and receive responses from - QUERY_REQ_UUID = GOPRO_BASE_UUID.format("0076") - QUERY_RSP_UUID = GOPRO_BASE_UUID.format("0077") - SETTINGS_REQ_UUID = GOPRO_BASE_UUID.format("0074") - SETTINGS_RSP_UUID = GOPRO_BASE_UUID.format("0075") + # Advance the buffer + buf = buf[param_len:] + +async def main(identifier: str | None) -> None: RESOLUTION_ID = 2 client: BleakClient - response = Response() + responses_by_uuid = GoProUuid.dict_by_uuid(QueryResponse) + received_responses: asyncio.Queue[QueryResponse] = asyncio.Queue() + + query_request_uuid = GoProUuid.QUERY_REQ_UUID + query_response_uuid = GoProUuid.QUERY_RSP_UUID + setting_request_uuid = GoProUuid.SETTINGS_REQ_UUID + setting_response_uuid = GoProUuid.SETTINGS_RSP_UUID - def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}') + async def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + logger.info(f'Received response at {uuid}: {data.hex(":")}') + response = responses_by_uuid[uuid] response.accumulate(data) # Notify the writer if we have received the entire response if response.is_received: - response.parse() - # If this is query response, it must contain a resolution value - if client.services.characteristics[characteristic.handle].uuid == QUERY_RSP_UUID: - global resolution - resolution = Resolution(response.data[RESOLUTION_ID][0]) + if uuid is query_response_uuid: + logger.info("Received the Resolution Query response") + await received_responses.put(response) # If this is a setting response, it will just show the status - elif client.services.characteristics[characteristic.handle].uuid == SETTINGS_RSP_UUID: - logger.info("Command sent successfully") + elif uuid is setting_response_uuid: + logger.info("Received Set Setting command response.") + await received_responses.put(response) # Anything else is unexpected. This shouldn't happen else: logger.error("Unexpected response") - - # Notify writer that the procedure is complete - event.set() + # Reset per-uuid response + responses_by_uuid[uuid] = QueryResponse(uuid) client = await connect_ble(notification_handler, identifier) # Write to query BleUUID to poll the current resolution logger.info("Getting the current resolution") - event.clear() - await client.write_gatt_char(QUERY_REQ_UUID, bytearray([0x02, 0x12, RESOLUTION_ID]), response=True) - await event.wait() # Wait to receive the notification response + request = bytes([0x02, 0x12, RESOLUTION_ID]) + logger.debug(f"Writing to {query_request_uuid}: {request.hex(':')}") + await client.write_gatt_char(query_request_uuid.value, request, response=True) + # Wait to receive the notification response + response = await received_responses.get() + response.parse() + resolution = Resolution(response.data[RESOLUTION_ID][0]) logger.info(f"Resolution is currently {resolution}") # Write to command request BleUUID to change the video resolution (either to 1080 or 2.7K) - new_resolution = Resolution.RES_2_7K if resolution is Resolution.RES_1080 else Resolution.RES_1080 - logger.info(f"Changing the resolution to {new_resolution}...") - event.clear() - await client.write_gatt_char( - SETTINGS_REQ_UUID, bytearray([0x03, 0x02, 0x01, new_resolution.value]), response=True - ) - await event.wait() # Wait to receive the notification response + target_resolution = Resolution.RES_2_7K if resolution is Resolution.RES_1080 else Resolution.RES_1080 + logger.info(f"Changing the resolution to {target_resolution}...") + request = bytes([0x03, 0x02, 0x01, target_resolution.value]) + logger.debug(f"Writing to {setting_request_uuid}: {request.hex(':')}") + await client.write_gatt_char(setting_request_uuid.value, request, response=True) + # Wait to receive the notification response + response = await received_responses.get() + response.parse() + # Ensure the setting was successful + assert response.status == 0x00 # Now let's poll again until we see the update occur - while resolution is not new_resolution: + while resolution is not target_resolution: logger.info("Polling the resolution to see if it has changed...") - event.clear() - await client.write_gatt_char(QUERY_REQ_UUID, bytearray([0x02, 0x12, RESOLUTION_ID]), response=True) - await event.wait() # Wait to receive the notification response + request = bytes([0x02, 0x12, RESOLUTION_ID]) + logger.debug(f"Writing to {query_request_uuid}: {request.hex(':')}") + await client.write_gatt_char(query_request_uuid.value, request, response=True) + response = await received_responses.get() # Wait to receive the notification response + response.parse() + resolution = Resolution(response.data[RESOLUTION_ID][0]) logger.info(f"Resolution is currently {resolution}") + logger.info("Resolution has changed as expected. Exiting...") + await client.disconnect() @@ -109,7 +148,7 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - try: asyncio.run(main(args.identifier)) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught logger.error(e) sys.exit(-1) else: diff --git a/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/ble_query_register_resolution_value_updates.py b/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/ble_query_register_resolution_value_updates.py index ad5d05af..1af98270 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/ble_query_register_resolution_value_updates.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/ble_query_register_resolution_value_updates.py @@ -2,95 +2,86 @@ # This copyright was auto-generated on Wed, Sep 1, 2021 5:06:00 PM import sys -import enum import asyncio import argparse -from typing import Optional from bleak import BleakClient from bleak.backends.characteristic import BleakGATTCharacteristic -from tutorial_modules import GOPRO_BASE_UUID, connect_ble, Response +from tutorial_modules import GoProUuid, connect_ble, QueryResponse, Resolution from tutorial_modules import logger -# Note that this may change based on the Open GoPro version! -class Resolution(enum.Enum): - RES_4K = 1 - RES_2_7K = 4 - RES_2_7K_4_3 = 6 - RES_1080 = 9 - RES_4K_4_3 = 18 - RES_5K = 24 - - -resolution: Resolution - - -async def main(identifier: Optional[str]) -> None: - # Synchronization event to wait until notification response is received - event = asyncio.Event() - - # UUIDs to write to and receive responses from - SETTINGS_REQ_UUID = GOPRO_BASE_UUID.format("0074") - SETTINGS_RSP_UUID = GOPRO_BASE_UUID.format("0075") - QUERY_REQ_UUID = GOPRO_BASE_UUID.format("0076") - QUERY_RSP_UUID = GOPRO_BASE_UUID.format("0077") - +async def main(identifier: str | None) -> None: RESOLUTION_ID = 2 client: BleakClient - response = Response() + responses_by_uuid = GoProUuid.dict_by_uuid(QueryResponse) + received_responses: asyncio.Queue[QueryResponse] = asyncio.Queue() - def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}') + query_request_uuid = GoProUuid.QUERY_REQ_UUID + query_response_uuid = GoProUuid.QUERY_RSP_UUID + setting_request_uuid = GoProUuid.SETTINGS_REQ_UUID + setting_response_uuid = GoProUuid.SETTINGS_RSP_UUID + async def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + logger.info(f'Received response at {uuid}: {data.hex(":")}') + + response = responses_by_uuid[uuid] response.accumulate(data) # Notify the writer if we have received the entire response if response.is_received: - response.parse() - # If this is query response, it must contain a resolution value - if client.services.characteristics[characteristic.handle].uuid == QUERY_RSP_UUID: - global resolution - resolution = Resolution(response.data[RESOLUTION_ID][0]) + if uuid is query_response_uuid: + logger.info("Received the Resolution Query response") + await received_responses.put(response) # If this is a setting response, it will just show the status - elif client.services.characteristics[characteristic.handle].uuid == SETTINGS_RSP_UUID: - logger.info("Command sent successfully") + elif uuid is setting_response_uuid: + logger.info("Received Set Setting command response.") + await received_responses.put(response) # Anything else is unexpected. This shouldn't happen else: logger.error("Unexpected response") - - # Notify writer that the procedure is complete - event.set() + # Reset the per-uuid response + responses_by_uuid[uuid] = QueryResponse(uuid) client = await connect_ble(notification_handler, identifier) # Register for updates when resolution value changes logger.info("Registering for resolution updates") - event.clear() - await client.write_gatt_char(QUERY_REQ_UUID, bytearray([0x02, 0x52, RESOLUTION_ID]), response=True) - await event.wait() # Wait to receive the notification response + request = bytes([0x02, 0x52, RESOLUTION_ID]) + logger.debug(f"Writing to {query_request_uuid}: {request.hex(':')}") + await client.write_gatt_char(query_request_uuid.value, request, response=True) + # Wait to receive the notification response + response = await received_responses.get() + response.parse() logger.info("Successfully registered for resolution value updates.") + resolution = Resolution(response.data[RESOLUTION_ID][0]) logger.info(f"Resolution is currently {resolution}") # Write to command request BleUUID to change the video resolution (either to 1080 or 2.7K) new_resolution = Resolution.RES_2_7K if resolution is Resolution.RES_1080 else Resolution.RES_1080 logger.info(f"Changing the resolution to {new_resolution}...") - event.clear() - await client.write_gatt_char( - SETTINGS_REQ_UUID, bytearray([0x03, 0x02, 0x01, new_resolution.value]), response=True - ) - await event.wait() # Wait to receive the notification response - logger.info("Successfully changed the resolution") + request = bytes([0x03, 0x02, 0x01, new_resolution.value]) + logger.debug(f"Writing to {setting_request_uuid}: {request.hex(':')}") + await client.write_gatt_char(setting_request_uuid.value, request, response=True) + # Wait to receive the notification response + response = await received_responses.get() + response.parse() + # Ensure the setting was successful + assert response.status == 0x00 # Let's verify we got the update - while resolution is not new_resolution: - event.clear() - await event.wait() - logger.info(f"Resolution is now {resolution}") + logger.info("Waiting to receive new resolution") + while resolution is not new_resolution and (response := await received_responses.get()): + response.parse() + resolution = Resolution(response.data[RESOLUTION_ID][0]) + logger.info(f"Resolution is currently {resolution}") + + logger.info("Resolution has changed as expected. Exiting...") await client.disconnect() @@ -110,7 +101,7 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - try: asyncio.run(main(args.identifier)) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught logger.error(e) sys.exit(-1) else: diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/__init__.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/__init__.py new file mode 100644 index 00000000..290990ae --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/__init__.py @@ -0,0 +1,2 @@ +# __init__.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/decipher_response.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/decipher_response.py new file mode 100644 index 00000000..98e8a921 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/decipher_response.py @@ -0,0 +1,348 @@ +# set_turbo_mode.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +from __future__ import annotations +import sys +import asyncio +import argparse +from dataclasses import dataclass +from typing import TypeAlias, cast + +from bleak import BleakClient +from bleak.backends.characteristic import BleakGATTCharacteristic +from google.protobuf.message import Message as ProtobufMessage + +from tutorial_modules import logger, proto +from tutorial_modules import GoProUuid, connect_ble, Response, QueryResponse, TlvResponse, ProtobufResponse, Resolution + +RESOLUTION_ID = 2 + + +@dataclass(frozen=True) +class ProtobufId: + """Protobuf feature / action identifier pair.""" + + feature_id: int + action_id: int + + +# From https://gopro.github.io/OpenGoPro/ble/protocol/id_tables.html#protobuf-ids +# TODO automatically generate this and fill out all messages. +ProtobufIdToMessage: dict[ProtobufId, type[ProtobufMessage] | None] = { + ProtobufId(0x02, 0x02): None, + ProtobufId(0x02, 0x04): None, + ProtobufId(0x02, 0x05): None, + ProtobufId(0x02, 0x0B): proto.NotifStartScanning, + ProtobufId(0x02, 0x0C): proto.NotifProvisioningState, + ProtobufId(0x02, 0x82): proto.ResponseStartScanning, + ProtobufId(0x02, 0x83): proto.ResponseGetApEntries, + ProtobufId(0x02, 0x84): proto.ResponseConnect, + ProtobufId(0x02, 0x85): proto.ResponseConnectNew, + ProtobufId(0xF1, 0x64): None, + ProtobufId(0xF1, 0x65): None, + ProtobufId(0xF1, 0x66): None, + ProtobufId(0xF1, 0x67): None, + ProtobufId(0xF1, 0x69): None, + ProtobufId(0xF1, 0x6B): None, + ProtobufId(0xF1, 0x79): None, + ProtobufId(0xF1, 0xE4): None, + ProtobufId(0xF1, 0xE5): None, + ProtobufId(0xF1, 0xE6): proto.ResponseGeneric, + ProtobufId(0xF1, 0xE7): proto.ResponseGeneric, + ProtobufId(0xF1, 0xE9): None, + ProtobufId(0xF1, 0xEB): proto.ResponseGeneric, + ProtobufId(0xF1, 0xF9): None, + ProtobufId(0xF5, 0x6D): None, + ProtobufId(0xF5, 0x6E): None, + ProtobufId(0xF5, 0x6F): None, + ProtobufId(0xF5, 0x72): None, + ProtobufId(0xF5, 0x74): None, + ProtobufId(0xF5, 0xED): None, + ProtobufId(0xF5, 0xEE): proto.ResponseCOHNCert, + ProtobufId(0xF5, 0xEF): proto.ResponseGeneric, + ProtobufId(0xF5, 0xEF): proto.NotifyCOHNStatus, + ProtobufId(0xF5, 0xF2): None, + ProtobufId(0xF5, 0xF3): None, + ProtobufId(0xF5, 0xF4): None, + ProtobufId(0xF5, 0xF5): None, +} + +ConcreteResponse: TypeAlias = ProtobufResponse | QueryResponse | TlvResponse + + +class ResponseManager: + """A wrapper around a BleakClient to manage accumulating, parsing, and retrieving responses. + + Before use, the client must be set via the `set_client` method. + """ + + def __init__(self) -> None: + """Constructor""" + + self._responses_by_uuid = GoProUuid.dict_by_uuid(Response) + self._q: asyncio.Queue[ConcreteResponse] = asyncio.Queue() + self._client: BleakClient | None = None + + def set_client(self, client: BleakClient) -> None: + """Set the client. This is required before use. + + Args: + client (BleakClient): bleak client to use for this manager instance. + """ + self._client = client + + @property + def is_initialized(self) -> bool: + """Has the client been set yet? + + Returns: + bool: True if the client is set. False otherwise. + """ + return self._client is not None + + @property + def client(self) -> BleakClient: + """Get the client. This property assumes that the client has already been set + + Raises: + RuntimeError: Client has not yet been set. + + Returns: + BleakClient: Client associated with this manager. + """ + if not self.is_initialized: + raise RuntimeError("Client has not been set") + return self._client # type: ignore + + def decipher_response(self, undeciphered_response: Response) -> ConcreteResponse: + """Given an undeciphered and unparsed response, decipher its type and parse as much of its payload as is feasible. + + Args: + undeciphered_response (Response): input response to decipher + + Raises: + RuntimeError: Found a Protobuf Response that does not have a defined message for its Feature / Action ID + + Returns: + ConcreteResponse: deciphered and parsed response + """ + payload = undeciphered_response.raw_bytes + # Are the first two payload bytes a real Fetaure / Action ID pair? + response: Response + if (index := ProtobufId(payload[0], payload[1])) in ProtobufIdToMessage: + if not (proto_message := ProtobufIdToMessage.get(index)): + # We've only added protobuf messages for operations used in this tutorial. + raise RuntimeError( + f"{index} is a valid Protobuf identifier but does not currently have a defined message." + ) + # Now use the protobuf messaged identified by the Feature / Action ID pair to parse the remaining payload + response = ProtobufResponse.from_received_response(undeciphered_response) + response.parse(proto_message) + return response + # TLV. Should it be parsed as Command or Query? + if undeciphered_response.uuid is GoProUuid.QUERY_RSP_UUID: + # It's a TLV query + response = QueryResponse.from_received_response(undeciphered_response) + else: + # It's a TLV command / setting. + response = TlvResponse.from_received_response(undeciphered_response) + # Parse the TLV payload (query, command, or setting) + response.parse() + return response + + async def notification_handler(self, characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + """Notification handler to use for the bleak client. + + Args: + characteristic (BleakGATTCharacteristic): characteristic notification was received on + data (bytearray): byte data of notification. + """ + uuid = GoProUuid(self.client.services.characteristics[characteristic.handle].uuid) + logger.debug(f'Received response at {uuid}: {data.hex(":")}') + + response = self._responses_by_uuid[uuid] + response.accumulate(data) + + # Enqueue if we have received the entire response + if response.is_received: + await self._q.put(self.decipher_response(response)) + # Reset the accumulating response + self._responses_by_uuid[uuid] = Response(uuid) + + @classmethod + def assert_generic_protobuf_success(cls, response: ProtobufMessage) -> None: + """Helper method to assert that a ResponseGeneric is successful + + Args: + response (ProtobufMessage): GenericResponse. This must be of type proto.ResponseGeneric + + Raises: + TypeError: response is not of type proto.ResponseGeneric + """ + generic_response = cast(proto.ResponseGeneric, response) + if (result := int(generic_response.result)) != int(proto.EnumResultGeneric.RESULT_SUCCESS): + raise TypeError(f"Received non-success status: {str(result)}") + + async def get_next_response(self) -> ConcreteResponse: + """Get the next received, deciphered, and parsed response from the queue. + + Note! If you know the type of response that you are expecting, use one of the more narrow-typed get methods. + + Returns: + ConcreteResponse: Dequeued response. + """ + return await self._q.get() + + # Helper methods to aid with typing. They are the same at run-time. + + async def get_next_response_as_tlv(self) -> TlvResponse: + """Get the next received, deciphered, and parsed response, casted as a TlvResponse. + + Returns: + TlvResponse: dequeued response + """ + return cast(TlvResponse, await self.get_next_response()) + + async def get_next_response_as_query(self) -> QueryResponse: + """Get the next received, deciphered, and parsed response, casted as a QueryResponse. + + Returns: + QueryResponse: dequeued response + """ + return cast(QueryResponse, await self.get_next_response()) + + async def get_next_response_as_protobuf(self) -> ProtobufResponse: + """Get the next received, deciphered, and parsed response, casted as a ProtobufResponse. + + Returns: + ProtobufResponse: dequeued response + """ + return cast(ProtobufResponse, await self.get_next_response()) + + +async def set_resolution(manager: ResponseManager) -> bool: + """Set the video resolution to 1080 + + Args: + manager (ResponseManager): manager used to perform the operation + + Returns: + bool: True if the setting was successfully set. False otherwise. + """ + logger.info("Setting the video resolution to 1080") + request = bytes([0x03, 0x02, 0x01, 0x09]) + request_uuid = GoProUuid.SETTINGS_REQ_UUID + logger.debug(f"Writing to {request_uuid}: {request.hex(':')}") + await manager.client.write_gatt_char(request_uuid.value, request, response=True) + tlv_response = await manager.get_next_response_as_tlv() + logger.info(f"Set resolution status: {tlv_response.status}") + return tlv_response.status == 0x00 + + +async def set_shutter_off(manager: ResponseManager) -> bool: + """Set the shutter off. + + Args: + manager (ResponseManager): manager used to perform the operation + + Returns: + bool: True if the shutter was successfully set off. False otherwise. + """ + # Write to command request BleUUID to turn the shutter on + logger.info("Setting the shutter on") + request = bytes([3, 1, 1, 0]) + request_uuid = GoProUuid.COMMAND_REQ_UUID + logger.debug(f"Writing to {request_uuid}: {request.hex(':')}") + await manager.client.write_gatt_char(request_uuid.value, request, response=True) + tlv_response = await manager.get_next_response_as_tlv() + logger.info(f"Set shutter status: {tlv_response.status}") + return tlv_response.status == 0x00 + + +async def get_resolution(manager: ResponseManager) -> Resolution: + """Get the current resolution. + + Args: + manager (ResponseManager): manager used to perform the operation + + Returns: + Resolution: The current resolution. + """ + logger.info("Getting the current resolution") + request = bytes([0x02, 0x12, 0x02]) + request_uuid = GoProUuid.QUERY_REQ_UUID + logger.debug(f"Writing to {request_uuid}: {request.hex(':')}") + await manager.client.write_gatt_char(request_uuid.value, request, response=True) + query_response = await manager.get_next_response_as_query() + resolution = Resolution(query_response.data[RESOLUTION_ID][0]) + logger.info(f"Received current resolution: {resolution}") + return resolution + + +async def set_turbo_mode(manager: ResponseManager) -> bool: + """Set the turbo mode off. + + Args: + manager (ResponseManager): manager used to perform the operation + + Returns: + bool: True if the turbo mode was successfully set off. False otherwise. + """ + request = bytearray( + [ + 0xF1, # Feature ID + 0x6B, # Action ID + *proto.RequestSetTurboActive(active=False).SerializeToString(), + ] + ) + request.insert(0, len(request)) + request_uuid = GoProUuid.COMMAND_REQ_UUID + # Write to command request UUID to enable turbo mode + logger.info(f"Writing {request.hex(':')} to {request_uuid}") + await manager.client.write_gatt_char(request_uuid.value, request, response=True) + protobuf_response = await manager.get_next_response_as_protobuf() + generic_response: proto.ResponseGeneric = protobuf_response.data # type: ignore + logger.info(f"Set Turbo Mode Status: {generic_response}") + return generic_response.result == proto.EnumResultGeneric.RESULT_SUCCESS + + +async def main(identifier: str | None) -> None: + manager = ResponseManager() + + try: + manager.set_client(await connect_ble(manager.notification_handler, identifier)) + # TLV Command (Setting) + await set_resolution(manager) + # TLV Command + await get_resolution(manager) + # TLV Query + await set_shutter_off(manager) + # Protobuf + await set_turbo_mode(manager) + except Exception as exc: # pylint: disable=broad-exception-caught + logger.error(repr(exc)) + finally: + if manager.is_initialized: + await manager.client.disconnect() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Connect to a GoPro camera, perform operations to demonstrate various responses types." + ) + parser.add_argument( + "-i", + "--identifier", + type=str, + help="Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to", + default=None, + ) + args = parser.parse_args() + + try: + asyncio.run(main(args.identifier)) + except Exception as e: # pylint: disable=broad-exception-caught + logger.error(e) + sys.exit(-1) + else: + sys.exit(0) diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/__init__.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/__init__.py new file mode 100644 index 00000000..39239c83 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/__init__.py @@ -0,0 +1,31 @@ +# __init__.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +from .cohn_pb2 import ( + ResponseCOHNCert, + NotifyCOHNStatus, + RequestClearCOHNCert, + RequestCOHNCert, + RequestCreateCOHNCert, + RequestGetCOHNStatus, + RequestSetCOHNSetting, + EnumCOHNNetworkState, + EnumCOHNStatus, +) +from .network_management_pb2 import ( + NotifProvisioningState, + NotifStartScanning, + ResponseGetApEntries, + ResponseConnectNew, + RequestConnect, + RequestConnectNew, + RequestGetApEntries, + RequestStartScan, + ResponseConnect, + ResponseStartScanning, + EnumProvisioning, + EnumScanning, + EnumScanEntryFlags, +) +from .response_generic_pb2 import ResponseGeneric, EnumResultGeneric +from .turbo_transfer_pb2 import RequestSetTurboActive diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/cohn_pb2.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/cohn_pb2.py new file mode 100644 index 00000000..2620e29c --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/cohn_pb2.py @@ -0,0 +1,38 @@ +# cohn_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +"""Generated protocol buffer code.""" + +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database + +_sym_db = _symbol_database.Default() +from . import response_generic_pb2 as response__generic__pb2 + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\ncohn.proto\x12\nopen_gopro\x1a\x16response_generic.proto"4\n\x14RequestGetCOHNStatus\x12\x1c\n\x14register_cohn_status\x18\x01 \x01(\x08"\xd9\x01\n\x10NotifyCOHNStatus\x12*\n\x06status\x18\x01 \x01(\x0e2\x1a.open_gopro.EnumCOHNStatus\x12/\n\x05state\x18\x02 \x01(\x0e2 .open_gopro.EnumCOHNNetworkState\x12\x10\n\x08username\x18\x03 \x01(\t\x12\x10\n\x08password\x18\x04 \x01(\t\x12\x11\n\tipaddress\x18\x05 \x01(\t\x12\x0f\n\x07enabled\x18\x06 \x01(\x08\x12\x0c\n\x04ssid\x18\x07 \x01(\t\x12\x12\n\nmacaddress\x18\x08 \x01(\t")\n\x15RequestCreateCOHNCert\x12\x10\n\x08override\x18\x01 \x01(\x08"\x16\n\x14RequestClearCOHNCert"\x11\n\x0fRequestCOHNCert"O\n\x10ResponseCOHNCert\x12-\n\x06result\x18\x01 \x01(\x0e2\x1d.open_gopro.EnumResultGeneric\x12\x0c\n\x04cert\x18\x02 \x01(\t",\n\x15RequestSetCOHNSetting\x12\x13\n\x0bcohn_active\x18\x01 \x01(\x08*>\n\x0eEnumCOHNStatus\x12\x16\n\x12COHN_UNPROVISIONED\x10\x00\x12\x14\n\x10COHN_PROVISIONED\x10\x01*\xec\x01\n\x14EnumCOHNNetworkState\x12\x13\n\x0fCOHN_STATE_Init\x10\x00\x12\x14\n\x10COHN_STATE_Error\x10\x01\x12\x13\n\x0fCOHN_STATE_Exit\x10\x02\x12\x13\n\x0fCOHN_STATE_Idle\x10\x05\x12\x1f\n\x1bCOHN_STATE_NetworkConnected\x10\x1b\x12"\n\x1eCOHN_STATE_NetworkDisconnected\x10\x1c\x12"\n\x1eCOHN_STATE_ConnectingToNetwork\x10\x1d\x12\x16\n\x12COHN_STATE_Invalid\x10\x1e' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "cohn_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMCOHNSTATUS._serialized_start = 537 + _ENUMCOHNSTATUS._serialized_end = 599 + _ENUMCOHNNETWORKSTATE._serialized_start = 602 + _ENUMCOHNNETWORKSTATE._serialized_end = 838 + _REQUESTGETCOHNSTATUS._serialized_start = 50 + _REQUESTGETCOHNSTATUS._serialized_end = 102 + _NOTIFYCOHNSTATUS._serialized_start = 105 + _NOTIFYCOHNSTATUS._serialized_end = 322 + _REQUESTCREATECOHNCERT._serialized_start = 324 + _REQUESTCREATECOHNCERT._serialized_end = 365 + _REQUESTCLEARCOHNCERT._serialized_start = 367 + _REQUESTCLEARCOHNCERT._serialized_end = 389 + _REQUESTCOHNCERT._serialized_start = 391 + _REQUESTCOHNCERT._serialized_end = 408 + _RESPONSECOHNCERT._serialized_start = 410 + _RESPONSECOHNCERT._serialized_end = 489 + _REQUESTSETCOHNSETTING._serialized_start = 491 + _REQUESTSETCOHNSETTING._serialized_end = 535 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/cohn_pb2.pyi b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/cohn_pb2.pyi new file mode 100644 index 00000000..03516118 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/cohn_pb2.pyi @@ -0,0 +1,279 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf messages for Camera On the Home Network +""" + +import builtins +import google.protobuf.descriptor +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +from . import response_generic_pb2 +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumCOHNStatus: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumCOHNStatusEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumCOHNStatus.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + COHN_UNPROVISIONED: _EnumCOHNStatus.ValueType + COHN_PROVISIONED: _EnumCOHNStatus.ValueType + +class EnumCOHNStatus(_EnumCOHNStatus, metaclass=_EnumCOHNStatusEnumTypeWrapper): ... + +COHN_UNPROVISIONED: EnumCOHNStatus.ValueType +COHN_PROVISIONED: EnumCOHNStatus.ValueType +global___EnumCOHNStatus = EnumCOHNStatus + +class _EnumCOHNNetworkState: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumCOHNNetworkStateEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumCOHNNetworkState.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + COHN_STATE_Init: _EnumCOHNNetworkState.ValueType + COHN_STATE_Error: _EnumCOHNNetworkState.ValueType + COHN_STATE_Exit: _EnumCOHNNetworkState.ValueType + COHN_STATE_Idle: _EnumCOHNNetworkState.ValueType + COHN_STATE_NetworkConnected: _EnumCOHNNetworkState.ValueType + COHN_STATE_NetworkDisconnected: _EnumCOHNNetworkState.ValueType + COHN_STATE_ConnectingToNetwork: _EnumCOHNNetworkState.ValueType + COHN_STATE_Invalid: _EnumCOHNNetworkState.ValueType + +class EnumCOHNNetworkState(_EnumCOHNNetworkState, metaclass=_EnumCOHNNetworkStateEnumTypeWrapper): ... + +COHN_STATE_Init: EnumCOHNNetworkState.ValueType +COHN_STATE_Error: EnumCOHNNetworkState.ValueType +COHN_STATE_Exit: EnumCOHNNetworkState.ValueType +COHN_STATE_Idle: EnumCOHNNetworkState.ValueType +COHN_STATE_NetworkConnected: EnumCOHNNetworkState.ValueType +COHN_STATE_NetworkDisconnected: EnumCOHNNetworkState.ValueType +COHN_STATE_ConnectingToNetwork: EnumCOHNNetworkState.ValueType +COHN_STATE_Invalid: EnumCOHNNetworkState.ValueType +global___EnumCOHNNetworkState = EnumCOHNNetworkState + +@typing_extensions.final +class RequestGetCOHNStatus(google.protobuf.message.Message): + """* + Get the current COHN status. + + Response: @ref NotifyCOHNStatus + + Additionally, asynchronous updates can also be registered to return more @ref NotifyCOHNStatus when a value + changes. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + REGISTER_COHN_STATUS_FIELD_NUMBER: builtins.int + register_cohn_status: builtins.bool + "1 to register, 0 to unregister" + + def __init__(self, *, register_cohn_status: builtins.bool | None = ...) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["register_cohn_status", b"register_cohn_status"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["register_cohn_status", b"register_cohn_status"], + ) -> None: ... + +global___RequestGetCOHNStatus = RequestGetCOHNStatus + +@typing_extensions.final +class NotifyCOHNStatus(google.protobuf.message.Message): + """ + Current COHN status triggered by a @ref RequestGetCOHNStatus + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + STATUS_FIELD_NUMBER: builtins.int + STATE_FIELD_NUMBER: builtins.int + USERNAME_FIELD_NUMBER: builtins.int + PASSWORD_FIELD_NUMBER: builtins.int + IPADDRESS_FIELD_NUMBER: builtins.int + ENABLED_FIELD_NUMBER: builtins.int + SSID_FIELD_NUMBER: builtins.int + MACADDRESS_FIELD_NUMBER: builtins.int + status: global___EnumCOHNStatus.ValueType + "Current COHN status" + state: global___EnumCOHNNetworkState.ValueType + "Current COHN network state" + username: builtins.str + "Username used for http basic auth header" + password: builtins.str + "Password used for http basic auth header" + ipaddress: builtins.str + "Camera's IP address on the local network" + enabled: builtins.bool + "Is COHN currently enabled?" + ssid: builtins.str + "Currently connected SSID" + macaddress: builtins.str + "MAC address of the wifi adapter" + + def __init__( + self, + *, + status: global___EnumCOHNStatus.ValueType | None = ..., + state: global___EnumCOHNNetworkState.ValueType | None = ..., + username: builtins.str | None = ..., + password: builtins.str | None = ..., + ipaddress: builtins.str | None = ..., + enabled: builtins.bool | None = ..., + ssid: builtins.str | None = ..., + macaddress: builtins.str | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "enabled", + b"enabled", + "ipaddress", + b"ipaddress", + "macaddress", + b"macaddress", + "password", + b"password", + "ssid", + b"ssid", + "state", + b"state", + "status", + b"status", + "username", + b"username", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "enabled", + b"enabled", + "ipaddress", + b"ipaddress", + "macaddress", + b"macaddress", + "password", + b"password", + "ssid", + b"ssid", + "state", + b"state", + "status", + b"status", + "username", + b"username", + ], + ) -> None: ... + +global___NotifyCOHNStatus = NotifyCOHNStatus + +@typing_extensions.final +class RequestCreateCOHNCert(google.protobuf.message.Message): + """* + Create the Camera On the Home Network SSL/TLS certificate. + + Returns a @ref ResponseGeneric with the status of the creation + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + OVERRIDE_FIELD_NUMBER: builtins.int + override: builtins.bool + "Override current provisioning and create new cert" + + def __init__(self, *, override: builtins.bool | None = ...) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["override", b"override"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["override", b"override"]) -> None: ... + +global___RequestCreateCOHNCert = RequestCreateCOHNCert + +@typing_extensions.final +class RequestClearCOHNCert(google.protobuf.message.Message): + """* + Clear the COHN certificate. + + Returns a @ref ResponseGeneric with the status of the clear + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__(self) -> None: ... + +global___RequestClearCOHNCert = RequestClearCOHNCert + +@typing_extensions.final +class RequestCOHNCert(google.protobuf.message.Message): + """* + Get the COHN certificate. + + Returns a @ref ResponseCOHNCert + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__(self) -> None: ... + +global___RequestCOHNCert = RequestCOHNCert + +@typing_extensions.final +class ResponseCOHNCert(google.protobuf.message.Message): + """ + COHN Certificate response triggered by @ref RequestCOHNCert + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + RESULT_FIELD_NUMBER: builtins.int + CERT_FIELD_NUMBER: builtins.int + result: response_generic_pb2.EnumResultGeneric.ValueType + "Was request successful?" + cert: builtins.str + "Root CA cert (ASCII text)" + + def __init__( + self, *, result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., cert: builtins.str | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["cert", b"cert", "result", b"result"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["cert", b"cert", "result", b"result"], + ) -> None: ... + +global___ResponseCOHNCert = ResponseCOHNCert + +@typing_extensions.final +class RequestSetCOHNSetting(google.protobuf.message.Message): + """* + Configure a COHN Setting + + Returns a @ref ResponseGeneric + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + COHN_ACTIVE_FIELD_NUMBER: builtins.int + cohn_active: builtins.bool + "*\n 1 to enable COHN, 0 to disable COHN\n\n When set to 1, STA Mode connection will be dropped and camera will not automatically re-connect for COHN.\n " + + def __init__(self, *, cohn_active: builtins.bool | None = ...) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["cohn_active", b"cohn_active"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["cohn_active", b"cohn_active"]) -> None: ... + +global___RequestSetCOHNSetting = RequestSetCOHNSetting diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/live_streaming_pb2.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/live_streaming_pb2.py new file mode 100644 index 00000000..8319589e --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/live_streaming_pb2.py @@ -0,0 +1,34 @@ +# live_streaming_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +"""Generated protocol buffer code.""" + +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database + +_sym_db = _symbol_database.Default() +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x14live_streaming.proto\x12\nopen_gopro"\xa4\x04\n\x16NotifyLiveStreamStatus\x12<\n\x12live_stream_status\x18\x01 \x01(\x0e2 .open_gopro.EnumLiveStreamStatus\x12:\n\x11live_stream_error\x18\x02 \x01(\x0e2\x1f.open_gopro.EnumLiveStreamError\x12\x1a\n\x12live_stream_encode\x18\x03 \x01(\x08\x12\x1b\n\x13live_stream_bitrate\x18\x04 \x01(\x05\x12K\n\'live_stream_window_size_supported_array\x18\x05 \x03(\x0e2\x1a.open_gopro.EnumWindowSize\x12$\n\x1clive_stream_encode_supported\x18\x06 \x01(\x08\x12(\n live_stream_max_lens_unsupported\x18\x07 \x01(\x08\x12*\n"live_stream_minimum_stream_bitrate\x18\x08 \x01(\x05\x12*\n"live_stream_maximum_stream_bitrate\x18\t \x01(\x05\x12"\n\x1alive_stream_lens_supported\x18\n \x01(\x08\x12>\n live_stream_lens_supported_array\x18\x0b \x03(\x0e2\x14.open_gopro.EnumLens"\xbc\x01\n\x1aRequestGetLiveStreamStatus\x12M\n\x1bregister_live_stream_status\x18\x01 \x03(\x0e2(.open_gopro.EnumRegisterLiveStreamStatus\x12O\n\x1dunregister_live_stream_status\x18\x02 \x03(\x0e2(.open_gopro.EnumRegisterLiveStreamStatus"\xe6\x01\n\x18RequestSetLiveStreamMode\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x0e\n\x06encode\x18\x02 \x01(\x08\x12/\n\x0bwindow_size\x18\x03 \x01(\x0e2\x1a.open_gopro.EnumWindowSize\x12\x0c\n\x04cert\x18\x06 \x01(\x0c\x12\x17\n\x0fminimum_bitrate\x18\x07 \x01(\x05\x12\x17\n\x0fmaximum_bitrate\x18\x08 \x01(\x05\x12\x18\n\x10starting_bitrate\x18\t \x01(\x05\x12"\n\x04lens\x18\n \x01(\x0e2\x14.open_gopro.EnumLens*>\n\x08EnumLens\x12\r\n\tLENS_WIDE\x10\x00\x12\x0f\n\x0bLENS_LINEAR\x10\x04\x12\x12\n\x0eLENS_SUPERVIEW\x10\x03*\xde\x03\n\x13EnumLiveStreamError\x12\x1a\n\x16LIVE_STREAM_ERROR_NONE\x10\x00\x12\x1d\n\x19LIVE_STREAM_ERROR_NETWORK\x10\x01\x12"\n\x1eLIVE_STREAM_ERROR_CREATESTREAM\x10\x02\x12!\n\x1dLIVE_STREAM_ERROR_OUTOFMEMORY\x10\x03\x12!\n\x1dLIVE_STREAM_ERROR_INPUTSTREAM\x10\x04\x12\x1e\n\x1aLIVE_STREAM_ERROR_INTERNET\x10\x05\x12\x1f\n\x1bLIVE_STREAM_ERROR_OSNETWORK\x10\x06\x12,\n(LIVE_STREAM_ERROR_SELECTEDNETWORKTIMEOUT\x10\x07\x12#\n\x1fLIVE_STREAM_ERROR_SSL_HANDSHAKE\x10\x08\x12$\n LIVE_STREAM_ERROR_CAMERA_BLOCKED\x10\t\x12\x1d\n\x19LIVE_STREAM_ERROR_UNKNOWN\x10\n\x12"\n\x1eLIVE_STREAM_ERROR_SD_CARD_FULL\x10(\x12%\n!LIVE_STREAM_ERROR_SD_CARD_REMOVED\x10)*\x80\x02\n\x14EnumLiveStreamStatus\x12\x1a\n\x16LIVE_STREAM_STATE_IDLE\x10\x00\x12\x1c\n\x18LIVE_STREAM_STATE_CONFIG\x10\x01\x12\x1b\n\x17LIVE_STREAM_STATE_READY\x10\x02\x12\x1f\n\x1bLIVE_STREAM_STATE_STREAMING\x10\x03\x12&\n"LIVE_STREAM_STATE_COMPLETE_STAY_ON\x10\x04\x12$\n LIVE_STREAM_STATE_FAILED_STAY_ON\x10\x05\x12"\n\x1eLIVE_STREAM_STATE_RECONNECTING\x10\x06*\xbc\x01\n\x1cEnumRegisterLiveStreamStatus\x12&\n"REGISTER_LIVE_STREAM_STATUS_STATUS\x10\x01\x12%\n!REGISTER_LIVE_STREAM_STATUS_ERROR\x10\x02\x12$\n REGISTER_LIVE_STREAM_STATUS_MODE\x10\x03\x12\'\n#REGISTER_LIVE_STREAM_STATUS_BITRATE\x10\x04*P\n\x0eEnumWindowSize\x12\x13\n\x0fWINDOW_SIZE_480\x10\x04\x12\x13\n\x0fWINDOW_SIZE_720\x10\x07\x12\x14\n\x10WINDOW_SIZE_1080\x10\x0c' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "live_streaming_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMLENS._serialized_start = 1011 + _ENUMLENS._serialized_end = 1073 + _ENUMLIVESTREAMERROR._serialized_start = 1076 + _ENUMLIVESTREAMERROR._serialized_end = 1554 + _ENUMLIVESTREAMSTATUS._serialized_start = 1557 + _ENUMLIVESTREAMSTATUS._serialized_end = 1813 + _ENUMREGISTERLIVESTREAMSTATUS._serialized_start = 1816 + _ENUMREGISTERLIVESTREAMSTATUS._serialized_end = 2004 + _ENUMWINDOWSIZE._serialized_start = 2006 + _ENUMWINDOWSIZE._serialized_end = 2086 + _NOTIFYLIVESTREAMSTATUS._serialized_start = 37 + _NOTIFYLIVESTREAMSTATUS._serialized_end = 585 + _REQUESTGETLIVESTREAMSTATUS._serialized_start = 588 + _REQUESTGETLIVESTREAMSTATUS._serialized_end = 776 + _REQUESTSETLIVESTREAMMODE._serialized_start = 779 + _REQUESTSETLIVESTREAMMODE._serialized_end = 1009 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/live_streaming_pb2.pyi b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/live_streaming_pb2.pyi new file mode 100644 index 00000000..1eb9200f --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/live_streaming_pb2.pyi @@ -0,0 +1,461 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf messages for working with Live Streams +""" + +import builtins +import collections.abc +import google.protobuf.descriptor +import google.protobuf.internal.containers +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumLens: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumLensEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumLens.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + LENS_WIDE: _EnumLens.ValueType + LENS_LINEAR: _EnumLens.ValueType + LENS_SUPERVIEW: _EnumLens.ValueType + +class EnumLens(_EnumLens, metaclass=_EnumLensEnumTypeWrapper): ... + +LENS_WIDE: EnumLens.ValueType +LENS_LINEAR: EnumLens.ValueType +LENS_SUPERVIEW: EnumLens.ValueType +global___EnumLens = EnumLens + +class _EnumLiveStreamError: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumLiveStreamErrorEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumLiveStreamError.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + LIVE_STREAM_ERROR_NONE: _EnumLiveStreamError.ValueType + "No error (success)" + LIVE_STREAM_ERROR_NETWORK: _EnumLiveStreamError.ValueType + "General network error during the stream" + LIVE_STREAM_ERROR_CREATESTREAM: _EnumLiveStreamError.ValueType + "Startup error: bad URL or valid with live stream server" + LIVE_STREAM_ERROR_OUTOFMEMORY: _EnumLiveStreamError.ValueType + "Not enough memory on camera to complete task" + LIVE_STREAM_ERROR_INPUTSTREAM: _EnumLiveStreamError.ValueType + "Failed to get stream from low level camera system" + LIVE_STREAM_ERROR_INTERNET: _EnumLiveStreamError.ValueType + "No internet access detected on startup of streamer" + LIVE_STREAM_ERROR_OSNETWORK: _EnumLiveStreamError.ValueType + "Error occured in linux networking stack. Usually means the server closed the connection" + LIVE_STREAM_ERROR_SELECTEDNETWORKTIMEOUT: _EnumLiveStreamError.ValueType + "Timed out attemping to connect to the wifi network when attemping live stream" + LIVE_STREAM_ERROR_SSL_HANDSHAKE: _EnumLiveStreamError.ValueType + "SSL handshake failed (commonly caused due to incorrect time / time zone)" + LIVE_STREAM_ERROR_CAMERA_BLOCKED: _EnumLiveStreamError.ValueType + "Low level camera system rejected attempt to start live stream" + LIVE_STREAM_ERROR_UNKNOWN: _EnumLiveStreamError.ValueType + "Unknown" + LIVE_STREAM_ERROR_SD_CARD_FULL: _EnumLiveStreamError.ValueType + "Can not perform livestream because sd card is full" + LIVE_STREAM_ERROR_SD_CARD_REMOVED: _EnumLiveStreamError.ValueType + "Livestream stopped because sd card was removed" + +class EnumLiveStreamError(_EnumLiveStreamError, metaclass=_EnumLiveStreamErrorEnumTypeWrapper): ... + +LIVE_STREAM_ERROR_NONE: EnumLiveStreamError.ValueType +"No error (success)" +LIVE_STREAM_ERROR_NETWORK: EnumLiveStreamError.ValueType +"General network error during the stream" +LIVE_STREAM_ERROR_CREATESTREAM: EnumLiveStreamError.ValueType +"Startup error: bad URL or valid with live stream server" +LIVE_STREAM_ERROR_OUTOFMEMORY: EnumLiveStreamError.ValueType +"Not enough memory on camera to complete task" +LIVE_STREAM_ERROR_INPUTSTREAM: EnumLiveStreamError.ValueType +"Failed to get stream from low level camera system" +LIVE_STREAM_ERROR_INTERNET: EnumLiveStreamError.ValueType +"No internet access detected on startup of streamer" +LIVE_STREAM_ERROR_OSNETWORK: EnumLiveStreamError.ValueType +"Error occured in linux networking stack. Usually means the server closed the connection" +LIVE_STREAM_ERROR_SELECTEDNETWORKTIMEOUT: EnumLiveStreamError.ValueType +"Timed out attemping to connect to the wifi network when attemping live stream" +LIVE_STREAM_ERROR_SSL_HANDSHAKE: EnumLiveStreamError.ValueType +"SSL handshake failed (commonly caused due to incorrect time / time zone)" +LIVE_STREAM_ERROR_CAMERA_BLOCKED: EnumLiveStreamError.ValueType +"Low level camera system rejected attempt to start live stream" +LIVE_STREAM_ERROR_UNKNOWN: EnumLiveStreamError.ValueType +"Unknown" +LIVE_STREAM_ERROR_SD_CARD_FULL: EnumLiveStreamError.ValueType +"Can not perform livestream because sd card is full" +LIVE_STREAM_ERROR_SD_CARD_REMOVED: EnumLiveStreamError.ValueType +"Livestream stopped because sd card was removed" +global___EnumLiveStreamError = EnumLiveStreamError + +class _EnumLiveStreamStatus: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumLiveStreamStatusEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumLiveStreamStatus.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + LIVE_STREAM_STATE_IDLE: _EnumLiveStreamStatus.ValueType + "Initial status. Livestream has not yet been configured" + LIVE_STREAM_STATE_CONFIG: _EnumLiveStreamStatus.ValueType + "Livestream is being configured" + LIVE_STREAM_STATE_READY: _EnumLiveStreamStatus.ValueType + "\n Livestream has finished configuration and is ready to start streaming\n " + LIVE_STREAM_STATE_STREAMING: _EnumLiveStreamStatus.ValueType + "Livestream is actively streaming" + LIVE_STREAM_STATE_COMPLETE_STAY_ON: _EnumLiveStreamStatus.ValueType + "Live stream is exiting. No errors occured." + LIVE_STREAM_STATE_FAILED_STAY_ON: _EnumLiveStreamStatus.ValueType + "Live stream is exiting. An error occurred." + LIVE_STREAM_STATE_RECONNECTING: _EnumLiveStreamStatus.ValueType + "An error occurred during livestream and stream is attempting to reconnect." + +class EnumLiveStreamStatus(_EnumLiveStreamStatus, metaclass=_EnumLiveStreamStatusEnumTypeWrapper): ... + +LIVE_STREAM_STATE_IDLE: EnumLiveStreamStatus.ValueType +"Initial status. Livestream has not yet been configured" +LIVE_STREAM_STATE_CONFIG: EnumLiveStreamStatus.ValueType +"Livestream is being configured" +LIVE_STREAM_STATE_READY: EnumLiveStreamStatus.ValueType +"\nLivestream has finished configuration and is ready to start streaming\n" +LIVE_STREAM_STATE_STREAMING: EnumLiveStreamStatus.ValueType +"Livestream is actively streaming" +LIVE_STREAM_STATE_COMPLETE_STAY_ON: EnumLiveStreamStatus.ValueType +"Live stream is exiting. No errors occured." +LIVE_STREAM_STATE_FAILED_STAY_ON: EnumLiveStreamStatus.ValueType +"Live stream is exiting. An error occurred." +LIVE_STREAM_STATE_RECONNECTING: EnumLiveStreamStatus.ValueType +"An error occurred during livestream and stream is attempting to reconnect." +global___EnumLiveStreamStatus = EnumLiveStreamStatus + +class _EnumRegisterLiveStreamStatus: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumRegisterLiveStreamStatusEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumRegisterLiveStreamStatus.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + REGISTER_LIVE_STREAM_STATUS_STATUS: _EnumRegisterLiveStreamStatus.ValueType + REGISTER_LIVE_STREAM_STATUS_ERROR: _EnumRegisterLiveStreamStatus.ValueType + REGISTER_LIVE_STREAM_STATUS_MODE: _EnumRegisterLiveStreamStatus.ValueType + REGISTER_LIVE_STREAM_STATUS_BITRATE: _EnumRegisterLiveStreamStatus.ValueType + +class EnumRegisterLiveStreamStatus( + _EnumRegisterLiveStreamStatus, + metaclass=_EnumRegisterLiveStreamStatusEnumTypeWrapper, +): ... + +REGISTER_LIVE_STREAM_STATUS_STATUS: EnumRegisterLiveStreamStatus.ValueType +REGISTER_LIVE_STREAM_STATUS_ERROR: EnumRegisterLiveStreamStatus.ValueType +REGISTER_LIVE_STREAM_STATUS_MODE: EnumRegisterLiveStreamStatus.ValueType +REGISTER_LIVE_STREAM_STATUS_BITRATE: EnumRegisterLiveStreamStatus.ValueType +global___EnumRegisterLiveStreamStatus = EnumRegisterLiveStreamStatus + +class _EnumWindowSize: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumWindowSizeEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumWindowSize.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + WINDOW_SIZE_480: _EnumWindowSize.ValueType + WINDOW_SIZE_720: _EnumWindowSize.ValueType + WINDOW_SIZE_1080: _EnumWindowSize.ValueType + +class EnumWindowSize(_EnumWindowSize, metaclass=_EnumWindowSizeEnumTypeWrapper): ... + +WINDOW_SIZE_480: EnumWindowSize.ValueType +WINDOW_SIZE_720: EnumWindowSize.ValueType +WINDOW_SIZE_1080: EnumWindowSize.ValueType +global___EnumWindowSize = EnumWindowSize + +@typing_extensions.final +class NotifyLiveStreamStatus(google.protobuf.message.Message): + """* + Live Stream status + + Sent either: + + - As a synchronous response to initial @ref RequestGetLiveStreamStatus + - As an asynchronous notifications registered for via @ref RequestGetLiveStreamStatus + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + LIVE_STREAM_STATUS_FIELD_NUMBER: builtins.int + LIVE_STREAM_ERROR_FIELD_NUMBER: builtins.int + LIVE_STREAM_ENCODE_FIELD_NUMBER: builtins.int + LIVE_STREAM_BITRATE_FIELD_NUMBER: builtins.int + LIVE_STREAM_WINDOW_SIZE_SUPPORTED_ARRAY_FIELD_NUMBER: builtins.int + LIVE_STREAM_ENCODE_SUPPORTED_FIELD_NUMBER: builtins.int + LIVE_STREAM_MAX_LENS_UNSUPPORTED_FIELD_NUMBER: builtins.int + LIVE_STREAM_MINIMUM_STREAM_BITRATE_FIELD_NUMBER: builtins.int + LIVE_STREAM_MAXIMUM_STREAM_BITRATE_FIELD_NUMBER: builtins.int + LIVE_STREAM_LENS_SUPPORTED_FIELD_NUMBER: builtins.int + LIVE_STREAM_LENS_SUPPORTED_ARRAY_FIELD_NUMBER: builtins.int + live_stream_status: global___EnumLiveStreamStatus.ValueType + "Live stream status" + live_stream_error: global___EnumLiveStreamError.ValueType + "Live stream error" + live_stream_encode: builtins.bool + "Is live stream encoding?" + live_stream_bitrate: builtins.int + "Live stream bitrate (Kbps)" + + @property + def live_stream_window_size_supported_array( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___EnumWindowSize.ValueType]: + """Set of currently supported resolutions""" + live_stream_encode_supported: builtins.bool + "Does the camera support encoding while live streaming?" + live_stream_max_lens_unsupported: builtins.bool + "Is the Max Lens feature NOT supported?" + live_stream_minimum_stream_bitrate: builtins.int + "Camera-defined minimum bitrate (static) (Kbps)" + live_stream_maximum_stream_bitrate: builtins.int + "Camera-defined maximum bitrate (static) (Kbps)" + live_stream_lens_supported: builtins.bool + "Does camera support setting lens for live streaming?" + + @property + def live_stream_lens_supported_array( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___EnumLens.ValueType]: + """Set of currently supported FOV options""" + + def __init__( + self, + *, + live_stream_status: global___EnumLiveStreamStatus.ValueType | None = ..., + live_stream_error: global___EnumLiveStreamError.ValueType | None = ..., + live_stream_encode: builtins.bool | None = ..., + live_stream_bitrate: builtins.int | None = ..., + live_stream_window_size_supported_array: ( + collections.abc.Iterable[global___EnumWindowSize.ValueType] | None + ) = ..., + live_stream_encode_supported: builtins.bool | None = ..., + live_stream_max_lens_unsupported: builtins.bool | None = ..., + live_stream_minimum_stream_bitrate: builtins.int | None = ..., + live_stream_maximum_stream_bitrate: builtins.int | None = ..., + live_stream_lens_supported: builtins.bool | None = ..., + live_stream_lens_supported_array: collections.abc.Iterable[global___EnumLens.ValueType] | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "live_stream_bitrate", + b"live_stream_bitrate", + "live_stream_encode", + b"live_stream_encode", + "live_stream_encode_supported", + b"live_stream_encode_supported", + "live_stream_error", + b"live_stream_error", + "live_stream_lens_supported", + b"live_stream_lens_supported", + "live_stream_max_lens_unsupported", + b"live_stream_max_lens_unsupported", + "live_stream_maximum_stream_bitrate", + b"live_stream_maximum_stream_bitrate", + "live_stream_minimum_stream_bitrate", + b"live_stream_minimum_stream_bitrate", + "live_stream_status", + b"live_stream_status", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "live_stream_bitrate", + b"live_stream_bitrate", + "live_stream_encode", + b"live_stream_encode", + "live_stream_encode_supported", + b"live_stream_encode_supported", + "live_stream_error", + b"live_stream_error", + "live_stream_lens_supported", + b"live_stream_lens_supported", + "live_stream_lens_supported_array", + b"live_stream_lens_supported_array", + "live_stream_max_lens_unsupported", + b"live_stream_max_lens_unsupported", + "live_stream_maximum_stream_bitrate", + b"live_stream_maximum_stream_bitrate", + "live_stream_minimum_stream_bitrate", + b"live_stream_minimum_stream_bitrate", + "live_stream_status", + b"live_stream_status", + "live_stream_window_size_supported_array", + b"live_stream_window_size_supported_array", + ], + ) -> None: ... + +global___NotifyLiveStreamStatus = NotifyLiveStreamStatus + +@typing_extensions.final +class RequestGetLiveStreamStatus(google.protobuf.message.Message): + """* + Get the current livestream status (and optionally register for future status changes) + + Response: @ref NotifyLiveStreamStatus + + Notification: @ref NotifyLiveStreamStatus + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + REGISTER_LIVE_STREAM_STATUS_FIELD_NUMBER: builtins.int + UNREGISTER_LIVE_STREAM_STATUS_FIELD_NUMBER: builtins.int + + @property + def register_live_stream_status( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[ + global___EnumRegisterLiveStreamStatus.ValueType + ]: + """Array of live stream statuses to be notified about""" + + @property + def unregister_live_stream_status( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[ + global___EnumRegisterLiveStreamStatus.ValueType + ]: + """Array of live stream statuses to stop being notified about""" + + def __init__( + self, + *, + register_live_stream_status: ( + collections.abc.Iterable[global___EnumRegisterLiveStreamStatus.ValueType] | None + ) = ..., + unregister_live_stream_status: ( + collections.abc.Iterable[global___EnumRegisterLiveStreamStatus.ValueType] | None + ) = ... + ) -> None: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "register_live_stream_status", + b"register_live_stream_status", + "unregister_live_stream_status", + b"unregister_live_stream_status", + ], + ) -> None: ... + +global___RequestGetLiveStreamStatus = RequestGetLiveStreamStatus + +@typing_extensions.final +class RequestSetLiveStreamMode(google.protobuf.message.Message): + """* + Configure Live Streaming + + Response: @ref ResponseGeneric + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + URL_FIELD_NUMBER: builtins.int + ENCODE_FIELD_NUMBER: builtins.int + WINDOW_SIZE_FIELD_NUMBER: builtins.int + CERT_FIELD_NUMBER: builtins.int + MINIMUM_BITRATE_FIELD_NUMBER: builtins.int + MAXIMUM_BITRATE_FIELD_NUMBER: builtins.int + STARTING_BITRATE_FIELD_NUMBER: builtins.int + LENS_FIELD_NUMBER: builtins.int + url: builtins.str + "RTMP(S) URL used for live stream" + encode: builtins.bool + "Save media to sdcard while streaming?" + window_size: global___EnumWindowSize.ValueType + "*\n Resolution to use for live stream\n\n The set of supported lenses is only available from the `live_stream_window_size_supported_array` in @ref NotifyLiveStreamStatus)\n " + cert: builtins.bytes + "Certificate for servers that require it in PEM format" + minimum_bitrate: builtins.int + "Minimum desired bitrate (may or may not be honored)" + maximum_bitrate: builtins.int + "Maximum desired bitrate (may or may not be honored)" + starting_bitrate: builtins.int + "Starting bitrate" + lens: global___EnumLens.ValueType + "*\n Lens to use for live stream\n\n The set of supported lenses is only available from the `live_stream_lens_supported_array` in @ref NotifyLiveStreamStatus)\n " + + def __init__( + self, + *, + url: builtins.str | None = ..., + encode: builtins.bool | None = ..., + window_size: global___EnumWindowSize.ValueType | None = ..., + cert: builtins.bytes | None = ..., + minimum_bitrate: builtins.int | None = ..., + maximum_bitrate: builtins.int | None = ..., + starting_bitrate: builtins.int | None = ..., + lens: global___EnumLens.ValueType | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "cert", + b"cert", + "encode", + b"encode", + "lens", + b"lens", + "maximum_bitrate", + b"maximum_bitrate", + "minimum_bitrate", + b"minimum_bitrate", + "starting_bitrate", + b"starting_bitrate", + "url", + b"url", + "window_size", + b"window_size", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "cert", + b"cert", + "encode", + b"encode", + "lens", + b"lens", + "maximum_bitrate", + b"maximum_bitrate", + "minimum_bitrate", + b"minimum_bitrate", + "starting_bitrate", + b"starting_bitrate", + "url", + b"url", + "window_size", + b"window_size", + ], + ) -> None: ... + +global___RequestSetLiveStreamMode = RequestSetLiveStreamMode diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/media_pb2.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/media_pb2.py new file mode 100644 index 00000000..94d1fef3 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/media_pb2.py @@ -0,0 +1,24 @@ +# media_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +"""Generated protocol buffer code.""" + +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database + +_sym_db = _symbol_database.Default() +from . import response_generic_pb2 as response__generic__pb2 + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x0bmedia.proto\x12\nopen_gopro\x1a\x16response_generic.proto"\x1d\n\x1bRequestGetLastCapturedMedia"l\n\x19ResponseLastCapturedMedia\x12-\n\x06result\x18\x01 \x01(\x0e2\x1d.open_gopro.EnumResultGeneric\x12 \n\x05media\x18\x02 \x01(\x0b2\x11.open_gopro.Media' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "media_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _REQUESTGETLASTCAPTUREDMEDIA._serialized_start = 51 + _REQUESTGETLASTCAPTUREDMEDIA._serialized_end = 80 + _RESPONSELASTCAPTUREDMEDIA._serialized_start = 82 + _RESPONSELASTCAPTUREDMEDIA._serialized_end = 190 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/media_pb2.pyi b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/media_pb2.pyi new file mode 100644 index 00000000..6de33cc0 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/media_pb2.pyi @@ -0,0 +1,75 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Commands to query and manipulate media files +""" + +import builtins +import google.protobuf.descriptor +import google.protobuf.message +from . import response_generic_pb2 +import sys + +if sys.version_info >= (3, 8): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +@typing_extensions.final +class RequestGetLastCapturedMedia(google.protobuf.message.Message): + """* + Get the last captured media filename + + Returns a @ref ResponseLastCapturedMedia + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__(self) -> None: ... + +global___RequestGetLastCapturedMedia = RequestGetLastCapturedMedia + +@typing_extensions.final +class ResponseLastCapturedMedia(google.protobuf.message.Message): + """* + The Last Captured Media + + Message is sent in response to a @ref RequestGetLastCapturedMedia. + + This contains the relative path of the last captured media starting from the `DCIM` directory on the SDCard. Depending + on the type of media captured, it will return: + + - The single media path for single photo/video media + - The path to the first captured media in the group for grouped media + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + RESULT_FIELD_NUMBER: builtins.int + MEDIA_FIELD_NUMBER: builtins.int + result: response_generic_pb2.EnumResultGeneric.ValueType + "Was the request successful?" + + @property + def media(self) -> response_generic_pb2.Media: + """* + Last captured media if result is RESULT_SUCCESS. Invalid if result is RESULT_RESOURCE_NOT_AVAILBLE. + """ + + def __init__( + self, + *, + result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., + media: response_generic_pb2.Media | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["media", b"media", "result", b"result"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["media", b"media", "result", b"result"], + ) -> None: ... + +global___ResponseLastCapturedMedia = ResponseLastCapturedMedia diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/network_management_pb2.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/network_management_pb2.py new file mode 100644 index 00000000..770915ca --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/network_management_pb2.py @@ -0,0 +1,50 @@ +# network_management_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +"""Generated protocol buffer code.""" + +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database + +_sym_db = _symbol_database.Default() +from . import response_generic_pb2 as response__generic__pb2 + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x18network_management.proto\x12\nopen_gopro\x1a\x16response_generic.proto"R\n\x16NotifProvisioningState\x128\n\x12provisioning_state\x18\x01 \x02(\x0e2\x1c.open_gopro.EnumProvisioning"\x8d\x01\n\x12NotifStartScanning\x120\n\x0escanning_state\x18\x01 \x02(\x0e2\x18.open_gopro.EnumScanning\x12\x0f\n\x07scan_id\x18\x02 \x01(\x05\x12\x15\n\rtotal_entries\x18\x03 \x01(\x05\x12\x1d\n\x15total_configured_ssid\x18\x04 \x02(\x05"\x1e\n\x0eRequestConnect\x12\x0c\n\x04ssid\x18\x01 \x02(\t"\x93\x01\n\x11RequestConnectNew\x12\x0c\n\x04ssid\x18\x01 \x02(\t\x12\x10\n\x08password\x18\x02 \x02(\t\x12\x11\n\tstatic_ip\x18\x03 \x01(\x0c\x12\x0f\n\x07gateway\x18\x04 \x01(\x0c\x12\x0e\n\x06subnet\x18\x05 \x01(\x0c\x12\x13\n\x0bdns_primary\x18\x06 \x01(\x0c\x12\x15\n\rdns_secondary\x18\x07 \x01(\x0c"P\n\x13RequestGetApEntries\x12\x13\n\x0bstart_index\x18\x01 \x02(\x05\x12\x13\n\x0bmax_entries\x18\x02 \x02(\x05\x12\x0f\n\x07scan_id\x18\x03 \x02(\x05"\x17\n\x15RequestReleaseNetwork"\x12\n\x10RequestStartScan"\x93\x01\n\x0fResponseConnect\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric\x128\n\x12provisioning_state\x18\x02 \x02(\x0e2\x1c.open_gopro.EnumProvisioning\x12\x17\n\x0ftimeout_seconds\x18\x03 \x02(\x05"\x96\x01\n\x12ResponseConnectNew\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric\x128\n\x12provisioning_state\x18\x02 \x02(\x0e2\x1c.open_gopro.EnumProvisioning\x12\x17\n\x0ftimeout_seconds\x18\x03 \x02(\x05"\x84\x02\n\x14ResponseGetApEntries\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric\x12\x0f\n\x07scan_id\x18\x02 \x02(\x05\x12;\n\x07entries\x18\x03 \x03(\x0b2*.open_gopro.ResponseGetApEntries.ScanEntry\x1ao\n\tScanEntry\x12\x0c\n\x04ssid\x18\x01 \x02(\t\x12\x1c\n\x14signal_strength_bars\x18\x02 \x02(\x05\x12\x1c\n\x14signal_frequency_mhz\x18\x04 \x02(\x05\x12\x18\n\x10scan_entry_flags\x18\x05 \x02(\x05"x\n\x15ResponseStartScanning\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric\x120\n\x0escanning_state\x18\x02 \x02(\x0e2\x18.open_gopro.EnumScanning*\xb5\x03\n\x10EnumProvisioning\x12\x18\n\x14PROVISIONING_UNKNOWN\x10\x00\x12\x1e\n\x1aPROVISIONING_NEVER_STARTED\x10\x01\x12\x18\n\x14PROVISIONING_STARTED\x10\x02\x12"\n\x1ePROVISIONING_ABORTED_BY_SYSTEM\x10\x03\x12"\n\x1ePROVISIONING_CANCELLED_BY_USER\x10\x04\x12\x1f\n\x1bPROVISIONING_SUCCESS_NEW_AP\x10\x05\x12\x1f\n\x1bPROVISIONING_SUCCESS_OLD_AP\x10\x06\x12*\n&PROVISIONING_ERROR_FAILED_TO_ASSOCIATE\x10\x07\x12$\n PROVISIONING_ERROR_PASSWORD_AUTH\x10\x08\x12$\n PROVISIONING_ERROR_EULA_BLOCKING\x10\t\x12"\n\x1ePROVISIONING_ERROR_NO_INTERNET\x10\n\x12\'\n#PROVISIONING_ERROR_UNSUPPORTED_TYPE\x10\x0b*\xac\x01\n\x0cEnumScanning\x12\x14\n\x10SCANNING_UNKNOWN\x10\x00\x12\x1a\n\x16SCANNING_NEVER_STARTED\x10\x01\x12\x14\n\x10SCANNING_STARTED\x10\x02\x12\x1e\n\x1aSCANNING_ABORTED_BY_SYSTEM\x10\x03\x12\x1e\n\x1aSCANNING_CANCELLED_BY_USER\x10\x04\x12\x14\n\x10SCANNING_SUCCESS\x10\x05*\xb2\x01\n\x12EnumScanEntryFlags\x12\x12\n\x0eSCAN_FLAG_OPEN\x10\x00\x12\x1b\n\x17SCAN_FLAG_AUTHENTICATED\x10\x01\x12\x18\n\x14SCAN_FLAG_CONFIGURED\x10\x02\x12\x17\n\x13SCAN_FLAG_BEST_SSID\x10\x04\x12\x18\n\x14SCAN_FLAG_ASSOCIATED\x10\x08\x12\x1e\n\x1aSCAN_FLAG_UNSUPPORTED_TYPE\x10\x10' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "network_management_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMPROVISIONING._serialized_start = 1290 + _ENUMPROVISIONING._serialized_end = 1727 + _ENUMSCANNING._serialized_start = 1730 + _ENUMSCANNING._serialized_end = 1902 + _ENUMSCANENTRYFLAGS._serialized_start = 1905 + _ENUMSCANENTRYFLAGS._serialized_end = 2083 + _NOTIFPROVISIONINGSTATE._serialized_start = 64 + _NOTIFPROVISIONINGSTATE._serialized_end = 146 + _NOTIFSTARTSCANNING._serialized_start = 149 + _NOTIFSTARTSCANNING._serialized_end = 290 + _REQUESTCONNECT._serialized_start = 292 + _REQUESTCONNECT._serialized_end = 322 + _REQUESTCONNECTNEW._serialized_start = 325 + _REQUESTCONNECTNEW._serialized_end = 472 + _REQUESTGETAPENTRIES._serialized_start = 474 + _REQUESTGETAPENTRIES._serialized_end = 554 + _REQUESTRELEASENETWORK._serialized_start = 556 + _REQUESTRELEASENETWORK._serialized_end = 579 + _REQUESTSTARTSCAN._serialized_start = 581 + _REQUESTSTARTSCAN._serialized_end = 599 + _RESPONSECONNECT._serialized_start = 602 + _RESPONSECONNECT._serialized_end = 749 + _RESPONSECONNECTNEW._serialized_start = 752 + _RESPONSECONNECTNEW._serialized_end = 902 + _RESPONSEGETAPENTRIES._serialized_start = 905 + _RESPONSEGETAPENTRIES._serialized_end = 1165 + _RESPONSEGETAPENTRIES_SCANENTRY._serialized_start = 1054 + _RESPONSEGETAPENTRIES_SCANENTRY._serialized_end = 1165 + _RESPONSESTARTSCANNING._serialized_start = 1167 + _RESPONSESTARTSCANNING._serialized_end = 1287 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/network_management_pb2.pyi b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/network_management_pb2.pyi new file mode 100644 index 00000000..c9f74c3d --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/network_management_pb2.pyi @@ -0,0 +1,633 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf messages for network management +""" + +import builtins +import collections.abc +import google.protobuf.descriptor +import google.protobuf.internal.containers +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +from . import response_generic_pb2 +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumProvisioning: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumProvisioningEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumProvisioning.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + PROVISIONING_UNKNOWN: _EnumProvisioning.ValueType + PROVISIONING_NEVER_STARTED: _EnumProvisioning.ValueType + PROVISIONING_STARTED: _EnumProvisioning.ValueType + PROVISIONING_ABORTED_BY_SYSTEM: _EnumProvisioning.ValueType + PROVISIONING_CANCELLED_BY_USER: _EnumProvisioning.ValueType + PROVISIONING_SUCCESS_NEW_AP: _EnumProvisioning.ValueType + PROVISIONING_SUCCESS_OLD_AP: _EnumProvisioning.ValueType + PROVISIONING_ERROR_FAILED_TO_ASSOCIATE: _EnumProvisioning.ValueType + PROVISIONING_ERROR_PASSWORD_AUTH: _EnumProvisioning.ValueType + PROVISIONING_ERROR_EULA_BLOCKING: _EnumProvisioning.ValueType + PROVISIONING_ERROR_NO_INTERNET: _EnumProvisioning.ValueType + PROVISIONING_ERROR_UNSUPPORTED_TYPE: _EnumProvisioning.ValueType + +class EnumProvisioning(_EnumProvisioning, metaclass=_EnumProvisioningEnumTypeWrapper): ... + +PROVISIONING_UNKNOWN: EnumProvisioning.ValueType +PROVISIONING_NEVER_STARTED: EnumProvisioning.ValueType +PROVISIONING_STARTED: EnumProvisioning.ValueType +PROVISIONING_ABORTED_BY_SYSTEM: EnumProvisioning.ValueType +PROVISIONING_CANCELLED_BY_USER: EnumProvisioning.ValueType +PROVISIONING_SUCCESS_NEW_AP: EnumProvisioning.ValueType +PROVISIONING_SUCCESS_OLD_AP: EnumProvisioning.ValueType +PROVISIONING_ERROR_FAILED_TO_ASSOCIATE: EnumProvisioning.ValueType +PROVISIONING_ERROR_PASSWORD_AUTH: EnumProvisioning.ValueType +PROVISIONING_ERROR_EULA_BLOCKING: EnumProvisioning.ValueType +PROVISIONING_ERROR_NO_INTERNET: EnumProvisioning.ValueType +PROVISIONING_ERROR_UNSUPPORTED_TYPE: EnumProvisioning.ValueType +global___EnumProvisioning = EnumProvisioning + +class _EnumScanning: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumScanningEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumScanning.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + SCANNING_UNKNOWN: _EnumScanning.ValueType + SCANNING_NEVER_STARTED: _EnumScanning.ValueType + SCANNING_STARTED: _EnumScanning.ValueType + SCANNING_ABORTED_BY_SYSTEM: _EnumScanning.ValueType + SCANNING_CANCELLED_BY_USER: _EnumScanning.ValueType + SCANNING_SUCCESS: _EnumScanning.ValueType + +class EnumScanning(_EnumScanning, metaclass=_EnumScanningEnumTypeWrapper): ... + +SCANNING_UNKNOWN: EnumScanning.ValueType +SCANNING_NEVER_STARTED: EnumScanning.ValueType +SCANNING_STARTED: EnumScanning.ValueType +SCANNING_ABORTED_BY_SYSTEM: EnumScanning.ValueType +SCANNING_CANCELLED_BY_USER: EnumScanning.ValueType +SCANNING_SUCCESS: EnumScanning.ValueType +global___EnumScanning = EnumScanning + +class _EnumScanEntryFlags: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumScanEntryFlagsEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumScanEntryFlags.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + SCAN_FLAG_OPEN: _EnumScanEntryFlags.ValueType + "This network does not require authentication" + SCAN_FLAG_AUTHENTICATED: _EnumScanEntryFlags.ValueType + "This network requires authentication" + SCAN_FLAG_CONFIGURED: _EnumScanEntryFlags.ValueType + "This network has been previously provisioned" + SCAN_FLAG_BEST_SSID: _EnumScanEntryFlags.ValueType + SCAN_FLAG_ASSOCIATED: _EnumScanEntryFlags.ValueType + "Camera is connected to this AP" + SCAN_FLAG_UNSUPPORTED_TYPE: _EnumScanEntryFlags.ValueType + +class EnumScanEntryFlags(_EnumScanEntryFlags, metaclass=_EnumScanEntryFlagsEnumTypeWrapper): ... + +SCAN_FLAG_OPEN: EnumScanEntryFlags.ValueType +"This network does not require authentication" +SCAN_FLAG_AUTHENTICATED: EnumScanEntryFlags.ValueType +"This network requires authentication" +SCAN_FLAG_CONFIGURED: EnumScanEntryFlags.ValueType +"This network has been previously provisioned" +SCAN_FLAG_BEST_SSID: EnumScanEntryFlags.ValueType +SCAN_FLAG_ASSOCIATED: EnumScanEntryFlags.ValueType +"Camera is connected to this AP" +SCAN_FLAG_UNSUPPORTED_TYPE: EnumScanEntryFlags.ValueType +global___EnumScanEntryFlags = EnumScanEntryFlags + +@typing_extensions.final +class NotifProvisioningState(google.protobuf.message.Message): + """ + Provision state notification + + Sent during provisioning triggered via @ref RequestConnect or @ref RequestConnectNew + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + PROVISIONING_STATE_FIELD_NUMBER: builtins.int + provisioning_state: global___EnumProvisioning.ValueType + "Provisioning / connection state" + + def __init__(self, *, provisioning_state: global___EnumProvisioning.ValueType | None = ...) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["provisioning_state", b"provisioning_state"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["provisioning_state", b"provisioning_state"], + ) -> None: ... + +global___NotifProvisioningState = NotifProvisioningState + +@typing_extensions.final +class NotifStartScanning(google.protobuf.message.Message): + """ + Scanning state notification + + Triggered via @ref RequestStartScan + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + SCANNING_STATE_FIELD_NUMBER: builtins.int + SCAN_ID_FIELD_NUMBER: builtins.int + TOTAL_ENTRIES_FIELD_NUMBER: builtins.int + TOTAL_CONFIGURED_SSID_FIELD_NUMBER: builtins.int + scanning_state: global___EnumScanning.ValueType + "Scanning state" + scan_id: builtins.int + "ID associated with scan results (included if scan was successful)" + total_entries: builtins.int + "Number of APs found during scan (included if scan was successful)" + total_configured_ssid: builtins.int + "Total count of camera's provisioned SSIDs" + + def __init__( + self, + *, + scanning_state: global___EnumScanning.ValueType | None = ..., + scan_id: builtins.int | None = ..., + total_entries: builtins.int | None = ..., + total_configured_ssid: builtins.int | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "scan_id", + b"scan_id", + "scanning_state", + b"scanning_state", + "total_configured_ssid", + b"total_configured_ssid", + "total_entries", + b"total_entries", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "scan_id", + b"scan_id", + "scanning_state", + b"scanning_state", + "total_configured_ssid", + b"total_configured_ssid", + "total_entries", + b"total_entries", + ], + ) -> None: ... + +global___NotifStartScanning = NotifStartScanning + +@typing_extensions.final +class RequestConnect(google.protobuf.message.Message): + """* + Connect to (but do not authenticate with) an Access Point + + This is intended to be used to connect to a previously-connected Access Point + + Response: @ref ResponseConnect + + Notification: @ref NotifProvisioningState sent periodically as provisioning state changes + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + SSID_FIELD_NUMBER: builtins.int + ssid: builtins.str + "AP SSID" + + def __init__(self, *, ssid: builtins.str | None = ...) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["ssid", b"ssid"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["ssid", b"ssid"]) -> None: ... + +global___RequestConnect = RequestConnect + +@typing_extensions.final +class RequestConnectNew(google.protobuf.message.Message): + """* + Connect to and authenticate with an Access Point + + This is only intended to be used if the AP is not previously provisioned. + + Response: @ref ResponseConnectNew sent immediately + + Notification: @ref NotifProvisioningState sent periodically as provisioning state changes + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + SSID_FIELD_NUMBER: builtins.int + PASSWORD_FIELD_NUMBER: builtins.int + STATIC_IP_FIELD_NUMBER: builtins.int + GATEWAY_FIELD_NUMBER: builtins.int + SUBNET_FIELD_NUMBER: builtins.int + DNS_PRIMARY_FIELD_NUMBER: builtins.int + DNS_SECONDARY_FIELD_NUMBER: builtins.int + ssid: builtins.str + "AP SSID" + password: builtins.str + "AP password" + static_ip: builtins.bytes + "Static IP address" + gateway: builtins.bytes + "Gateway IP address" + subnet: builtins.bytes + "Subnet mask" + dns_primary: builtins.bytes + "Primary DNS" + dns_secondary: builtins.bytes + "Secondary DNS" + + def __init__( + self, + *, + ssid: builtins.str | None = ..., + password: builtins.str | None = ..., + static_ip: builtins.bytes | None = ..., + gateway: builtins.bytes | None = ..., + subnet: builtins.bytes | None = ..., + dns_primary: builtins.bytes | None = ..., + dns_secondary: builtins.bytes | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "dns_primary", + b"dns_primary", + "dns_secondary", + b"dns_secondary", + "gateway", + b"gateway", + "password", + b"password", + "ssid", + b"ssid", + "static_ip", + b"static_ip", + "subnet", + b"subnet", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "dns_primary", + b"dns_primary", + "dns_secondary", + b"dns_secondary", + "gateway", + b"gateway", + "password", + b"password", + "ssid", + b"ssid", + "static_ip", + b"static_ip", + "subnet", + b"subnet", + ], + ) -> None: ... + +global___RequestConnectNew = RequestConnectNew + +@typing_extensions.final +class RequestGetApEntries(google.protobuf.message.Message): + """* + Get a list of Access Points found during a @ref RequestStartScan + + Response: @ref ResponseGetApEntries + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + START_INDEX_FIELD_NUMBER: builtins.int + MAX_ENTRIES_FIELD_NUMBER: builtins.int + SCAN_ID_FIELD_NUMBER: builtins.int + start_index: builtins.int + "Used for paging. 0 <= start_index < @ref ResponseGetApEntries .total_entries" + max_entries: builtins.int + "Used for paging. Value must be < @ref ResponseGetApEntries .total_entries" + scan_id: builtins.int + "ID corresponding to a set of scan results (i.e. @ref ResponseGetApEntries .scan_id)" + + def __init__( + self, + *, + start_index: builtins.int | None = ..., + max_entries: builtins.int | None = ..., + scan_id: builtins.int | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "max_entries", + b"max_entries", + "scan_id", + b"scan_id", + "start_index", + b"start_index", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "max_entries", + b"max_entries", + "scan_id", + b"scan_id", + "start_index", + b"start_index", + ], + ) -> None: ... + +global___RequestGetApEntries = RequestGetApEntries + +@typing_extensions.final +class RequestReleaseNetwork(google.protobuf.message.Message): + """* + Request to disconnect from currently-connected AP + + This drops the camera out of Station (STA) Mode and returns it to Access Point (AP) mode. + + Response: @ref ResponseGeneric + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__(self) -> None: ... + +global___RequestReleaseNetwork = RequestReleaseNetwork + +@typing_extensions.final +class RequestStartScan(google.protobuf.message.Message): + """* + Start scanning for Access Points + + @note Serialization of this object is zero bytes. + + Response: @ref ResponseStartScanning are sent immediately after the camera receives this command + + Notifications: @ref NotifStartScanning are sent periodically as scanning state changes. Use to detect scan complete. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__(self) -> None: ... + +global___RequestStartScan = RequestStartScan + +@typing_extensions.final +class ResponseConnect(google.protobuf.message.Message): + """* + The status of an attempt to connect to an Access Point + + Sent as the initial response to @ref RequestConnect + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + RESULT_FIELD_NUMBER: builtins.int + PROVISIONING_STATE_FIELD_NUMBER: builtins.int + TIMEOUT_SECONDS_FIELD_NUMBER: builtins.int + result: response_generic_pb2.EnumResultGeneric.ValueType + "Generic pass/fail/error info" + provisioning_state: global___EnumProvisioning.ValueType + "Provisioning/connection state" + timeout_seconds: builtins.int + "Network connection timeout (seconds)" + + def __init__( + self, + *, + result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., + provisioning_state: global___EnumProvisioning.ValueType | None = ..., + timeout_seconds: builtins.int | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "provisioning_state", + b"provisioning_state", + "result", + b"result", + "timeout_seconds", + b"timeout_seconds", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "provisioning_state", + b"provisioning_state", + "result", + b"result", + "timeout_seconds", + b"timeout_seconds", + ], + ) -> None: ... + +global___ResponseConnect = ResponseConnect + +@typing_extensions.final +class ResponseConnectNew(google.protobuf.message.Message): + """* + The status of an attempt to connect to an Access Point + + Sent as the initial response to @ref RequestConnectNew + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + RESULT_FIELD_NUMBER: builtins.int + PROVISIONING_STATE_FIELD_NUMBER: builtins.int + TIMEOUT_SECONDS_FIELD_NUMBER: builtins.int + result: response_generic_pb2.EnumResultGeneric.ValueType + "Status of Connect New request" + provisioning_state: global___EnumProvisioning.ValueType + "Current provisioning state of the network" + timeout_seconds: builtins.int + "*\n Number of seconds camera will wait before declaring a network connection attempt failed\n " + + def __init__( + self, + *, + result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., + provisioning_state: global___EnumProvisioning.ValueType | None = ..., + timeout_seconds: builtins.int | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "provisioning_state", + b"provisioning_state", + "result", + b"result", + "timeout_seconds", + b"timeout_seconds", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "provisioning_state", + b"provisioning_state", + "result", + b"result", + "timeout_seconds", + b"timeout_seconds", + ], + ) -> None: ... + +global___ResponseConnectNew = ResponseConnectNew + +@typing_extensions.final +class ResponseGetApEntries(google.protobuf.message.Message): + """* + A list of scan entries describing a scanned Access Point + + This is sent in response to a @ref RequestGetApEntries + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + @typing_extensions.final + class ScanEntry(google.protobuf.message.Message): + """* + An individual Scan Entry in a @ref ResponseGetApEntries response + + @note When `scan_entry_flags` contains `SCAN_FLAG_CONFIGURED`, it is an indication that this network has already been provisioned. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + SSID_FIELD_NUMBER: builtins.int + SIGNAL_STRENGTH_BARS_FIELD_NUMBER: builtins.int + SIGNAL_FREQUENCY_MHZ_FIELD_NUMBER: builtins.int + SCAN_ENTRY_FLAGS_FIELD_NUMBER: builtins.int + ssid: builtins.str + "AP SSID" + signal_strength_bars: builtins.int + "Signal strength (3 bars: >-70 dBm; 2 bars: >-85 dBm; 1 bar: <=-85 dBm)" + signal_frequency_mhz: builtins.int + "Signal frequency (MHz)" + scan_entry_flags: builtins.int + "Bitmasked value from @ref EnumScanEntryFlags" + + def __init__( + self, + *, + ssid: builtins.str | None = ..., + signal_strength_bars: builtins.int | None = ..., + signal_frequency_mhz: builtins.int | None = ..., + scan_entry_flags: builtins.int | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "scan_entry_flags", + b"scan_entry_flags", + "signal_frequency_mhz", + b"signal_frequency_mhz", + "signal_strength_bars", + b"signal_strength_bars", + "ssid", + b"ssid", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "scan_entry_flags", + b"scan_entry_flags", + "signal_frequency_mhz", + b"signal_frequency_mhz", + "signal_strength_bars", + b"signal_strength_bars", + "ssid", + b"ssid", + ], + ) -> None: ... + + RESULT_FIELD_NUMBER: builtins.int + SCAN_ID_FIELD_NUMBER: builtins.int + ENTRIES_FIELD_NUMBER: builtins.int + result: response_generic_pb2.EnumResultGeneric.ValueType + "Generic pass/fail/error info" + scan_id: builtins.int + "ID associated with this batch of results" + + @property + def entries( + self, + ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___ResponseGetApEntries.ScanEntry]: + """Array containing details about discovered APs""" + + def __init__( + self, + *, + result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., + scan_id: builtins.int | None = ..., + entries: collections.abc.Iterable[global___ResponseGetApEntries.ScanEntry] | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["result", b"result", "scan_id", b"scan_id"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["entries", b"entries", "result", b"result", "scan_id", b"scan_id"], + ) -> None: ... + +global___ResponseGetApEntries = ResponseGetApEntries + +@typing_extensions.final +class ResponseStartScanning(google.protobuf.message.Message): + """* + The current scanning state. + + This is the initial response to a @ref RequestStartScan + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + RESULT_FIELD_NUMBER: builtins.int + SCANNING_STATE_FIELD_NUMBER: builtins.int + result: response_generic_pb2.EnumResultGeneric.ValueType + "Generic pass/fail/error info" + scanning_state: global___EnumScanning.ValueType + "Scanning state" + + def __init__( + self, + *, + result: response_generic_pb2.EnumResultGeneric.ValueType | None = ..., + scanning_state: global___EnumScanning.ValueType | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["result", b"result", "scanning_state", b"scanning_state"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["result", b"result", "scanning_state", b"scanning_state"], + ) -> None: ... + +global___ResponseStartScanning = ResponseStartScanning diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/preset_status_pb2.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/preset_status_pb2.py new file mode 100644 index 00000000..666abc10 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/preset_status_pb2.py @@ -0,0 +1,40 @@ +# preset_status_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +"""Generated protocol buffer code.""" + +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database + +_sym_db = _symbol_database.Default() +from . import response_generic_pb2 as response__generic__pb2 + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x13preset_status.proto\x12\nopen_gopro\x1a\x16response_generic.proto"I\n\x12NotifyPresetStatus\x123\n\x12preset_group_array\x18\x01 \x03(\x0b2\x17.open_gopro.PresetGroup"\xaf\x02\n\x06Preset\x12\n\n\x02id\x18\x01 \x01(\x05\x12&\n\x04mode\x18\x02 \x01(\x0e2\x18.open_gopro.EnumFlatMode\x12-\n\x08title_id\x18\x03 \x01(\x0e2\x1b.open_gopro.EnumPresetTitle\x12\x14\n\x0ctitle_number\x18\x04 \x01(\x05\x12\x14\n\x0cuser_defined\x18\x05 \x01(\x08\x12(\n\x04icon\x18\x06 \x01(\x0e2\x1a.open_gopro.EnumPresetIcon\x120\n\rsetting_array\x18\x07 \x03(\x0b2\x19.open_gopro.PresetSetting\x12\x13\n\x0bis_modified\x18\x08 \x01(\x08\x12\x10\n\x08is_fixed\x18\t \x01(\x08\x12\x13\n\x0bcustom_name\x18\n \x01(\t"\x8c\x01\n\x19RequestCustomPresetUpdate\x12-\n\x08title_id\x18\x01 \x01(\x0e2\x1b.open_gopro.EnumPresetTitle\x12\x13\n\x0bcustom_name\x18\x02 \x01(\t\x12+\n\x07icon_id\x18\x03 \x01(\x0e2\x1a.open_gopro.EnumPresetIcon"\xa7\x01\n\x0bPresetGroup\x12\'\n\x02id\x18\x01 \x01(\x0e2\x1b.open_gopro.EnumPresetGroup\x12(\n\x0cpreset_array\x18\x02 \x03(\x0b2\x12.open_gopro.Preset\x12\x16\n\x0ecan_add_preset\x18\x03 \x01(\x08\x12-\n\x04icon\x18\x04 \x01(\x0e2\x1f.open_gopro.EnumPresetGroupIcon">\n\rPresetSetting\x12\n\n\x02id\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x05\x12\x12\n\nis_caption\x18\x03 \x01(\x08*\x9b\x05\n\x0cEnumFlatMode\x12\x1e\n\x11FLAT_MODE_UNKNOWN\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x12\x16\n\x12FLAT_MODE_PLAYBACK\x10\x04\x12\x13\n\x0fFLAT_MODE_SETUP\x10\x05\x12\x13\n\x0fFLAT_MODE_VIDEO\x10\x0c\x12\x1e\n\x1aFLAT_MODE_TIME_LAPSE_VIDEO\x10\r\x12\x15\n\x11FLAT_MODE_LOOPING\x10\x0f\x12\x1a\n\x16FLAT_MODE_PHOTO_SINGLE\x10\x10\x12\x13\n\x0fFLAT_MODE_PHOTO\x10\x11\x12\x19\n\x15FLAT_MODE_PHOTO_NIGHT\x10\x12\x12\x19\n\x15FLAT_MODE_PHOTO_BURST\x10\x13\x12\x1e\n\x1aFLAT_MODE_TIME_LAPSE_PHOTO\x10\x14\x12\x1f\n\x1bFLAT_MODE_NIGHT_LAPSE_PHOTO\x10\x15\x12\x1e\n\x1aFLAT_MODE_BROADCAST_RECORD\x10\x16\x12!\n\x1dFLAT_MODE_BROADCAST_BROADCAST\x10\x17\x12\x1d\n\x19FLAT_MODE_TIME_WARP_VIDEO\x10\x18\x12\x18\n\x14FLAT_MODE_LIVE_BURST\x10\x19\x12\x1f\n\x1bFLAT_MODE_NIGHT_LAPSE_VIDEO\x10\x1a\x12\x13\n\x0fFLAT_MODE_SLOMO\x10\x1b\x12\x12\n\x0eFLAT_MODE_IDLE\x10\x1c\x12\x1e\n\x1aFLAT_MODE_VIDEO_STAR_TRAIL\x10\x1d\x12"\n\x1eFLAT_MODE_VIDEO_LIGHT_PAINTING\x10\x1e\x12\x1f\n\x1bFLAT_MODE_VIDEO_LIGHT_TRAIL\x10\x1f\x12\x1f\n\x1bFLAT_MODE_VIDEO_BURST_SLOMO\x10 *i\n\x0fEnumPresetGroup\x12\x1a\n\x15PRESET_GROUP_ID_VIDEO\x10\xe8\x07\x12\x1a\n\x15PRESET_GROUP_ID_PHOTO\x10\xe9\x07\x12\x1e\n\x19PRESET_GROUP_ID_TIMELAPSE\x10\xea\x07*\xbc\x02\n\x13EnumPresetGroupIcon\x12\x1e\n\x1aPRESET_GROUP_VIDEO_ICON_ID\x10\x00\x12\x1e\n\x1aPRESET_GROUP_PHOTO_ICON_ID\x10\x01\x12"\n\x1ePRESET_GROUP_TIMELAPSE_ICON_ID\x10\x02\x12\'\n#PRESET_GROUP_LONG_BAT_VIDEO_ICON_ID\x10\x03\x12(\n$PRESET_GROUP_ENDURANCE_VIDEO_ICON_ID\x10\x04\x12"\n\x1ePRESET_GROUP_MAX_VIDEO_ICON_ID\x10\x05\x12"\n\x1ePRESET_GROUP_MAX_PHOTO_ICON_ID\x10\x06\x12&\n"PRESET_GROUP_MAX_TIMELAPSE_ICON_ID\x10\x07*\xc1\r\n\x0eEnumPresetIcon\x12\x15\n\x11PRESET_ICON_VIDEO\x10\x00\x12\x18\n\x14PRESET_ICON_ACTIVITY\x10\x01\x12\x19\n\x15PRESET_ICON_CINEMATIC\x10\x02\x12\x15\n\x11PRESET_ICON_PHOTO\x10\x03\x12\x1a\n\x16PRESET_ICON_LIVE_BURST\x10\x04\x12\x15\n\x11PRESET_ICON_BURST\x10\x05\x12\x1b\n\x17PRESET_ICON_PHOTO_NIGHT\x10\x06\x12\x18\n\x14PRESET_ICON_TIMEWARP\x10\x07\x12\x19\n\x15PRESET_ICON_TIMELAPSE\x10\x08\x12\x1a\n\x16PRESET_ICON_NIGHTLAPSE\x10\t\x12\x15\n\x11PRESET_ICON_SNAIL\x10\n\x12\x17\n\x13PRESET_ICON_VIDEO_2\x10\x0b\x12\x17\n\x13PRESET_ICON_PHOTO_2\x10\r\x12\x18\n\x14PRESET_ICON_PANORAMA\x10\x0e\x12\x17\n\x13PRESET_ICON_BURST_2\x10\x0f\x12\x1a\n\x16PRESET_ICON_TIMEWARP_2\x10\x10\x12\x1b\n\x17PRESET_ICON_TIMELAPSE_2\x10\x11\x12\x16\n\x12PRESET_ICON_CUSTOM\x10\x12\x12\x13\n\x0fPRESET_ICON_AIR\x10\x13\x12\x14\n\x10PRESET_ICON_BIKE\x10\x14\x12\x14\n\x10PRESET_ICON_EPIC\x10\x15\x12\x16\n\x12PRESET_ICON_INDOOR\x10\x16\x12\x15\n\x11PRESET_ICON_MOTOR\x10\x17\x12\x17\n\x13PRESET_ICON_MOUNTED\x10\x18\x12\x17\n\x13PRESET_ICON_OUTDOOR\x10\x19\x12\x13\n\x0fPRESET_ICON_POV\x10\x1a\x12\x16\n\x12PRESET_ICON_SELFIE\x10\x1b\x12\x15\n\x11PRESET_ICON_SKATE\x10\x1c\x12\x14\n\x10PRESET_ICON_SNOW\x10\x1d\x12\x15\n\x11PRESET_ICON_TRAIL\x10\x1e\x12\x16\n\x12PRESET_ICON_TRAVEL\x10\x1f\x12\x15\n\x11PRESET_ICON_WATER\x10 \x12\x17\n\x13PRESET_ICON_LOOPING\x10!\x12\x15\n\x11PRESET_ICON_STARS\x10"\x12\x16\n\x12PRESET_ICON_ACTION\x10#\x12\x1a\n\x16PRESET_ICON_FOLLOW_CAM\x10$\x12\x14\n\x10PRESET_ICON_SURF\x10%\x12\x14\n\x10PRESET_ICON_CITY\x10&\x12\x15\n\x11PRESET_ICON_SHAKY\x10\'\x12\x16\n\x12PRESET_ICON_CHESTY\x10(\x12\x16\n\x12PRESET_ICON_HELMET\x10)\x12\x14\n\x10PRESET_ICON_BITE\x10*\x12\x15\n\x11PRESET_ICON_BASIC\x10:\x12\x1c\n\x18PRESET_ICON_ULTRA_SLO_MO\x10;\x12"\n\x1ePRESET_ICON_STANDARD_ENDURANCE\x10<\x12"\n\x1ePRESET_ICON_ACTIVITY_ENDURANCE\x10=\x12#\n\x1fPRESET_ICON_CINEMATIC_ENDURANCE\x10>\x12\x1f\n\x1bPRESET_ICON_SLOMO_ENDURANCE\x10?\x12\x1c\n\x18PRESET_ICON_STATIONARY_1\x10@\x12\x1c\n\x18PRESET_ICON_STATIONARY_2\x10A\x12\x1c\n\x18PRESET_ICON_STATIONARY_3\x10B\x12\x1c\n\x18PRESET_ICON_STATIONARY_4\x10C\x12"\n\x1ePRESET_ICON_SIMPLE_SUPER_PHOTO\x10F\x12"\n\x1ePRESET_ICON_SIMPLE_NIGHT_PHOTO\x10G\x12%\n!PRESET_ICON_HIGHEST_QUALITY_VIDEO\x10I\x12&\n"PRESET_ICON_STANDARD_QUALITY_VIDEO\x10J\x12#\n\x1fPRESET_ICON_BASIC_QUALITY_VIDEO\x10K\x12\x1a\n\x16PRESET_ICON_STAR_TRAIL\x10L\x12\x1e\n\x1aPRESET_ICON_LIGHT_PAINTING\x10M\x12\x1b\n\x17PRESET_ICON_LIGHT_TRAIL\x10N\x12\x1a\n\x16PRESET_ICON_FULL_FRAME\x10O\x12 \n\x1bPRESET_ICON_TIMELAPSE_PHOTO\x10\xe8\x07\x12!\n\x1cPRESET_ICON_NIGHTLAPSE_PHOTO\x10\xe9\x07*\xfe\x0e\n\x0fEnumPresetTitle\x12\x19\n\x15PRESET_TITLE_ACTIVITY\x10\x00\x12\x19\n\x15PRESET_TITLE_STANDARD\x10\x01\x12\x1a\n\x16PRESET_TITLE_CINEMATIC\x10\x02\x12\x16\n\x12PRESET_TITLE_PHOTO\x10\x03\x12\x1b\n\x17PRESET_TITLE_LIVE_BURST\x10\x04\x12\x16\n\x12PRESET_TITLE_BURST\x10\x05\x12\x16\n\x12PRESET_TITLE_NIGHT\x10\x06\x12\x1a\n\x16PRESET_TITLE_TIME_WARP\x10\x07\x12\x1b\n\x17PRESET_TITLE_TIME_LAPSE\x10\x08\x12\x1c\n\x18PRESET_TITLE_NIGHT_LAPSE\x10\t\x12\x16\n\x12PRESET_TITLE_VIDEO\x10\n\x12\x16\n\x12PRESET_TITLE_SLOMO\x10\x0b\x12\x18\n\x14PRESET_TITLE_PHOTO_2\x10\r\x12\x19\n\x15PRESET_TITLE_PANORAMA\x10\x0e\x12\x1c\n\x18PRESET_TITLE_TIME_WARP_2\x10\x10\x12\x17\n\x13PRESET_TITLE_CUSTOM\x10\x12\x12\x14\n\x10PRESET_TITLE_AIR\x10\x13\x12\x15\n\x11PRESET_TITLE_BIKE\x10\x14\x12\x15\n\x11PRESET_TITLE_EPIC\x10\x15\x12\x17\n\x13PRESET_TITLE_INDOOR\x10\x16\x12\x16\n\x12PRESET_TITLE_MOTOR\x10\x17\x12\x18\n\x14PRESET_TITLE_MOUNTED\x10\x18\x12\x18\n\x14PRESET_TITLE_OUTDOOR\x10\x19\x12\x14\n\x10PRESET_TITLE_POV\x10\x1a\x12\x17\n\x13PRESET_TITLE_SELFIE\x10\x1b\x12\x16\n\x12PRESET_TITLE_SKATE\x10\x1c\x12\x15\n\x11PRESET_TITLE_SNOW\x10\x1d\x12\x16\n\x12PRESET_TITLE_TRAIL\x10\x1e\x12\x17\n\x13PRESET_TITLE_TRAVEL\x10\x1f\x12\x16\n\x12PRESET_TITLE_WATER\x10 \x12\x18\n\x14PRESET_TITLE_LOOPING\x10!\x12\x16\n\x12PRESET_TITLE_STARS\x10"\x12\x17\n\x13PRESET_TITLE_ACTION\x10#\x12\x1b\n\x17PRESET_TITLE_FOLLOW_CAM\x10$\x12\x15\n\x11PRESET_TITLE_SURF\x10%\x12\x15\n\x11PRESET_TITLE_CITY\x10&\x12\x16\n\x12PRESET_TITLE_SHAKY\x10\'\x12\x17\n\x13PRESET_TITLE_CHESTY\x10(\x12\x17\n\x13PRESET_TITLE_HELMET\x10)\x12\x15\n\x11PRESET_TITLE_BITE\x10*\x12\x16\n\x12PRESET_TITLE_BASIC\x10:\x12\x1d\n\x19PRESET_TITLE_ULTRA_SLO_MO\x10;\x12#\n\x1fPRESET_TITLE_STANDARD_ENDURANCE\x10<\x12#\n\x1fPRESET_TITLE_ACTIVITY_ENDURANCE\x10=\x12$\n PRESET_TITLE_CINEMATIC_ENDURANCE\x10>\x12 \n\x1cPRESET_TITLE_SLOMO_ENDURANCE\x10?\x12\x1d\n\x19PRESET_TITLE_STATIONARY_1\x10@\x12\x1d\n\x19PRESET_TITLE_STATIONARY_2\x10A\x12\x1d\n\x19PRESET_TITLE_STATIONARY_3\x10B\x12\x1d\n\x19PRESET_TITLE_STATIONARY_4\x10C\x12\x1d\n\x19PRESET_TITLE_SIMPLE_VIDEO\x10D\x12!\n\x1dPRESET_TITLE_SIMPLE_TIME_WARP\x10E\x12#\n\x1fPRESET_TITLE_SIMPLE_SUPER_PHOTO\x10F\x12#\n\x1fPRESET_TITLE_SIMPLE_NIGHT_PHOTO\x10G\x12\'\n#PRESET_TITLE_SIMPLE_VIDEO_ENDURANCE\x10H\x12 \n\x1cPRESET_TITLE_HIGHEST_QUALITY\x10I\x12!\n\x1dPRESET_TITLE_EXTENDED_BATTERY\x10J\x12 \n\x1cPRESET_TITLE_LONGEST_BATTERY\x10K\x12\x1b\n\x17PRESET_TITLE_STAR_TRAIL\x10L\x12\x1f\n\x1bPRESET_TITLE_LIGHT_PAINTING\x10M\x12\x1c\n\x18PRESET_TITLE_LIGHT_TRAIL\x10N\x12\x1b\n\x17PRESET_TITLE_FULL_FRAME\x10O\x12\'\n#PRESET_TITLE_STANDARD_QUALITY_VIDEO\x10R\x12$\n PRESET_TITLE_BASIC_QUALITY_VIDEO\x10S\x12&\n"PRESET_TITLE_HIGHEST_QUALITY_VIDEO\x10]\x12)\n%PRESET_TITLE_USER_DEFINED_CUSTOM_NAME\x10^' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "preset_status_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMFLATMODE._serialized_start = 818 + _ENUMFLATMODE._serialized_end = 1485 + _ENUMPRESETGROUP._serialized_start = 1487 + _ENUMPRESETGROUP._serialized_end = 1592 + _ENUMPRESETGROUPICON._serialized_start = 1595 + _ENUMPRESETGROUPICON._serialized_end = 1911 + _ENUMPRESETICON._serialized_start = 1914 + _ENUMPRESETICON._serialized_end = 3643 + _ENUMPRESETTITLE._serialized_start = 3646 + _ENUMPRESETTITLE._serialized_end = 5564 + _NOTIFYPRESETSTATUS._serialized_start = 59 + _NOTIFYPRESETSTATUS._serialized_end = 132 + _PRESET._serialized_start = 135 + _PRESET._serialized_end = 438 + _REQUESTCUSTOMPRESETUPDATE._serialized_start = 441 + _REQUESTCUSTOMPRESETUPDATE._serialized_end = 581 + _PRESETGROUP._serialized_start = 584 + _PRESETGROUP._serialized_end = 751 + _PRESETSETTING._serialized_start = 753 + _PRESETSETTING._serialized_end = 815 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/preset_status_pb2.pyi b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/preset_status_pb2.pyi new file mode 100644 index 00000000..73bd5fc7 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/preset_status_pb2.pyi @@ -0,0 +1,702 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf message received from camera containing preset status +""" + +import builtins +import collections.abc +import google.protobuf.descriptor +import google.protobuf.internal.containers +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumFlatMode: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumFlatModeEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumFlatMode.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + FLAT_MODE_UNKNOWN: _EnumFlatMode.ValueType + FLAT_MODE_PLAYBACK: _EnumFlatMode.ValueType + FLAT_MODE_SETUP: _EnumFlatMode.ValueType + FLAT_MODE_VIDEO: _EnumFlatMode.ValueType + FLAT_MODE_TIME_LAPSE_VIDEO: _EnumFlatMode.ValueType + FLAT_MODE_LOOPING: _EnumFlatMode.ValueType + FLAT_MODE_PHOTO_SINGLE: _EnumFlatMode.ValueType + FLAT_MODE_PHOTO: _EnumFlatMode.ValueType + FLAT_MODE_PHOTO_NIGHT: _EnumFlatMode.ValueType + FLAT_MODE_PHOTO_BURST: _EnumFlatMode.ValueType + FLAT_MODE_TIME_LAPSE_PHOTO: _EnumFlatMode.ValueType + FLAT_MODE_NIGHT_LAPSE_PHOTO: _EnumFlatMode.ValueType + FLAT_MODE_BROADCAST_RECORD: _EnumFlatMode.ValueType + FLAT_MODE_BROADCAST_BROADCAST: _EnumFlatMode.ValueType + FLAT_MODE_TIME_WARP_VIDEO: _EnumFlatMode.ValueType + FLAT_MODE_LIVE_BURST: _EnumFlatMode.ValueType + FLAT_MODE_NIGHT_LAPSE_VIDEO: _EnumFlatMode.ValueType + FLAT_MODE_SLOMO: _EnumFlatMode.ValueType + FLAT_MODE_IDLE: _EnumFlatMode.ValueType + FLAT_MODE_VIDEO_STAR_TRAIL: _EnumFlatMode.ValueType + FLAT_MODE_VIDEO_LIGHT_PAINTING: _EnumFlatMode.ValueType + FLAT_MODE_VIDEO_LIGHT_TRAIL: _EnumFlatMode.ValueType + FLAT_MODE_VIDEO_BURST_SLOMO: _EnumFlatMode.ValueType + +class EnumFlatMode(_EnumFlatMode, metaclass=_EnumFlatModeEnumTypeWrapper): ... + +FLAT_MODE_UNKNOWN: EnumFlatMode.ValueType +FLAT_MODE_PLAYBACK: EnumFlatMode.ValueType +FLAT_MODE_SETUP: EnumFlatMode.ValueType +FLAT_MODE_VIDEO: EnumFlatMode.ValueType +FLAT_MODE_TIME_LAPSE_VIDEO: EnumFlatMode.ValueType +FLAT_MODE_LOOPING: EnumFlatMode.ValueType +FLAT_MODE_PHOTO_SINGLE: EnumFlatMode.ValueType +FLAT_MODE_PHOTO: EnumFlatMode.ValueType +FLAT_MODE_PHOTO_NIGHT: EnumFlatMode.ValueType +FLAT_MODE_PHOTO_BURST: EnumFlatMode.ValueType +FLAT_MODE_TIME_LAPSE_PHOTO: EnumFlatMode.ValueType +FLAT_MODE_NIGHT_LAPSE_PHOTO: EnumFlatMode.ValueType +FLAT_MODE_BROADCAST_RECORD: EnumFlatMode.ValueType +FLAT_MODE_BROADCAST_BROADCAST: EnumFlatMode.ValueType +FLAT_MODE_TIME_WARP_VIDEO: EnumFlatMode.ValueType +FLAT_MODE_LIVE_BURST: EnumFlatMode.ValueType +FLAT_MODE_NIGHT_LAPSE_VIDEO: EnumFlatMode.ValueType +FLAT_MODE_SLOMO: EnumFlatMode.ValueType +FLAT_MODE_IDLE: EnumFlatMode.ValueType +FLAT_MODE_VIDEO_STAR_TRAIL: EnumFlatMode.ValueType +FLAT_MODE_VIDEO_LIGHT_PAINTING: EnumFlatMode.ValueType +FLAT_MODE_VIDEO_LIGHT_TRAIL: EnumFlatMode.ValueType +FLAT_MODE_VIDEO_BURST_SLOMO: EnumFlatMode.ValueType +global___EnumFlatMode = EnumFlatMode + +class _EnumPresetGroup: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumPresetGroupEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumPresetGroup.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + PRESET_GROUP_ID_VIDEO: _EnumPresetGroup.ValueType + PRESET_GROUP_ID_PHOTO: _EnumPresetGroup.ValueType + PRESET_GROUP_ID_TIMELAPSE: _EnumPresetGroup.ValueType + +class EnumPresetGroup(_EnumPresetGroup, metaclass=_EnumPresetGroupEnumTypeWrapper): ... + +PRESET_GROUP_ID_VIDEO: EnumPresetGroup.ValueType +PRESET_GROUP_ID_PHOTO: EnumPresetGroup.ValueType +PRESET_GROUP_ID_TIMELAPSE: EnumPresetGroup.ValueType +global___EnumPresetGroup = EnumPresetGroup + +class _EnumPresetGroupIcon: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumPresetGroupIconEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumPresetGroupIcon.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + PRESET_GROUP_VIDEO_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_PHOTO_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_TIMELAPSE_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_LONG_BAT_VIDEO_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_ENDURANCE_VIDEO_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_MAX_VIDEO_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_MAX_PHOTO_ICON_ID: _EnumPresetGroupIcon.ValueType + PRESET_GROUP_MAX_TIMELAPSE_ICON_ID: _EnumPresetGroupIcon.ValueType + +class EnumPresetGroupIcon(_EnumPresetGroupIcon, metaclass=_EnumPresetGroupIconEnumTypeWrapper): ... + +PRESET_GROUP_VIDEO_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_PHOTO_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_TIMELAPSE_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_LONG_BAT_VIDEO_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_ENDURANCE_VIDEO_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_MAX_VIDEO_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_MAX_PHOTO_ICON_ID: EnumPresetGroupIcon.ValueType +PRESET_GROUP_MAX_TIMELAPSE_ICON_ID: EnumPresetGroupIcon.ValueType +global___EnumPresetGroupIcon = EnumPresetGroupIcon + +class _EnumPresetIcon: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumPresetIconEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumPresetIcon.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + PRESET_ICON_VIDEO: _EnumPresetIcon.ValueType + PRESET_ICON_ACTIVITY: _EnumPresetIcon.ValueType + PRESET_ICON_CINEMATIC: _EnumPresetIcon.ValueType + PRESET_ICON_PHOTO: _EnumPresetIcon.ValueType + PRESET_ICON_LIVE_BURST: _EnumPresetIcon.ValueType + PRESET_ICON_BURST: _EnumPresetIcon.ValueType + PRESET_ICON_PHOTO_NIGHT: _EnumPresetIcon.ValueType + PRESET_ICON_TIMEWARP: _EnumPresetIcon.ValueType + PRESET_ICON_TIMELAPSE: _EnumPresetIcon.ValueType + PRESET_ICON_NIGHTLAPSE: _EnumPresetIcon.ValueType + PRESET_ICON_SNAIL: _EnumPresetIcon.ValueType + PRESET_ICON_VIDEO_2: _EnumPresetIcon.ValueType + PRESET_ICON_PHOTO_2: _EnumPresetIcon.ValueType + PRESET_ICON_PANORAMA: _EnumPresetIcon.ValueType + PRESET_ICON_BURST_2: _EnumPresetIcon.ValueType + PRESET_ICON_TIMEWARP_2: _EnumPresetIcon.ValueType + PRESET_ICON_TIMELAPSE_2: _EnumPresetIcon.ValueType + PRESET_ICON_CUSTOM: _EnumPresetIcon.ValueType + PRESET_ICON_AIR: _EnumPresetIcon.ValueType + PRESET_ICON_BIKE: _EnumPresetIcon.ValueType + PRESET_ICON_EPIC: _EnumPresetIcon.ValueType + PRESET_ICON_INDOOR: _EnumPresetIcon.ValueType + PRESET_ICON_MOTOR: _EnumPresetIcon.ValueType + PRESET_ICON_MOUNTED: _EnumPresetIcon.ValueType + PRESET_ICON_OUTDOOR: _EnumPresetIcon.ValueType + PRESET_ICON_POV: _EnumPresetIcon.ValueType + PRESET_ICON_SELFIE: _EnumPresetIcon.ValueType + PRESET_ICON_SKATE: _EnumPresetIcon.ValueType + PRESET_ICON_SNOW: _EnumPresetIcon.ValueType + PRESET_ICON_TRAIL: _EnumPresetIcon.ValueType + PRESET_ICON_TRAVEL: _EnumPresetIcon.ValueType + PRESET_ICON_WATER: _EnumPresetIcon.ValueType + PRESET_ICON_LOOPING: _EnumPresetIcon.ValueType + PRESET_ICON_STARS: _EnumPresetIcon.ValueType + PRESET_ICON_ACTION: _EnumPresetIcon.ValueType + PRESET_ICON_FOLLOW_CAM: _EnumPresetIcon.ValueType + PRESET_ICON_SURF: _EnumPresetIcon.ValueType + PRESET_ICON_CITY: _EnumPresetIcon.ValueType + PRESET_ICON_SHAKY: _EnumPresetIcon.ValueType + PRESET_ICON_CHESTY: _EnumPresetIcon.ValueType + PRESET_ICON_HELMET: _EnumPresetIcon.ValueType + PRESET_ICON_BITE: _EnumPresetIcon.ValueType + PRESET_ICON_BASIC: _EnumPresetIcon.ValueType + PRESET_ICON_ULTRA_SLO_MO: _EnumPresetIcon.ValueType + PRESET_ICON_STANDARD_ENDURANCE: _EnumPresetIcon.ValueType + PRESET_ICON_ACTIVITY_ENDURANCE: _EnumPresetIcon.ValueType + PRESET_ICON_CINEMATIC_ENDURANCE: _EnumPresetIcon.ValueType + PRESET_ICON_SLOMO_ENDURANCE: _EnumPresetIcon.ValueType + PRESET_ICON_STATIONARY_1: _EnumPresetIcon.ValueType + PRESET_ICON_STATIONARY_2: _EnumPresetIcon.ValueType + PRESET_ICON_STATIONARY_3: _EnumPresetIcon.ValueType + PRESET_ICON_STATIONARY_4: _EnumPresetIcon.ValueType + PRESET_ICON_SIMPLE_SUPER_PHOTO: _EnumPresetIcon.ValueType + PRESET_ICON_SIMPLE_NIGHT_PHOTO: _EnumPresetIcon.ValueType + PRESET_ICON_HIGHEST_QUALITY_VIDEO: _EnumPresetIcon.ValueType + PRESET_ICON_STANDARD_QUALITY_VIDEO: _EnumPresetIcon.ValueType + PRESET_ICON_BASIC_QUALITY_VIDEO: _EnumPresetIcon.ValueType + PRESET_ICON_STAR_TRAIL: _EnumPresetIcon.ValueType + PRESET_ICON_LIGHT_PAINTING: _EnumPresetIcon.ValueType + PRESET_ICON_LIGHT_TRAIL: _EnumPresetIcon.ValueType + PRESET_ICON_FULL_FRAME: _EnumPresetIcon.ValueType + PRESET_ICON_TIMELAPSE_PHOTO: _EnumPresetIcon.ValueType + PRESET_ICON_NIGHTLAPSE_PHOTO: _EnumPresetIcon.ValueType + +class EnumPresetIcon(_EnumPresetIcon, metaclass=_EnumPresetIconEnumTypeWrapper): ... + +PRESET_ICON_VIDEO: EnumPresetIcon.ValueType +PRESET_ICON_ACTIVITY: EnumPresetIcon.ValueType +PRESET_ICON_CINEMATIC: EnumPresetIcon.ValueType +PRESET_ICON_PHOTO: EnumPresetIcon.ValueType +PRESET_ICON_LIVE_BURST: EnumPresetIcon.ValueType +PRESET_ICON_BURST: EnumPresetIcon.ValueType +PRESET_ICON_PHOTO_NIGHT: EnumPresetIcon.ValueType +PRESET_ICON_TIMEWARP: EnumPresetIcon.ValueType +PRESET_ICON_TIMELAPSE: EnumPresetIcon.ValueType +PRESET_ICON_NIGHTLAPSE: EnumPresetIcon.ValueType +PRESET_ICON_SNAIL: EnumPresetIcon.ValueType +PRESET_ICON_VIDEO_2: EnumPresetIcon.ValueType +PRESET_ICON_PHOTO_2: EnumPresetIcon.ValueType +PRESET_ICON_PANORAMA: EnumPresetIcon.ValueType +PRESET_ICON_BURST_2: EnumPresetIcon.ValueType +PRESET_ICON_TIMEWARP_2: EnumPresetIcon.ValueType +PRESET_ICON_TIMELAPSE_2: EnumPresetIcon.ValueType +PRESET_ICON_CUSTOM: EnumPresetIcon.ValueType +PRESET_ICON_AIR: EnumPresetIcon.ValueType +PRESET_ICON_BIKE: EnumPresetIcon.ValueType +PRESET_ICON_EPIC: EnumPresetIcon.ValueType +PRESET_ICON_INDOOR: EnumPresetIcon.ValueType +PRESET_ICON_MOTOR: EnumPresetIcon.ValueType +PRESET_ICON_MOUNTED: EnumPresetIcon.ValueType +PRESET_ICON_OUTDOOR: EnumPresetIcon.ValueType +PRESET_ICON_POV: EnumPresetIcon.ValueType +PRESET_ICON_SELFIE: EnumPresetIcon.ValueType +PRESET_ICON_SKATE: EnumPresetIcon.ValueType +PRESET_ICON_SNOW: EnumPresetIcon.ValueType +PRESET_ICON_TRAIL: EnumPresetIcon.ValueType +PRESET_ICON_TRAVEL: EnumPresetIcon.ValueType +PRESET_ICON_WATER: EnumPresetIcon.ValueType +PRESET_ICON_LOOPING: EnumPresetIcon.ValueType +PRESET_ICON_STARS: EnumPresetIcon.ValueType +PRESET_ICON_ACTION: EnumPresetIcon.ValueType +PRESET_ICON_FOLLOW_CAM: EnumPresetIcon.ValueType +PRESET_ICON_SURF: EnumPresetIcon.ValueType +PRESET_ICON_CITY: EnumPresetIcon.ValueType +PRESET_ICON_SHAKY: EnumPresetIcon.ValueType +PRESET_ICON_CHESTY: EnumPresetIcon.ValueType +PRESET_ICON_HELMET: EnumPresetIcon.ValueType +PRESET_ICON_BITE: EnumPresetIcon.ValueType +PRESET_ICON_BASIC: EnumPresetIcon.ValueType +PRESET_ICON_ULTRA_SLO_MO: EnumPresetIcon.ValueType +PRESET_ICON_STANDARD_ENDURANCE: EnumPresetIcon.ValueType +PRESET_ICON_ACTIVITY_ENDURANCE: EnumPresetIcon.ValueType +PRESET_ICON_CINEMATIC_ENDURANCE: EnumPresetIcon.ValueType +PRESET_ICON_SLOMO_ENDURANCE: EnumPresetIcon.ValueType +PRESET_ICON_STATIONARY_1: EnumPresetIcon.ValueType +PRESET_ICON_STATIONARY_2: EnumPresetIcon.ValueType +PRESET_ICON_STATIONARY_3: EnumPresetIcon.ValueType +PRESET_ICON_STATIONARY_4: EnumPresetIcon.ValueType +PRESET_ICON_SIMPLE_SUPER_PHOTO: EnumPresetIcon.ValueType +PRESET_ICON_SIMPLE_NIGHT_PHOTO: EnumPresetIcon.ValueType +PRESET_ICON_HIGHEST_QUALITY_VIDEO: EnumPresetIcon.ValueType +PRESET_ICON_STANDARD_QUALITY_VIDEO: EnumPresetIcon.ValueType +PRESET_ICON_BASIC_QUALITY_VIDEO: EnumPresetIcon.ValueType +PRESET_ICON_STAR_TRAIL: EnumPresetIcon.ValueType +PRESET_ICON_LIGHT_PAINTING: EnumPresetIcon.ValueType +PRESET_ICON_LIGHT_TRAIL: EnumPresetIcon.ValueType +PRESET_ICON_FULL_FRAME: EnumPresetIcon.ValueType +PRESET_ICON_TIMELAPSE_PHOTO: EnumPresetIcon.ValueType +PRESET_ICON_NIGHTLAPSE_PHOTO: EnumPresetIcon.ValueType +global___EnumPresetIcon = EnumPresetIcon + +class _EnumPresetTitle: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumPresetTitleEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumPresetTitle.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + PRESET_TITLE_ACTIVITY: _EnumPresetTitle.ValueType + PRESET_TITLE_STANDARD: _EnumPresetTitle.ValueType + PRESET_TITLE_CINEMATIC: _EnumPresetTitle.ValueType + PRESET_TITLE_PHOTO: _EnumPresetTitle.ValueType + PRESET_TITLE_LIVE_BURST: _EnumPresetTitle.ValueType + PRESET_TITLE_BURST: _EnumPresetTitle.ValueType + PRESET_TITLE_NIGHT: _EnumPresetTitle.ValueType + PRESET_TITLE_TIME_WARP: _EnumPresetTitle.ValueType + PRESET_TITLE_TIME_LAPSE: _EnumPresetTitle.ValueType + PRESET_TITLE_NIGHT_LAPSE: _EnumPresetTitle.ValueType + PRESET_TITLE_VIDEO: _EnumPresetTitle.ValueType + PRESET_TITLE_SLOMO: _EnumPresetTitle.ValueType + PRESET_TITLE_PHOTO_2: _EnumPresetTitle.ValueType + PRESET_TITLE_PANORAMA: _EnumPresetTitle.ValueType + PRESET_TITLE_TIME_WARP_2: _EnumPresetTitle.ValueType + PRESET_TITLE_CUSTOM: _EnumPresetTitle.ValueType + PRESET_TITLE_AIR: _EnumPresetTitle.ValueType + PRESET_TITLE_BIKE: _EnumPresetTitle.ValueType + PRESET_TITLE_EPIC: _EnumPresetTitle.ValueType + PRESET_TITLE_INDOOR: _EnumPresetTitle.ValueType + PRESET_TITLE_MOTOR: _EnumPresetTitle.ValueType + PRESET_TITLE_MOUNTED: _EnumPresetTitle.ValueType + PRESET_TITLE_OUTDOOR: _EnumPresetTitle.ValueType + PRESET_TITLE_POV: _EnumPresetTitle.ValueType + PRESET_TITLE_SELFIE: _EnumPresetTitle.ValueType + PRESET_TITLE_SKATE: _EnumPresetTitle.ValueType + PRESET_TITLE_SNOW: _EnumPresetTitle.ValueType + PRESET_TITLE_TRAIL: _EnumPresetTitle.ValueType + PRESET_TITLE_TRAVEL: _EnumPresetTitle.ValueType + PRESET_TITLE_WATER: _EnumPresetTitle.ValueType + PRESET_TITLE_LOOPING: _EnumPresetTitle.ValueType + PRESET_TITLE_STARS: _EnumPresetTitle.ValueType + PRESET_TITLE_ACTION: _EnumPresetTitle.ValueType + PRESET_TITLE_FOLLOW_CAM: _EnumPresetTitle.ValueType + PRESET_TITLE_SURF: _EnumPresetTitle.ValueType + PRESET_TITLE_CITY: _EnumPresetTitle.ValueType + PRESET_TITLE_SHAKY: _EnumPresetTitle.ValueType + PRESET_TITLE_CHESTY: _EnumPresetTitle.ValueType + PRESET_TITLE_HELMET: _EnumPresetTitle.ValueType + PRESET_TITLE_BITE: _EnumPresetTitle.ValueType + PRESET_TITLE_BASIC: _EnumPresetTitle.ValueType + PRESET_TITLE_ULTRA_SLO_MO: _EnumPresetTitle.ValueType + PRESET_TITLE_STANDARD_ENDURANCE: _EnumPresetTitle.ValueType + PRESET_TITLE_ACTIVITY_ENDURANCE: _EnumPresetTitle.ValueType + PRESET_TITLE_CINEMATIC_ENDURANCE: _EnumPresetTitle.ValueType + PRESET_TITLE_SLOMO_ENDURANCE: _EnumPresetTitle.ValueType + PRESET_TITLE_STATIONARY_1: _EnumPresetTitle.ValueType + PRESET_TITLE_STATIONARY_2: _EnumPresetTitle.ValueType + PRESET_TITLE_STATIONARY_3: _EnumPresetTitle.ValueType + PRESET_TITLE_STATIONARY_4: _EnumPresetTitle.ValueType + PRESET_TITLE_SIMPLE_VIDEO: _EnumPresetTitle.ValueType + PRESET_TITLE_SIMPLE_TIME_WARP: _EnumPresetTitle.ValueType + PRESET_TITLE_SIMPLE_SUPER_PHOTO: _EnumPresetTitle.ValueType + PRESET_TITLE_SIMPLE_NIGHT_PHOTO: _EnumPresetTitle.ValueType + PRESET_TITLE_SIMPLE_VIDEO_ENDURANCE: _EnumPresetTitle.ValueType + PRESET_TITLE_HIGHEST_QUALITY: _EnumPresetTitle.ValueType + PRESET_TITLE_EXTENDED_BATTERY: _EnumPresetTitle.ValueType + PRESET_TITLE_LONGEST_BATTERY: _EnumPresetTitle.ValueType + PRESET_TITLE_STAR_TRAIL: _EnumPresetTitle.ValueType + PRESET_TITLE_LIGHT_PAINTING: _EnumPresetTitle.ValueType + PRESET_TITLE_LIGHT_TRAIL: _EnumPresetTitle.ValueType + PRESET_TITLE_FULL_FRAME: _EnumPresetTitle.ValueType + PRESET_TITLE_STANDARD_QUALITY_VIDEO: _EnumPresetTitle.ValueType + PRESET_TITLE_BASIC_QUALITY_VIDEO: _EnumPresetTitle.ValueType + PRESET_TITLE_HIGHEST_QUALITY_VIDEO: _EnumPresetTitle.ValueType + PRESET_TITLE_USER_DEFINED_CUSTOM_NAME: _EnumPresetTitle.ValueType + +class EnumPresetTitle(_EnumPresetTitle, metaclass=_EnumPresetTitleEnumTypeWrapper): ... + +PRESET_TITLE_ACTIVITY: EnumPresetTitle.ValueType +PRESET_TITLE_STANDARD: EnumPresetTitle.ValueType +PRESET_TITLE_CINEMATIC: EnumPresetTitle.ValueType +PRESET_TITLE_PHOTO: EnumPresetTitle.ValueType +PRESET_TITLE_LIVE_BURST: EnumPresetTitle.ValueType +PRESET_TITLE_BURST: EnumPresetTitle.ValueType +PRESET_TITLE_NIGHT: EnumPresetTitle.ValueType +PRESET_TITLE_TIME_WARP: EnumPresetTitle.ValueType +PRESET_TITLE_TIME_LAPSE: EnumPresetTitle.ValueType +PRESET_TITLE_NIGHT_LAPSE: EnumPresetTitle.ValueType +PRESET_TITLE_VIDEO: EnumPresetTitle.ValueType +PRESET_TITLE_SLOMO: EnumPresetTitle.ValueType +PRESET_TITLE_PHOTO_2: EnumPresetTitle.ValueType +PRESET_TITLE_PANORAMA: EnumPresetTitle.ValueType +PRESET_TITLE_TIME_WARP_2: EnumPresetTitle.ValueType +PRESET_TITLE_CUSTOM: EnumPresetTitle.ValueType +PRESET_TITLE_AIR: EnumPresetTitle.ValueType +PRESET_TITLE_BIKE: EnumPresetTitle.ValueType +PRESET_TITLE_EPIC: EnumPresetTitle.ValueType +PRESET_TITLE_INDOOR: EnumPresetTitle.ValueType +PRESET_TITLE_MOTOR: EnumPresetTitle.ValueType +PRESET_TITLE_MOUNTED: EnumPresetTitle.ValueType +PRESET_TITLE_OUTDOOR: EnumPresetTitle.ValueType +PRESET_TITLE_POV: EnumPresetTitle.ValueType +PRESET_TITLE_SELFIE: EnumPresetTitle.ValueType +PRESET_TITLE_SKATE: EnumPresetTitle.ValueType +PRESET_TITLE_SNOW: EnumPresetTitle.ValueType +PRESET_TITLE_TRAIL: EnumPresetTitle.ValueType +PRESET_TITLE_TRAVEL: EnumPresetTitle.ValueType +PRESET_TITLE_WATER: EnumPresetTitle.ValueType +PRESET_TITLE_LOOPING: EnumPresetTitle.ValueType +PRESET_TITLE_STARS: EnumPresetTitle.ValueType +PRESET_TITLE_ACTION: EnumPresetTitle.ValueType +PRESET_TITLE_FOLLOW_CAM: EnumPresetTitle.ValueType +PRESET_TITLE_SURF: EnumPresetTitle.ValueType +PRESET_TITLE_CITY: EnumPresetTitle.ValueType +PRESET_TITLE_SHAKY: EnumPresetTitle.ValueType +PRESET_TITLE_CHESTY: EnumPresetTitle.ValueType +PRESET_TITLE_HELMET: EnumPresetTitle.ValueType +PRESET_TITLE_BITE: EnumPresetTitle.ValueType +PRESET_TITLE_BASIC: EnumPresetTitle.ValueType +PRESET_TITLE_ULTRA_SLO_MO: EnumPresetTitle.ValueType +PRESET_TITLE_STANDARD_ENDURANCE: EnumPresetTitle.ValueType +PRESET_TITLE_ACTIVITY_ENDURANCE: EnumPresetTitle.ValueType +PRESET_TITLE_CINEMATIC_ENDURANCE: EnumPresetTitle.ValueType +PRESET_TITLE_SLOMO_ENDURANCE: EnumPresetTitle.ValueType +PRESET_TITLE_STATIONARY_1: EnumPresetTitle.ValueType +PRESET_TITLE_STATIONARY_2: EnumPresetTitle.ValueType +PRESET_TITLE_STATIONARY_3: EnumPresetTitle.ValueType +PRESET_TITLE_STATIONARY_4: EnumPresetTitle.ValueType +PRESET_TITLE_SIMPLE_VIDEO: EnumPresetTitle.ValueType +PRESET_TITLE_SIMPLE_TIME_WARP: EnumPresetTitle.ValueType +PRESET_TITLE_SIMPLE_SUPER_PHOTO: EnumPresetTitle.ValueType +PRESET_TITLE_SIMPLE_NIGHT_PHOTO: EnumPresetTitle.ValueType +PRESET_TITLE_SIMPLE_VIDEO_ENDURANCE: EnumPresetTitle.ValueType +PRESET_TITLE_HIGHEST_QUALITY: EnumPresetTitle.ValueType +PRESET_TITLE_EXTENDED_BATTERY: EnumPresetTitle.ValueType +PRESET_TITLE_LONGEST_BATTERY: EnumPresetTitle.ValueType +PRESET_TITLE_STAR_TRAIL: EnumPresetTitle.ValueType +PRESET_TITLE_LIGHT_PAINTING: EnumPresetTitle.ValueType +PRESET_TITLE_LIGHT_TRAIL: EnumPresetTitle.ValueType +PRESET_TITLE_FULL_FRAME: EnumPresetTitle.ValueType +PRESET_TITLE_STANDARD_QUALITY_VIDEO: EnumPresetTitle.ValueType +PRESET_TITLE_BASIC_QUALITY_VIDEO: EnumPresetTitle.ValueType +PRESET_TITLE_HIGHEST_QUALITY_VIDEO: EnumPresetTitle.ValueType +PRESET_TITLE_USER_DEFINED_CUSTOM_NAME: EnumPresetTitle.ValueType +global___EnumPresetTitle = EnumPresetTitle + +@typing_extensions.final +class NotifyPresetStatus(google.protobuf.message.Message): + """* + Current Preset status + + Sent either: + + - Synchronously via initial response to @ref RequestGetPresetStatus + - Asynchronously when Preset change if registered in @ref RequestGetPresetStatus + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + PRESET_GROUP_ARRAY_FIELD_NUMBER: builtins.int + + @property + def preset_group_array( + self, + ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___PresetGroup]: + """List of currently available Preset Groups""" + + def __init__(self, *, preset_group_array: collections.abc.Iterable[global___PresetGroup] | None = ...) -> None: ... + def ClearField( + self, + field_name: typing_extensions.Literal["preset_group_array", b"preset_group_array"], + ) -> None: ... + +global___NotifyPresetStatus = NotifyPresetStatus + +@typing_extensions.final +class Preset(google.protobuf.message.Message): + """* + An individual preset. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + ID_FIELD_NUMBER: builtins.int + MODE_FIELD_NUMBER: builtins.int + TITLE_ID_FIELD_NUMBER: builtins.int + TITLE_NUMBER_FIELD_NUMBER: builtins.int + USER_DEFINED_FIELD_NUMBER: builtins.int + ICON_FIELD_NUMBER: builtins.int + SETTING_ARRAY_FIELD_NUMBER: builtins.int + IS_MODIFIED_FIELD_NUMBER: builtins.int + IS_FIXED_FIELD_NUMBER: builtins.int + CUSTOM_NAME_FIELD_NUMBER: builtins.int + id: builtins.int + "Preset ID" + mode: global___EnumFlatMode.ValueType + "Preset flatmode ID" + title_id: global___EnumPresetTitle.ValueType + "Preset Title ID" + title_number: builtins.int + "Preset Title Number (e.g. 1/2/3 in Custom1, Custom2, Custom3)" + user_defined: builtins.bool + "Is the Preset custom/user-defined?" + icon: global___EnumPresetIcon.ValueType + "Preset Icon ID" + + @property + def setting_array( + self, + ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___PresetSetting]: + """Array of settings associated with this Preset""" + is_modified: builtins.bool + "Has Preset been modified from factory defaults? (False for user-defined Presets)" + is_fixed: builtins.bool + "Is this Preset mutable?" + custom_name: builtins.str + "Custom string name given to this preset via @ref RequestCustomPresetUpdate" + + def __init__( + self, + *, + id: builtins.int | None = ..., + mode: global___EnumFlatMode.ValueType | None = ..., + title_id: global___EnumPresetTitle.ValueType | None = ..., + title_number: builtins.int | None = ..., + user_defined: builtins.bool | None = ..., + icon: global___EnumPresetIcon.ValueType | None = ..., + setting_array: collections.abc.Iterable[global___PresetSetting] | None = ..., + is_modified: builtins.bool | None = ..., + is_fixed: builtins.bool | None = ..., + custom_name: builtins.str | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "custom_name", + b"custom_name", + "icon", + b"icon", + "id", + b"id", + "is_fixed", + b"is_fixed", + "is_modified", + b"is_modified", + "mode", + b"mode", + "title_id", + b"title_id", + "title_number", + b"title_number", + "user_defined", + b"user_defined", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "custom_name", + b"custom_name", + "icon", + b"icon", + "id", + b"id", + "is_fixed", + b"is_fixed", + "is_modified", + b"is_modified", + "mode", + b"mode", + "setting_array", + b"setting_array", + "title_id", + b"title_id", + "title_number", + b"title_number", + "user_defined", + b"user_defined", + ], + ) -> None: ... + +global___Preset = Preset + +@typing_extensions.final +class RequestCustomPresetUpdate(google.protobuf.message.Message): + """* + Request to Update the Title and / or Icon of the Active Custom Preset + + This only operates on the currently active Preset and will fail if the current + Preset is not custom. + + The use cases are: + + 1. Update the Custom Preset Icon + + - `icon_id` is always optional and can always be passed + + and / or + + 2. Update the Custom Preset Title to a... + + - **Factory Preset Title**: Set `title_id` to a non-PRESET_TITLE_USER_DEFINED_CUSTOM_NAME (94) value + - **Custom Preset Name**: Set `title_id` to PRESET_TITLE_USER_DEFINED_CUSTOM_NAME (94) and specify a `custom_name` + + Returns a @ref ResponseGeneric with the status of the preset update request. + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + TITLE_ID_FIELD_NUMBER: builtins.int + CUSTOM_NAME_FIELD_NUMBER: builtins.int + ICON_ID_FIELD_NUMBER: builtins.int + title_id: global___EnumPresetTitle.ValueType + "*\n Preset Title ID\n\n The range of acceptable custom title ID's can be found in the initial @ref NotifyPresetStatus response\n to @ref RequestGetPresetStatus\n " + custom_name: builtins.str + "*\n UTF-8 encoded custom preset name\n\n The name must obey the following:\n\n - Custom titles must be between 1 and 16 characters (inclusive)\n - No special characters outside of the following languages: English, French, Italian, German,\n Spanish, Portuguese, Swedish, Russian\n " + icon_id: global___EnumPresetIcon.ValueType + "*\n Preset Icon ID\n\n The range of acceptable custom icon ID's can be found in the initial @ref NotifyPresetStatus response to\n @ref RequestGetPresetStatus\n " + + def __init__( + self, + *, + title_id: global___EnumPresetTitle.ValueType | None = ..., + custom_name: builtins.str | None = ..., + icon_id: global___EnumPresetIcon.ValueType | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "custom_name", + b"custom_name", + "icon_id", + b"icon_id", + "title_id", + b"title_id", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "custom_name", + b"custom_name", + "icon_id", + b"icon_id", + "title_id", + b"title_id", + ], + ) -> None: ... + +global___RequestCustomPresetUpdate = RequestCustomPresetUpdate + +@typing_extensions.final +class PresetGroup(google.protobuf.message.Message): + """ + Preset Group meta information and contained Presets + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + ID_FIELD_NUMBER: builtins.int + PRESET_ARRAY_FIELD_NUMBER: builtins.int + CAN_ADD_PRESET_FIELD_NUMBER: builtins.int + ICON_FIELD_NUMBER: builtins.int + id: global___EnumPresetGroup.ValueType + "Preset Group ID" + + @property + def preset_array( + self, + ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Preset]: + """Array of Presets contained in this Preset Group""" + can_add_preset: builtins.bool + "Is there room in the group to add additional Presets?" + icon: global___EnumPresetGroupIcon.ValueType + "The icon to display for this preset group" + + def __init__( + self, + *, + id: global___EnumPresetGroup.ValueType | None = ..., + preset_array: collections.abc.Iterable[global___Preset] | None = ..., + can_add_preset: builtins.bool | None = ..., + icon: global___EnumPresetGroupIcon.ValueType | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["can_add_preset", b"can_add_preset", "icon", b"icon", "id", b"id"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "can_add_preset", + b"can_add_preset", + "icon", + b"icon", + "id", + b"id", + "preset_array", + b"preset_array", + ], + ) -> None: ... + +global___PresetGroup = PresetGroup + +@typing_extensions.final +class PresetSetting(google.protobuf.message.Message): + """* + Setting representation that comprises a @ref Preset + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + ID_FIELD_NUMBER: builtins.int + VALUE_FIELD_NUMBER: builtins.int + IS_CAPTION_FIELD_NUMBER: builtins.int + id: builtins.int + "Setting ID" + value: builtins.int + "Setting value" + is_caption: builtins.bool + 'Does this setting appear on the Preset "pill" in the camera UI?' + + def __init__( + self, *, id: builtins.int | None = ..., value: builtins.int | None = ..., is_caption: builtins.bool | None = ... + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["id", b"id", "is_caption", b"is_caption", "value", b"value"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["id", b"id", "is_caption", b"is_caption", "value", b"value"], + ) -> None: ... + +global___PresetSetting = PresetSetting diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/request_get_preset_status_pb2.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/request_get_preset_status_pb2.py new file mode 100644 index 00000000..28fe041f --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/request_get_preset_status_pb2.py @@ -0,0 +1,22 @@ +# request_get_preset_status_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +"""Generated protocol buffer code.""" + +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database + +_sym_db = _symbol_database.Default() +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x1frequest_get_preset_status.proto\x12\nopen_gopro"\xa6\x01\n\x16RequestGetPresetStatus\x12D\n\x16register_preset_status\x18\x01 \x03(\x0e2$.open_gopro.EnumRegisterPresetStatus\x12F\n\x18unregister_preset_status\x18\x02 \x03(\x0e2$.open_gopro.EnumRegisterPresetStatus*l\n\x18EnumRegisterPresetStatus\x12!\n\x1dREGISTER_PRESET_STATUS_PRESET\x10\x01\x12-\n)REGISTER_PRESET_STATUS_PRESET_GROUP_ARRAY\x10\x02' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "request_get_preset_status_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMREGISTERPRESETSTATUS._serialized_start = 216 + _ENUMREGISTERPRESETSTATUS._serialized_end = 324 + _REQUESTGETPRESETSTATUS._serialized_start = 48 + _REQUESTGETPRESETSTATUS._serialized_end = 214 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/request_get_preset_status_pb2.pyi b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/request_get_preset_status_pb2.pyi new file mode 100644 index 00000000..13e7d1c8 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/request_get_preset_status_pb2.pyi @@ -0,0 +1,93 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf messages for obtaining preset status +""" + +import builtins +import collections.abc +import google.protobuf.descriptor +import google.protobuf.internal.containers +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumRegisterPresetStatus: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumRegisterPresetStatusEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumRegisterPresetStatus.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + REGISTER_PRESET_STATUS_PRESET: _EnumRegisterPresetStatus.ValueType + "Send notification when properties of a preset change" + REGISTER_PRESET_STATUS_PRESET_GROUP_ARRAY: _EnumRegisterPresetStatus.ValueType + "Send notification when properties of a preset group change" + +class EnumRegisterPresetStatus(_EnumRegisterPresetStatus, metaclass=_EnumRegisterPresetStatusEnumTypeWrapper): ... + +REGISTER_PRESET_STATUS_PRESET: EnumRegisterPresetStatus.ValueType +"Send notification when properties of a preset change" +REGISTER_PRESET_STATUS_PRESET_GROUP_ARRAY: EnumRegisterPresetStatus.ValueType +"Send notification when properties of a preset group change" +global___EnumRegisterPresetStatus = EnumRegisterPresetStatus + +@typing_extensions.final +class RequestGetPresetStatus(google.protobuf.message.Message): + """* + Get the set of currently available presets and optionally register to be notified when it changes. + + Response: @ref NotifyPresetStatus sent immediately + + Notification: @ref NotifyPresetStatus sent periodically as preset status changes, if registered. + + The preset status changes when: + + - A client changes one of a preset's captioned settings via the API + - The user exits from a preset's settings UI on the camera (e.g. long-press the preset pill and then press the back arrow) + - The user creates/deletes/reorders a preset within a group + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + REGISTER_PRESET_STATUS_FIELD_NUMBER: builtins.int + UNREGISTER_PRESET_STATUS_FIELD_NUMBER: builtins.int + + @property + def register_preset_status( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___EnumRegisterPresetStatus.ValueType]: + """Array of Preset statuses to be notified about""" + + @property + def unregister_preset_status( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___EnumRegisterPresetStatus.ValueType]: + """Array of Preset statuses to stop being notified about""" + + def __init__( + self, + *, + register_preset_status: collections.abc.Iterable[global___EnumRegisterPresetStatus.ValueType] | None = ..., + unregister_preset_status: collections.abc.Iterable[global___EnumRegisterPresetStatus.ValueType] | None = ... + ) -> None: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "register_preset_status", + b"register_preset_status", + "unregister_preset_status", + b"unregister_preset_status", + ], + ) -> None: ... + +global___RequestGetPresetStatus = RequestGetPresetStatus diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/response_generic_pb2.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/response_generic_pb2.py new file mode 100644 index 00000000..a61b782b --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/response_generic_pb2.py @@ -0,0 +1,24 @@ +# response_generic_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +"""Generated protocol buffer code.""" + +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database + +_sym_db = _symbol_database.Default() +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x16response_generic.proto\x12\nopen_gopro"@\n\x0fResponseGeneric\x12-\n\x06result\x18\x01 \x02(\x0e2\x1d.open_gopro.EnumResultGeneric"%\n\x05Media\x12\x0e\n\x06folder\x18\x01 \x01(\t\x12\x0c\n\x04file\x18\x02 \x01(\t*\xcf\x01\n\x11EnumResultGeneric\x12\x12\n\x0eRESULT_UNKNOWN\x10\x00\x12\x12\n\x0eRESULT_SUCCESS\x10\x01\x12\x15\n\x11RESULT_ILL_FORMED\x10\x02\x12\x18\n\x14RESULT_NOT_SUPPORTED\x10\x03\x12!\n\x1dRESULT_ARGUMENT_OUT_OF_BOUNDS\x10\x04\x12\x1b\n\x17RESULT_ARGUMENT_INVALID\x10\x05\x12!\n\x1dRESULT_RESOURCE_NOT_AVAILABLE\x10\x06' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "response_generic_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMRESULTGENERIC._serialized_start = 144 + _ENUMRESULTGENERIC._serialized_end = 351 + _RESPONSEGENERIC._serialized_start = 38 + _RESPONSEGENERIC._serialized_end = 102 + _MEDIA._serialized_start = 104 + _MEDIA._serialized_end = 141 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/response_generic_pb2.pyi b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/response_generic_pb2.pyi new file mode 100644 index 00000000..85655c36 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/response_generic_pb2.pyi @@ -0,0 +1,90 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf message containing generic response to a command +""" + +import builtins +import google.protobuf.descriptor +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumResultGeneric: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumResultGenericEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumResultGeneric.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + RESULT_UNKNOWN: _EnumResultGeneric.ValueType + RESULT_SUCCESS: _EnumResultGeneric.ValueType + RESULT_ILL_FORMED: _EnumResultGeneric.ValueType + RESULT_NOT_SUPPORTED: _EnumResultGeneric.ValueType + RESULT_ARGUMENT_OUT_OF_BOUNDS: _EnumResultGeneric.ValueType + RESULT_ARGUMENT_INVALID: _EnumResultGeneric.ValueType + RESULT_RESOURCE_NOT_AVAILABLE: _EnumResultGeneric.ValueType + +class EnumResultGeneric(_EnumResultGeneric, metaclass=_EnumResultGenericEnumTypeWrapper): ... + +RESULT_UNKNOWN: EnumResultGeneric.ValueType +RESULT_SUCCESS: EnumResultGeneric.ValueType +RESULT_ILL_FORMED: EnumResultGeneric.ValueType +RESULT_NOT_SUPPORTED: EnumResultGeneric.ValueType +RESULT_ARGUMENT_OUT_OF_BOUNDS: EnumResultGeneric.ValueType +RESULT_ARGUMENT_INVALID: EnumResultGeneric.ValueType +RESULT_RESOURCE_NOT_AVAILABLE: EnumResultGeneric.ValueType +global___EnumResultGeneric = EnumResultGeneric + +@typing_extensions.final +class ResponseGeneric(google.protobuf.message.Message): + """ + Generic Response used across many response / notification messages + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + RESULT_FIELD_NUMBER: builtins.int + result: global___EnumResultGeneric.ValueType + "Generic pass/fail/error info" + + def __init__(self, *, result: global___EnumResultGeneric.ValueType | None = ...) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["result", b"result"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["result", b"result"]) -> None: ... + +global___ResponseGeneric = ResponseGeneric + +@typing_extensions.final +class Media(google.protobuf.message.Message): + """* + A common model to represent a media file + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + FOLDER_FIELD_NUMBER: builtins.int + FILE_FIELD_NUMBER: builtins.int + folder: builtins.str + "Directory in which the media is contained" + file: builtins.str + "Filename of media" + + def __init__(self, *, folder: builtins.str | None = ..., file: builtins.str | None = ...) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["file", b"file", "folder", b"folder"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["file", b"file", "folder", b"folder"], + ) -> None: ... + +global___Media = Media diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/set_camera_control_status_pb2.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/set_camera_control_status_pb2.py new file mode 100644 index 00000000..543ced5f --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/set_camera_control_status_pb2.py @@ -0,0 +1,22 @@ +# set_camera_control_status_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +"""Generated protocol buffer code.""" + +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database + +_sym_db = _symbol_database.Default() +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x1fset_camera_control_status.proto\x12\nopen_gopro"c\n\x1dRequestSetCameraControlStatus\x12B\n\x15camera_control_status\x18\x01 \x02(\x0e2#.open_gopro.EnumCameraControlStatus*[\n\x17EnumCameraControlStatus\x12\x0f\n\x0bCAMERA_IDLE\x10\x00\x12\x12\n\x0eCAMERA_CONTROL\x10\x01\x12\x1b\n\x17CAMERA_EXTERNAL_CONTROL\x10\x02' +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "set_camera_control_status_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _ENUMCAMERACONTROLSTATUS._serialized_start = 148 + _ENUMCAMERACONTROLSTATUS._serialized_end = 239 + _REQUESTSETCAMERACONTROLSTATUS._serialized_start = 47 + _REQUESTSETCAMERACONTROLSTATUS._serialized_end = 146 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/set_camera_control_status_pb2.pyi b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/set_camera_control_status_pb2.pyi new file mode 100644 index 00000000..37b27336 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/set_camera_control_status_pb2.pyi @@ -0,0 +1,74 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf messages for setting camera control status +""" + +import builtins +import google.protobuf.descriptor +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _EnumCameraControlStatus: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _EnumCameraControlStatusEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_EnumCameraControlStatus.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + CAMERA_IDLE: _EnumCameraControlStatus.ValueType + CAMERA_CONTROL: _EnumCameraControlStatus.ValueType + "Can only be set by camera, not by app or third party" + CAMERA_EXTERNAL_CONTROL: _EnumCameraControlStatus.ValueType + +class EnumCameraControlStatus(_EnumCameraControlStatus, metaclass=_EnumCameraControlStatusEnumTypeWrapper): ... + +CAMERA_IDLE: EnumCameraControlStatus.ValueType +CAMERA_CONTROL: EnumCameraControlStatus.ValueType +"Can only be set by camera, not by app or third party" +CAMERA_EXTERNAL_CONTROL: EnumCameraControlStatus.ValueType +global___EnumCameraControlStatus = EnumCameraControlStatus + +@typing_extensions.final +class RequestSetCameraControlStatus(google.protobuf.message.Message): + """* + Set Camera Control Status (as part of Global Behaviors feature) + + This command is used to tell the camera that the app (i.e. External Control) wishes to claim control of the camera. + This causes the camera to immediately exit most contextual menus and return to the idle screen. Any interaction with + the camera's physical buttons will cause the camera to reclaim control and update control status accordingly. If the + user returns the camera UI to the idle screen, the camera updates control status to Idle. + + The entity currently claiming control of the camera is advertised in camera status 114. Information about whether the + camera is in a contextual menu or not is advertised in camera status 63. + + Response: @ref ResponseGeneric + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + CAMERA_CONTROL_STATUS_FIELD_NUMBER: builtins.int + camera_control_status: global___EnumCameraControlStatus.ValueType + "Declare who is taking control of the camera" + + def __init__(self, *, camera_control_status: global___EnumCameraControlStatus.ValueType | None = ...) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal["camera_control_status", b"camera_control_status"], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["camera_control_status", b"camera_control_status"], + ) -> None: ... + +global___RequestSetCameraControlStatus = RequestSetCameraControlStatus diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/turbo_transfer_pb2.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/turbo_transfer_pb2.py new file mode 100644 index 00000000..97d913a0 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/turbo_transfer_pb2.py @@ -0,0 +1,20 @@ +# turbo_transfer_pb2.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +"""Generated protocol buffer code.""" + +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database + +_sym_db = _symbol_database.Default() +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b"\n\x14turbo_transfer.proto\x12\nopen_gopro\"'\n\x15RequestSetTurboActive\x12\x0e\n\x06active\x18\x01 \x02(\x08" +) +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "turbo_transfer_pb2", globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _REQUESTSETTURBOACTIVE._serialized_start = 36 + _REQUESTSETTURBOACTIVE._serialized_end = 75 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/turbo_transfer_pb2.pyi b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/turbo_transfer_pb2.pyi new file mode 100644 index 00000000..0c79e66a --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/proto/turbo_transfer_pb2.pyi @@ -0,0 +1,36 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +* +Defines the structure of protobuf messages for enabling and disabling Turbo Transfer feature +""" + +import builtins +import google.protobuf.descriptor +import google.protobuf.message +import sys + +if sys.version_info >= (3, 8): + import typing as typing_extensions +else: + import typing_extensions +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +@typing_extensions.final +class RequestSetTurboActive(google.protobuf.message.Message): + """* + Enable/disable display of "Transferring Media" UI + + Response: @ref ResponseGeneric + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + ACTIVE_FIELD_NUMBER: builtins.int + active: builtins.bool + "Enable or disable Turbo Transfer feature" + + def __init__(self, *, active: builtins.bool | None = ...) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["active", b"active"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["active", b"active"]) -> None: ... + +global___RequestSetTurboActive = RequestSetTurboActive diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/protobuf_example.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/protobuf_example.py new file mode 100644 index 00000000..bf7cab06 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/protobuf_example.py @@ -0,0 +1,32 @@ +# protobuf_example.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +import sys +import argparse + +from tutorial_modules import logger, proto + + +def main() -> None: + request = proto.RequestSetTurboActive(active=False) + logger.info(f"Sending ==> {request}") + logger.info(request.SerializeToString().hex(":")) + + # We're not hard-coding serialized bytes here since it may not be constant across Protobuf versions + response_bytes = proto.ResponseGeneric(result=proto.EnumResultGeneric.RESULT_SUCCESS).SerializeToString() + logger.info(f"Received bytes ==> {response_bytes.hex(':')}") + response = proto.ResponseGeneric.FromString(response_bytes) + logger.info(f"Received ==> {response}") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Perform some basic protobuf manipulation.") + args = parser.parse_args() + + try: + main() + except Exception as e: # pylint: disable=broad-exception-caught + logger.error(e) + sys.exit(-1) + else: + sys.exit(0) diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/set_turbo_mode.py b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/set_turbo_mode.py new file mode 100644 index 00000000..ff85efea --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_5_ble_protobuf/set_turbo_mode.py @@ -0,0 +1,114 @@ +# set_turbo_mode.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +import sys +import asyncio +import argparse + +from bleak import BleakClient +from bleak.backends.characteristic import BleakGATTCharacteristic +from google.protobuf.message import Message as ProtobufMessage + +from tutorial_modules import logger +from tutorial_modules import GoProUuid, connect_ble, Response, proto + + +class ProtobufResponse(Response): + """Accumulate and parse protobuf responses""" + + def __init__(self, uuid: GoProUuid) -> None: + super().__init__(uuid) + self.feature_id: int + self.action_id: int + self.uuid = uuid + self.data: ProtobufMessage + + def parse(self, proto_message: type[ProtobufMessage]) -> None: + """Set the responses data by parsing using the passed in protobuf container + + Args: + proto_message (type[ProtobufMessage]): protobuf container to use for parsing + """ + self.feature_id = self.raw_bytes[0] + self.action_id = self.raw_bytes[1] + self.data = proto_message.FromString(bytes(self.raw_bytes[2:])) + + +async def main(identifier: str | None) -> None: + client: BleakClient + responses_by_uuid = GoProUuid.dict_by_uuid(ProtobufResponse) + received_responses: asyncio.Queue[ProtobufResponse] = asyncio.Queue() + + request_uuid = GoProUuid.COMMAND_REQ_UUID + response_uuid = GoProUuid.COMMAND_RSP_UUID + + async def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + logger.info(f"Received response at UUID {uuid}: {data.hex(':')}") + + response = responses_by_uuid[uuid] + response.accumulate(data) + + # Notify the writer if we have received the entire response + if response.is_received: + # The turbo mode response will come on the Command Response characteristic + if uuid is response_uuid: + logger.info("Set Turbo Mode response complete received.") + # Notify writer that the procedure is complete + await received_responses.put(response) + # Anything else is unexpected. This shouldn't happen + else: + logger.error("Unexpected response") + # Reset the per-uuid Response + responses_by_uuid[uuid] = ProtobufResponse(uuid) + + client = await connect_ble(notification_handler, identifier) + + logger.info("Setting Turbo Mode off.") + + # Build raw bytes request from feature / action IDs and serialized protobuf message + turbo_mode_request = bytearray( + [ + 0xF1, # Feature ID + 0x6B, # Action ID + *proto.RequestSetTurboActive(active=False).SerializeToString(), + ] + ) + turbo_mode_request.insert(0, len(turbo_mode_request)) + + # Write to command request UUID to enable turbo mode + logger.info(f"Writing {turbo_mode_request.hex(':')} to {request_uuid}") + await client.write_gatt_char(request_uuid.value, turbo_mode_request, response=True) + + # Wait to receive the response, then parse it + response = await received_responses.get() + response.parse(proto.ResponseGeneric) + # Deserialize into protobuf message + assert response.feature_id == 0xF1 + assert response.action_id == 0xEB + logger.info("Successfully set turbo mode") + logger.info(response.data) + + await client.disconnect() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Connect to a GoPro camera, send Set Turbo Mode and parse the response" + ) + parser.add_argument( + "-i", + "--identifier", + type=str, + help="Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to", + default=None, + ) + args = parser.parse_args() + + try: + asyncio.run(main(args.identifier)) + except Exception as e: # pylint: disable=broad-exception-caught + logger.error(e) + sys.exit(-1) + else: + sys.exit(0) diff --git a/demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi/__init__.py b/demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi/__init__.py new file mode 100644 index 00000000..e3af0028 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi/__init__.py @@ -0,0 +1,2 @@ +# __init__.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Thu Apr 4 21:50:02 UTC 2024 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi/connect_as_sta.py b/demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi/connect_as_sta.py new file mode 100644 index 00000000..be97f628 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi/connect_as_sta.py @@ -0,0 +1,258 @@ +# connect_sta.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +import sys +import asyncio +import argparse +from typing import Generator, Final + +from bleak import BleakClient +from tutorial_modules import GoProUuid, connect_ble, proto, logger, ResponseManager + + +def yield_fragmented_packets(payload: bytes) -> Generator[bytes, None, None]: + """Generate fragmented packets from a monolithic payload to accommodate the max BLE packet size of 20 bytes. + + Args: + payload (bytes): input payload to fragment + + Raises: + ValueError: Input payload is too large. + + Yields: + Generator[bytes, None, None]: fragmented packets. + """ + length = len(payload) + + CONTINUATION_HEADER: Final = bytearray([0x80]) + MAX_PACKET_SIZE: Final = 20 + is_first_packet = True + + # Build initial length header + if length < (2**5 - 1): + header = bytearray([length]) + elif length < (2**13 - 1): + header = bytearray((length | 0x2000).to_bytes(2, "big", signed=False)) + elif length < (2**16 - 1): + header = bytearray((length | 0x6400).to_bytes(2, "big", signed=False)) + else: + raise ValueError(f"Data length {length} is too big for this protocol.") + + byte_index = 0 + while bytes_remaining := length - byte_index: + # If this is the first packet, use the appropriate header. Else use the continuation header + if is_first_packet: + packet = bytearray(header) + is_first_packet = False + else: + packet = bytearray(CONTINUATION_HEADER) + # Build the current packet + packet_size = min(MAX_PACKET_SIZE - len(packet), bytes_remaining) + packet.extend(bytearray(payload[byte_index : byte_index + packet_size])) + yield bytes(packet) + # Increment byte_index for continued processing + byte_index += packet_size + + +async def fragment_and_write_gatt_char(client: BleakClient, char_specifier: str, data: bytes) -> None: + """Fragment the data into BLE packets and send each packet via GATT write. + + Args: + client (BleakClient): Bleak client to perform GATT Writes with + char_specifier (str): BLE characteristic to write to + data (bytes): data to fragment and write. + """ + for packet in yield_fragmented_packets(data): + await client.write_gatt_char(char_specifier, packet, response=True) + + +async def scan_for_networks(manager: ResponseManager) -> int: + """Scan for WiFi networks + + Args: + manager (ResponseManager): manager used to perform the operation + + Raises: + RuntimeError: Received unexpected response. + + Returns: + int: Scan ID to use to retrieve scan results + """ + logger.info(msg="Scanning for available Wifi Networks") + + start_scan_request = bytearray( + [ + 0x02, # Feature ID + 0x02, # Action ID + *proto.RequestStartScan().SerializePartialToString(), + ] + ) + start_scan_request.insert(0, len(start_scan_request)) + + # Send the scan request + logger.debug(f"Writing: {start_scan_request.hex(':')}") + await manager.client.write_gatt_char(GoProUuid.NETWORK_MANAGEMENT_REQ_UUID.value, start_scan_request, response=True) + while response := await manager.get_next_response_as_protobuf(): + if response.feature_id != 0x02: + raise RuntimeError("Only expect to receive Feature ID 0x02 responses after scan request") + if response.action_id == 0x82: # Initial Scan Response + manager.assert_generic_protobuf_success(response.data) + elif response.action_id == 0x0B: # Scan Notifications + scan_notification: proto.NotifStartScanning = response.data # type: ignore + logger.info(f"Received scan notification: {scan_notification}") + if scan_notification.scanning_state == proto.EnumScanning.SCANNING_SUCCESS: + return scan_notification.scan_id + else: + raise RuntimeError("Only expect to receive Action ID 0x02 or 0x0B responses after scan request") + raise RuntimeError("Loop should not exit without return") + + +async def get_scan_results(manager: ResponseManager, scan_id: int) -> list[proto.ResponseGetApEntries.ScanEntry]: + """Retrieve the results from a completed Wifi Network scan + + Args: + manager (ResponseManager): manager used to perform the operation + scan_id (int): identifier returned from completed scan + + Raises: + RuntimeError: Received unexpected response. + + Returns: + list[proto.ResponseGetApEntries.ScanEntry]: list of scan entries + """ + logger.info("Getting the scanned networks.") + + results_request = bytearray( + [ + 0x02, # Feature ID + 0x03, # Action ID + *proto.RequestGetApEntries(start_index=0, max_entries=100, scan_id=scan_id).SerializePartialToString(), + ] + ) + results_request.insert(0, len(results_request)) + + # Send the request + logger.debug(f"Writing: {results_request.hex(':')}") + await manager.client.write_gatt_char(GoProUuid.NETWORK_MANAGEMENT_REQ_UUID.value, results_request, response=True) + while response := await manager.get_next_response_as_protobuf(): + if response.feature_id != 0x02 or response.action_id != 0x83: + raise RuntimeError("Only expect to receive Feature ID 0x02 Action ID 0x83 responses after scan request") + entries_response: proto.ResponseGetApEntries = response.data # type: ignore + manager.assert_generic_protobuf_success(entries_response) + logger.info("Found the following networks:") + for entry in entries_response.entries: + logger.info(str(entry)) + return list(entries_response.entries) + raise RuntimeError("Loop should not exit without return") + + +async def connect_to_network( + manager: ResponseManager, entry: proto.ResponseGetApEntries.ScanEntry, password: str +) -> None: + """Connect to a WiFi network + + Args: + manager (ResponseManager): manager used to perform the operation + entry (proto.ResponseGetApEntries.ScanEntry): scan entry that contains network (and its metadata) to connect to + password (str): password corresponding to network from `entry` + + Raises: + RuntimeError: Received unexpected response. + """ + logger.info(f"Connecting to {entry.ssid}") + + if entry.scan_entry_flags & proto.EnumScanEntryFlags.SCAN_FLAG_CONFIGURED: + connect_request = bytearray( + [ + 0x02, # Feature ID + 0x04, # Action ID + *proto.RequestConnect(ssid=entry.ssid).SerializePartialToString(), + ] + ) + else: + connect_request = bytearray( + [ + 0x02, # Feature ID + 0x05, # Action ID + *proto.RequestConnectNew(ssid=entry.ssid, password=password).SerializePartialToString(), + ] + ) + + # Send the request + logger.debug(f"Writing: {connect_request.hex(':')}") + await fragment_and_write_gatt_char(manager.client, GoProUuid.NETWORK_MANAGEMENT_REQ_UUID.value, connect_request) + while response := await manager.get_next_response_as_protobuf(): + if response.feature_id != 0x02: + raise RuntimeError("Only expect to receive Feature ID 0x02 responses after connect request") + if response.action_id == 0x84: # RequestConnect Response + manager.assert_generic_protobuf_success(response.data) + elif response.action_id == 0x85: # RequestConnectNew Response + manager.assert_generic_protobuf_success(response.data) + elif response.action_id == 0x0C: # NotifProvisioningState Notifications + provisioning_notification: proto.NotifProvisioningState = response.data # type: ignore + logger.info(f"Received network provisioning status: {provisioning_notification}") + if provisioning_notification.provisioning_state == proto.EnumProvisioning.PROVISIONING_SUCCESS_NEW_AP: + return + if provisioning_notification.provisioning_state != proto.EnumProvisioning.PROVISIONING_STARTED: + raise RuntimeError(f"Unexpected provisioning state: {provisioning_notification.provisioning_state}") + else: + raise RuntimeError("Only expect to receive Action ID 0x84, 0x85, or 0x0C responses after scan request") + raise RuntimeError("Loop should not exit without return") + + +async def connect_to_access_point(manager: ResponseManager, ssid: str, password: str) -> None: + """Top level method to connect to an access point. + + Args: + manager (ResponseManager): manager used to perform the operation + ssid (str): SSID of WiFi network to connect to + password (str): password of WiFi network to connect to + + Raises: + RuntimeError: Received unexpected response. + """ + entries = await get_scan_results(manager, await scan_for_networks(manager)) + try: + entry = [entry for entry in entries if entry.ssid == ssid][0] + except IndexError as exc: + raise RuntimeError(f"Did not find {ssid}") from exc + + await connect_to_network(manager, entry, password) + logger.info(f"Successfully connected to {ssid}") + + +async def main(ssid: str, password: str, identifier: str | None) -> None: + manager = ResponseManager() + try: + client = await connect_ble(manager.notification_handler, identifier) + manager.set_client(client) + await connect_to_access_point(manager, ssid, password) + except Exception as exc: # pylint: disable=broad-exception-caught + logger.error(repr(exc)) + finally: + if manager.is_initialized: + await manager.client.disconnect() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Connect the GoPro to a Wifi network where the GoPro is in Station Mode (STA)." + ) + parser.add_argument("ssid", type=str, help="SSID of network to connect to") + parser.add_argument("password", type=str, help="Password of network to connect to") + parser.add_argument( + "-i", + "--identifier", + type=str, + help="Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to", + default=None, + ) + args = parser.parse_args() + + try: + asyncio.run(main(args.ssid, args.password, args.identifier)) + except Exception as e: # pylint: disable=broad-exception-caught + logger.error(e) + sys.exit(-1) + else: + sys.exit(0) diff --git a/demos/python/tutorial/tutorial_modules/tutorial_5_connect_wifi/wifi_enable.py b/demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi/enable_wifi_ap.py similarity index 63% rename from demos/python/tutorial/tutorial_modules/tutorial_5_connect_wifi/wifi_enable.py rename to demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi/enable_wifi_ap.py index 16207f26..75a32ba4 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_5_connect_wifi/wifi_enable.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi/enable_wifi_ap.py @@ -2,18 +2,16 @@ # This copyright was auto-generated on Wed, Sep 1, 2021 5:06:01 PM import sys -import time import asyncio import argparse -from typing import Tuple, Optional from bleak import BleakClient from bleak.backends.characteristic import BleakGATTCharacteristic -from tutorial_modules import GOPRO_BASE_UUID, connect_ble, logger +from tutorial_modules import GoProUuid, connect_ble, logger -async def enable_wifi(identifier: Optional[str] = None) -> Tuple[str, str, BleakClient]: +async def enable_wifi(identifier: str | None = None) -> tuple[str, str, BleakClient]: """Connect to a GoPro via BLE, find its WiFi AP SSID and password, and enable its WiFI AP If identifier is None, the first discovered GoPro will be connected to. @@ -26,20 +24,14 @@ async def enable_wifi(identifier: Optional[str] = None) -> Tuple[str, str, Bleak """ # Synchronization event to wait until notification response is received event = asyncio.Event() - - # UUIDs to write to and receive responses from, and read from - COMMAND_REQ_UUID = GOPRO_BASE_UUID.format("0072") - COMMAND_RSP_UUID = GOPRO_BASE_UUID.format("0073") - WIFI_AP_SSID_UUID = GOPRO_BASE_UUID.format("0002") - WIFI_AP_PASSWORD_UUID = GOPRO_BASE_UUID.format("0003") - client: BleakClient - def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}') + async def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + logger.info(f'Received response at {uuid}: {data.hex(":")}') # If this is the correct handle and the status is success, the command was a success - if client.services.characteristics[characteristic.handle].uuid == COMMAND_RSP_UUID and data[2] == 0x00: + if uuid is GoProUuid.COMMAND_RSP_UUID and data[2] == 0x00: logger.info("Command sent successfully") # Anything else is unexpected. This shouldn't happen else: @@ -51,42 +43,46 @@ def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) - client = await connect_ble(notification_handler, identifier) # Read from WiFi AP SSID BleUUID - logger.info("Reading the WiFi AP SSID") - ssid = (await client.read_gatt_char(WIFI_AP_SSID_UUID)).decode() + ssid_uuid = GoProUuid.WIFI_AP_SSID_UUID + logger.info(f"Reading the WiFi AP SSID at {ssid_uuid}") + ssid = (await client.read_gatt_char(ssid_uuid.value)).decode() logger.info(f"SSID is {ssid}") # Read from WiFi AP Password BleUUID - logger.info("Reading the WiFi AP password") - password = (await client.read_gatt_char(WIFI_AP_PASSWORD_UUID)).decode() + password_uuid = GoProUuid.WIFI_AP_PASSWORD_UUID + logger.info(f"Reading the WiFi AP password at {password_uuid}") + password = (await client.read_gatt_char(password_uuid.value)).decode() logger.info(f"Password is {password}") # Write to the Command Request BleUUID to enable WiFi logger.info("Enabling the WiFi AP") event.clear() - await client.write_gatt_char(COMMAND_REQ_UUID, bytearray([0x03, 0x17, 0x01, 0x01]), response=True) + request = bytes([0x03, 0x17, 0x01, 0x01]) + command_request_uuid = GoProUuid.COMMAND_REQ_UUID + logger.debug(f"Writing to {command_request_uuid}: {request.hex(':')}") + await client.write_gatt_char(command_request_uuid.value, request, response=True) await event.wait() # Wait to receive the notification response logger.info("WiFi AP is enabled") return ssid, password, client -async def main(identifier: Optional[str], timeout: Optional[int]) -> None: +async def main(identifier: str | None, timeout: int | None) -> None: *_, client = await enable_wifi(identifier) - if not timeout: - logger.info("Maintaining BLE Connection indefinitely. Send keyboard interrupt to exit.") - while True: - time.sleep(1) - else: + if timeout: logger.info(f"Maintaining BLE connection for {timeout} seconds") - time.sleep(timeout) + await asyncio.sleep(timeout) + else: + input("Maintaining BLE Connection indefinitely. Press enter to exit.") + logger.info("Disconnect from BLE...") await client.disconnect() if __name__ == "__main__": parser = argparse.ArgumentParser( - description="Connect to a GoPro camera via BLE, get WiFi info, and enable WiFi." + description="Connect to a GoPro camera via BLE, get its WiFi Access Point (AP) info, and enable its AP." ) parser.add_argument( "-i", diff --git a/demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/__init__.py b/demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/__init__.py similarity index 100% rename from demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/__init__.py rename to demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/__init__.py diff --git a/demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_get_media_list.py b/demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_get_media_list.py similarity index 100% rename from demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_get_media_list.py rename to demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_get_media_list.py diff --git a/demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_get_state.py b/demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_get_state.py similarity index 100% rename from demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_get_state.py rename to demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_get_state.py diff --git a/demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_load_group.py b/demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_load_group.py similarity index 100% rename from demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_load_group.py rename to demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_load_group.py diff --git a/demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_preview_stream.py b/demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_preview_stream.py similarity index 100% rename from demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_preview_stream.py rename to demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_preview_stream.py diff --git a/demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_set_resolution.py b/demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_set_resolution.py similarity index 97% rename from demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_set_resolution.py rename to demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_set_resolution.py index 2888711b..960513c9 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_set_resolution.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_set_resolution.py @@ -13,8 +13,6 @@ def main() -> None: # Note!! The endpoint below changed between Open GoPro version 1.0 and 2.0 # This endpoint supports >= 2.0 - - # Build the HTTP GET request url = GOPRO_BASE_URL + "/gopro/camera/setting?setting=2&option=9" logger.info(f"Setting the video resolution to 1080: sending {url}") diff --git a/demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_set_shutter.py b/demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_set_shutter.py similarity index 100% rename from demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/wifi_command_set_shutter.py rename to demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/wifi_command_set_shutter.py diff --git a/demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/__init__.py b/demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/__init__.py similarity index 100% rename from demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/__init__.py rename to demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/__init__.py diff --git a/demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/wifi_media_download_file.py b/demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/wifi_media_download_file.py similarity index 69% rename from demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/wifi_media_download_file.py rename to demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/wifi_media_download_file.py index 27c35333..5ebb857f 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/wifi_media_download_file.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/wifi_media_download_file.py @@ -3,7 +3,6 @@ import sys import argparse -from typing import Optional import requests @@ -15,19 +14,28 @@ def main() -> None: media_list = get_media_list() # Find a photo. We're just taking the first one we find. - photo: Optional[str] = None - for media_file in [x["n"] for x in media_list["media"][0]["fs"]]: - if media_file.lower().endswith(".jpg"): - logger.info(f"found a photo: {media_file}") - photo = media_file + photo: str | None = None + directory: str | None = None + found_photo = False + # TODO update tutorial docs to get directory + for media in media_list["media"]: + for media_file in [x["n"] for x in media["fs"]]: + if media_file.lower().endswith(".jpg"): + logger.info(f"found a photo: {media_file}") + photo = media_file + directory = media["d"] + found_photo = True + break + if found_photo: break else: raise RuntimeError("Couldn't find a photo on the GoPro") - assert photo is not None + assert photo + assert directory # Build the url to get the thumbnail data for the photo logger.info(f"Downloading {photo}") - url = GOPRO_BASE_URL + f"/videos/DCIM/100GOPRO/{photo}" + url = GOPRO_BASE_URL + f"/videos/DCIM/{directory}/{photo}" logger.info(f"Sending: {url}") with requests.get(url, stream=True, timeout=10) as request: request.raise_for_status() diff --git a/demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/wifi_media_get_gpmf.py b/demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/wifi_media_get_gpmf.py similarity index 68% rename from demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/wifi_media_get_gpmf.py rename to demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/wifi_media_get_gpmf.py index bbb25f94..0dc289d7 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/wifi_media_get_gpmf.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/wifi_media_get_gpmf.py @@ -3,7 +3,6 @@ import sys import argparse -from typing import Optional import requests @@ -15,19 +14,28 @@ def main() -> None: media_list = get_media_list() # Find a photo. We're just taking the first one we find. - photo: Optional[str] = None - for media_file in [x["n"] for x in media_list["media"][0]["fs"]]: - if media_file.lower().endswith(".jpg"): - logger.info(f"found a photo: {media_file}") - photo = media_file + photo: str | None = None + directory: str | None = None + found_photo = False + # TODO update tutorial docs to get directory + for media in media_list["media"]: + for media_file in [x["n"] for x in media["fs"]]: + if media_file.lower().endswith(".jpg"): + logger.info(f"found a photo: {media_file}") + photo = media_file + directory = media["d"] + found_photo = True + break + if found_photo: break else: raise RuntimeError("Couldn't find a photo on the GoPro") - assert photo is not None + assert photo + assert directory # Build the url to get the GPMF data for the photo logger.info(f"Getting the GPMF for {photo}") - url = GOPRO_BASE_URL + f"/gopro/media/gpmf?path=100GOPRO/{photo}" + url = GOPRO_BASE_URL + f"/gopro/media/gpmf?path={directory}/{photo}" logger.info(f"Sending: {url}") with requests.get(url, stream=True, timeout=10) as request: request.raise_for_status() diff --git a/demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/wifi_media_get_screennail.py b/demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/wifi_media_get_screennail.py similarity index 68% rename from demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/wifi_media_get_screennail.py rename to demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/wifi_media_get_screennail.py index b9146dc4..f4338833 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/wifi_media_get_screennail.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/wifi_media_get_screennail.py @@ -3,7 +3,6 @@ import sys import argparse -from typing import Optional import requests @@ -15,19 +14,28 @@ def main() -> None: media_list = get_media_list() # Find a photo. We're just taking the first one we find. - photo: Optional[str] = None - for media_file in [x["n"] for x in media_list["media"][0]["fs"]]: - if media_file.lower().endswith(".jpg"): - logger.info(f"found a photo: {media_file}") - photo = media_file + photo: str | None = None + directory: str | None = None + found_photo = False + # TODO update tutorial docs to get directory + for media in media_list["media"]: + for media_file in [x["n"] for x in media["fs"]]: + if media_file.lower().endswith(".jpg"): + logger.info(f"found a photo: {media_file}") + photo = media_file + directory = media["d"] + found_photo = True + break + if found_photo: break else: raise RuntimeError("Couldn't find a photo on the GoPro") - assert photo is not None + assert photo + assert directory # Build the url to get the screennail data for the photo logger.info(f"Getting the screennail for {photo}") - url = GOPRO_BASE_URL + f"/gopro/media/screennail?path=100GOPRO/{photo}" + url = GOPRO_BASE_URL + f"/gopro/media/screennail?path={directory}/{photo}" logger.info(f"Sending: {url}") with requests.get(url, stream=True, timeout=10) as request: request.raise_for_status() diff --git a/demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/wifi_media_get_thumbnail.py b/demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/wifi_media_get_thumbnail.py similarity index 68% rename from demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/wifi_media_get_thumbnail.py rename to demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/wifi_media_get_thumbnail.py index 2c26c31b..89759beb 100644 --- a/demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/wifi_media_get_thumbnail.py +++ b/demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/wifi_media_get_thumbnail.py @@ -3,7 +3,6 @@ import sys import argparse -from typing import Optional import requests @@ -15,19 +14,28 @@ def main() -> None: media_list = get_media_list() # Find a photo. We're just taking the first one we find. - photo: Optional[str] = None - for media_file in [x["n"] for x in media_list["media"][0]["fs"]]: - if media_file.lower().endswith(".jpg"): - logger.info(f"found a photo: {media_file}") - photo = media_file + photo: str | None = None + directory: str | None = None + found_photo = False + # TODO update tutorial docs to get directory + for media in media_list["media"]: + for media_file in [x["n"] for x in media["fs"]]: + if media_file.lower().endswith(".jpg"): + logger.info(f"found a photo: {media_file}") + photo = media_file + directory = media["d"] + found_photo = True + break + if found_photo: break else: raise RuntimeError("Couldn't find a photo on the GoPro") - assert photo is not None + assert photo + assert directory # Build the url to get the thumbnail data for the photo logger.info(f"Getting the thumbnail for {photo}") - url = GOPRO_BASE_URL + f"/gopro/media/thumbnail?path=100GOPRO/{photo}" + url = GOPRO_BASE_URL + f"/gopro/media/thumbnail?path={directory}/{photo}" logger.info(f"Sending: {url}") with requests.get(url, stream=True, timeout=10) as request: request.raise_for_status() diff --git a/demos/python/tutorial/tutorial_modules/tutorial_9_cohn/__init__.py b/demos/python/tutorial/tutorial_modules/tutorial_9_cohn/__init__.py new file mode 100644 index 00000000..e3af0028 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_9_cohn/__init__.py @@ -0,0 +1,2 @@ +# __init__.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Thu Apr 4 21:50:02 UTC 2024 diff --git a/demos/python/tutorial/tutorial_modules/tutorial_9_cohn/communicate_via_cohn.py b/demos/python/tutorial/tutorial_modules/tutorial_9_cohn/communicate_via_cohn.py new file mode 100644 index 00000000..802c26d6 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_9_cohn/communicate_via_cohn.py @@ -0,0 +1,48 @@ +# communicate_via_cohn.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +import sys +import json +import argparse +import asyncio +from base64 import b64encode +from pathlib import Path + +import requests + +from tutorial_modules import logger + + +async def main(ip_address: str, username: str, password: str, certificate: Path) -> None: + url = f"https://{ip_address}" + "/gopro/camera/state" + logger.debug(f"Sending: {url}") + + token = b64encode(f"{username}:{password}".encode("utf-8")).decode("ascii") + response = requests.get( + url, + timeout=10, + headers={"Authorization": f"Basic {token}"}, + verify=str(certificate), + ) + # Check for errors (if an error is found, an exception will be raised) + response.raise_for_status() + logger.info("Command sent successfully") + # Log response as json + logger.info(f"Response: {json.dumps(response.json(), indent=4)}") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Demonstrate HTTPS communication via COHN.") + parser.add_argument("ip_address", type=str, help="IP Address of camera on the home network") + parser.add_argument("username", type=str, help="COHN username") + parser.add_argument("password", type=str, help="COHN password") + parser.add_argument("certificate", type=Path, help="Path to read COHN cert from.", default=Path("cohn.crt")) + args = parser.parse_args() + + try: + asyncio.run(main(args.ip_address, args.username, args.password, args.certificate)) + except Exception as e: # pylint: disable=broad-exception-caught + logger.error(e) + sys.exit(-1) + else: + sys.exit(0) diff --git a/demos/python/tutorial/tutorial_modules/tutorial_9_cohn/provision_cohn.py b/demos/python/tutorial/tutorial_modules/tutorial_9_cohn/provision_cohn.py new file mode 100644 index 00000000..13e56ce0 --- /dev/null +++ b/demos/python/tutorial/tutorial_modules/tutorial_9_cohn/provision_cohn.py @@ -0,0 +1,292 @@ +# provision_cohn.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). +# This copyright was auto-generated on Wed Mar 27 22:05:49 UTC 2024 + +import sys +import json +import asyncio +import argparse +from pathlib import Path +from dataclasses import dataclass, asdict +from datetime import datetime + +import pytz +from tzlocal import get_localzone + +from tutorial_modules import GoProUuid, connect_ble, proto, connect_to_access_point, ResponseManager, logger + + +async def set_date_time(manager: ResponseManager) -> None: + """Get and then set the camera's date, time, timezone, and daylight savings time status + + Args: + manager (ResponseManager): manager used to perform the operation + """ + # First find the current time, timezone and is_dst + tz = pytz.timezone(get_localzone().key) + now = tz.localize(datetime.now(), is_dst=None) + try: + is_dst = now.tzinfo._dst.seconds != 0 # type: ignore + offset = (now.utcoffset().total_seconds() - now.tzinfo._dst.seconds) / 60 # type: ignore + except AttributeError: + is_dst = False + offset = (now.utcoffset().total_seconds()) / 60 # type: ignore + if is_dst: + offset += 60 # Handle daylight savings time + offset = int(offset) + logger.info(f"Setting the camera's date and time to {now}:{offset} {is_dst=}") + + # Build the request bytes + datetime_request = bytearray( + [ + 0x0F, # Command ID + 10, # Length of following datetime parameter + *now.year.to_bytes(2, "big", signed=False), # uint16 year + now.month, + now.day, + now.hour, + now.minute, + now.second, + *offset.to_bytes(2, "big", signed=True), # int16 offset in minutes + is_dst, + ] + ) + datetime_request.insert(0, len(datetime_request)) + + # Send the request + logger.debug(f"Writing: {datetime_request.hex(':')}") + await manager.client.write_gatt_char(GoProUuid.COMMAND_REQ_UUID.value, datetime_request, response=True) + response = await manager.get_next_response_as_tlv() + assert response.id == 0x0F + assert response.status == 0x00 + logger.info("Successfully set the date time.") + + +async def clear_certificate(manager: ResponseManager) -> None: + """Clear the camera's COHN certificate. + + Args: + manager (ResponseManager): manager used to perform the operation + + Raises: + RuntimeError: Received unexpected response + """ + logger.info("Clearing any preexisting COHN certificate.") + + clear_request = bytearray( + [ + 0xF1, # Feature ID + 0x66, # Action ID + *proto.RequestClearCOHNCert().SerializePartialToString(), + ] + ) + clear_request.insert(0, len(clear_request)) + + # Send the request + logger.debug(f"Writing: {clear_request.hex(':')}") + await manager.client.write_gatt_char(GoProUuid.COMMAND_REQ_UUID.value, clear_request, response=True) + while response := await manager.get_next_response_as_protobuf(): + if response.feature_id != 0xF1 or response.action_id != 0xE6: + raise RuntimeError( + "Only expect to receive Feature ID 0xF1 Action ID 0xE6 responses after clear cert request" + ) + manager.assert_generic_protobuf_success(response.data) + logger.info("COHN certificate successfully cleared") + return + raise RuntimeError("Loop should not exit without return") + + +async def create_certificate(manager: ResponseManager) -> None: + """Instruct the camera to create the COHN certificate. + + Args: + manager (ResponseManager): manager used to perform the operation + + Raises: + RuntimeError: Received unexpected response + """ + logger.info("Creating a new COHN certificate.") + + create_request = bytearray( + [ + 0xF1, # Feature ID + 0x67, # Action ID + *proto.RequestCreateCOHNCert().SerializePartialToString(), + ] + ) + create_request.insert(0, len(create_request)) + + # Send the request + logger.debug(f"Writing: {create_request.hex(':')}") + await manager.client.write_gatt_char(GoProUuid.COMMAND_REQ_UUID.value, create_request, response=True) + while response := await manager.get_next_response_as_protobuf(): + if response.feature_id != 0xF1 or response.action_id != 0xE7: + raise RuntimeError( + "Only expect to receive Feature ID 0xF1 Action ID 0xE7 responses after create cert request" + ) + manager.assert_generic_protobuf_success(response.data) + logger.info("COHN certificate successfully created") + return + raise RuntimeError("Loop should not exit without return") + + +@dataclass(frozen=True) +class Credentials: + """COHN credentials.""" + + certificate: str + username: str + password: str + ip_address: str + + def __str__(self) -> str: + return json.dumps(asdict(self), indent=4) + + +async def get_cohn_certificate(manager: ResponseManager) -> str: + """Get the camera's COHN certificate + + Args: + manager (ResponseManager): manager used to perform the operation + + Raises: + RuntimeError: Received unexpected response + + Returns: + str: certificate in string form. + """ + logger.info("Getting the current COHN certificate.") + + cert_request = bytearray( + [ + 0xF5, # Feature ID + 0x6E, # Action ID + *proto.RequestCOHNCert().SerializePartialToString(), + ] + ) + cert_request.insert(0, len(cert_request)) + + # Send the request + logger.debug(f"Writing: {cert_request.hex(':')}") + await manager.client.write_gatt_char(GoProUuid.QUERY_REQ_UUID.value, cert_request, response=True) + while response := await manager.get_next_response_as_protobuf(): + if response.feature_id != 0xF5 or response.action_id != 0xEE: + raise RuntimeError("Only expect to receive Feature ID 0xF5 Action ID 0xEE responses after get cert request") + cert_response: proto.ResponseCOHNCert = response.data # type: ignore + manager.assert_generic_protobuf_success(cert_response) + logger.info("COHN certificate successfully retrieved") + return cert_response.cert + raise RuntimeError("Loop should not exit without return") + + +async def get_cohn_status(manager: ResponseManager) -> proto.NotifyCOHNStatus: + """Get the COHN status until it is provisioned and connected. + + Args: + manager (ResponseManager): manager used to perform the operation + + Raises: + RuntimeError: Received unexpected response + + Returns: + proto.NotifyCOHNStatus: Connected COHN status that includes the credentials. + """ + logger.info("Checking COHN status until provisioning is complete") + + status_request = bytearray( + [ + 0xF5, # Feature ID + 0x6F, # Action ID + *proto.RequestGetCOHNStatus(register_cohn_status=True).SerializePartialToString(), + ] + ) + status_request.insert(0, len(status_request)) + + # Send the scan request + logger.debug(f"Writing: {status_request.hex(':')}") + await manager.client.write_gatt_char(GoProUuid.QUERY_REQ_UUID.value, status_request, response=True) + while response := await manager.get_next_response_as_protobuf(): + if response.feature_id != 0xF5 or response.action_id != 0xEF: + raise RuntimeError( + "Only expect to receive Feature ID 0xF5, Action ID 0xEF responses after COHN status request" + ) + cohn_status: proto.NotifyCOHNStatus = response.data # type: ignore + logger.info(f"Received COHN Status: {cohn_status}") + if cohn_status.state == proto.EnumCOHNNetworkState.COHN_STATE_NetworkConnected: + return cohn_status + raise RuntimeError("Loop should not exit without return") + + +async def provision_cohn(manager: ResponseManager) -> Credentials: + """Helper method to provision COHN. + + Args: + manager (ResponseManager): manager used to perform the operation + + Returns: + Credentials: COHN credentials to use for future COHN communication. + """ + logger.info("Provisioning COHN") + await clear_certificate(manager) + await create_certificate(manager) + certificate = await get_cohn_certificate(manager) + # Wait for COHN to be provisioned and get the provisioned status + status = await get_cohn_status(manager) + logger.info("Successfully provisioned COHN.") + credentials = Credentials( + certificate=certificate, + username=status.username, + password=status.password, + ip_address=status.ipaddress, + ) + logger.info(credentials) + return credentials + + +async def main(ssid: str, password: str, identifier: str | None, certificate: Path) -> Credentials | None: + manager = ResponseManager() + credentials: Credentials | None = None + try: + client = await connect_ble(manager.notification_handler, identifier) + manager.set_client(client) + await set_date_time(manager) + await connect_to_access_point(manager, ssid, password) + credentials = await provision_cohn(manager) + with open(certificate, "w") as fp: + fp.write(credentials.certificate) + logger.info(f"Certificate written to {certificate.resolve()}") + + except Exception as exc: # pylint: disable=broad-exception-caught + logger.error(repr(exc)) + finally: + if manager.is_initialized: + await manager.client.disconnect() + return credentials + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Provision COHN via BLE to be ready for communication.") + parser.add_argument("ssid", type=str, help="SSID of network to connect to") + parser.add_argument("password", type=str, help="Password of network to connect to") + parser.add_argument( + "-i", + "--identifier", + type=str, + help="Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to", + default=None, + ) + parser.add_argument( + "-c", + "--certificate", + type=Path, + help="Path to write retrieved COHN certificate.", + default=Path("cohn.crt"), + ) + args = parser.parse_args() + + try: + asyncio.run(main(args.ssid, args.password, args.identifier, args.certificate)) + except Exception as e: # pylint: disable=broad-exception-caught + logger.error(e) + sys.exit(-1) + else: + sys.exit(0) diff --git a/docker-compose.yml b/docker-compose.yml index 90674770..1ab800d6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,10 +27,10 @@ services: networks: - open_gopro depends_on: - - plant_uml + - plant-uml - plant_uml: - container_name: plant_uml + plant-uml: + container_name: plant-uml # Note! v1.2023.7 seems to be broken image: plantuml/plantuml-server:jetty-v1.2023.6 ports: @@ -39,6 +39,16 @@ services: networks: - open_gopro + proto-build: + build: + context: .admin/proto_build + container_name: proto-build + profiles: + - ephemeral + volumes: + - ./protobuf:/proto_in + - ./.build/protobuf/python:/proto_python_out + linkchecker: image: ghcr.io/gopro/opengopro/gplinkchecker:main container_name: linkchecker diff --git a/docs/_config.yml b/docs/_config.yml index 0eb1fbf0..203625f2 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -222,7 +222,7 @@ jekyll-spaceship: syntax: code: 'plantuml!' custom: ['@startuml', '@enduml'] - src: http://plant_uml:8080/svg/ # TODO make this run-time configurable + src: http://plant-uml:8080/svg/ # TODO make this run-time configurable mermaid-processor: mode: pre-fetch # fetch image at build-time css: diff --git a/docs/_data/navigation.yml b/docs/_data/navigation.yml index 5ac4b82e..8b4bdd71 100644 --- a/docs/_data/navigation.yml +++ b/docs/_data/navigation.yml @@ -24,11 +24,15 @@ tutorials: url: /tutorials/parse-ble-responses - title: '4: BLE Queries' url: /tutorials/ble-queries - - title: '5: Connect WiFi' + - title: '5: BLE Protobuf' + url: /tutorials/ble-protobuf + - title: '6: Connect WiFi' url: /tutorials/connect-wifi - - title: '6: Send WiFi Commands' + - title: '7: Send WiFi Commands' url: /tutorials/send-wifi-commands - - title: '7: Camera Media List' + - title: '8: Camera Media List' url: /tutorials/camera-media-list + - title: '9: Camera on the Home Network' + url: /tutorials/cohn diff --git a/docs/_tutorials/tutorial_1_connect_ble/tutorial.md b/docs/_tutorials/tutorial_1_connect_ble/tutorial.md index 7f92486d..c9d4090f 100644 --- a/docs/_tutorials/tutorial_1_connect_ble/tutorial.md +++ b/docs/_tutorials/tutorial_1_connect_ble/tutorial.md @@ -13,17 +13,21 @@ This tutorial will provide a walk-through to connect to the GoPro camera via Blu ## Hardware -* A GoPro camera that is [supported by Open GoPro](/ble/index.html#supported-cameras) +- A GoPro camera that is [supported by Open GoPro]({{site.baseurl}}/ble/index.html#supported-cameras) + {% linkedTabs hardware_prereqs %} {% tab hardware_prereqs python %} -* One of the following systems: - - Windows 10, version 16299 (Fall Creators Update) or greater - - Linux distribution with [BlueZ](http://www.bluez.org/) >= 5.43 - - OS X/macOS support via Core Bluetooth API, from at least OS X version 10.11 +- One of the following systems: + - Windows 10, version 16299 (Fall Creators Update) or greater + - Linux distribution with [BlueZ](http://www.bluez.org/) >= 5.43 + - OS X/macOS support via Core Bluetooth API, from at least OS X version 10.11 + {% endtab %} {% tab hardware_prereqs kotlin %} -* An Android Device supporting SDK >= 33 + +- An Android Device supporting SDK >= 33 + {% endtab %} {% endlinkedTabs %} @@ -31,12 +35,13 @@ This tutorial will provide a walk-through to connect to the GoPro camera via Blu {% linkedTabs software_prereqs %} {% tab software_prereqs python %} -- Python >= 3.8.x must be installed. See this [Python installation guide](https://docs.python-guide.org/starting/installation/). -{% endtab %} -{% tab software_prereqs kotlin %} -- [Android Studio](https://developer.android.com/studio) >= 2022.1.1 (Electric Eel) -{% endtab %} -{% endlinkedTabs %} + +- Python >= 3.9 and < 3.12 must be installed. See this [Python installation guide](https://docs.python-guide.org/starting/installation/). + {% endtab %} + {% tab software_prereqs kotlin %} +- [Android Studio](https://developer.android.com/studio) >= 2022.1.1 (Electric Eel) + {% endtab %} + {% endlinkedTabs %} # Overview / Assumptions @@ -47,8 +52,7 @@ This tutorial will use [bleak](https://pypi.org/project/bleak/) to control the O {% warning %} The Bleak BLE controller does not currently support autonomous pairing for the BlueZ backend. So if you are using BlueZ (i.e. Ubuntu, RaspberryPi, etc.), you need to first pair the camera from the command line as shown in the -[BlueZ tutorial](https://gopro.github.io/OpenGoPro/tutorials/bash/bluez). There is work to add this feature -and progress can be tracked on the [Github Issue](https://github.com/hbldh/bleak/pull/1100). +[BlueZ tutorial](https://gopro.github.io/OpenGoPro/tutorials/bash/bluez). {% endwarning %} The bleak module is based on asyncio which means that its awaitable functions need to @@ -93,10 +97,10 @@ do not prioritize the following: These tutorials assume familiarity and a base level of competence with: -- Android Studio -- Bluetooth Low Energy -- JSON -- HTTP +- [Android Studio](https://developer.android.com/studio) +- [Bluetooth Low Energy](https://www.bluetooth.com/bluetooth-resources/intro-to-bluetooth-low-energy/) +- [JSON](https://www.w3schools.com/js/js_json_intro.asp) +- [HTTP](https://www.tutorialspoint.com/http/index.htm) {% endtab %} {% endlinkedTabs %} @@ -144,7 +148,7 @@ Required-by: {% tab setup kotlin %} This set of tutorials is accompanied by an Android Studio project consisting of, among other project infrastructure, Kotlin files separated by tutorial module. -The project can be found on [Github](https://github.com/gopro/OpenGoPro/tree/main/demos/kotlin/tutorial/). Once the +The project can be found on [Github](https://github.com/gopro/OpenGoPro/tree/main/demos/kotlin/tutorial/). Once the Github repo has been cloned or downloaded to your local machine, open the project in Android studio. At this point you should be able to build and load the project to your Android device. @@ -160,10 +164,10 @@ The project will not work on an emulated device since BLE can not be emulated. {% linkedTabs demo %} {% tab demo python %} Each of the scripts for this tutorial can be found in the Tutorial 1 -[directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_1_connect_ble).. +[directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_1_connect_ble). {% warning %} -Python >= 3.8.x must be used as specified in the requirements +Python >= 3.9 and < 3.12 must be used as specified in the requirements {% endwarning %} You can test connecting to your camera through BLE using the following script: @@ -261,9 +265,10 @@ We are keeping any devices that have a device name. # Scan callback to also catch nonconnectable scan responses def _scan_callback(device: BleakDevice, _: Any) -> None: # Add to the dict if not unknown - if device.name != "Unknown" and device.name is not None: + if device.name and device.name != "Unknown": devices[device.name] = device + # Now discover and add connectable advertisements for device in await BleakScanner.discover(timeout=5, detection_callback=_scan_callback): if device.name != "Unknown" and device.name is not None: @@ -280,11 +285,10 @@ steps accordingly. {% endwarning %} First, we define a regex which is either "GoPro " followed by any four alphanumeric characters if no identifier was passed, -or "GoPro " concatenated with the identifier if it exists. In the demo `ble_connect.py`, the identifier is taken -from the command-line arguments. +or the identifier if it exists. In the demo `ble_connect.py`, the identifier is taken from the command-line arguments. ```python -token = re.compile(r"GoPro [A-Z0-9]{4}" if identifier is None else f"GoPro {identifier}") +token = re.compile(identifier or r"GoPro [A-Z0-9]{4}") ``` Now we build a list of matched devices by checking if each device's name includes the token regex. @@ -324,8 +328,8 @@ your camera's serial number. {% endtab %} {% tab scan kotlin %} -First let's define a filter to find the GoPro. We do this by filtering on the GoPro Service UUID that is -included in all GoPro advertisements: +First let's define a filter that will be used to find GoPro device advertisements. We do this by filtering on the GoPro +Service UUID that is included in all GoPro advertisements: ```kotlin private val scanFilters = listOf( @@ -353,7 +357,7 @@ ble.startScan(scanFilters).onSuccess { scanResults -> } ``` -At this point, the GoPro's BLE address is stored (as a String) in `goproAddress`. +At this point, the GoPro's BLE address is stored (as a string) in `goproAddress`. Here is an example log output from this process: @@ -362,6 +366,7 @@ Scanning for GoPro's Received scan result: GoPro 0992 Found GoPro: GoPro 0992 ``` + {% endtab %} {% endlinkedTabs %} @@ -372,6 +377,7 @@ establish a BLE connection to the camera. {% linkedTabs connect %} {% tab connect python %} + ```python # We're just taking the first device if there are multiple. device = matched_devices[0] @@ -387,8 +393,10 @@ INFO:root:Establishing BLE connection to EF:5A:F6:13:E6:5A: GoPro 0456... INFO:bleak.backends.dotnet.client:Services resolved for BleakClientDotNet (EF:5A:F6:13:E6:5A) INFO:root:BLE Connected! ``` + {% endtab %} {% tab connect kotlin %} + ```kotlin ble.connect(goproAddress) ``` @@ -406,6 +414,7 @@ writing to them. Therefore now that we are connected, we need to attempt to pair {% linkedTabs pair %} {% tab pair python %} + ```python try: await client.pair() @@ -421,7 +430,7 @@ catching the exception when it fails. {% tab pair kotlin %} Rather than explicitly request pairing, we rely on the fact that Android will automatically start the pairing process if you try to read a characteristic that requires encryption. To do this, we read the -[Wifi AP Password characteristic](https://gopro.github.io/OpenGoPro/ble/protocol/ble_setup.html#ble-characteristics). +[Wifi AP Password characteristic](https://gopro.github.io/OpenGoPro/ble_2_0#services-and-characteristics). First we discover all characteristics (this will also be needed later when enabling notifications): @@ -429,6 +438,11 @@ First we discover all characteristics (this will also be needed later when enabl ble.discoverCharacteristics(goproAddress) ``` +{% note %} +This API will discover the characteristics over-the-air but not return them here. They are stored to the `ble` object +for later access via the `servicesOf` method. +{% endnote %} + Then we read the relevant characteristic to trigger pairing: ```kotlin @@ -450,50 +464,7 @@ Characteristics: |--00002a00-0000-1000-8000-00805f9b34fb: READABLE |--00002a01-0000-1000-8000-00805f9b34fb: READABLE |--00002a04-0000-1000-8000-00805f9b34fb: READABLE -Service 0000180f-0000-1000-8000-00805f9b34fb -Characteristics: -|--00002a19-0000-1000-8000-00805f9b34fb: READABLE, NOTIFIABLE -|------00002902-0000-1000-8000-00805f9b34fb: EMPTY -Service 0000180a-0000-1000-8000-00805f9b34fb -Characteristics: -|--00002a29-0000-1000-8000-00805f9b34fb: READABLE -|--00002a24-0000-1000-8000-00805f9b34fb: READABLE -|--00002a25-0000-1000-8000-00805f9b34fb: READABLE -|--00002a27-0000-1000-8000-00805f9b34fb: READABLE -|--00002a26-0000-1000-8000-00805f9b34fb: READABLE -|--00002a28-0000-1000-8000-00805f9b34fb: READABLE -|--00002a23-0000-1000-8000-00805f9b34fb: READABLE -|--00002a50-0000-1000-8000-00805f9b34fb: READABLE -Service b5f90001-aa8d-11e3-9046-0002a5d5c51b -Characteristics: -|--b5f90002-aa8d-11e3-9046-0002a5d5c51b: READABLE, WRITABLE -|--b5f90003-aa8d-11e3-9046-0002a5d5c51b: READABLE, WRITABLE -|--b5f90004-aa8d-11e3-9046-0002a5d5c51b: WRITABLE -|--b5f90005-aa8d-11e3-9046-0002a5d5c51b: READABLE, INDICATABLE -|------00002902-0000-1000-8000-00805f9b34fb: EMPTY -|--b5f90006-aa8d-11e3-9046-0002a5d5c51b: READABLE -Service 0000fea6-0000-1000-8000-00805f9b34fb -Characteristics: -|--b5f90072-aa8d-11e3-9046-0002a5d5c51b: WRITABLE -|--b5f90073-aa8d-11e3-9046-0002a5d5c51b: NOTIFIABLE -|------00002902-0000-1000-8000-00805f9b34fb: EMPTY -|--b5f90074-aa8d-11e3-9046-0002a5d5c51b: WRITABLE -|--b5f90075-aa8d-11e3-9046-0002a5d5c51b: NOTIFIABLE -|------00002902-0000-1000-8000-00805f9b34fb: EMPTY -|--b5f90076-aa8d-11e3-9046-0002a5d5c51b: WRITABLE -|--b5f90077-aa8d-11e3-9046-0002a5d5c51b: NOTIFIABLE -|------00002902-0000-1000-8000-00805f9b34fb: EMPTY -|--b5f90078-aa8d-11e3-9046-0002a5d5c51b: WRITABLE -|--b5f90079-aa8d-11e3-9046-0002a5d5c51b: NOTIFIABLE -|------00002902-0000-1000-8000-00805f9b34fb: EMPTY -Service b5f90090-aa8d-11e3-9046-0002a5d5c51b -Characteristics: -|--b5f90091-aa8d-11e3-9046-0002a5d5c51b: WRITABLE -|--b5f90092-aa8d-11e3-9046-0002a5d5c51b: NOTIFIABLE -|------00002902-0000-1000-8000-00805f9b34fb: EMPTY -Service b5f90080-aa8d-11e3-9046-0002a5d5c51b -Characteristics: -|--b5f90081-aa8d-11e3-9046-0002a5d5c51b: NOTIFIABLE +... |------00002902-0000-1000-8000-00805f9b34fb: EMPTY |--b5f90082-aa8d-11e3-9046-0002a5d5c51b: WRITABLE |--b5f90083-aa8d-11e3-9046-0002a5d5c51b: NOTIFIABLE @@ -506,6 +477,7 @@ Characteristics: Pairing Read characteristic b5f90003-aa8d-11e3-9046-0002a5d5c51b : value: 66:3F:54:2D:38:35:72:2D:4E:35:63 ``` + {% endtab %} {% endlinkedTabs %} @@ -518,8 +490,9 @@ re-establish encryption using stored keys. That is, they are "bonded." ## Enable Notifications -As specified in the [Open GoPro Bluetooth API](/ble/index.html#sending-and-receiving-messages), -we must enable notifications for a given characteristic to receive responses from it. +As specified in the Open GoPRo BLE Spec, we must +[enable notifications]({{site.baseurl}}/ble/protocol/ble_setup.html#configure-gatt-characteristics) for a given +characteristic to receive responses from it. To enable notifications, we loop over each characteristic in each service and enable the characteristic for notification if it has `notify` properties: @@ -554,9 +527,12 @@ INFO:root:Enabling notification on char b5f90081-aa8d-11e3-9046-0002a5d5c51b INFO:root:Enabling notification on char b5f90083-aa8d-11e3-9046-0002a5d5c51b INFO:root:Enabling notification on char b5f90084-aa8d-11e3-9046-0002a5d5c51b INFO:root:Done enabling notifications +INFO:root:BLE Connection is ready for communication. ``` + {% endtab %} {% tab enable_notifications kotlin %} + ```kotlin ble.servicesOf(goproAddress).onSuccess { services -> services.forEach { service -> @@ -593,11 +569,12 @@ Enabling notifications for b5f90084-aa8d-11e3-9046-0002a5d5c51b Wrote to descriptor 00002902-0000-1000-8000-00805f9b34fb Bluetooth is ready for communication! ``` + {% endtab %} {% endlinkedTabs %} The characteristics that correspond to each UUID listed in the log can be found in the -[Open GoPro API](/ble/index.html#services-and-characteristics). These +[Open GoPro API]({{site.baseurl}}/ble/protocol/ble_setup.html#ble-characteristics). These will be used in a future tutorial to send data. Once the notifications are enabled, the GoPro BLE initialization is complete and it is ready to communicate via diff --git a/docs/_tutorials/tutorial_2_send_ble_commands/tutorial.md b/docs/_tutorials/tutorial_2_send_ble_commands/tutorial.md index b717a06e..0531bc0d 100644 --- a/docs/_tutorials/tutorial_2_send_ble_commands/tutorial.md +++ b/docs/_tutorials/tutorial_2_send_ble_commands/tutorial.md @@ -5,31 +5,36 @@ sidebar: lesson: 2 --- -# Tutorial 2: Send BLE Commands +# Tutorial 2: Send BLE TLV Commands This document will provide a walk-through tutorial to use the -[Open GoPro BLE Interface](/ble/index.html) to send commands and receive responses. +[Open GoPro BLE Interface]({{site.baseurl}}/ble/index.html) to send [Type-Length-Value](https://en.wikipedia.org/wiki/Type-length-value) +(TLV)commands and receive TLV responses. -"Commands" in this sense are specifically procedures that are initiated by either: +[Commands]({{site.baseurl}}/ble/protocol/data_protocol.html#commands) in this sense are operations that are initiated by either: -- Writing to the Command Request UUID and receiving responses via the Command Response UUID. They are - listed [here](/ble/index.html#commands). -- Writing to the Setting UUID and receiving responses via the Setting Response UUID. They are listed - [here](/ble/index.html#settings). +- Writing to the Command Request UUID and receiving responses via the Command Response + [UUID]({{site.baseurl}}/ble/protocol/ble_setup.html#ble-characteristics). +- Writing to the Setting UUID and receiving responses via the Setting Response + [UUID]({{site.baseurl}}/ble/protocol/ble_setup.html#ble-characteristics) -{% tip %} -It is suggested that you have first completed the -[connect tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#requirements) before going through -this tutorial. -{% endtip %} +A list of TLV commands can be found in the [Command ID Table]{{site.baseurl}}/ble/protocol/id_tables.html#command-ids). -This tutorial only considers sending these commands as one-off commands. That is, it does not consider state +{% note %} +This tutorial only considers sending these as one-off commands. That is, it does not consider state management / synchronization when sending multiple commands. This will be discussed in a future lab. +{% endnote %} # Requirements It is assumed that the hardware and software requirements from the -[connect tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}) are present and configured correctly. +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}) are present and configured correctly. + +{% tip %} +It is suggested that you have first completed the +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#requirements) before going through +this tutorial. +{% endtip %} # Just Show me the Demo(s)!! @@ -39,12 +44,13 @@ Each of the scripts for this tutorial can be found in the Tutorial 2 [directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/). {% warning %} -Python >= 3.8.x must be used as specified in the requirements +Python >= 3.9 and < 3.12 must be used as specified in the requirements {% endwarning %} {% accordion Set Shutter %} You can test sending the Set Shutter command to your camera through BLE using the following script: + ```console $ python ble_command_set_shutter.py ``` @@ -63,11 +69,13 @@ optional arguments: Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to ``` + {% endaccordion %} {% accordion Load Preset Group %} You can test sending the Load Preset Group command to your camera through BLE using the following script: + ```console $ python ble_command_load_group.py ``` @@ -86,12 +94,13 @@ optional arguments: Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to ``` -{% endaccordion %} +{% endaccordion %} {% accordion Set the Video Resolution %} You can test sending the Set Video Resolution command to your camera through BLE using the following script: + ```console $ python ble_command_set_resolution.py ``` @@ -110,12 +119,13 @@ optional arguments: Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to ``` -{% endaccordion %} +{% endaccordion %} {% accordion Set the Frames Per Second (FPS) %} You can test sending the Set FPS command to your camera through BLE using the following script: + ```console $ python ble_command_set_fps.py ``` @@ -134,6 +144,7 @@ optional arguments: Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to ``` + {% endaccordion %} {% endtab %} {% tab demo kotlin %} @@ -144,7 +155,7 @@ To perform the tutorial, run the Android Studio project, select "Tutorial 2" fro This requires that a GoPro is already connected via BLE, i.e. that Tutorial 1 was already run. You can check the BLE status at the top of the app. -{% include figure image_path="/assets/images/tutorials/kotlin/tutorial_1.png" alt="kotlin_tutorial_2" size="40%" caption="Perform Tutorial 2" %} +{% include figure image_path="/assets/images/tutorials/kotlin/tutorial_2.png" alt="kotlin_tutorial_2" size="40%" caption="Perform Tutorial 2" %} This will start the tutorial and log to the screen as it executes. When the tutorial is complete, click "Exit Tutorial" to return to the Tutorial selection screen. @@ -154,20 +165,21 @@ This will start the tutorial and log to the screen as it executes. When the tuto # Setup -We must first connect as was discussed in the [connect tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}). In -this case, however, we are defining a meaningful (albeit naive) notification handler that will: +We must first connect as was discussed in the [connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}). +In this case, however, we are defining a functional (albeit naive) notification handler that will: -1. print byte data and handle that the notification was received on -1. check if the response is what we expected -1. set an event to notify the writer that the response was received +1. Log byte data and handle that the notification was received on +1. Check if the response is what we expected +1. Set an event to notify the writer that the response was received This is a very simple handler; response parsing will be expanded upon in the [next tutorial]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}). {% linkedTabs response_parsing %} {% tab response_parsing python %} + ```python -def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: +async def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}') # If this is the correct handle and the status is success, the command was a success @@ -186,6 +198,7 @@ received. For now, we're just checking that the handle matches what is expected that the status (third byte) is success (0x00). {% endtab %} {% tab response_parsing kotlin %} + ```kotlin private val receivedData: Channel = Channel() @@ -209,6 +222,7 @@ We are registering this notification handler with the BLE API before sending any ```kotlin ble.registerListener(goproAddress, bleListeners) ``` + {% endtab %} {% endlinkedTabs %} @@ -217,16 +231,16 @@ discussed in future tutorials. # Command Overview -Both Command Requests and Setting Requests follow the same procedure: +All commands follow the same procedure: -1. Write to relevant request UUID +1. Write to the relevant request UUID 1. Receive confirmation from GoPro (via notification from relevant response UUID) that request was received. 1. GoPro reacts to command -{% note %} +{% warning %} The notification response only indicates that the request was received and whether it was accepted or rejected. The relevant behavior of the GoPro must be observed to verify when the command's effects have been applied. -{% endnote %} +{% endwarning %} Here is the procedure from power-on to finish: @@ -247,25 +261,26 @@ sequenceDiagram Now that we are are connected, paired, and have enabled notifications (registered to our defined callback), we can send some commands. -First, we need to define the attributes to write to / receive responses from, which are: - -- For commands - - "Command Request" characteristic (UUID `b5f90072-aa8d-11e3-9046-0002a5d5c51b`) - - "Command Response" characteristic (UUID `b5f90073-aa8d-11e3-9046-0002a5d5c51b`) -- For settings - - "Settings" characteristic (UUID `b5f90074-aa8d-11e3-9046-0002a5d5c51b`) - - "Settings Response" (UUID `b5f90075-aa8d-11e3-9046-0002a5d5c51b`) +First, we need to define the [UUIDs]({{site.baseurl}}/ble/protocol/ble_setup.html#configure-gatt-characteristics) +to write to / receive responses from, which are: {% linkedTabs uuid %} {% tab uuid python %} -```python -COMMAND_REQ_UUID = GOPRO_BASE_UUID.format("0072") -COMMAND_RSP_UUID = GOPRO_BASE_UUID.format("0073") -``` + +We'll define these and any others used throughout the tutorials and store them in a `GoProUUID` class: ```python -SETTINGS_REQ_UUID = GOPRO_BASE_UUID.format("0074") -SETTINGS_RSP_UUID = GOPRO_BASE_UUID.format("0075") +class GoProUuid: + COMMAND_REQ_UUID = GOPRO_BASE_UUID.format("0072") + COMMAND_RSP_UUID = GOPRO_BASE_UUID.format("0073") + SETTINGS_REQ_UUID = GOPRO_BASE_UUID.format("0074") + SETTINGS_RSP_UUID = GOPRO_BASE_UUID.format("0075") + QUERY_REQ_UUID = GOPRO_BASE_UUID.format("0076") + QUERY_RSP_UUID = GOPRO_BASE_UUID.format("0077") + WIFI_AP_SSID_UUID = GOPRO_BASE_UUID.format("0002") + WIFI_AP_PASSWORD_UUID = GOPRO_BASE_UUID.format("0003") + NETWORK_MANAGEMENT_REQ_UUID = GOPRO_BASE_UUID.format("0091") + NETWORK_MANAGEMENT_RSP_UUID = GOPRO_BASE_UUID.format("0092") ``` {% tip %} @@ -296,7 +311,7 @@ enum class GoProUUID(val uuid: UUID) { ## Set Shutter -The first command we will be sending is [Set Shutter](/ble/index.html#commands-quick-reference), +The first command we will be sending is [Set Shutter]({{site.baseurl}}/ble/features/control.html#set-shutter), which at byte level is: | Command | Bytes | @@ -308,10 +323,13 @@ Now, let's write the bytes to the "Command Request" UUID to turn the shutter on {% linkedTabs set_shutter_on %} {% tab set_shutter_on python %} + ```python +request_uuid = GoProUuid.COMMAND_REQ_UUID event.clear() -await client.write_gatt_char(COMMAND_REQ_UUID, bytearray([3, 1, 1, 1])) -await event.wait() # Wait to receive the notification response +request = bytes([3, 1, 1, 1]) +await client.write_gatt_char(request_uuid.value, request, response=True) +await event.wait() # Wait to receive the notification response ``` {% success %} @@ -320,12 +338,18 @@ the notification callback. {% endsuccess %} {% endtab %} {% tab set_shutter_on kotlin %} + ```kotlin val setShutterOnCmd = ubyteArrayOf(0x03U, 0x01U, 0x01U, 0x01U) ble.writeCharacteristic(goproAddress, GoProUUID.CQ_COMMAND.uuid, setShutterOnCmd) // Wait to receive the notification response, then check its status checkStatus(receivedData.receive()) ``` + +{% success %} +We're waiting to receive the data from the queue that is posted to in the notification handler when the response is received. +{% endsuccess %} + {% endtab %} {% endlinkedTabs %} @@ -339,13 +363,17 @@ This can be seen in the demo log: {% linkedTabs set_shutter_on %} {% tab set_shutter_on python %} + ```console -INFO:root:Setting the shutter on -INFO:root:Received response at handle=52: b'02:01:00' -INFO:root:Shutter command sent successfully +Setting the shutter on +Writing to GoProUuid.COMMAND_REQ_UUID: 03:01:01:01 +Received response at GoProUuid.COMMAND_RSP_UUID: 02:01:00 +Command sent successfully ``` + {% endtab %} {% tab set_shutter_on kotlin %} + ```console Writing characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b ==> 03:01:01:01 Wrote characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b @@ -353,14 +381,13 @@ Characteristic b5f90073-aa8d-11e3-9046-0002a5d5c51b changed | value: 02:01:00 Received response on b5f90073-aa8d-11e3-9046-0002a5d5c51b: 02:01:00 Command sent successfully ``` + {% endtab %} {% endlinkedTabs %} -As expected, the response was received on the correct handle and the status was "success". - -If you are recording a video, continue reading to set the shutter off. +As expected, the response was received on the correct UUID and the status was "success" (third byte == 0x00). -We can now set the shutter off: +If you are recording a video, continue reading to set the shutter off: {% tip %} We're waiting 2 seconds in case you are in video mode so that we can capture a 2 second video. @@ -368,22 +395,28 @@ We're waiting 2 seconds in case you are in video mode so that we can capture a 2 {% linkedTabs set_shutter_off %} {% tab set_shutter_off python %} + ```python -time.sleep(2) +await asyncio.sleep(2) +request_uuid = GoProUuid.COMMAND_REQ_UUID +request = bytes([3, 1, 1, 0]) event.clear() -await client.write_gatt_char(COMMAND_REQ_UUID, bytearray([3, 1, 1, 0])) -await event.wait() # Wait to receive the notification response +await client.write_gatt_char(request_uuid.value, request, response=True) +await event.wait() # Wait to receive the notification response ``` This will log in the console as follows: ```python -INFO:root:Setting the shutter off -INFO:root:Received response at handle=52: b'02:01:00' -INFO:root:Shutter command sent successfully +Setting the shutter off +Writing to GoProUuid.COMMAND_REQ_UUID: 03:01:01:00 +Received response at GoProUuid.COMMAND_RSP_UUID: 02:01:00 +Command sent successfully ``` + {% endtab %} {% tab set_shutter_off kotlin %} + ```kotlin delay(2000) val setShutterOffCmd = ubyteArrayOf(0x03U, 0x01U, 0x01U, 0x00U) @@ -391,6 +424,10 @@ val setShutterOffCmd = ubyteArrayOf(0x03U, 0x01U, 0x01U, 0x00U) checkStatus(receivedData.receive()) ``` +{% success %} +We're waiting to receive the data from the queue that is posted to in the notification handler when the response is received. +{% endsuccess %} + This will log as such: ```console @@ -401,13 +438,14 @@ Characteristic b5f90073-aa8d-11e3-9046-0002a5d5c51b changed | value: 02:01:00 Received response on b5f90073-aa8d-11e3-9046-0002a5d5c51b: 02:01:00 Command sent successfully ``` + {% endtab %} {% endlinkedTabs %} ## Load Preset Group The next command we will be sending is -[Load Preset Group](/ble/index.html#commands-quick-reference), which is used +[Load Preset Group]({{site.baseurl}}/ble/features/presets.html#load-preset-group), which is used to toggle between the 3 groups of presets (video, photo, and timelapse). At byte level, the commands are: | Command | Bytes | @@ -416,19 +454,16 @@ to toggle between the 3 groups of presets (video, photo, and timelapse). At byte | Load Photo Preset Group | 0x04 0x3E 0x02 0x03 0xE9 | | Load Timelapse Preset Group | 0x04 0x3E 0x02 0x03 0xEA | -{% note %} -It is possible that the preset GroupID values will vary in future cameras. The only absolutely correct way to know -the preset ID is to read them from the "Get Preset Status" protobuf command. A future lab will discuss protobuf -commands. -{% endnote %} - Now, let's write the bytes to the "Command Request" UUID to change the preset group to Video! {% linkedTabs load_preset_group_send %} {% tab load_preset_group_send python %} + ```python +request_uuid = GoProUuid.COMMAND_REQ_UUID +request = bytes([0x04, 0x3E, 0x02, 0x03, 0xE8]) event.clear() -await client.write_gatt_char(COMMAND_REQ_UUID, bytearray([0x04, 0x3E, 0x02, 0x03, 0xE8])) +await client.write_gatt_char(request_uuid.value, request, response=True) await event.wait() # Wait to receive the notification response ``` @@ -438,12 +473,18 @@ the notification callback. {% endsuccess %} {% endtab %} {% tab load_preset_group_send kotlin %} + ```kotlin val loadPreset = ubyteArrayOf(0x04U, 0x3EU, 0x02U, 0x03U, 0xE8U) ble.writeCharacteristic(goproAddress, GoProUUID.CQ_COMMAND.uuid, loadPreset) // Wait to receive the notification response, then check its status checkStatus(receivedData.receive()) ``` + +{% success %} +We're waiting to receive the data from the queue that is posted to in the notification handler when the response is received. +{% endsuccess %} + {% endtab %} {% endlinkedTabs %} @@ -459,13 +500,17 @@ be seen in the demo log: {% linkedTabs load_preset_group_receive %} {% tab load_preset_group_receive python %} + ```console -INFO:root:Loading the video preset group... -INFO:root:Received response at handle=52: b'02:3e:00' -INFO:root:Command sent successfully +Loading the video preset group... +Sending to GoProUuid.COMMAND_REQ_UUID: 04:3e:02:03:e8 +Received response at GoProUuid.COMMAND_RSP_UUID: 02:3e:00 +Command sent successfully ``` + {% endtab %} {% tab load_preset_group_receive kotlin %} + ```console Loading Video Preset Group Writing characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b ==> 04:3E:02:03:E8 @@ -475,16 +520,18 @@ Received response on b5f90073-aa8d-11e3-9046-0002a5d5c51b: 02:3E:00 Command status received Command sent successfully ``` + {% endtab %} {% endlinkedTabs %} -As expected, the response was received on the correct handle and the status was "success". +As expected, the response was received on the correct UUID and the status was "success" (third byte == 0x00). ## Set the Video Resolution The next command we will be sending is -[Set Video Resolution](/ble/index.html#commands-quick-reference). This is -used to change the value of the Video Resolution setting. It is important to note that this only affects +[Set Setting]({{site.baseurl}}/ble/features/settings.html#set-setting) to set the +[Video Resolution]({{site.baseurl}}/ble/features/settings.html#setting-2). +This is used to change the value of the Video Resolution setting. It is important to note that this only affects **video** resolution (not photo). Therefore, the Video Preset Group must be active in order for it to succeed. This can be done either manually through the camera UI or by sending [Load Preset Group](#load-preset-group). @@ -505,9 +552,12 @@ Now, let's write the bytes to the "Setting Request" UUID to change the video res {% linkedTabs set_resolution %} {% tab set_resolution python %} + ```python +request_uuid = GoProUuid.COMMAND_REQ_UUID +request = bytes([0x03, 0x02, 0x01, 0x09]) event.clear() -await client.write_gatt_char(SETTINGS_REQ_UUID, bytearray([0x03, 0x02, 0x01, 0x09])) +await client.write_gatt_char(request_uuid.value, request, response=True) await event.wait() # Wait to receive the notification response ``` @@ -518,12 +568,18 @@ the notification callback. {% endtab %} {% tab set_resolution kotlin %} + ```kotlin val setResolution = ubyteArrayOf(0x03U, 0x02U, 0x01U, 0x09U) ble.writeCharacteristic(goproAddress, GoProUUID.CQ_COMMAND.uuid, setResolution) // Wait to receive the notification response, then check its status checkStatus(receivedData.receive()) ``` + +{% success %} +We're waiting to receive the data from the queue that is posted to in the notification handler when the response is received. +{% endsuccess %} + {% endtab %} {% endlinkedTabs %} @@ -534,18 +590,22 @@ screen: Also note that we have received the "Command Status" notification response from the Command Response characteristic since we enabled its notifications in -[Enable Notifications]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#enable-notifications).. This can +[Enable Notifications]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#enable-notifications). This can be seen in the demo log: {% linkedTabs set_resolution %} {% tab set_resolution python %} + ```console -INFO:root:Loading the video preset group... -INFO:root:Received response at handle=52: b'02:3e:00' -INFO:root:Command sent successfully +Setting the video resolution to 1080 +Writing to GoProUuid.SETTINGS_REQ_UUID: 03:02:01:09 +Received response at GoProUuid.SETTINGS_RSP_UUID: 02:02:00 +Command sent successfully ``` + {% endtab %} {% tab set_resolution kotlin %} + ```console Setting resolution to 1080 Writing characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b ==> 03:02:01:09 @@ -555,21 +615,24 @@ Received response on b5f90073-aa8d-11e3-9046-0002a5d5c51b: 02:02:00 Command status received Command sent successfully ``` + {% endtab %} {% endlinkedTabs %} -As expected, the response was received on the correct handle and the status was "success". If the Preset +As expected, the response was received on the correct UUID and the status was "success" (third byte == 0x00). If the Preset Group was not Video, the status will not be success. ## Set the Frames Per Second (FPS) The next command we will be sending is -[Set FPS](/ble/index.html#commands-quick-reference). This is +[Set Setting]({{site.baseurl}}/ble/features/settings.html#set-setting) to set the +[FPS]({{site.baseurl}}/ble/features/settings.html#setting-3). This is used to change the value of the FPS setting. It is important to note that this setting is dependent on the video resolution. That is, certain FPS values are not valid with certain resolutions. In general, higher -resolutions only allow lower FPS values. Also, the current anti-flicker value may further limit possible FPS -values. Check the [camera capabilities ](/ble/index.html#camera-capabilities) to see which FPS -values are valid for given use cases. +resolutions only allow lower FPS values. Other settings such as the current anti-flicker value may further limit possible +FPS values. Futhermore, these capabilities all vary by camera. Check the +[camera capabilities ]({{site.baseurl}}/ble/index.html#camera-capabilities) to see which FPS values are valid for +given use cases. Therefore, for this step of the tutorial, it is assumed that the resolution has been set to 1080 as in [Set the Video Resolution](#set-the-video-resolution). @@ -582,17 +645,18 @@ Here are some of the byte level commands for various FPS values. | Set FPS to 60 | 0x03 0x03 0x01 0x05 | | Set FPS to 240 | 0x03 0x03 0x01 0x00 | -Note that the possible FPS values can vary based on the Open GoPro version that the camera supports. -Therefore, it is necessary to -[check the version]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}#complex-command-response). +Note that the possible FPS values can vary based on the Camera that is being operated on. Now, let's write the bytes to the "Setting Request" UUID to change the FPS to 240! {% linkedTabs set_fps %} {% tab set_fps python %} + ```python +request_uuid = GoProUuid.COMMAND_REQ_UUID +request = bytes([0x03, 0x03, 0x01, 0x00]) event.clear() -await client.write_gatt_char(SETTINGS_REQ_UUID, bytearray([0x03, 0x03, 0x01, 0x00])) +await client.write_gatt_char(request_uuid.value, request, response=True) await event.wait() # Wait to receive the notification response ``` @@ -602,12 +666,18 @@ the notification callback. {% endsuccess %} {% endtab %} {% tab set_fps kotlin %} + ```kotlin val setFps = ubyteArrayOf(0x03U, 0x03U, 0x01U, 0x00U) ble.writeCharacteristic(goproAddress, GoProUUID.CQ_COMMAND.uuid, setFps) // Wait to receive the notification response, then check its status checkStatus(receivedData.receive()) ``` + +{% success %} +We're waiting to receive the data from the queue that is posted to in the notification handler when the response is received. +{% endsuccess %} + {% endtab %} {% endlinkedTabs %} @@ -623,13 +693,17 @@ be seen in the demo log: {% linkedTabs set_fps %} {% tab set_fps python %} + ```console -INFO:root:Setting the fps to 240 -INFO:root:Received response at handle=57: b'02:03:00' -INFO:root:Command sent successfully +Setting the fps to 240 +Writing to GoProUuid.SETTINGS_REQ_UUID: 03:03:01:00 +Received response at GoProUuid.SETTINGS_RSP_UUID: 02:03:00 +Command sent successfully ``` + {% endtab %} {% tab set_fps kotlin %} + ```console Setting the FPS to 240 Writing characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b ==> 03:03:01:00 @@ -639,11 +713,12 @@ Received response on b5f90073-aa8d-11e3-9046-0002a5d5c51b: 02:03:00 Command status received Command sent successfully ``` + {% endtab %} {% endlinkedTabs %} -As expected, the response was received on the correct handle and the status was "success". If the video resolution -was higher, for example 5K, this would fail. +As expected, the response was received on the correct UUID and the status was "success" (third byte == 0x00). If the video +resolution was higher, for example 5K, this would fail. **Quiz time! 📚 ✏️** @@ -663,7 +738,7 @@ was higher, for example 5K, this would fail. option="A:::True" option="B:::False" correct="B" - info="Each resolution can support all or only some FPS values. You can find out which resolutions support which fps values by consulting the [capabilities section of the spec](https://gopro.github.io/OpenGoPro/ble/features/settings.html#camera-capabilities)." + info="Each resolution can support all or only some FPS values. You can find out which resolutions support which FPS values by consulting the [capabilities section of the spec](https://gopro.github.io/OpenGoPro/ble_2_0#camera-capabilities)." %} {% quiz @@ -686,7 +761,7 @@ See the first tutorial's Congratulations 🤙 {% endsuccess %} -You can now send any of the other BLE commands detailed in the Open GoPro documentation in -a similar manner. +You can now send any of the other BLE [commands]({{site.baseurl}}/ble/protocol/data_protocol.html#commands) detailed in the +Open GoPro documentation in a similar manner. -To see how to parse more complicate responses, proceed to the next tutorial. +To see how to parse responses, proceed to the next tutorial. diff --git a/docs/_tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md b/docs/_tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md index a2254efa..c9978749 100644 --- a/docs/_tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md +++ b/docs/_tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md @@ -8,11 +8,23 @@ lesson: 3 # Tutorial 3: Parse BLE TLV Responses This document will provide a walk-through tutorial to implement -the [Open GoPro Interface](/ble/index.html) to parse BLE +the [Open GoPro Interface]({{site.baseurl}}/ble/index.html) to parse BLE [Type-Length-Value](https://en.wikipedia.org/wiki/Type-length-value) (TLV) Responses. -Besides TLV, some BLE commands instead return protobuf responses. These are not considered here and will be -discussed in a future tutorial. +{% note %} +Besides TLV, some BLE operations instead return protobuf responses. These are not considered here and will be +discussed in a [future tutorial]({% link _tutorials/tutorial_5_ble_protobuf/tutorial.md %}) +{% endnote %} + +This tutorial will provide an overview of how to handle responses of both single and multiple packets lengths, then +give parsing examples for each case, and finally create `Response` and `TlvResponse` classes that will be reused in +future tutorials. + +# Requirements + +It is assumed that the hardware and software requirements from the +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}) +are present and configured correctly. {% tip %} It is suggested that you have first completed the @@ -21,29 +33,21 @@ and [sending commands]({% link _tutorials/tutorial_2_send_ble_commands/tutorial. through this tutorial. {% endtip %} -This tutorial will give an overview of types of responses, then give examples of parsing each type -before finally providing a **Response** class that will be used in future tutorials. - -# Requirements - -It is assumed that the hardware and software requirements from the -[connect tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}) -are present and configured correctly. - # Just Show me the Demo(s)!! {% linkedTabs demo %} {% tab demo python %} -Each of the scripts for this tutorial can be found in the Tutorial 2 +Each of the scripts for this tutorial can be found in the Tutorial 3 [directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_3_parse_ble_tlv_responses/). {% warning %} -Python >= 3.8.x must be used as specified in the requirements +Python >= 3.9 and < 3.12 must be used as specified in the requirements {% endwarning %} {% accordion Parsing a One Packet TLV Response %} You can test parsing a one packet TLV response with your camera through BLE using the following script: + ```console $ python ble_command_get_version.py ``` @@ -62,30 +66,33 @@ optional arguments: Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to ``` -{% endaccordion %} +{% endaccordion %} {% accordion Parsing Multiple Packet TLV Responses %} You can test parsing multiple packet TVL responses with your camera through BLE using the following script: + ```console -$ python ble_command_get_state.py +$ python ble_command_get_hardware_info.py ``` See the help for parameter definitions: ```console -$ python ble_command_get_state.py --help -usage: ble_command_get_state.py [-h] [-i IDENTIFIER] +$ python ble_command_get_hardware_info.py --help +usage: ble_command_get_hardware_info.py [-h] [-i IDENTIFIER] -Connect to a GoPro camera via BLE, then get its statuses and settings. +Connect to a GoPro camera via BLE, then get its hardware info. -optional arguments: +options: -h, --help show this help message and exit -i IDENTIFIER, --identifier IDENTIFIER - Last 4 digits of GoPro serial number, which is the last 4 digits of the - default camera SSID. If not used, first discovered GoPro will be connected to + Last 4 digits of GoPro serial number, which is the last 4 digits of + the default camera SSID. If not used, first discovered GoPro will be + connected to ``` + {% endaccordion %} {% endtab %} @@ -108,14 +115,14 @@ This will start the tutorial and log to the screen as it executes. When the tuto # Setup We must first connect as was discussed in the -[connect tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}). When enabling notifications, +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}). When enabling notifications, one of the notification handlers described in the following sections will be used. # Response Overview In the preceding tutorials, we have been using a very simple response handling procedure where the notification handler simply checks that the UUID is the expected UUID and that the status byte of the response is 0 (Success). -This has been fine since we were only sending specific commands where this works and we know that the sequence +This has been fine since we were only performing specific operations where this works and we know that the sequence always appears as such (connection sequence left out for brevity): ```mermaid! @@ -128,8 +135,8 @@ sequenceDiagram ``` In actuality, responses can be more complicated. As described in the -[Open GoPro Interface](/ble/index.html#packet-headers), responses can be -be comprised of multiple packets where each packet is <= 20 bytes such as: +[BLE Spec]({{site.baseurl}}/ble/protocol/data_protocol.html#packetization), responses can be be comprised of multiple +packets where each packet is <= 20 bytes such as: ```mermaid! sequenceDiagram @@ -143,19 +150,19 @@ sequenceDiagram GoPro ->> PC: Notification Response (MSB == 1 (continuation)) ``` -This requires the implementation of accumulating and parsing algorithms which will be described in -[Parsing Multiple Packet TLV Responses]. +This requires the implementation of accumulating and parsing algorithms which will be described +[below](#parsing-multiple-packet-tlv-responses). # Parsing a One Packet TLV Response This section will describe how to parse one packet (<= 20 byte) responses. A one-packet response is formatted as such: -| Header (length) | Command / Setting ID | Status | Response | -| --------------- | -------------------- | ------- | ---------------- | -| 1 byte | 1 byte | 1 bytes | Length - 2 bytes | +| Header (length) | Operation ID | Status | Response | +| --------------- | ------------ | ------- | ---------------- | +| 1 byte | 1 byte | 1 bytes | Length - 2 bytes | -## Command / Setting Responses with Response Length 0 +## Responses with Payload Length 0 These are the only responses that we have seen thus far through the first 2 tutorials. They return a status but have a 0 length additional response. For example, consider @@ -168,186 +175,202 @@ of: This equates to: -| Header (length) | Command / Setting / Status ID | Status | Response | -| --------------- | ----------------------------- | --------------- | ---------------- | -| 1 byte | 1 byte | 1 bytes | Length - 2 bytes | -| 0x02 | 0x01 == Set Shutter | 0x00 == Success | (2 -2 = 0 bytes) | +| Header (length) | Command ID | Status | Response | +| --------------- | ------------------- | --------------- | ---------------- | +| 1 byte | 1 byte | 1 bytes | Length - 2 bytes | +| 0x02 | 0x01 == Set Shutter | 0x00 == Success | (2 -2 = 0 bytes) | We can see how this response includes the status but no additional response data. This type of response will be used for most Commands and Setting Responses as seen in the [previous tutorial]({% link _tutorials/tutorial_2_send_ble_commands/tutorial.md %}). -## Complex Command Response +## Responses with Payload -There are some commands that do return additional response data. These are called "complex responses." -From the [commands reference](/ble/index.html#commands-quick-reference), we can see that these are: +However, there are some operations that do return additional response data. These are identified by the presence of +`parameters` in their Response documentation as shown in the red box here: -- Get Open GoPro Version (ID == 0x51) -- Get Hardware Info (ID == 0x3C) +{% include figure image_path="/assets/images/tutorials/complex_response_doc.png" alt="complex response example" size="40%" caption="Response With Payload" %} -In this tutorial, we will walk through creating a simple parser to parse the Open GoPro Get Version Command. +In this tutorial, we will walk through creating a simple parser to parse the +[Open GoPro Get Version Command]({{site.baseurl}}/ble/features/query.html#get-open-gopro-version) which is an example +of such an operation. {% tip %} It is important to always query the version after connecting in order to know which API is supported. See the relevant version of the BLE and / or WiFi spec for more details about each version. {% endtip %} -First, we send the command to the Command Request [UUID](/ble/index.html#services-and-characteristics): +First, we send the Get Version Command to the Command Request +[UUID]({{site.baseurl}}/ble/protocol/ble_setup.html#configure-gatt-characteristics) in the same manner as commands +were sent in the previous tutorial: {% linkedTabs send_command %} {% tab send_command python %} + ```python -COMMAND_REQ_UUID = GOPRO_BASE_UUID.format("0072") -event.clear() -await client.write_gatt_char(COMMAND_REQ_UUID, bytearray([0x01, 0x51])) +request_uuid = GoProUuid.COMMAND_REQ_UUID +request = bytes([0x01, 0x51]) +await client.write_gatt_char(request_uuid.value, request, response=True) await event.wait() # Wait to receive the notification response ``` -We then receive a response at the expected handle. This is logged as: +We receive a response at the expected handle (as a TLV Response). This is logged as: ```console -INFO:root:Getting the Open GoPro version... -INFO:root:Received response at handle=52: b'06:51:00:01:02:01:00' +Getting the Open GoPro version... +Writing to GoProUuid.COMMAND_REQ_UUID: 01:51 +Received response GoProUuid.COMMAND_RSP_UUID: 06:51:00:01:02:01:00 ``` + {% endtab %} {% tab send_command kotlin %} + ```kotlin - val getVersion = ubyteArrayOf(0x01U, 0x51U) - ble.writeCharacteristic(goproAddress, GoProUUID.CQ_COMMAND.uuid, getVersion) - val version = receivedResponse.receive() as Response.Complex // Wait to receive response +val versionRequest = ubyteArrayOf(0x01U, 0x51U) +ble.writeCharacteristic(goproAddress, GoProUUID.CQ_COMMAND.uuid, versionRequest) +var tlvResponse = receivedResponses.receive() as Response.Tlv ``` -This is loged as such: +We then receive a response at the expected handle. This is logged as: + +This is logged as such: ```console Getting the Open GoPro version Writing characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b ==> 01:51 Wrote characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b Characteristic b5f90073-aa8d-11e3-9046-0002a5d5c51b changed | value: 06:51:00:01:02:01:00 -Received response on b5f90073-aa8d-11e3-9046-0002a5d5c51b: 06:51:00:01:02:01:00 +Received response on CQ_COMMAND_RSP +Received packet of length 6. 0 bytes remaining ``` + {% endtab %} {% endlinkedTabs %} This response equates to: -| Header (length) | Command / Setting / Status ID | Status | Response | -| --------------- | ----------------------------- | --------------- | ------------------- | -| 1 byte | 1 byte | 1 bytes | Length - 2 bytes | -| 0x06 | 0x51 == Get Version | 0x00 == Success | 0x01 0x02 0x01 0x00 | +| Header (length) | Command ID | Status | Response | +| --------------- | ------------------- | --------------- | ------------------- | +| 1 byte | 1 byte | 1 bytes | Length - 2 bytes | +| 0x06 | 0x51 == Get Version | 0x00 == Success | 0x01 0x02 0x01 0x00 | -We can see that this "complex response" contains 4 additional bytes that need to be parsed. Using the information -from the [interface description](/ble/index.html#complex-command-responses), -we know to parse this as: +We can see that this response payload contains 4 additional bytes that need to be parsed. Using the information +from the [Get Version Documentation]({{site.baseurl}}/ble/features/query.html#get-open-gopro-version), we know to +parse this as: -| Byte | Meaning | -| ---- | ------------------------------ | -| 0x01 | Length of Major Version Number | -| 0x02 | Major Version Number | -| 0x01 | Length of Minor Version Number | -| 0x00 | Minor Version Number | +| Byte | Meaning | +| ---- | ------------------------------------- | +| 0x01 | Length of Major Version Number | +| 0x02 | Major Version Number of length 1 byte | +| 0x01 | Length of Minor Version Number | +| 0x00 | Minor Version Number of length 1 byte | -We implement this in the notification handler as follows. First, we parse the length, command ID, and status -from the first 3 bytes of the response. Then we parse the remaining four bytes of the response as individual -values formatted as such: - -| Length | Value | -| ------ | ------------ | -| 1 byte | Length bytes | +We implement this as follows. First, we parse the length, command ID, and status from the first 3 bytes of the response. +The remainder is stored as the payload. This is all of the common parsing across TLV Responses. Each individual +response will document how to further parse the payload. {% linkedTabs parse_response %} {% tab parse_response python %} + {% note %} The snippets of code included in this section are taken from the `notification handler` {% endnote %} - ```python -# Parse first 3 bytes +# First byte is the length of this response. length = data[0] +# Second byte is the ID command_id = data[1] +# Third byte is the status status = data[2] +# The remainder is the payload +payload = data[3 : length + 1] ``` -```python -# Parse remaining four bytes -index = 3 -params = [] -while index <= length: - param_len = data[index] - index += 1 - params.append(data[index : index + param_len]) - index += param_len -``` {% endtab %} {% tab parse_response kotlin %} + {% note %} -The snippets of code included in this section are taken from the `Response.Complex` `parse` method. For the -contrived code in this tutorial, we have separate `Response` sealed classes to handle each use case. +The snippets of code included in this section are taken from the `Response.Tlv.Parse` method {% endnote %} ```kotlin // Parse header bytes -id = packet[0].toInt() -status = packet[1].toInt() -var buf = packet.drop(2) -``` +tlvResponse.parse() -```kotlin -// Parse remaining packet -while (buf.isNotEmpty()) { - // Get each parameter's ID and length - val paramLen = buf[0].toInt() - buf = buf.drop(1) - // Get the parameter's value - val paramVal = buf.take(paramLen) - // Store in data list - data += paramVal.toUByteArray() - // Advance the buffer for continued parsing - buf = buf.drop(paramLen) +... + +open fun parse() { + require(isReceived) + id = rawBytes[0].toInt() + status = rawBytes[1].toInt() + // Store remainder as payload + payload = rawBytes.drop(2).toUByteArray() } + ``` + {% endtab %} {% endlinkedTabs %} -From the complex response definition, we know these parameters are one byte each and equate to the major and +From the response definition, we know these parameters are one byte each and equate to the major and the minor version so let's print them (and all of the other response information) as such: {% linkedTabs print_response %} {% tab print_response python %} + ```python -major, minor = params +major_length = payload[0] +payload.pop(0) +major = payload[:major_length] +payload.pop(major_length) +minor_length = payload[0] +payload.pop(0) +minor = payload[:minor_length] +logger.info(f"The version is Open GoPro {major[0]}.{minor[0]}") logger.info(f"Received a response to {command_id=} with {status=}: version={major[0]}.{minor[0]}") ``` which shows on the log as: ```console -INFO:root:Received a response to command_id=81 with status=0: version=2.0 +Received a response to command_id=81 with status=0, payload=01:02:01:00 +The version is Open GoPro 2.0 ``` + {% endtab %} {% tab print_response kotlin %} + +{% note %} +The snippets of code included in this section are taken from the `OpenGoProVersion` `from_bytes` method. This class +is a simple data class to contain the Get Version information. +{% endnote %} + ```kotlin -val version = receivedResponse.receive() as Response.Complex // Wait to receive response -val major = version.data[0].first().toInt() -val minor = version.data[1].first().toInt() -Timber.i("Got the Open GoPro version successfully: $major.$minor") +var buf = data.toUByteArray() +val minorLen = buf[0].toInt() +buf = buf.drop(1).toUByteArray() +val minor = buf.take(minorLen).toInt() +val majorLen = buf[0].toInt() +buf = buf.drop(1).toUByteArray() +val major = buf.take(majorLen).toInt() +return OpenGoProVersion(minor, major) ``` which shows on the log as such: ```console +Received response: ID: 81, Status: 0, Payload: 01:02:01:00 Got the Open GoPro version successfully: 2.0 ``` - {% endtab %} {% endlinkedTabs %} **Quiz time! 📚 ✏️** {% quiz - question="What is the maximum size of an individual notification response packet?" + question="What is the maximum size of an individual notification response packet at the Open GoPro application layer?" option="A:::20 bytes" option="B:::256 bytes" option="C:::There is no maximum size" @@ -357,7 +380,7 @@ Got the Open GoPro version successfully: 2.0 %} {% quiz - question="What is the maximum amount of packets that one response can be composed of?" + question="What is the maximum amount of bytes that one response can be composed of?" option="A:::20 bytes" option="B:::256 bytes" option="C:::There is no maximum size" @@ -366,38 +389,36 @@ Got the Open GoPro version successfully: 2.0 %} {% quiz - question="What is the maximum amount of packets that one response can be composed of?" + question="How many packets are command responses composed of?" option="A:::Always 1 packet" option="B:::Always multiple packets." - option="C:::Always 1 packet except for complex responses." + option="C:::A variable amount of packets depending on the payload size" correct="C" - info="Command responses are almost always 1 packet (just returning the status). - The exception are complex responses which can be multiple packets (in the case of Get Hardware - Info)" + info="Command responses are sometimes 1 packet (just returning the status). + Other times, command responses also contain a payload and can thus be multiple packets if the payload is big enough + (i.e. in the case of Get Hardware Info). This is described in the per-command documentation in the BLE spec." %} {% quiz question="How many packets are setting responses comprised of?" option="A:::Always 1 packet" option="B:::Always multiple packets." - option="C:::Always 1 packet except for complex responses." + option="C:::A variable amount of packets depending on the payload size" correct="A" - info="Settings Responses only ever contain the command status. Furthermore, there - is no concept of complex responses for setting commands." + info="Settings Responses only ever contain the response status." %} # Parsing Multiple Packet TLV Responses This section will describe parsing TLV responses that contain more than one packet. It will first describe how -to accumulate such responses and then provide a parsing example. The example script that will be walked through -for this section is `ble_command_get_state.py`. We will be creating a small _Response_ class that will be -re-used for future tutorials. +to accumulate such responses and then provide a parsing example. We will be creating small _Response_ and _TlvResponse_ +classes that will be re-used for future tutorials. ## Accumulating the Response The first step is to accumulate the multiple packets into one response. Whereas for all tutorials until now, we -have just used the header bytes of the response as the length, we now must completely parse the header as it is -defined: +have just used the header bytes of the response as the length, we now must completely parse the headers as they are +[defined]({{site.baseurl}}/ble/protocol/data_protocol.html#packet-headers), reproduced for reference here: @@ -462,37 +483,46 @@ defined:
-The basic algorithm here (which is implemented in the _Message.accumulate_ method) is as follows: +The basic accumulation algorithm (which is implemented in the _Response.Accumulate_ method) is as follows: ---
-Continuation bit set? +Is the continuation bit set? {% linkedTabs is_cont_set %} {% tab is_cont_set python %} + +{% note %} +The example script that will be walked through for this section is `ble_command_get_hardware_info.py`. +{% endnote %} + ```python if buf[0] & CONT_MASK: buf.pop(0) else: ... ``` + {% endtab %} {% tab is_cont_set kotlin %} + ```kotlin if (data.first().and(Mask.Continuation.value) == Mask.Continuation.value) { buf = buf.drop(1).toUByteArray() // Pop the header byte } else { // This is a new packet ... ``` + {% endtab %} {% endlinkedTabs %} -No, continuation bit was not set. So create new response, then get its length. +No, the continuation bit was not set. Therefore create new response, then get its length. {% linkedTabs cont_not_set %} {% tab cont_not_set python %} + ```python # This is a new packet so start with an empty byte array self.bytes = bytearray() @@ -507,8 +537,10 @@ elif hdr is Header.EXT_16: self.bytes_remaining = (buf[1] << 8) + buf[2] buf = buf[3:] ``` + {% endtab %} {% tab cont_not_set kotlin %} + ```kotlin // This is a new packet so start with empty array packet = ubyteArrayOf() @@ -531,6 +563,7 @@ when (Header.fromValue((buf.first() and Mask.Header.value).toInt() shr 5)) { } } ``` + {% endtab %} {% endlinkedTabs %} @@ -538,43 +571,69 @@ Append current packet to response and decrement bytes remaining. {% linkedTabs append_packet %} {% tab append_packet python %} + ```python # Append payload to buffer and update remaining / complete self.bytes.extend(buf) self.bytes_remaining -= len(buf) ``` + {% endtab %} {% tab append_packet kotlin %} + ```kotlin // Accumulate the payload now that headers are handled and dropped packet += buf bytesRemaining -= buf.size ``` + {% endtab %} {% endlinkedTabs %} -In the notification handler, we are then parsing if there are no bytes remaining. +In the notification handler, we are then enqueueing the received response if there are no bytes remaining. {% linkedTabs parse_if_done %} {% tab parse_if_done python %} + ```python if response.is_received: - response.parse() + ... + await received_responses.put(response) ``` + +and finally parsing the payload back in the main task after it receives the accumulated response from the queue which, +at the current TLV Response level, is just extracting the ID, status, and payload: + +```python +class TlvResponse(Response): + def parse(self) -> None: + self.id = self.raw_bytes[0] + self.status = self.raw_bytes[1] + self.payload = self.raw_bytes[2:] + +... + +response = await received_responses.get() +response.parse() +``` + {% endtab %} {% tab parse_if_done kotlin %} + ```kotlin -rsp.accumulate(data) -if (rsp.isReceived) { - rsp.parse() +if (response.isReceived) { + if (uuid == GoProUUID.CQ_COMMAND_RSP) { + CoroutineScope(Dispatchers.IO).launch { receivedResponses.send(response) } + } ... ``` + {% endtab %} {% endlinkedTabs %}
-
+



```mermaid! graph TD @@ -592,416 +651,277 @@ graph TD --- -We can see this in action when we send the _Get All Setting Values_ Query. - -{% note %} -Queries aren't introduced until the next tutorial so for now, just pay attention to the response. -{% endnote %} - -We send the command as such: +We can see this in action when we send the +[Get Hardware Info]({{site.baseurl}}/ble/features/query.html#get-hardware-info) Command: {% linkedTabs get_all_settings_values %} {% tab get_all_settings_values python %} + ```python -QUERY_REQ_UUID = GOPRO_BASE_UUID.format("0076") -event.clear() -await client.write_gatt_char(QUERY_REQ_UUID, bytearray([0x01, 0x12])) -await event.wait() # Wait to receive the notification response +request_uuid = GoProUuid.COMMAND_REQ_UUID +request = bytearray([0x01, 0x3C]) +await client.write_gatt_char(request_uuid.value, request, response=True) +response = await received_responses.get() ``` + {% endtab %} {% tab get_all_settings_values kotlin %} + ```kotlin -val getCameraSettings = ubyteArrayOf(0x01U, 0x12U) -ble.writeCharacteristic(goproAddress, GoProUUID.CQ_QUERY.uuid, getCameraSettings) -val settings = receivedResponse.receive() +val hardwareInfoRequest = ubyteArrayOf(0x01U, 0x3CU) +ble.writeCharacteristic(goproAddress, GoProUUID.CQ_COMMAND.uuid, hardwareInfoRequest) ``` + {% endtab %} {% endlinkedTabs %} -Then, in the notification handler, we continuously receive and accumulate packets until we have -received the entire response, at which point we notify the writer that the response is ready: +Then, in the notification handler, we continuously receive and accumulate packets (per UUID) until we have +received an entire response, at which point we perform common TLV parsing (via the `TlvResponse`'s `parse` method) +to extract Command ID, Status, and payload. Then we enqueue the received response to notify the writer that the response +is ready. Finally we reset the per-UUID response to prepare it to receive a new response. + +{% note %} +This notification handler is only designed to handle TlvResponses. This is fine for this tutorial since that is all +we will be receiving. +{% endnote %} + +{% linkedTabs parse_get_hardware_info %} +{% tab parse_get_hardware_info python %} -{% linkedTabs parse_get_all_settings_values %} -{% tab parse_get_all_settings_values python %} ```python - def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - response.accumulate(data) +request_uuid = GoProUuid.COMMAND_REQ_UUID +response_uuid = GoProUuid.COMMAND_RSP_UUID +responses_by_uuid = GoProUuid.dict_by_uuid(TlvResponse) +received_responses: asyncio.Queue[TlvResponse] = asyncio.Queue() - if response.is_received: - response.parse() +async def tlv_notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + response = responses_by_uuid[uuid] + response.accumulate(data) - # Notify writer that procedure is complete - event.set() + if response.is_received: + # If this is the correct handle, enqueue it for processing + if uuid is response_uuid: + logger.info("Received the get hardware info response") + await received_responses.put(response) + # Anything else is unexpected. This shouldn't happen + else: + logger.error("Unexpected response") + # Reset the per-UUID response + responses_by_uuid[uuid] = TlvResponse(uuid) ``` + {% endtab %} -{% tab parse_get_all_settings_values kotlin %} +{% tab parse_get_hardware_info kotlin %} + ```kotlin -private fun tlvResponseNotificationHandler(characteristic: UUID, data: UByteArray) { +private fun notificationHandler(characteristic: UUID, data: UByteArray) { ... - rsp.accumulate(data) - if (rsp.isReceived) { - rsp.parse() - - // Notify the command sender the the procedure is complete - response = null // Clear for next command - CoroutineScope(Dispatchers.IO).launch { receivedResponse.send(rsp) } + responsesByUuid[uuid]?.let { response -> + response.accumulate(data) + if (response.isReceived) { + if (uuid == GoProUUID.CQ_COMMAND_RSP) { + CoroutineScope(Dispatchers.IO).launch { receivedResponses.send(response) } + } + ... + responsesByUuid[uuid] = Response.muxByUuid(uuid) + } } +} ``` + {% endtab %} {% endlinkedTabs %} -{% note %} -We also first parse the response but that will be described in the next section. -{% endnote %} - We can see the individual packets being accumulated in the log: -{% linkedTabs print_get_all_settings_values %} -{% tab print_get_all_settings_values python %} +{% linkedTabs get_hardware_info_log %} +{% tab get_hardware_info_log python %} + ```console -INFO:root:Getting the camera's settings... -INFO:root:Received response at handle=62: b'21:25:12:00:02:01:09:03:01:01:05:0 -INFO:root:self.bytes_remaining=275 -INFO:root:Received response at handle=62: b'80:01:00:18:01:00:1e:04:00:00:00:0 -INFO:root:self.bytes_remaining=256 -INFO:root:Received response at handle=62: b'81:0a:25:01:00:29:01:09:2a:01:05:2 -INFO:root:self.bytes_remaining=237 -INFO:root:Received response at handle=62: b'82:2f:01:04:30:01:03:36:01:00:3b:0 -INFO:root:self.bytes_remaining=218 -INFO:root:Received response at handle=62: b'83:04:00:00:00:00:3e:04:00:00:00:0 -INFO:root:self.bytes_remaining=199 -INFO:root:Received response at handle=62: b'84:00:42:04:00:00:00:00:43:04:00:0 -INFO:root:self.bytes_remaining=180 -INFO:root:Received response at handle=62: b'85:4f:01:00:53:01:00:54:01:00:55:0 -INFO:root:self.bytes_remaining=161 -INFO:root:Received response at handle=62: b'86:01:28:5b:01:02:60:01:00:66:01:0 -INFO:root:self.bytes_remaining=142 -INFO:root:Received response at handle=62: b'87:00:6a:01:00:6f:01:0a:70:01:ff:7 -INFO:root:self.bytes_remaining=123 -INFO:root:Received response at handle=62: b'88:75:01:00:76:01:04:79:01:00:7a:0 -INFO:root:self.bytes_remaining=104 -INFO:root:Received response at handle=62: b'89:01:00:7e:01:00:80:01:0c:81:01:0 -INFO:root:self.bytes_remaining=85 -INFO:root:Received response at handle=62: b'8a:0c:85:01:09:86:01:00:87:01:01:8 -INFO:root:self.bytes_remaining=66 -INFO:root:Received response at handle=62: b'8b:92:01:00:93:01:00:94:01:02:95:0 -INFO:root:self.bytes_remaining=47 -INFO:root:Received response at handle=62: b'8c:01:00:9c:01:00:9d:01:00:9e:01:0 -INFO:root:self.bytes_remaining=28 -INFO:root:Received response at handle=62: b'8d:00:a2:01:00:a3:01:01:a4:01:00:a -INFO:root:self.bytes_remaining=9 -INFO:root:Received response at handle=62: b'8e:a8:04:00:00:00:00:a9:01:01' -INFO:root:self.bytes_remaining=0 -INFO:root:Successfully received the response +Getting the camera's hardware info... +Writing to GoProUuid.COMMAND_REQ_UUID: 01:3c +Received response at handle 47: 20:62:3c:00:04:00:00:00:3e:0c:48:45:52:4f:31:32:20:42:6c:61 +self.bytes_remaining=80 +Received response at handle 47: 80:63:6b:04:30:78:30:35:0f:48:32:33:2e:30:31:2e:30:31:2e:39 +self.bytes_remaining=61 +Received response at handle 47: 81:39:2e:35:36:0e:43:33:35:30:31:33:32:34:35:30:30:37:30:32 +self.bytes_remaining=42 +Received response at handle 47: 82:11:48:45:52:4f:31:32:20:42:6c:61:63:6b:64:65:62:75:67:0c +self.bytes_remaining=23 +Received response at handle 47: 83:32:36:37:34:66:37:66:36:36:31:30:34:01:00:01:01:01:00:02 +self.bytes_remaining=4 +Received response at handle 47: 84:5b:5d:01:01 +self.bytes_remaining=0 +Received the get hardware info response ``` + {% endtab %} -{% tab print_get_all_settings_values kotlin %} +{% tab get_hardware_info_log kotlin %} ```console -Writing characteristic b5f90076-aa8d-11e3-9046-0002a5d5c51b ==> 01:12 -Wrote characteristic b5f90076-aa8d-11e3-9046-0002a5d5c51b -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 21:2B:12:00:02:01:04:03:01:05:05:01:00:06:01:01:0D:01:01:13 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 21:2B:12:00:02:01:04:03:01:05:05:01:00:06:01:01:0D:01:01:13 -Received packet of length 18. 281 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 80:01:00:18:01:00:1E:04:00:00:00:6E:1F:01:00:20:04:00:00:00 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 80:01:00:18:01:00:1E:04:00:00:00:6E:1F:01:00:20:04:00:00:00 -Received packet of length 19. 262 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 81:0A:25:01:00:29:01:09:2A:01:08:2B:01:00:2C:01:09:2D:01:08 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 81:0A:25:01:00:29:01:09:2A:01:08:2B:01:00:2C:01:09:2D:01:08 -Received packet of length 19. 243 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 82:2F:01:07:36:01:01:3B:01:04:3C:04:00:00:00:00:3D:04:00:00 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 82:2F:01:07:36:01:01:3B:01:04:3C:04:00:00:00:00:3D:04:00:00 -Received packet of length 19. 224 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 83:00:00:3E:04:00:12:4F:80:40:01:04:41:04:00:00:00:00:42:04 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 83:00:00:3E:04:00:12:4F:80:40:01:04:41:04:00:00:00:00:42:04 -Received packet of length 19. 205 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 84:00:00:00:00:43:04:00:12:4F:80:4B:01:00:4C:01:00:53:01:01 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 84:00:00:00:00:43:04:00:12:4F:80:4B:01:00:4C:01:00:53:01:01 -Received packet of length 19. 186 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 85:54:01:00:55:01:00:56:01:00:57:01:00:58:01:32:5B:01:03:66 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 85:54:01:00:55:01:00:56:01:00:57:01:00:58:01:32:5B:01:03:66 -Received packet of length 19. 167 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 86:01:08:67:01:03:69:01:00:6F:01:0A:70:01:64:72:01:01:73:01 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 86:01:08:67:01:03:69:01:00:6F:01:0A:70:01:64:72:01:01:73:01 -Received packet of length 19. 148 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 87:00:74:01:02:75:01:01:76:01:04:79:01:03:7A:01:65:7B:01:65 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 87:00:74:01:02:75:01:01:76:01:04:79:01:03:7A:01:65:7B:01:65 -Received packet of length 19. 129 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 88:7C:01:64:7D:01:00:7E:01:00:80:01:0D:81:01:02:82:01:69:83 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 88:7C:01:64:7D:01:00:7E:01:00:80:01:0D:81:01:02:82:01:69:83 -Received packet of length 19. 110 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 89:01:03:84:01:0C:86:01:02:87:01:01:8B:01:03:90:01:0C:91:01 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 89:01:03:84:01:0C:86:01:02:87:01:01:8B:01:03:90:01:0C:91:01 -Received packet of length 19. 91 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 8A:00:92:01:00:93:01:00:94:01:01:95:01:02:96:01:00:97:01:00 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 8A:00:92:01:00:93:01:00:94:01:01:95:01:02:96:01:00:97:01:00 -Received packet of length 19. 72 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 8B:99:01:64:9A:01:02:9B:01:64:9C:01:64:9D:01:64:9E:01:01:9F -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 8B:99:01:64:9A:01:02:9B:01:64:9C:01:64:9D:01:64:9E:01:01:9F -Received packet of length 19. 53 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 8C:01:01:A0:01:00:A1:01:64:A2:01:00:A3:01:01:A4:01:64:A7:01 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 8C:01:01:A0:01:00:A1:01:64:A2:01:00:A3:01:01:A4:01:64:A7:01 -Received packet of length 19. 34 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 8D:04:A8:04:00:00:00:00:A9:01:01:AE:01:00:AF:01:01:B0:01:03 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 8D:04:A8:04:00:00:00:00:A9:01:01:AE:01:00:AF:01:01:B0:01:03 -Received packet of length 19. 15 bytes remaining -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 8E:B1:01:00:B2:01:01:B3:01:03:B4:01:00:B5:01:00 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 8E:B1:01:00:B2:01:01:B3:01:03:B4:01:00:B5:01:00 -Received packet of length 15. 0 bytes remaining -Received the expected successful response -Got the camera's settings successfully +Getting the Hardware Info +Writing characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b ==> 01:3C +Characteristic b5f90073-aa8d-11e3-9046-0002a5d5c51b changed | value: 20:5B:3C:00:04:00:00:00:3E:0C:48:45:52:4F:31:32:20:42:6C:61 +Received response on CQ_COMMAND_RSP +Received packet of length 18. 73 bytes remaining +Characteristic b5f90073-aa8d-11e3-9046-0002a5d5c51b changed | value: 80:63:6B:04:30:78:30:35:0F:48:32:33:2E:30:31:2E:30:31:2E:39 +Received response on CQ_COMMAND_RSP +Received packet of length 19. 54 bytes remaining +Wrote characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b +Characteristic b5f90073-aa8d-11e3-9046-0002a5d5c51b changed | value: 81:39:2E:35:36:0E:43:33:35:30:31:33:32:34:35:30:30:37:30:32 +Received response on CQ_COMMAND_RSP +Received packet of length 19. 35 bytes remaining +Characteristic b5f90073-aa8d-11e3-9046-0002a5d5c51b changed | value: 82:0A:47:50:32:34:35:30:30:37:30:32:0C:32:36:37:34:66:37:66 +Received response on CQ_COMMAND_RSP +Received packet of length 19. 16 bytes remaining +Characteristic b5f90073-aa8d-11e3-9046-0002a5d5c51b changed | value: 83:36:36:31:30:34:01:00:01:01:01:00:02:5B:5D:01:01 +Received response on CQ_COMMAND_RSP +Received packet of length 16. 0 bytes remaining ``` + {% endtab %} {% endlinkedTabs %} -At this point the response has been accumulated. See the next section for how to parse it. +At this point the response has been accumulated. We then parse and log the payload using the +[Get Hardware Info]({{site.baseurl}}/ble/features/query.html#get-hardware-info) response documentation: -**Quiz time! 📚 ✏️** - -{% quiz - question="How can we know that a response has been completely received?" - option="A:::The stop bit will be set in the header" - option="B:::The response has accumulated length bytes" - option="C:::By checking for the end of frame (EOF) sentinel character" - correct="B" - info="The length of the entire response is parsed from the first packet. We - then accumulate packets, keeping track of the received length, until all of the bytes - have been received. A and C are just made up 😜." -%} +{% linkedTabs parse_get_hardware_info_payload %} +{% tab parse_get_hardware_info_payload python %} -## Parsing a Query Response - -This section is going to describe responses to to BLE status / setting queries. We don't actually -introduce such queries until [the next tutorial]({% link _tutorials/tutorial_4_ble_queries/tutorial.md %}) so -for now, only the parsing of the response is important. - -{% tip %} -While multi-packet responses are almost always Query Responses, they can also be from Command Complex -responses. In a real-world implementation, it is therefore necessary to check the received UUID to see -how to parse. -{% endtip %} - -Query Responses contain one or more TLV groups in their Response data. To recap, the generic response format is: - -| Header (length) | Query ID | Status | Response | -| --------------- | -------- | ------- | ---------------- | -| 1-2 bytes | 1 byte | 1 bytes | Length - 2 bytes | - -This means that query responses will contain an array of additional TLV groups in the "Response" field as such: - -| ID1 | Length1 | Value1 | ID2 | Length2 | Value 2 | ... | IDN | LengthN | ValueN | -| ------ | ------- | ------------- | ------ | ------- | ------------- | --- | ------ | ------- | ------------- | -| 1 byte | 1 byte | Length1 bytes | 1 byte | 1 byte | Length2 bytes | ... | 1 byte | 1 byte | LengthN bytes | - -Depending on the amount of query results in the response, this response can be one or multiple packets. -Therefore, we need to account for the possibility that it may always be more than 1 packet. - -We can see an example of such parsing in the response parse method as shown below: - ---- - -
-
- -We have already parsed the length when we were accumulating the packet. So the next step is to parse the Query -ID and Status: - -{% linkedTabs id_status_query_response %} -{% tab id_status_query_response python %} ```python -self.id = self.bytes[0] -self.status = self.bytes[1] +hardware_info = HardwareInfo.from_bytes(response.payload) +logger.info(f"Received hardware info: {hardware_info}") ``` -{% endtab %} -{% tab id_status_query_response kotlin %} -```kotlin -id = packet[0].toInt() -status = packet[1].toInt() -``` -{% endtab %} -{% endlinkedTabs %} -We then continuously parse **Type (ID) - Length - Value** groups until we have consumed the response. We are -storing each value in a hash map indexed by ID for later access. +where the parsing is done as such: -{% linkedTabs tlv_query_response %} -{% tab tlv_query_response python %} ```python -buf = self.bytes[2:] -while len(buf) > 0: - # Get ID and Length - param_id = buf[0] - param_len = buf[1] - buf = buf[2:] - # Get the value - value = buf[:param_len] - - # Store in dict for later access - self.data[param_id] = value + @classmethod + def from_bytes(cls, data: bytes) -> HardwareInfo: + buf = bytearray(data) + # Get model number + model_num_length = buf.pop(0) + model = int.from_bytes(buf[:model_num_length]) + buf = buf[model_num_length:] + # Get model name + model_name_length = buf.pop(0) + model_name = (buf[:model_name_length]).decode() + buf = buf[model_name_length:] + # Advance past deprecated bytes + deprecated_length = buf.pop(0) + buf = buf[deprecated_length:] + # Get firmware version + firmware_length = buf.pop(0) + firmware = (buf[:firmware_length]).decode() + buf = buf[firmware_length:] + # Get serial number + serial_length = buf.pop(0) + serial = (buf[:serial_length]).decode() + buf = buf[serial_length:] + # Get AP SSID + ssid_length = buf.pop(0) + ssid = (buf[:ssid_length]).decode() + buf = buf[ssid_length:] + # Get MAC address + mac_length = buf.pop(0) + mac = (buf[:mac_length]).decode() + buf = buf[mac_length:] + + return cls(model, model_name, firmware, serial, ssid, mac) +``` + +This logs as: - # Advance the buffer - buf = buf[param_len:] -``` -{% endtab %} -{% tab tlv_query_response kotlin %} -```kotlin -while (buf.isNotEmpty()) { - // Get each parameter's ID and length - val paramId = buf[0] - val paramLen = buf[1].toInt() - buf = buf.drop(2) - // Get the parameter's value - val paramVal = buf.take(paramLen) - // Store in data dict for access later - data[paramId] = paramVal.toUByteArray() - // Advance the buffer for continued parsing - buf = buf.drop(paramLen) -} +```console +Parsed hardware info: { + "model_name": "HERO12 Black", + "firmware_version": "H23.01.01.99.56", + "serial_number": "C3501324500702", + "ap_ssid": "HERO12 Blackdebug", + "ap_mac_address": "2674f7f66104" + } ``` -{% endtab %} -{% endlinkedTabs %} - -
-
-


+{% endtab %} +{% tab parse_get_hardware_info_payload kotlin %} -```mermaid! -graph TD - A[Parse Query ID] --> B[Parse Status] - B --> C{More data?} - C --> |yes|D[Get Value ID] - D --> E[Get Value Length] - E --> F[Get Value] - F --> C - C --> |no|G(done) +```kotlin +tlvResponse.parse() +val hardwareInfo = HardwareInfo.fromBytes(tlvResponse.payload) ``` -
-
- ---- - -In the tutorial demo, we then log this entire dict after parsing is complete as such (abbreviated for brevity): - -{% linkedTabs print_query_response %} -{% tab print_query_response python %} +where the parsing is done as such: -```console -INFO:root:Received settings -: { - "2": "09", - "3": "01", - "5": "00", - "6": "01", - "13": "01", - "19": "00", - "30": "00:00:00:00", - "31": "00", - "32": "00:00:00:0a", - "41": "09", - "42": "05", - "43": "00", - ... - "160": "00", - "161": "00", - "162": "00", - "163": "01", - "164": "00", - "165": "00", - "166": "00", - "167": "04", - "168": "00:00:00:00", - "169": "01" +```kotlin +fun fromBytes(data: UByteArray): HardwareInfo { + // Parse header bytes + var buf = data.toUByteArray() + // Get model number + val modelNumLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + val model = buf.take(modelNumLength).toInt() + buf = buf.drop(modelNumLength).toUByteArray() + // Get model name + val modelNameLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + val modelName = buf.take(modelNameLength).decodeToString() + buf = buf.drop(modelNameLength).toUByteArray() + // Advance past deprecated bytes + val deprecatedLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + buf = buf.drop(deprecatedLength).toUByteArray() + // Get firmware version + val firmwareLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + val firmware = buf.take(firmwareLength).decodeToString() + buf = buf.drop(firmwareLength).toUByteArray() + // Get serial number + val serialLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + val serial = buf.take(serialLength).decodeToString() + buf = buf.drop(serialLength).toUByteArray() + // Get AP SSID + val ssidLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + val ssid = buf.take(ssidLength).decodeToString() + buf = buf.drop(ssidLength).toUByteArray() + // Get MAC Address + val macLength = buf.first().toInt() + buf = buf.drop(1).toUByteArray() + val mac = buf.take(macLength).decodeToString() + + return HardwareInfo(model, modelName, firmware, serial, ssid, mac) } ``` -{% endtab %} -{% tab print_query_response kotlin %} + +This logs as: ```console -{ - "2": "09", - "3": "01", - "5": "00", - "6": "01", - "13": "01", - "19": "00", - "24": "00", - "30": "00:00:00:6E", - "31": "00", - "32": "00:00:00:0A", - "37": "00", - "41": "09", - "42": "08", - "43": "00", - "44": "09", - "45": "08", - "47": "07", - ... - "115": "00", - "116": "02", - "117": "01", - "151": "00", - "153": "64", - "154": "02", - "155": "64", - "156": "64", - "157": "64", - "158": "01", - "159": "01", - "160": "00", - "161": "64", - "162": "00", - "163": "01", - "164": "64", - "167": "04", - "168": "00:00:00:00", - "169": "01", - "174": "00", - "175": "01", - "176": "03", - "177": "00", - "178": "01", - "179": "03", - "180": "00", - "181": "00" -} +Got the Hardware Info successfully: HardwareInfo( + modelNumber=1040187392, + modelName=HERO12 Black, + firmwareVersion=H23.01.01.99.56, + serialNumber=C3501324500702, + apSsid=GP24500702, + apMacAddress=2674f7f66104 +) ``` - {% endtab %} {% endlinkedTabs %} -We can see what each of these values mean by looking at the -[Open GoPro Interface](/ble/index.html#settings-quick-reference). - -For example: - -- ID 2 == 9 equates to Resolution == 1080 -- ID 3 == 1 equates to FPS == 120 - -{% quiz - question="How many packets are query responses?" - option="A:::Always 1 packet" - option="B:::Always multiple packets" - option="C:::Always 1 packet except for complex responses" - option="D:::Can be 1 or multiple packets" - correct="D" - info="Query responses can be one packet (if for example querying a specific -setting) or multiple packets (when querying many or all settings as in the example here). -See the next tutorial for more information on queries." -%} +**Quiz time! 📚 ✏️** {% quiz - question="Which field is not common to all responses?" - option="A:::length" - option="B:::status" - option="C:::ID" - option="D:::None of the Above" - correct="D" - info="Query responses can be one packet (if for example querying a specific -setting) or multiple packets (when querying many or all settings as in the example here). -See the next tutorial for more information on queries." + question="How can we know that a response has been completely received?" + option="A:::The stop bit will be set in the header" + option="B:::The response has accumulated length bytes" + option="C:::By checking for the end of frame (EOF) sentinel character" + correct="B" + info="The length of the entire response is parsed from the first packet. We + then accumulate packets, keeping track of the received length, until all of the bytes + have been received. A and C are just made up 😜." %} # Troubleshooting @@ -1015,9 +935,9 @@ See the first tutorial's Congratulations 🤙 {% endsuccess %} -You can now parse any TLV response that is received from the GoPro, at least if it is received uninterrupted. +You now know how to accumulate TLV responses that are received from the GoPro, at least if they are received uninterrupted. There is additional logic required for a complete solution such as checking the UUID the response is received on and storing a dict of response per UUID. At the current time, this endeavor is left for the reader. For a complete example of this, see the [Open GoPro Python SDK](https://gopro.github.io/OpenGoPro/python_sdk/). -To learn more about queries, go to the next tutorial. \ No newline at end of file +To learn about a different type of operation (Queries), go to the next tutorial. diff --git a/docs/_tutorials/tutorial_4_ble_queries/tutorial.md b/docs/_tutorials/tutorial_4_ble_queries/tutorial.md index bae4950d..4982ddc7 100644 --- a/docs/_tutorials/tutorial_4_ble_queries/tutorial.md +++ b/docs/_tutorials/tutorial_4_ble_queries/tutorial.md @@ -5,18 +5,31 @@ sidebar: lesson: 4 --- -# Tutorial 4: BLE Queries +# Tutorial 4: BLE TLV Queries -This document will provide a walk-through tutorial to implement the -[Open GoPro Interface](/ble/index.html) to query the camera's setting and status -information via BLE. +This document will provide a walk-through tutorial to use the Open GoPro Interface to query the camera's setting +and status information via BLE. -"Queries" in this sense are specifically procedures that: +[Queries]({{site.baseurl}}/ble/protocol/data_protocol.html#queries) in this sense are operations that are initiated by +writing to the Query [UUID]({{site.baseurl}}/ble/protocol/ble_setup.html#ble-characteristics) and receiving responses +via the Query Response [UUID]({{site.baseurl}}/ble/protocol/ble_setup.html#ble-characteristics). -- are initiated by writing to the Query UUID -- receive responses via the Query Response UUID. +A list of queries can be found in the [Query ID Table]({{site.baseurl}}/ble/protocol/id_tables.html#query-ids). -This will be described in more detail below. +It is important to distinguish between queries and +[commands]({% link _tutorials/tutorial_2_send_ble_commands/tutorial.md %}) because they each have different request +and response packet formats. + +{% note %} +This tutorial only considers sending these queries as one-off queries. That is, it does not consider state +management / synchronization when sending multiple queries. This will be discussed in a future lab. +{% endnote %} + +# Requirements + +It is assumed that the hardware and software requirements from the +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}) +are present and configured correctly. {% tip %} It is suggested that you have first completed the @@ -26,38 +39,30 @@ It is suggested that you have first completed the through this tutorial. {% endtip %} -This tutorial only considers sending these queries as one-off commands. That is, it does not consider state -management / synchronization when sending multiple commands. This will be discussed in a future lab. - -# Requirements - -It is assumed that the hardware and software requirements from the -[connect tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}) -are present and configured correctly. - # Just Show me the Demo(s)!! {% linkedTabs demo %} {% tab demo python %} -Each of the scripts for this tutorial can be found in the Tutorial 2 +Each of the scripts for this tutorial can be found in the Tutorial 4 [directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_4_ble_queries/). {% warning %} -Python >= 3.8.x must be used as specified in the requirements +Python >= 3.9 and < 3.12 must be used as specified in the requirements {% endwarning %} {% accordion Individual Query Poll %} You can test an individual query poll with your camera through BLE using the following script: + ```console -$ python ble_command_poll_resolution_value.py +$ python ble_query_poll_resolution_value.py ``` See the help for parameter definitions: ```console -$ python ble_command_poll_resolution_value.py --help -usage: ble_command_poll_resolution_value.py [-h] [-i IDENTIFIER] +$ python ble_query_poll_resolution_value.py --help +usage: ble_query_poll_resolution_value.py [-h] [-i IDENTIFIER] Connect to a GoPro camera, get the current resolution, modify the resolution, and confirm the change was successful. @@ -67,21 +72,22 @@ optional arguments: Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to ``` -{% endaccordion %} +{% endaccordion %} {% accordion Multiple Simultaneous Query Polls %} You can test querying multiple queries simultaneously with your camera through BLE using the following script: + ```console -$ python ble_command_poll_multiple_setting_values.py +$ python ble_query_poll_multiple_setting_values.py ``` See the help for parameter definitions: ```console -$ python ble_command_poll_multiple_setting_values.py --help -usage: ble_command_poll_multiple_setting_values.py [-h] [-i IDENTIFIER] +$ python ble_query_poll_multiple_setting_values.py --help +usage: ble_query_poll_multiple_setting_values.py [-h] [-i IDENTIFIER] Connect to a GoPro camera then get the current resolution, fps, and fov. @@ -91,23 +97,26 @@ optional arguments: Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to ``` -{% endaccordion %} +{% endaccordion %} {% accordion Registering for Query Push Notifications %} -You can test registering for querties and receiving push notifications with your camera through BLE using the following script: +You can test registering for querties and receiving push notifications with your camera through BLE using the following +script: + ```console -$ python ble_command_register_resolution_value_updates.py +$ python ble_query_register_resolution_value_updates.py ``` See the help for parameter definitions: ```console -$ python ble_command_register_resolution_value_updates.py --help -usage: ble_command_register_resolution_value_updates.py [-h] [-i IDENTIFIER] +$ python ble_query_register_resolution_value_updates.py --help +usage: ble_query_register_resolution_value_updates.py [-h] [-i IDENTIFIER] -Connect to a GoPro camera, register for updates to the resolution, receive the current resolution, modify the resolution, and confirm receipt of the change notification. +Connect to a GoPro camera, register for updates to the resolution, receive the current resolution, modify the resolution, +and confirm receipt of the change notification. optional arguments: -h, --help show this help message and exit @@ -115,6 +124,7 @@ optional arguments: Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first discovered GoPro will be connected to ``` + {% endaccordion %} {% endtab %} {% tab demo kotlin %} @@ -136,57 +146,53 @@ This will start the tutorial and log to the screen as it executes. When the tuto # Setup We must first connect as was discussed in the -[connect tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}). +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}). -We will also be using the **Response** class that was defined in the -[parsing responses]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}) tutorial to accumulate -and parse notification responses to the Query Response -[characteristic](/ble/index.html#services-and-characteristics). -Throughout this tutorial, the query information that we will be reading is the Resolution Setting (ID 0x02). {% linkedTabs notification_handler %} {% tab notification_handler python %} -Therefore, we have slightly changed the notification handler to update a global resolution variable as it -queries the resolution: + +We have slightly updated the notification handler from the previous tutorial to handle a `QueryResponse` instead of +a `TlvResponse` where `QueryResponse` is a subclass of `TlvResponse` that will be created in this tutorial. ```python -def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: +responses_by_uuid = GoProUuid.dict_by_uuid(QueryResponse) +received_responses: asyncio.Queue[QueryResponse] = asyncio.Queue() + +query_request_uuid = GoProUuid.QUERY_REQ_UUID +query_response_uuid = GoProUuid.QUERY_RSP_UUID +setting_request_uuid = GoProUuid.SETTINGS_REQ_UUID +setting_response_uuid = GoProUuid.SETTINGS_RSP_UUID + +async def notification_handler(characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(client.services.characteristics[characteristic.handle].uuid) + response = responses_by_uuid[uuid] response.accumulate(data) + # Notify the writer if we have received the entire response if response.is_received: - response.parse() + # If this is query response, it must contain a resolution value + if uuid is query_response_uuid: + logger.info("Received a Query response") + await received_responses.put(response) + # If this is a setting response, it will just show the status + elif uuid is setting_response_uuid: + logger.info("Received Set Setting command response.") + await received_responses.put(response) + # Anything else is unexpected. This shouldn't happen + else: + logger.error("Unexpected response") + # Reset per-uuid Response + responses_by_uuid[uuid] = QueryResponse(uuid) +``` - if client.services.characteristics[characteristic.handle].uuid == QUERY_RSP_UUID: - resolution = Resolution(response.data[RESOLUTION_ID][0]) +{% note %} +The code above is taken from `ble_query_poll_resolution_value.py` +{% endnote %} - # Notify writer that the procedure is complete - event.set() -``` {% endtab %} {% tab notification_handler kotlin %} -Therefore, we have slightly updated the notification handler to only handle query responses: -```kotlin -fun resolutionPollingNotificationHandler(characteristic: UUID, data: UByteArray) { - GoProUUID.fromUuid(characteristic)?.let { - // If response is currently empty, create a new one - response = response ?: Response.Query() // We're only handling queries in this tutorial - } ?: return // We don't care about non-GoPro characteristics (i.e. the BT Core Battery service) - - Timber.d("Received response on $characteristic: ${data.toHexString()}") - - response?.let { rsp -> - rsp.accumulate(data) - if (rsp.isReceived) { - rsp.parse() - - // If this is a query response, it must contain a resolution value - if (characteristic == GoProUUID.CQ_QUERY_RSP.uuid) { - Timber.i("Received resolution query response") - } - ... -``` - -We are also defining a resolution enum that will be updated as we receive new resolutions: +We are defining a resolution enum that will be updated as we receive new resolutions: ```kotlin private enum class Resolution(val value: UByte) { @@ -216,21 +222,136 @@ section: - [Polling Query Information]({% link _tutorials/tutorial_4_ble_queries/tutorial.md %}#polling-query-information) - [Registering for query push notifications]({% link _tutorials/tutorial_4_ble_queries/tutorial.md %}#registering-for-query-push-notifications) +# Parsing a Query Response + +Before sending queries, we must first describe how Query response parsing differs from the Command response parsing +that was introduced in the previous tutorial. + +To recap, the generic response format for both Commands and Queries is: + +| Header (length) | Operation ID (Command / Query ID) | Status | Response | +| --------------- | --------------------------------- | ------- | ---------------- | +| 1-2 bytes | 1 byte | 1 bytes | Length - 2 bytes | + +Query Responses contain an array of additional TLV groups in the **Response** field as such: + +| ID1 | Length1 | Value1 | ID2 | Length2 | Value 2 | ... | IDN | LengthN | ValueN | +| ------ | ------- | ------------- | ------ | ------- | ------------- | --- | ------ | ------- | ------------- | +| 1 byte | 1 byte | Length1 bytes | 1 byte | 1 byte | Length2 bytes | ... | 1 byte | 1 byte | LengthN bytes | + +We will be extending the `TlvResponse` class that was defined in the +[parsing responses]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}) tutorial to perform common +parsing shared among all queries into a `QueryResponse` class as seen below: + +--- + +
+
+ +We have already parsed the length, Operation ID, and status, and extracted the payload in the `TlvResponse` class. +The next step is to parse the payload. + +Therefore, we now continuously parse **Type (ID) - Length - Value** groups until we have consumed the response. We are +storing each value in a hash map indexed by ID for later access. + +{% linkedTabs tlv_query_response %} +{% tab tlv_query_response python %} + +```python +class QueryResponse(TlvResponse): + ... + + def parse(self) -> None: + super().parse() + buf = bytearray(self.payload) + while len(buf) > 0: + # Get ID and Length of query parameter + param_id = buf[0] + param_len = buf[1] + buf = buf[2:] + # Get the value + value = buf[:param_len] + # Store in dict for later access + self.data[param_id] = bytes(value) + + # Advance the buffer + buf = buf[param_len:] +``` + +{% endtab %} +{% tab tlv_query_response kotlin %} + +```kotlin +while (buf.isNotEmpty()) { + // Get each parameter's ID and length + val paramId = buf[0] + val paramLen = buf[1].toInt() + buf = buf.drop(2) + // Get the parameter's value + val paramVal = buf.take(paramLen) + // Store in data dict for access later + data[paramId] = paramVal.toUByteArray() + // Advance the buffer for continued parsing + buf = buf.drop(paramLen) +} +``` + +{% endtab %} +{% endlinkedTabs %} + +
+
+ +


+ +```mermaid! +graph TD + A[Parse Query ID] --> B[Parse Status] + B --> C{More data?} + C --> |yes|D[Get Value ID] + D --> E[Get Value Length] + E --> F[Get Value] + F --> C + C --> |no|G(done) +``` + +
+
+ +{% quiz + question="How many packets are query responses?" + option="A:::Always 1 packet" + option="B:::Always multiple packets" + option="C:::Can be 1 or multiple packets" + correct="C" + info="Query responses can be one packet (if for example querying a specific +setting) or multiple packets (when querying many or all settings as in the example here)." +%} + +{% quiz + question="Which field is not common to all TLV responses?" + option="A:::length" + option="B:::status" + option="C:::ID" + option="D:::None of the Above" + correct="D" + info="All Commands and Query responses have a length, ID, and status." +%} + # Polling Query Information -It is possible to poll one or more setting / status values using the following -[commands](/ble/index.html#query-commands): +It is possible to poll one or more setting / status values using the following queries: -| Query ID | Request | Query | -| -------- | -------------------- | ------------ | -| 0x12 | Get Setting value(s) | len:12:xx:xx | -| 0x13 | Get Status value(s) | len:13:xx:xx | +| Query ID | Request | Query | +| -------- | ------------------------------------------------------------------------------------- | ------------ | +| 0x12 | [Get Setting value(s)]({{site.baseurl}}/ble/features/query.html#get-setting-values) | len:12:xx:xx | +| 0x13 | [Get Status value(s)]({{site.baseurl}}/ble/features/query.html#get-status-values) | len:13:xx:xx | -where **xx** are setting / status ID(s) and **len** is the length of the rest of the query (the number of query bytes plus one for the request ID byte). -There will be specific examples below. +where **xx** are setting / status ID(s) and **len** is the length of the rest of the query (the number of query bytes +plus one for the request ID byte). There will be specific examples below. {% note %} -Since they are two separate commands, combination of settings / statuses can not be polled simultaneously. +Since they are two separate queries, combination of settings / statuses can not be polled simultaneously. {% endnote %} Here is a generic sequence diagram (the same is true for statuses): @@ -240,7 +361,7 @@ sequenceDiagram participant PC as Open GoPro user device participant GoPro note over PC, GoPro: Connected (steps from connect tutorial) - PC ->> GoPro: Get Setting value(s) command written to Query UUID + PC ->> GoPro: Get Setting value(s) queries written to Query UUID GoPro ->> PC: Setting values responded to Query Response UUID GoPro ->> PC: More setting values responded to Query Response UUID GoPro ->> PC: ... @@ -251,86 +372,81 @@ The number of notification responses will vary depending on the amount of settin Note that setting values will be combined into one notification until it reaches the maximum notification size (20 bytes). At this point, a new response will be sent. Therefore, it is necessary to accumulate and then parse these responses as was described in -[parsing query responses]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}#query-responses) +[parsing query responses]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}#parsing-a-query-response) ## Individual Query Poll Here we will walk through an example of polling one setting (Resolution). -First we send the query command: +First we send the query: {% linkedTabs individual_send %} {% tab individual_send python %} + +{% note %} The sample code can be found in in `ble_query_poll_resolution_value.py`. -Let's first define the UUID's to write to and receive from: +{% endnote %} ```python -QUERY_REQ_UUID = GOPRO_BASE_UUID.format("0076") -QUERY_RSP_UUID = GOPRO_BASE_UUID.format("0077") +query_request_uuid = GoProUuid.QUERY_REQ_UUID +request = bytes([0x02, 0x12, RESOLUTION_ID]) +await client.write_gatt_char(query_request_uuid.value, request, response=True) ``` -Then actually send the command: - -```python -event.clear() -await client.write_gatt_char(QUERY_REQ_UUID, bytearray([0x02, 0x12, RESOLUTION_ID])) -await event.wait() # Wait to receive the notification response -``` {% endtab %} {% tab individual_send kotlin %} + ```kotlin val pollResolution = ubyteArrayOf(0x02U, 0x12U, RESOLUTION_ID) ble.writeCharacteristic(goproAddress, GoProUUID.CQ_QUERY.uuid, pollResolution) ``` + {% endtab %} {% endlinkedTabs %} -When the response is received in / from the notification handler, we update the global resolution variable: +Then when the response is received from the notification handler we parse it into individual query elements in the +`QueryResponse` class and extract the new resolution value. {% linkedTabs individual_parse %} {% tab individual_parse python %} -```python -def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - response.accumulate(data) - # Notify the writer if we have received the entire response - if response.is_received: - response.parse() - - # If this is query response, it must contain a resolution value - if client.services.characteristics[characteristic.handle].uuid == QUERY_RSP_UUID: - resolution = Resolution(response.data[RESOLUTION_ID][0]) +```python +# Wait to receive the notification response +response = await received_responses.get() +response.parse() +resolution = Resolution(response.data[RESOLUTION_ID][0]) ``` which logs as such: ```console -INFO:root:Getting the current resolution -INFO:root:Received response at handle=62: b'05:12:00:02:01:09' -INFO:root:self.bytes_remaining=0 -INFO:root:Resolution is currently Resolution.RES_1080 +Getting the current resolution + Writing to GoProUuid.QUERY_REQ_UUID: 02:12:02 +Received response at handle=62: b'05:12:00:02:01:09' +eceived the Resolution Query response +Resolution is currently Resolution.RES_1080 ``` {% endtab %} {% tab individual_parse kotlin %} + ```kotlin // Wait to receive the response and then convert it to resolution -resolution = Resolution.fromValue( - receivedResponse.receive().data.getValue(RESOLUTION_ID).first() -) +val queryResponse = (receivedResponses.receive() as Response.Query).apply { parse() } +resolution = Resolution.fromValue(queryResponse.data.getValue(RESOLUTION_ID).first()) ``` which logs as such: ```console - Polling the current resolution +Polling the current resolution Writing characteristic b5f90076-aa8d-11e3-9046-0002a5d5c51b ==> 02:12:02 Wrote characteristic b5f90076-aa8d-11e3-9046-0002a5d5c51b -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 05:12:00:02:01:04 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 05:12:00:02:01:04 +Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 05:12:00:02:01:09 +Received response on CQ_QUERY_RSP Received packet of length 5. 0 bytes remaining -Received resolution query response -Camera resolution is RES_2_7K +Received Query Response +Camera resolution is RES_1080 ``` {% endtab %} @@ -341,46 +457,62 @@ has changed: {% linkedTabs individual_verify %} {% tab individual_verify python %} + +```python +while resolution is not target_resolution: + request = bytes([0x02, 0x12, RESOLUTION_ID]) + await client.write_gatt_char(query_request_uuid.value, request, response=True) + response = await received_responses.get() # Wait to receive the notification response + response.parse() + resolution = Resolution(response.data[RESOLUTION_ID][0]) +``` + +which logs as such: + ```console -INFO:root:Changing the resolution to Resolution.RES_2_7K... -INFO:root:Received response at handle=57: b'02:02:00' -INFO:root:self.bytes_remaining=0 -INFO:root:Command sent successfully -INFO:root:Polling the resolution to see if it has changed... -INFO:root:Received response at handle=62: b'05:12:00:02:01:07' -INFO:root:self.bytes_remaining=0 -INFO:root:Resolution is currently Resolution.RES_2_7K +Changing the resolution to Resolution.RES_2_7K... +Writing to GoProUuid.SETTINGS_REQ_UUID: 03:02:01:04 +Writing to GoProUuid.SETTINGS_REQ_UUID: 03:02:01:04 +Received response at GoProUuid.SETTINGS_RSP_UUID: 02:02:00 +Received Set Setting command response. +Polling the resolution to see if it has changed... +Writing to GoProUuid.QUERY_REQ_UUID: 02:12:02 +Received response at GoProUuid.QUERY_RSP_UUID: 05:12:00:02:01:04 +Received the Resolution Query response +Resolution is currently Resolution.RES_2_7K +Resolution has changed as expected. Exiting... ``` {% endtab %} {% tab individual_verify kotlin %} + ```kotlin - while (resolution != newResolution) { - ble.writeCharacteristic(goproAddress, GoProUUID.CQ_QUERY.uuid, pollResolution) - resolution = Resolution.fromValue( - receivedResponse.receive().data.getValue(RESOLUTION_ID).first() - ) - Timber.i("Camera resolution is currently $resolution") - } +while (resolution != newResolution) { + ble.writeCharacteristic(goproAddress, GoProUUID.CQ_QUERY.uuid, pollResolution) + val queryNotification = (receivedResponses.receive() as Response.Query).apply { parse() } + resolution = Resolution.fromValue(queryNotification.data.getValue(RESOLUTION_ID).first()) +} ``` which logs as such: ```console -Changing the resolution to RES_1080 -Writing characteristic b5f90074-aa8d-11e3-9046-0002a5d5c51b ==> 03:02:01:09 +Changing the resolution to RES_2_7K +Writing characteristic b5f90074-aa8d-11e3-9046-0002a5d5c51b ==> 03:02:01:04 Wrote characteristic b5f90074-aa8d-11e3-9046-0002a5d5c51b Characteristic b5f90075-aa8d-11e3-9046-0002a5d5c51b changed | value: 02:02:00 -Received response on b5f90075-aa8d-11e3-9046-0002a5d5c51b: 02:02:00 -Command sent successfully +Received response on CQ_SETTING_RSP +Received packet of length 2. 0 bytes remaining +Received set setting response. Resolution successfully changed Polling the resolution until it changes Writing characteristic b5f90076-aa8d-11e3-9046-0002a5d5c51b ==> 02:12:02 -Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 05:12:00:02:01:09 -Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 05:12:00:02:01:09 -Received resolution query response +Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 05:12:00:02:01:04 +Received response on CQ_QUERY_RSP +Received packet of length 5. 0 bytes remaining +Received Query Response Wrote characteristic b5f90076-aa8d-11e3-9046-0002a5d5c51b -Camera resolution is currently RES_1080 +Camera resolution is currently RES_2_7K ``` {% endtab %} @@ -389,19 +521,24 @@ Camera resolution is currently RES_1080 ## Multiple Simultaneous Query Polls Rather than just polling one setting, it is also possible to poll multiple settings. An example of this is shown -below. It is very similar to the previous example except for the following: - -The query command now includes 3 settings: Resolution, FPS, and FOV. +below. It is very similar to the previous example except that the query now includes 3 settings: +[Resolution]({{site.baseurl}}/ble/features/settings.html#setting-2), +[FPS]({{site.baseurl}}/ble/features/settings.html#setting-3), +and [FOV]({{site.baseurl}}/ble/features/settings.html#setting-121). {% linkedTabs multiple_send %} {% tab multiple_send python %} + ```python RESOLUTION_ID = 2 FPS_ID = 3 FOV_ID = 121 -await client.write_gatt_char(QUERY_REQ_UUID, bytearray([0x04, 0x12, RESOLUTION_ID, FPS_ID, FOV_ID])) +request = bytes([0x04, 0x12, RESOLUTION_ID, FPS_ID, FOV_ID]) +await client.write_gatt_char(query_request_uuid.value, request, response=True) +response = await received_responses.get() # Wait to receive the notification response ``` + {% endtab %} {% tab multiple_send kotlin %} TODO @@ -409,25 +546,21 @@ TODO {% endlinkedTabs %} {% note %} -The length (first byte of the command) has been increased to 4 to accommodate the extra settings +The length (first byte of the query) has been increased to 4 to accommodate the extra settings {% endnote %} We are also parsing the response to get all 3 values: {% linkedTabs multiple_parse %} {% tab multiple_parse python %} -```python -def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - response.accumulate(data) - if response.is_received: - response.parse() - - if client.services.characteristics[characteristic.handle].uuid == QUERY_RSP_UUID: - resolution = Resolution(response.data[RESOLUTION_ID][0]) - fps = FPS(response.data[FPS_ID][0]) - video_fov = VideoFOV(response.data[FOV_ID][0]) +```python +response.parse() +logger.info(f"Resolution is currently {Resolution(response.data[RESOLUTION_ID][0])}") +logger.info(f"Video FOV is currently {VideoFOV(response.data[FOV_ID][0])}") +logger.info(f"FPS is currently {FPS(response.data[FPS_ID][0])}") ``` + {% endtab %} {% tab multiple_parse kotlin %} TODO @@ -444,43 +577,52 @@ They are then printed to the log which will look like the following: {% linkedTabs multiple_print %} {% tab multiple_print python %} + ```console -INFO:root:Received response at handle=62: b'0b:12:00:02:01:07:03:01:01:79:01:00' -INFO:root:self.bytes_remaining=0 -INFO:root:Resolution is currently Resolution.RES_2_7K -INFO:root:Video FOV is currently VideoFOV.FOV_WIDE -INFO:root:FPS is currently FPS.FPS_120 +Getting the current resolution, fps, and fov. +Writing to GoProUuid.QUERY_REQ_UUID: 04:12:02:03:79 +Received response at GoProUuid.QUERY_RSP_UUID: 0b:12:00:02:01:09:03:01:00:79:01:00 +Received the Query Response +Resolution is currently Resolution.RES_1080 +Video FOV is currently VideoFOV.FOV_WIDE +FPS is currently FPS.FPS_240 ``` + {% endtab %} {% tab multiple_print kotlin %} TODO {% endtab %} {% endlinkedTabs %} +In general, we can parse query values by looking at relevant documentation linked from the +[Setting]({{site.baseurl}}/ble/protocol/id_tables.html#setting-ids) or +[Status]({{site.baseurl}}/ble/protocol/id_tables.html#status-ids) ID tables. + +For example (for settings): + +- ID 2 == 9 equates to [Resolution]({{site.baseurl}}/ble/features/settings.html#setting-2) == 1080 +- ID 3 == 1 equates to [FPS]({{site.baseurl}}/ble/features/settings.html#setting-3) == 120 + ## Query All -It is also possible to query all settings / statuses by not passing any ID's into the the query command, i.e.: +It is also possible to query all settings / statuses by not passing any ID's into the the query, i.e.: | Query ID | Request | Query | | -------- | ---------------- | ----- | | 0x12 | Get All Settings | 01:12 | | 0x13 | Get All Statuses | 01:13 | -An example of this can be seen in the -[parsing query responses]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}#query-responses) -tutorial - **Quiz time! 📚 ✏️** {% quiz - question="How can we poll the encoding status and the resolution setting using one command?" - option="A:::Concatenate a 'Get Setting Value' command and a 'Get Status' command with the relevant ID's" - option="B:::Concatenate the 'Get All Setting' and 'Get All Status' commands." + question="How can we poll the encoding status and the resolution setting using one query?" + option="A:::Concatenate a 'Get Setting Value' query and a 'Get Status' query with the relevant ID's" + option="B:::Concatenate the 'Get All Setting' and 'Get All Status' queries." option="C:::It is not possible" correct="C" - info="It is not possible to concatenate commands. This would result in an unknown sequence of bytes + info="It is not possible to concatenate queries. This would result in an unknown sequence of bytes from the camera's perspective. So it is not possible to get a setting value and a status value in one - command. The Get Setting command (with resolution ID) and Get Status command(with encoding ID) must be + query. The Get Setting Query (with resolution ID) and Get Status Query (with encoding ID) must be sent sequentially in order to get this information." %} @@ -489,18 +631,18 @@ tutorial Rather than polling the query information, it is also possible to use an interrupt scheme to register for push notifications when the relevant query information changes. -The relevant [commands](/ble/index.html#query-commands) are: +The relevant queries are: -| Query ID | Request | Query | -| -------- | --------------------------------- | ------------ | -| 0x52 | Register updates for setting(s) | len:52:xx:xx | -| 0x53 | Register updates for status(es) | len:53:xx:xx | -| 0x72 | Unregister updates for setting(s) | len:72:xx:xx | -| 0x73 | Unregister updates for status(es) | len:73:xx:xx | +| Query ID | Request | Query | +| -------- | -------------------------------------------------------------------------------------------------------------------- | ------------ | +| 0x52 | [Register updates for setting(s)]({{site.baseurl}}/ble/features/query.html#register-for-setting-value-updates) | len:52:xx:xx | +| 0x53 | [Register updates for status(es)]({{site.baseurl}}/ble/features/query.html#register-for-status-value-updates) | len:53:xx:xx | +| 0x72 | [Unregister updates for setting(s)]({{site.baseurl}}/ble/features/query.html#unregister-for-setting-value-updates) | len:72:xx:xx | +| 0x73 | [Unregister updates for status(es)]({{site.baseurl}}/ble/features/query.html#unregister-for-status-value-updates) | len:73:xx:xx | where **xx** are setting / status ID(s) and **len** is the length of the rest of the query (the number of query bytes plus one for the request ID byte). -The Query ID's for push notification responses are as follows: +The [Query ID's]({{site.baseurl}}/ble/protocol/id_tables.html#query-ids) for push notification responses are as follows: | Query ID | Response | | -------- | ------------------------------- | @@ -535,7 +677,7 @@ That is, after registering for push notifications for a given query, notificatio be sent whenever the query changes until the client unregisters for push notifications for the given query. {% tip %} -The initial response to the Register command also contains the current setting / status value. +The initial response to the Register query also contains the current setting / status value. {% endtip %} We will walk through an example of this below: @@ -544,25 +686,18 @@ First, let's register for updates when the resolution setting changes: {% linkedTabs register_register %} {% tab register_register python %} -First, let's define the UUID's we will be using: - -```python -SETTINGS_REQ_UUID = GOPRO_BASE_UUID.format("0074") -SETTINGS_RSP_UUID = GOPRO_BASE_UUID.format("0075") -QUERY_REQ_UUID = GOPRO_BASE_UUID.format("0076") -QUERY_RSP_UUID = GOPRO_BASE_UUID.format("0077") -``` - -Then, let's send the register BLE message... ```python -event.clear() -await client.write_gatt_char(QUERY_REQ_UUID, bytearray([0x02, 0x52, RESOLUTION_ID])) -await event.wait() # Wait to receive the notification response +query_request_uuid = GoProUuid.QUERY_REQ_UUID +request = bytes([0x02, 0x52, RESOLUTION_ID]) +await client.write_gatt_char(query_request_uuid.value, request, response=True) +# Wait to receive the notification response +response = await received_responses.get() ``` {% endtab %} {% tab register_register kotlin %} + ```kotlin val registerResolutionUpdates = ubyteArrayOf(0x02U, 0x52U, RESOLUTION_ID) ble.writeCharacteristic(goproAddress, GoProUUID.CQ_QUERY.uuid, registerResolutionUpdates) @@ -572,50 +707,36 @@ ble.writeCharacteristic(goproAddress, GoProUUID.CQ_QUERY.uuid, registerResolutio {% endlinkedTabs %} and parse its response (which includes the current resolution value). This is very similar to the polling -example with the exception that the Query ID is now 0x52 (Register Updates for Settings). This can be seen in -the raw byte data as well as by inspecting the response's `id` property. +example with the exception that the Query ID is now 0x52 +([Register Updates for Settings]({{site.baseurl}}/ble/features/query.html#register-for-setting-value-updates)). +This can be seen in the raw byte data as well as by inspecting the response's `id` property. {% linkedTabs register_parse %} {% tab register_parse python %} -```python -def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None: - logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}') - - response.accumulate(data) - # Notify the writer if we have received the entire response - if response.is_received: - response.parse() - - # If this is query response, it must contain a resolution value - if client.services.characteristics[characteristic.handle].uuid == QUERY_RSP_UUID: - global resolution - resolution = Resolution(response.data[RESOLUTION_ID][0]) +```python +response.parse() +resolution = Resolution(response.data[RESOLUTION_ID][0]) +logger.info(f"Resolution is currently {resolution}") ``` This will show in the log as such: ```console -INFO:root:Registering for resolution updates -INFO:root:Received response at handle=62: b'05:52:00:02:01:07' -INFO:root:self.bytes_remaining=0 -INFO:root:Successfully registered for resolution value updates. -INFO:root:Resolution is currently Resolution.RES_2_7K +Registering for resolution updates +Writing to GoProUuid.QUERY_REQ_UUID: 02:52:02 +Received response at GoProUuid.QUERY_RSP_UUID: 05:52:00:02:01:09 +Received the Resolution Query response +Successfully registered for resolution value updates +Resolution is currently Resolution.RES_1080 ``` + {% endtab %} {% tab register_parse kotlin %} -```kotlin -fun resolutionRegisteringNotificationHandler(characteristic: UUID, data: UByteArray) { - ... - if (rsp.isReceived) { - rsp.parse() - - if (characteristic == GoProUUID.CQ_QUERY_RSP.uuid) { - Timber.i("Received resolution query response") - resolution = Resolution.fromValue(rsp.data.getValue(RESOLUTION_ID).first()) - Timber.i("Resolution is now $resolution") - ... +```kotlin +val queryResponse = (receivedResponses.receive() as Response.Query).apply { parse() } +resolution = Resolution.fromValue(queryResponse.data.getValue(RESOLUTION_ID).first()) ``` This will show in the log as such: @@ -624,34 +745,65 @@ This will show in the log as such: Registering for resolution value updates Writing characteristic b5f90076-aa8d-11e3-9046-0002a5d5c51b ==> 02:52:02 Wrote characteristic b5f90076-aa8d-11e3-9046-0002a5d5c51b +Characteristic b5f90077-aa8d-11e3-9046-0002a5d5c51b changed | value: 05:52:00:02:01:04 +Received response on CQ_QUERY_RSP +Received packet of length 5. 0 bytes remaining +Received Query Response +Camera resolution is RES_2_7K ``` + {% endtab %} {% endlinkedTabs %} We are now successfully registered for resolution value updates and will receive push notifications whenever -the resolution changes. We verify this in the demo by then changing the resolution. +the resolution changes. We verify this in the demo by then changing the resolution and waiting to receive the update. +notification.. {% linkedTabs register_response %} {% tab register_response python %} + +```python +target_resolution = Resolution.RES_2_7K if resolution is Resolution.RES_1080 else Resolution.RES_1080 +request = bytes([0x03, 0x02, 0x01, target_resolution.value]) +await client.write_gatt_char(setting_request_uuid.value, request, response=True) +response = await received_responses.get() +response.parse() + +while resolution is not target_resolution: + request = bytes([0x02, 0x12, RESOLUTION_ID]) + await client.write_gatt_char(query_request_uuid.value, request, response=True) + response = await received_responses.get() # Wait to receive the notification response + response.parse() + resolution = Resolution(response.data[RESOLUTION_ID][0]) +``` + This will show in the log as such: ```console -INFO:root:Successfully changed the resolution -INFO:root:Received response at handle=62: b'05:92:00:02:01:09' -INFO:root:self.bytes_remaining=0 -INFO:root:Resolution is now Resolution.RES_1080 +Changing the resolution to Resolution.RES_2_7K... +Writing to GoProUuid.SETTINGS_REQ_UUID: 03:02:01:04 +Received response at GoProUuid.SETTINGS_RSP_UUID: 02:02:00 +Received Set Setting command response. +Waiting to receive new resolution +Received response at GoProUuid.QUERY_RSP_UUID: 05:92:00:02:01:04 +Received the Resolution Query response +Resolution is currently Resolution.RES_2_7K +Resolution has changed as expected. Exiting... ``` + {% endtab %} {% tab register_response kotlin %} + ```kotlin -val newResolution = if (resolution == Resolution.RES_2_7K) Resolution.RES_1080 else Resolution.RES_2_7K -val setResolution = ubyteArrayOf(0x03U, RESOLUTION_ID, 0x01U, newResolution.value) +val targetResolution = if (resolution == Resolution.RES_2_7K) Resolution.RES_1080 else Resolution.RES_2_7K +val setResolution = ubyteArrayOf(0x03U, RESOLUTION_ID, 0x01U, targetResolution.value) ble.writeCharacteristic(goproAddress, GoProUUID.CQ_SETTING.uuid, setResolution) -val setResolutionResponse = receivedResponse.receive() +val setResolutionResponse = (receivedResponses.receive() as Response.Tlv).apply { parse() } // Verify we receive the update from the camera when the resolution changes -while (resolution != newResolution) { - receivedResponse.receive() +while (resolution != targetResolution) { + val queryNotification = (receivedResponses.receive() as Response.Query).apply { parse() } + resolution = Resolution.fromValue(queryNotification.data.getValue(RESOLUTION_ID).first()) } ``` @@ -668,6 +820,7 @@ Received response on b5f90077-aa8d-11e3-9046-0002a5d5c51b: 05:92:00:02:01:04 Received resolution query response Resolution is now RES_2_7K ``` + {% endtab %} {% endlinkedTabs %} @@ -714,9 +867,3 @@ Congratulations 🤙 {% endsuccess %} You can now query any of the settings / statuses from the camera using one of the above patterns. - -If you have been following these tutorials in order, here is an extra 🥇🍾 **Congratulations** 🍰👍 because you have -completed all of the BLE tutorials. - -Next, to get started with WiFI (specifically to enable and connect to it), -proceed to the next tutorial. diff --git a/docs/_tutorials/tutorial_5_ble_protobuf/tutorial.md b/docs/_tutorials/tutorial_5_ble_protobuf/tutorial.md new file mode 100644 index 00000000..7443b66a --- /dev/null +++ b/docs/_tutorials/tutorial_5_ble_protobuf/tutorial.md @@ -0,0 +1,506 @@ +--- +permalink: '/tutorials/ble-protobuf' +sidebar: + nav: 'tutorials' +lesson: 5 +--- + +# Tutorial 5: BLE Protobuf Operations + +This document will provide a walk-through tutorial to use the Open GoPro Interface to send and receive BLE +[Protobuf]({{site.baseurl}}/ble/protocol/data_protocol.html#protobuf) Data. + +{% tip %} +Open GoPro uses [Protocol Buffers Version 2](https://protobuf.dev/reference/protobuf/proto2-spec/) +{% endtip %} + +A list of Protobuf Operations can be found in the +[Protobuf ID Table]({{site.baseurl}}/ble/protocol/id_tables.html#protobuf-ids). + +{% note %} +This tutorial only considers sending these as one-off operations. That is, it does not consider state +management / synchronization when sending multiple operations. This will be discussed in a future lab. +{% endnote %} + +# Requirements + +It is assumed that the hardware and software requirements from the +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}) are present and configured correctly. + +{% tip %} +It is suggested that you have first completed the +[connect]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#requirements), +[sending commands]({% link _tutorials/tutorial_2_send_ble_commands/tutorial.md %}), and +[parsing responses]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}) tutorials before going +through this tutorial. +{% endtip %} + +# Just Show me the Demo(s)!! + +{% linkedTabs demo %} +{% tab demo python %} +Each of the scripts for this tutorial can be found in the Tutorial 5 +[directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_2_send_ble_commands/). + +{% warning %} +Python >= 3.9 and < 3.12 must be used as specified in the requirements +{% endwarning %} + +{% accordion Protobuf Example %} + +You can see some basic Protobuf usage, independent of a BLE connection, in the following script: + +```console +$ python protobuf_example.py +``` + +{% endaccordion %} + +{% accordion Set Turbo Mode %} + +You can test sending Set Turbo Mode to your camera through BLE using the following script: + +```console +$ python set_turbo_mode.py +``` + +See the help for parameter definitions: + +```console +$ python set_turbo_mode.py --help +usage: set_turbo_mode.py [-h] [-i IDENTIFIER] + +Connect to a GoPro camera, send Set Turbo Mode and parse the response + +options: + -h, --help show this help message and exit + -i IDENTIFIER, --identifier IDENTIFIER + Last 4 digits of GoPro serial number, which is the last 4 digits of the default + camera SSID. If not used, first discovered GoPro will be connected to +``` + +{% endaccordion %} + +{% accordion Decipher Response Type %} + +TODO + +{% endaccordion %} + +{% endtab %} +{% tab demo kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +# Compiling Protobuf Files + +The Protobuf files used to compile source code for the Open GoPro Interface exist in the top-level +[protobuf](https://github.com/gopro/OpenGoPro/tree/main/protobuf) directory of the Open GoPro repository. + +It is mostly out of the scope of these tutorials to describe how to compile these since this process is clearly defined +in the per-language [Protobuf Tutorial](https://protobuf.dev/getting-started/). For the purposes of these tutorials +(and shared with the [Python SDK](https://gopro.github.io/OpenGoPro/python_sdk/)), the Protobuf files are compiled +using the Docker image defined in [.admin/proto_build](https://github.com/gopro/OpenGoPro/tree/main/.admin/proto_build). +This build process can be performed using `make protos` from the top level of this repo. + +{% note %} +This information is strictly explanatory. It is in no way necessary to (re)build the Protobuf files for these tutorials +as the pre-compiled Protobuf source code already resides in the same directory as this tutorial's example code. +{% endnote %} + +# Working with Protobuf Messages + +Let's first perform some basic serialization and deserialization of a Protobuf message. For this example, we are going +to use the [Set Turbo Transfer]({{site.baseurl}}/ble/features/control.html#set-turbo-transfer) operation: + +{% include figure image_path="/assets/images/tutorials/protobuf_doc.png" alt="protobuf_doc" size="40%" caption="Set Turbo Mode Documentation" %} + +Per the documentation, this operation's request payload should be serialized using the Protobuf message which can be found +either in [Documentation]({{site.baseurl}}/ble/protocol/protobuf.html#proto-requestsetturboactive): + +{% include figure image_path="/assets/images/tutorials/protobuf_message_doc.png" alt="protobuf_message_doc" size="40%" caption="RequestSetTurboActive documentation" %} + +or [source code](https://github.com/gopro/OpenGoPro/blob/main/protobuf/turbo_transfer.proto): + +```proto +/** + * Enable/disable display of "Transferring Media" UI + * + * Response: @ref ResponseGeneric + */ +message RequestSetTurboActive { + required bool active = 1; // Enable or disable Turbo Transfer feature +} +``` + +{% note %} +This code can be found in `protobuf_example.py` +{% endnote %} + +## Protobuf Message Example + +First let's instantiate the request message by setting the `active` parameter and log the serialized bytes: + +{% tip %} +Your IDE should show the Protobuf Message's API signature since type stubs were generated when compiling the Protobuf files. +{% endtip %} + +{% linkedTabs import %} +{% tab import python %} + +```python +from tutorial_modules import proto + +request = proto.RequestSetTurboActive(active=False) +logger.info(f"Sending ==> {request}") +logger.info(request.SerializeToString().hex(":")) +``` + +which will log as such: + +```console +Sending ==> active: false +08:00 +``` + +{% endtab %} +{% tab import kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +We're not going to analyze these bytes since it is the purpose of the Protobuf framework is to abstract this. However it is +important to be able to generate the serialized bytes from the instantiated Protobuf Message object in order to send +the bytes via BLE. + +Similarly, let's now create a serialized response and show how to deserialize it into a +[ResponseGeneric]({{site.baseurl}}/ble/protocol/protobuf.html#responsegeneric) object. + +{% linkedTabs import %} +{% tab import python %} + +```python +response_bytes = proto.ResponseGeneric(result=proto.EnumResultGeneric.RESULT_SUCCESS).SerializeToString() +logger.info(f"Received bytes ==> {response_bytes.hex(':')}") +response = proto.ResponseGeneric.FromString(response_bytes) +logger.info(f"Received ==> {response}") +``` + +which will log as such: + +```console +Received bytes ==> 08:01 +Received ==> result: RESULT_SUCCESS +``` + +{% endtab %} +{% tab import kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +{% note %} +We're not hard-coding serialized bytes here since it may not be constant across Protobuf versions +{% endnote %} + +# Performing a Protobuf Operation + +Now let's actually perform a Protobuf Operation via BLE. First we need to discuss additional non-Protobuf-defined +header bytes that are required for Protobuf Operations in the Open GoPro Interface. + +## Protobuf Packet Format + +Besides having a compressed payload as defined per the [Protobuf Specification](https://protobuf.dev/), Open GoPro +Protobuf operations also are identified by "Feature" and "Action" IDs. The top level message format (not including +the [standard headers]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}#accumulating-the-response)) +is as follows: + +| Feature ID | Action ID | Serialized Protobuf Payload | +| ---------- | --------- | --------------------------- | +| 1 Byte | 1 Byte | Variable Length | + +This Feature / Action ID pair is used to identify the Protobuf Message that should be used to serialize / deserialize +the payload. This mapping can be found in the +[Protobuf ID Table]({{site.baseurl}}/ble/protocol/id_tables.html#protobuf-ids). + +## Protobuf Response Parser + +Since the parsing of Protobuf messages is different than +TLV Parsing, we need to create a +`ProtobufResponse` class by extending the `Response` class from the +[TLV Parsing Tutorial]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}). This `ProtobufResponse` +`parse` method will: + +1. Extract Feature and Action ID's +2. Parse the Protobuf payload using the specified Protobuf Message + +{% linkedTabs import %} +{% tab import python %} + +{% note %} +This code can be found in `set_turbo_mode.py` +{% endnote %} + +```python +class ProtobufResponse(Response): + ... + + def parse(self, proto: type[ProtobufMessage]) -> None: + self.feature_id = self.raw_bytes[0] + self.action_id = self.raw_bytes[1] + self.data = proto.FromString(bytes(self.raw_bytes[2:])) +``` + +{% endtab %} +{% tab import kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +The accumulation process is the same for TLV and Protobuf responses so have not overridden the base `Response` class's +`accumulation` method and we are using the same notification handler as previous labs. + +## Set Turbo Transfer + +Now let's perform the [Set Turbo Transfer]({{site.baseurl}}/ble/features/control.html#set-turbo-transfer) operation and +receive the response. First, we build the serialized byte request in the same manner as +[above]({% link _tutorials/tutorial_5_ble_protobuf/tutorial.md %}#working-with-protobuf-messages)), then prepend the +Feature ID, Action ID, and length bytes: + +{% linkedTabs import %} +{% tab import python %} + +```python +turbo_mode_request = bytearray( + [ + 0xF1, # Feature ID + 0x6B, # Action ID + *proto.RequestSetTurboActive(active=False).SerializeToString(), + ] +) +turbo_mode_request.insert(0, len(turbo_mode_request)) +``` + +{% endtab %} +{% tab import kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +We then send the message, wait to receive the response, and parse the response using the Protobuf Message specified +from the Set Turbo Mode Documentation: [ResponseGeneric]({{site.baseurl}}/ble/protocol/protobuf.html#responsegeneric). + +{% linkedTabs import %} +{% tab import python %} + +```python +await client.write_gatt_char(request_uuid.value, turbo_mode_request, response=True) +response = await received_responses.get() +response.parse(proto.ResponseGeneric) +assert response.feature_id == 0xF1 +assert response.action_id == 0xEB +logger.info(response.data) +``` + +which will log as such: + +```console +Setting Turbo Mode Off +Writing 04:f1:6b:08:00 to GoProUuid.COMMAND_REQ_UUID +Received response at UUID GoProUuid.COMMAND_RSP_UUID: 04:f1:eb:08:01 +Set Turbo Mode response complete received. +Successfully set turbo mode +result: RESULT_SUCCESS +``` + +{% endtab %} +{% tab import kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +# Deciphering Response Type + +This same procedure is used for all [Protobuf Operations]({{site.baseurl}}/ble/protocol/id_tables.html#protobuf-ids). +Coupled with the information from previous tutorials, you are now capable of parsing any response received from the +GoPro. + +However we have not yet covered how to decipher the response type: Command, Query, Protobuf, etc. The algorithm to do +so is defined in the +[GoPro BLE Spec]({{site.baseurl}}/ble/protocol/data_protocol.html#decipher-message-payload-type) and reproduced here for reference: + +{% include figure image_path="/assets/images/plantuml_ble_tlv_vs_protobuf.png" alt="Message Deciphering" size="70%" caption="Message Deciphering Algorithm" %} + +## Response Manager + +We're now going to create a monolithic `ResponseManager` class to implement this algorithm to perform (at least initial) +parsing of all response types: + +{% linkedTabs import %} +{% tab import python %} + +{% note %} +The sample code below is taken from `decipher_response.py` +{% endnote %} + +The `ResponseManager` is a wrapper around a `BleakClient` to manage accumulating, parsing, and retrieving responses. + +First, let's create a non-initialized response manager, connect to get a `BleakClient` and initialize the manager by +setting the client: + +```python +manager = ResponseManager() +manager.set_client(await connect_ble(manager.notification_handler, identifier)) +``` + +Then, in the notification handler, we "decipher" the response before enqueueing it to the received response queue: + +```python +async def notification_handler(self, characteristic: BleakGATTCharacteristic, data: bytearray) -> None: + uuid = GoProUuid(self.client.services.characteristics[characteristic.handle].uuid) + logger.debug(f'Received response at {uuid}: {data.hex(":")}') + + response = self._responses_by_uuid[uuid] + response.accumulate(data) + + # Enqueue if we have received the entire response + if response.is_received: + await self._q.put(self.decipher_response(response)) + # Reset the accumulating response + self._responses_by_uuid[uuid] = Response(uuid) +``` + +where "deciphering" is the implementation of the above algorithm: + +```python +def decipher_response(self, undeciphered_response: Response) -> ConcreteResponse: + payload = undeciphered_response.raw_bytes + # Are the first two payload bytes a real Fetaure / Action ID pair? + if (index := ProtobufId(payload[0], payload[1])) in ProtobufIdToMessage: + if not (proto_message := ProtobufIdToMessage.get(index)): + # We've only added protobuf messages for operations used in this tutorial. + raise RuntimeError( + f"{index} is a valid Protobuf identifier but does not currently have a defined message." + ) + else: + # Now use the protobuf messaged identified by the Feature / Action ID pair to parse the remaining payload + response = ProtobufResponse.from_received_response(undeciphered_response) + response.parse(proto_message) + return response + # TLV. Should it be parsed as Command or Query? + if undeciphered_response.uuid is GoProUuid.QUERY_RSP_UUID: + # It's a TLV query + response = QueryResponse.from_received_response(undeciphered_response) + else: + # It's a TLV command / setting. + response = TlvResponse.from_received_response(undeciphered_response) + # Parse the TLV payload (query, command, or setting) + response.parse() + return response +``` + +{% warning %} +Only the minimal functionality needed for these tutorials have been added. For example, many Protobuf Feature / Action ID +pairs do not have corresponding Protobuf Messages defined. +{% endwarning %} + +{% endtab %} +{% tab import kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +After deciphering, the parsed method is placed in the response queue as a either a `TlvResponse`, `QueryResponse`, or +`ProtobufResponse`. + +## Examples of Each Response Type + +Now let's perform operations that will demonstrate each response type: + +{% linkedTabs import %} +{% tab import python %} + +```python +# TLV Command (Setting) +await set_resolution(manager) +# TLV Command +await get_resolution(manager) +# TLV Query +await set_shutter_off(manager) +# Protobuf +await set_turbo_mode(manager) +``` + +These four methods will perform the same functionality we've demonstrated in previous tutorials, now using our +`ResponseManager`. + +We'll walk through the `get_resolution` method here. First build the request and send it: + +```python +request = bytes([0x03, 0x02, 0x01, 0x09]) +request_uuid = GoProUuid.SETTINGS_REQ_UUID +await manager.client.write_gatt_char(request_uuid.value, request, response=True) +``` + +Then retrieve the response from the manager: + +```python +tlv_response = await manager.get_next_response_as_tlv() +logger.info(f"Set resolution status: {tlv_response.status}") +``` + +This logs as such: + +```console +Getting the current resolution +Writing to GoProUuid.QUERY_REQ_UUID: 02:12:02 +Received response at GoProUuid.QUERY_RSP_UUID: 05:12:00:02:01:09 +Received current resolution: Resolution.RES_1080 +``` + +Note that each example retrieves the parsed response from the manager via one of the following methods: + +- `get_next_response_as_tlv` +- `get_next_response_as_query` +- `get_next_response_as_response` + +{% tip %} +These are functionally the same as they just retrieve the next received response from the manager's queue and only +exist as helpers to simplify typing. +{% endtip %} + +{% endtab %} +{% tab import kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +# Troubleshooting + +See the first tutorial's +[troubleshooting section]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#troubleshooting). + +# Good Job! + +{% success %} +Congratulations 🤙 +{% endsuccess %} + +You can now accumulate, decipher, and parse any BLE response received from the GoPro. diff --git a/docs/_tutorials/tutorial_5_connect_wifi/tutorial.md b/docs/_tutorials/tutorial_5_connect_wifi/tutorial.md deleted file mode 100644 index ba37d08e..00000000 --- a/docs/_tutorials/tutorial_5_connect_wifi/tutorial.md +++ /dev/null @@ -1,370 +0,0 @@ ---- -permalink: '/tutorials/connect-wifi' -sidebar: - nav: 'tutorials' -lesson: 5 ---- - -# Tutorial 5: Connect WiFi - -This document will provide a walk-through tutorial to implement -the [Open GoPro Interface](/http) to enable the GoPro's WiFi Access Point (AP) so that it -can be connected to. It will also provide an example of connecting to the WiFi AP. - -{% tip %} -It is recommended that you have first completed the -[connecting]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}), -[sending commands]({% link _tutorials/tutorial_2_send_ble_commands/tutorial.md %}), and -[parsing responses]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}) tutorials before proceeding. -{% endtip %} - -# Requirements - -It is assumed that the hardware and software requirements from the -[connect tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#requirements) -are present and configured correctly. - -The scripts that will be used for this tutorial can be found in the -[Tutorial 5 Folder](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_5_connect_wifi). - -# Just Show me the Demo(s)!! - -{% linkedTabs demo %} -{% tab demo python %} -Each of the scripts for this tutorial can be found in the Tutorial 2 -[directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_5_connect_wifi/). - -{% warning %} -Python >= 3.8.x must be used as specified in the requirements -{% endwarning %} - -{% accordion Enable WiFi AP %} - -You can test querying the current Resolution on your camera through BLE using the following script: -```console -$ python wifi_enable.py -``` - -See the help for parameter definitions: - -```console -$ python wifi_enable.py --help -usage: wifi_enable.py [-h] [-i IDENTIFIER] [-t TIMEOUT] - -Connect to a GoPro camera via BLE, get WiFi info, and enable WiFi. - -optional arguments: - -h, --help show this help message and exit - -i IDENTIFIER, --identifier IDENTIFIER - Last 4 digits of GoPro serial number, which is the last 4 digits of the - default camera SSID. If not used, first discovered GoPro will be connected to - -t TIMEOUT, --timeout TIMEOUT - time in seconds to maintain connection before disconnecting. If not set, will - maintain connection indefinitely -``` -{% endaccordion %} - -{% endtab %} -{% tab demo kotlin %} -The Kotlin file for this tutorial can be found on -[Github](https://github.com/gopro/OpenGoPro/tree/main/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/tutorials/Tutorial5ConnectWifi.kt). - -To perform the tutorial, run the Android Studio project, select "Tutorial 5" from the dropdown and click on "Perform." -This requires that a GoPro is already connected via BLE, i.e. that Tutorial 1 was already run. You can -check the BLE status at the top of the app. - -{% include figure image_path="/assets/images/tutorials/kotlin/tutorial_5.png" alt="kotlin_tutorial_5" size="40%" caption="Perform Tutorial 5" %} - -This will start the tutorial and log to the screen as it executes. When the tutorial is complete, click -"Exit Tutorial" to return to the Tutorial selection screen. - -{% endtab %} -{% endlinkedTabs %} - -# Setup - -We must first connect to BLE as was discussed in the -[connect tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}). We are also -using the same notification handler as was used in the -[sending commands tutorial]({% link _tutorials/tutorial_2_send_ble_commands/tutorial.md %}#setup) - -# Connecting to WiFi AP - -Now that we are connected via BLE, paired, and have enabled notifications, we can send the command to enable -the WiFi AP. - -Here is an outline of the steps to do so: - -```mermaid! -sequenceDiagram - participant PC as Open GoPro user device - participant GoProBLE - participant GoProWiFi - loop Steps from Connect Tutorial - GoProBLE-->>PC: Advertising - GoProBLE-->>PC: Advertising - note over PC: Scanning - PC->>GoProBLE: Connect - note over GoProBLE, PC: Connected - alt If not Previously Paired - PC ->> GoProBLE: Pair Request - GoProBLE ->> PC: Pair Response - else - - end - note over GoProBLE, PC: Paired - PC ->> GoProBLE: Enable Notifications on Characteristic 1 - PC ->> GoProBLE: Enable Notifications on Characteristic 2 - PC ->> GoProBLE: Enable Notifications on Characteristic .. - PC ->> GoProBLE: Enable Notifications on Characteristic N - note over GoProBLE, PC: Ready to Communicate - end - PC ->> GoProBLE: Read Wifi AP SSID - PC ->> GoProBLE: Read Wifi AP Password - PC ->> GoProBLE: Write to Enable WiFi AP - GoProBLE ->> PC: Response sent as notification - note over GoProWiFi: WiFi AP enabled - PC ->> GoProWiFi: Connect to WiFi AP -``` - -Essentially we will be finding the WiFi AP information (SSID and password) via BLE, enabling the WiFi AP via -BLE, then connecting to the WiFi AP. - -## Find WiFi Information - -Note that the process to get this information is different than all procedures described up to this point. -Whereas the previous command, setting, and query procedures all followed the Write Request-Notification -Response pattern, the WiFi Information is retrieved via direct Read Requests to BLE characteristics. - -### Get WiFi SSID - -The WiFi SSID can be found by reading from the WiFi AP SSID -[characteristic](/ble/index.html#services-and-characteristics) of the -WiFi Access Point service. - -First, let's send the read request to get the SSID (and decode it into a string). - -{% linkedTabs get_ssid %} -{% tab get_ssid python %} -Let's define the attribute to read from: - -```python -WIFI_AP_SSID_UUID = GOPRO_BASE_UUID.format("0002") -``` - -Then send the BLE read request: - -```python -ssid = await client.read_gatt_char(WIFI_AP_SSID_UUID) -ssid = ssid.decode() -``` - -{% tip %} -There is no need for a synchronization event as the information is available when the `read_gatt_char` method -returns. -{% endtip %} - -In the demo, this information is logged as such: - -```console -INFO:root:Reading the WiFi AP SSID -INFO:root:SSID is GP24500456 -``` -{% endtab %} -{% tab get_ssid kotlin %} -```kotlin -ble.readCharacteristic(goproAddress, GoProUUID.WIFI_AP_SSID.uuid).onSuccess { ssid = it.decodeToString() } -Timber.i("SSID is $ssid") -``` - -In the demo, this information is logged as such: - -```console -Getting the SSID -Read characteristic b5f90002-aa8d-11e3-9046-0002a5d5c51b : value: 64:65:62:75:67:68:65:72:6F:31:31 -SSID is debughero11 -``` -{% endtab %} -{% endlinkedTabs %} - -### Get WiFi Password - -The WiFi password can be found by reading from the WiFi AP password -[characteristic](/ble/index.html#services-and-characteristics) of the -WiFi Access Point service. - -First, let's send the read request to get the password (and decode it into a string). - -{% linkedTabs get_password %} -{% tab get_password python %} -Let's define the attribute to read from: - -```python -WIFI_AP_PASSWORD_UUID = GOPRO_BASE_UUID.format("0003") -``` -Then send the BLE read request: - -{% tip %} -There is no need for a synchronization event as the information is available when the `read_gatt_char` method -returns. -{% endtip %} - -In the demo, this information is logged as such: - -```console -INFO:root:Reading the WiFi AP password -INFO:root:Password is g@6-Tj9-C7K -``` -{% endtab %} -{% tab get_password kotlin %} -```kotlin -ble.readCharacteristic(goproAddress, GoProUUID.WIFI_AP_PASSWORD.uuid).onSuccess { password = it.decodeToString() } -Timber.i("Password is $password") -``` - -In the demo, this information is logged as such: - -```console -Getting the password -Read characteristic b5f90003-aa8d-11e3-9046-0002a5d5c51b : value: 7A:33:79:2D:44:43:58:2D:50:68:6A -Password is z3y-DCX-Phj -``` -{% endtab %} -{% endlinkedTabs %} - -## Enable WiFi AP - -Before we can connect to the WiFi AP, we have to make sure it is enabled. This is accomplished by using the -"AP Control" [command](/ble/index.html#commands-quick-reference): - -| Command | Bytes | -| ------------------ | :-----------------: | -| Ap Control Enable | 0x03 0x17 0x01 0x01 | -| Ap Control Disable | 0x03 0x17 0x01 0x00 | - -This is done in the same manner that we did in the -[sending commands tutorial]({% link _tutorials/tutorial_2_send_ble_commands/tutorial.md %}). - -Now, let's write the bytes to the "Command Request UUID" to enable the WiFi AP! - -{% linkedTabs enable_ap_send %} -{% tab enable_ap_send python %} -```python -event.clear() -await client.write_gatt_char(COMMAND_REQ_UUID, bytearray([0x03, 0x17, 0x01, 0x01])) -await event.wait() # Wait to receive the notification response -``` - -{% success %} -We make sure to clear the synchronization event before writing, then pend on the event until it is set in -the notification callback. -{% endsuccess %} -{% endtab %} -{% tab enable_ap_send kotlin %} -```kotlin -val enableWifiCommand = ubyteArrayOf(0x03U, 0x17U, 0x01U, 0x01U) -ble.writeCharacteristic(goproAddress, GoProUUID.CQ_COMMAND.uuid, enableWifiCommand) -receivedData.receive() -``` -{% endtab %} -{% endlinkedTabs %} - -Note that we have received the "Command Status" notification response from the -Command Response characteristic since we enabled it's notifications in -[Enable Notifications]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#enable-notifications). This can -be seen in the demo log: - -{% linkedTabs enable_ap_print %} -{% tab enable_ap_print python %} -```console -INFO:root:Enabling the WiFi AP -INFO:root:Received response at handle=52: b'02:17:00' -INFO:root:Command sent successfully -INFO:root:WiFi AP is enabled -``` -{% endtab %} -{% tab enable_ap_print kotlin %} -```console -Enabling the camera's Wifi AP -Writing characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b ==> 03:17:01:01 -Wrote characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b -Characteristic b5f90073-aa8d-11e3-9046-0002a5d5c51b changed | value: 02:17:00 -Received response on b5f90073-aa8d-11e3-9046-0002a5d5c51b: 02:17:00 -Command sent successfully -``` -{% endtab %} -{% endlinkedTabs %} - -As expected, the response was received on the correct handle and the status was "success". - -## Establish Connection to WiFi AP - -{% linkedTabs connect_wifi %} -{% tab connect_wifi python %} -If you have been following through the `ble_enable_wifi.py` script, you will notice that it ends here such that -we know the WiFi SSID and password and the WiFi AP is enabled and ready to connect to. This is because there -are many different methods of connecting to the WiFi AP depending on your OS and the framework you are -using to develop. You could, for example, simply use your OS's WiFi GUI to connect. - -{% tip %} -While out of the scope of these tutorials, there is a programmatic example of this in the cross-platform -`WiFi Demo` from the [Open GoPro Python SDK](https://gopro.github.io/OpenGoPro/python_sdk/quickstart.html#wifi-demo). -{% endtip %} - -{% endtab %} -{% tab connect_wifi kotlin %} -Using the passwsord and SSID we discovered above, we will now connect to the camera's network: - -```kotlin -wifi.connect(ssid, password) -``` - -This should show a system popup on your Android device that eventually goes away once the Wifi is -connected. - -{% note %} -This connection process appears to vary drastically in time. -{% endnote %} -{% endtab %} -{% endlinkedTabs %} - -**Quiz time! 📚 ✏️** - -{% quiz - question="How is the WiFi password response received?" - option="A:::As a read response from the WiFi AP Password characteristic" - option="B:::As write responses to the WiFi Request characteristic" - option="C:::As notifications of the Command Response characteristic" - correct="A" - info="This (and WiFi AP SSID) is an exception to the rule. Usually responses - are received as notifications to a response characteristic. However, in this case, it is - received as a direct read response (since we are reading from the characteristic and not - writing to it)." -%} - -{% quiz - question="Which of the following statements about the GoPro WiFi AP is true?" - option="A:::It only needs to be enabled once and it will then always remain on" - option="B:::The WiFi password will never change" - option="C:::The WiFi SSID will never change" - option="D:::None of the Above" - correct="D" - info="While the WiFi AP will remain on for some time, it can and will eventually turn off so - it is always recommended to first connect via BLE and ensure that it is enabled. The password - and SSID will almost never change. However, they will change if the connections are reset via - Connections->Reset Connections." -%} - -# Troubleshooting - -See the first tutorial's -[troubleshooting section]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#troubleshooting). - -# Good Job! - -{% success %} -Congratulations 🤙 -{% endsuccess %} - -You are now connected to the GoPro's Wifi AP and can send any of the HTTP commands defined in the -[Open GoPro Interface](/http). Proceed to the next tutorial. diff --git a/docs/_tutorials/tutorial_6_connect_wifi/tutorial.md b/docs/_tutorials/tutorial_6_connect_wifi/tutorial.md new file mode 100644 index 00000000..02b1c271 --- /dev/null +++ b/docs/_tutorials/tutorial_6_connect_wifi/tutorial.md @@ -0,0 +1,765 @@ +--- +permalink: '/tutorials/connect-wifi' +sidebar: + nav: 'tutorials' +lesson: 6 +--- + +# Tutorial 6: Connect WiFi + +This document will provide a walk-through tutorial to use the Open GoPro Interface to connect the GoPro to a Wifi +network either in Access Point (AP) mode or Station (STA) Mode. + +{% tip %} +It is recommended that you have first completed the +[connecting BLE]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}), +[sending commands]({% link _tutorials/tutorial_2_send_ble_commands/tutorial.md %}), +[parsing responses]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}), and +[protobuf]({% link _tutorials/tutorial_5_ble_protobuf/tutorial.md %}) tutorials before proceeding. +{% endtip %} + +# Requirements + +It is assumed that the hardware and software requirements from the +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#requirements) +are present and configured correctly. + +The scripts that will be used for this tutorial can be found in the +[Tutorial 6 Folder](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi). + +# Just Show me the Demo(s)!! + +{% linkedTabs demo %} +{% tab demo python %} +Each of the scripts for this tutorial can be found in the Tutorial 6 +[directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi/). + +{% warning %} +Python >= 3.9 and < 3.12 must be used as specified in the requirements +{% endwarning %} + +{% accordion Enable WiFi AP %} + +You can enable the GoPro's Access Point to allow it accept Wifi connections as an Access Point via: + +```console +$ python wifi_enable.py +``` + +See the help for parameter definitions: + +```console +$ python wifi_enable.py --help +usage: enable_wifi_ap.py [-h] [-i IDENTIFIER] [-t TIMEOUT] + +Connect to a GoPro camera via BLE, get its WiFi Access Point (AP) info, and enable its AP. + +options: + -h, --help show this help message and exit + -i IDENTIFIER, --identifier IDENTIFIER + Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. If not used, first + discovered GoPro will be connected to + -t TIMEOUT, --timeout TIMEOUT + time in seconds to maintain connection before disconnecting. If not set, will maintain connection indefinitely +``` + +{% endaccordion %} + +{% accordion Connect GoPro as STA %} + +You can connect the GoPro to a Wifi network where the GoPro is in Station Mode (STA) via: + +```console +$ python connect_as_sta.py +``` + +See the help for parameter definitions: + +```console +$ python connect_as_sta.py --help +Connect the GoPro to a Wifi network where the GoPro is in Station Mode (STA). + +positional arguments: + ssid SSID of network to connect to + password Password of network to connect to + +options: + -h, --help show this help message and exit + -i IDENTIFIER, --identifier IDENTIFIER + Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera SSID. + If not used, first discovered GoPro will be connected to +``` + +{% endaccordion %} + +{% endtab %} +{% tab demo kotlin %} +The Kotlin file for this tutorial can be found on +[Github](https://github.com/gopro/OpenGoPro/tree/main/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/tutorials/Tutorial5ConnectWifi.kt). + +To perform the tutorial, run the Android Studio project, select "Tutorial 6" from the dropdown and click on "Perform." +This requires that a GoPro is already connected via BLE, i.e. that Tutorial 1 was already run. You can +check the BLE status at the top of the app. + +{% include figure image_path="/assets/images/tutorials/kotlin/tutorial_5.png" alt="kotlin_connect_wifi" size="40%" caption="Perform Tutorial 6" %} + +This will start the tutorial and log to the screen as it executes. When the tutorial is complete, click +"Exit Tutorial" to return to the Tutorial selection screen. + +{% endtab %} +{% endlinkedTabs %} + +# Setup + +For both cases, we must first connect to BLE as was discussed in the +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}). + +# Access Point Mode (AP) + +In AP mode, the GoPro operates as an Access Point, allowing wireless clients to connect and communicate using the +Open GoPro [HTTP API]({{site.baseurl}}/http). The HTTP API provides much of the same functionality as the BLE API as +well as some additional functionality. For more information on the HTTP API, see the next 2 tutorials. + +```plantuml! +left to right direction +rectangle AccessPoint { + frame GoPro as gopro +} +component client +gopro <--[dashed]--> client: BLE +gopro <----> client: WiFi +``` + +In order to connect to the camera in AP mode, after connecting via BLE, pairing, and enabling notifications, we must: + +- find the GoPro's WiFi AP information (SSID and password) via BLE, +- enable the WiFi AP via BLE +- connect to the WiFi AP. + +Here is an outline of the steps to do so: + +```mermaid! +sequenceDiagram + participant PC as Open GoPro user device + participant GoProBLE + participant GoProWiFi + loop Steps from Connect Tutorial + GoProBLE-->>PC: Advertising + GoProBLE-->>PC: Advertising + note over PC: Scanning + PC->>GoProBLE: Connect + note over GoProBLE, PC: Connected + alt If not Previously Paired + PC ->> GoProBLE: Pair Request + GoProBLE ->> PC: Pair Response + else + + end + note over GoProBLE, PC: Paired + PC ->> GoProBLE: Enable Notifications on Characteristic 1 + PC ->> GoProBLE: Enable Notifications on Characteristic 2 + PC ->> GoProBLE: Enable Notifications on Characteristic .. + PC ->> GoProBLE: Enable Notifications on Characteristic N + note over GoProBLE, PC: Ready to Communicate + end + PC ->> GoProBLE: Read Wifi AP SSID + PC ->> GoProBLE: Read Wifi AP Password + PC ->> GoProBLE: Write to Enable WiFi AP + GoProBLE ->> PC: Response sent as notification + note over GoProWiFi: WiFi AP enabled + PC ->> GoProWiFi: Connect to WiFi AP +``` + +The following subsections will detail this process. + +## Find WiFi Information + +First we must find the target Wifi network's SSID and password. + +{% note %} +The process to get this information is different than all other BLE operations described up to this point. +Whereas the previous command, setting, and query operations all followed the Write Request-Notification +Response pattern, the WiFi Information is retrieved via direct Read Requests to BLE characteristics. +{% endnote %} + +### Get WiFi SSID + +The WiFi SSID can be found by reading from the WiFi AP SSID +[characteristic]({{site.baseurl}}/ble/protocol/ble_setup.html#ble-characteristics) of the +WiFi Access Point service. + +Let's send the read request to get the SSID and decode it into a string. + +{% linkedTabs get_ssid %} +{% tab get_ssid python %} + +```python +ssid_uuid = GoProUuid.WIFI_AP_SSID_UUID +logger.info(f"Reading the WiFi AP SSID at {ssid_uuid}") +ssid = (await client.read_gatt_char(ssid_uuid.value)).decode() +logger.info(f"SSID is {ssid}") +``` + +{% tip %} +There is no need for a synchronization event as the information is available when the `read_gatt_char` method +returns. +{% endtip %} + +In the demo, this information is logged as such: + +```console +Reading the WiFi AP SSID at GoProUuid.WIFI_AP_SSID_UUID +SSID is GP24500702 +``` + +{% endtab %} +{% tab get_ssid kotlin %} + +```kotlin +ble.readCharacteristic(goproAddress, GoProUUID.WIFI_AP_SSID.uuid).onSuccess { ssid = it.decodeToString() } +Timber.i("SSID is $ssid") +``` + +In the demo, this information is logged as such: + +```console +Getting the SSID +Read characteristic b5f90002-aa8d-11e3-9046-0002a5d5c51b : value: 64:65:62:75:67:68:65:72:6F:31:31 +SSID is debughero11 +``` + +{% endtab %} +{% endlinkedTabs %} + +### Get WiFi Password + +The WiFi password can be found by reading from the WiFi AP password +[characteristic]({{site.baseurl}}/ble/protocol/ble_setup.html#ble-characteristics) of the +WiFi Access Point service. + +Let's send the read request to get the password and decode it into a string. + +{% linkedTabs get_password %} +{% tab get_password python %} + +```python +password_uuid = GoProUuid.WIFI_AP_PASSWORD_UUID +logger.info(f"Reading the WiFi AP password at {password_uuid}") +password = (await client.read_gatt_char(password_uuid.value)).decode() +logger.info(f"Password is {password}") +``` + +{% tip %} +There is no need for a synchronization event as the information is available when the `read_gatt_char` method +returns. +{% endtip %} + +In the demo, this information is logged as such: + +```console +Reading the WiFi AP password at GoProUuid.WIFI_AP_PASSWORD_UUID +Password is p@d-NNc-2ts +``` + +{% endtab %} +{% tab get_password kotlin %} + +```kotlin +ble.readCharacteristic(goproAddress, GoProUUID.WIFI_AP_PASSWORD.uuid).onSuccess { password = it.decodeToString() } +Timber.i("Password is $password") +``` + +In the demo, this information is logged as such: + +```console +Getting the password +Read characteristic b5f90003-aa8d-11e3-9046-0002a5d5c51b : value: 7A:33:79:2D:44:43:58:2D:50:68:6A +Password is z3y-DCX-Phj +``` + +{% endtab %} +{% endlinkedTabs %} + +## Enable WiFi AP + +Before we can connect to the WiFi AP, we have to make sure the access point is enabled. This is accomplished via the +[AP Control command]({{site.baseurl}}/ble/features/control.html#set-ap-control): + +| Command | Bytes | +| ------------------ | :-----------------: | +| Ap Control Enable | 0x03 0x17 0x01 0x01 | +| Ap Control Disable | 0x03 0x17 0x01 0x00 | + +{% tip %} +We are using the same notification handler that was defined in the +[sending commands tutorial]({% link _tutorials/tutorial_2_send_ble_commands/tutorial.md %}#setup). +{% endtip %} + +Let's write the bytes to the "Command Request UUID" to enable the WiFi AP! + +{% linkedTabs enable_ap_send %} +{% tab enable_ap_send python %} + +```python +event.clear() +request = bytes([0x03, 0x17, 0x01, 0x01]) +command_request_uuid = GoProUuid.COMMAND_REQ_UUID +await client.write_gatt_char(command_request_uuid.value, request, response=True) +await event.wait() # Wait to receive the notification response +``` + +{% success %} +We make sure to clear the synchronization event before writing, then pend on the event until it is set in +the notification callback. +{% endsuccess %} +{% endtab %} +{% tab enable_ap_send kotlin %} + +```kotlin +val enableWifiCommand = ubyteArrayOf(0x03U, 0x17U, 0x01U, 0x01U) +ble.writeCharacteristic(goproAddress, GoProUUID.CQ_COMMAND.uuid, enableWifiCommand) +receivedData.receive() +``` + +{% endtab %} +{% endlinkedTabs %} + +Note that we have received the "Command Status" notification response from the +Command Response characteristic since we enabled it's notifications in +[Enable Notifications]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#enable-notifications). This can +be seen in the demo log: + +{% linkedTabs enable_ap_print %} +{% tab enable_ap_print python %} + +```console +Enabling the WiFi AP +Writing to GoProUuid.COMMAND_REQ_UUID: 03:17:01:01 +Received response at GoProUuid.COMMAND_RSP_UUID: 02:17:00 +Command sent successfully +WiFi AP is enabled +``` + +{% endtab %} +{% tab enable_ap_print kotlin %} + +```console +Enabling the camera's Wifi AP +Writing characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b ==> 03:17:01:01 +Wrote characteristic b5f90072-aa8d-11e3-9046-0002a5d5c51b +Characteristic b5f90073-aa8d-11e3-9046-0002a5d5c51b changed | value: 02:17:00 +Received response on b5f90073-aa8d-11e3-9046-0002a5d5c51b: 02:17:00 +Command sent successfully +``` + +{% endtab %} +{% endlinkedTabs %} + +As expected, the response was received on the correct UUID and the status was "success". + +## Establish Connection to WiFi AP + +{% linkedTabs connect_wifi %} +{% tab connect_wifi python %} +If you have been following through the `ble_enable_wifi.py` script, you will notice that it ends here such that +we know the WiFi SSID / password and the WiFi AP is enabled. This is because there +are many different methods of connecting to the WiFi AP depending on your OS and the framework you are +using to develop. You could, for example, simply use your OS's WiFi GUI to connect. + +{% tip %} +While out of the scope of these tutorials, there is a programmatic example of this in the cross-platform +`WiFi Demo` from the [Open GoPro Python SDK](https://gopro.github.io/OpenGoPro/python_sdk/quickstart.html#wifi-demo). +{% endtip %} + +{% endtab %} +{% tab connect_wifi kotlin %} +Using the passwsord and SSID we discovered above, we will now connect to the camera's network: + +```kotlin +wifi.connect(ssid, password) +``` + +This should show a system popup on your Android device that eventually goes away once the Wifi is +connected. + +{% warning %} +This connection process appears to vary drastically in time. +{% endwarning %} +{% endtab %} +{% endlinkedTabs %} + +**Quiz time! 📚 ✏️** + +{% quiz + question="How is the WiFi password response received?" + option="A:::As a read response from the WiFi AP Password characteristic" + option="B:::As write responses to the WiFi Request characteristic" + option="C:::As notifications of the Command Response characteristic" + correct="A" + info="This (and WiFi AP SSID) is an exception to the rule. Usually responses + are received as notifications to a response characteristic. However, in this case, it is + received as a direct read response (since we are reading from the characteristic and not + writing to it)." +%} + +{% quiz + question="Which of the following statements about the GoPro WiFi AP is true?" + option="A:::It only needs to be enabled once and it will then always remain on" + option="B:::The WiFi password will never change" + option="C:::The WiFi SSID will never change" + option="D:::None of the Above" + correct="D" + info="While the WiFi AP will remain on for some time, it can and will eventually turn off so + it is always recommended to first connect via BLE and ensure that it is enabled. The password + and SSID will almost never change. However, they will change if the connections are reset via + Connections->Reset Connections." +%} + +You are now connected to the GoPro's Wifi AP and can send any of the HTTP commands defined in the +[HTTP Specification]({{site.baseurl}}/http). + +# Station (STA) Mode + +Station Mode is where the GoPro operates as a [Station](), allowing +the camera to connect to and communicate with an Access Point such as a switch or a router. This is used, for example, +in the livestreaming and [camera on the home network]({% link _tutorials/tutorial_9_cohn/tutorial.md %}) (COHN) features. + +```plantuml! +left to right direction +rectangle Station { + frame GoPro as gopro +} +component client +rectangle AccessPoint { + component router +} +gopro <--[dashed]--> client: BLE +gopro <----> router: Wifi +``` + +{% tip %} +When the GoPro is in Station Mode, there is no HTTP communication channel to the Open GoPro client. The GoPro can still +be controlled via BLE. +{% endtip %} + +In order to configure the GoPro in Station mode, after connecting via BLE, pairing, and enabling notifications, we must: + +- scan for available networks +- connect to a discovered network, using the correct API based on whether or not we have previously connected to this + network + +The following subsections will detail these steps. All of the Protobuf operations are performed in the same manner as +in the [protobuf tutorial]({% link _tutorials/tutorial_5_ble_protobuf/tutorial.md %}) such as reusing the `ResponseManager`. + +## Scan for Networks + +{% warning %} +It is always necessary to scan for networks, regardless of whether you already have a network's information and know it +is available. Failure to do so follows an untested and unsupported path in the GoPro's connection state machine. +{% endwarning %} + +The process of scanning for networks requires several Protobuf Operations as summarized here: + +{% include figure image_path="/assets/images/plantuml_ble_scan_for_ssids.png" alt="scan_for_ssids" size="70%" caption="Scan For Networks" %} + +First we must request the GoPro to +[Scan For Access Points]({{site.baseurl}}/ble/features/access_points.html#scan-for-access-points): + +{% linkedTabs scan_for_networks %} +{% tab scan_for_networks python %} + +{% note %} +The code here is taken from `connect_as_sta.py` +{% endnote %} + +Let's send the [scan request]({{site.baseurl}}/ble/protocol/protobuf.html#requeststartscan) and then retrieve and parse +[notifications]({{site.baseurl}}/ble/protocol/protobuf.html#notifstartscanning) until we receive a notification where the +`scanning_state` is set to [SCANNING_SUCCESS]({{site.baseurl}}/ble/protocol/protobuf.html#enumscanning). +Then we store the `scan id` from the notification for later use in retrieving the scan results. + +```python +start_scan_request = bytearray( + [ + 0x02, # Feature ID + 0x02, # Action ID + *proto.RequestStartScan().SerializePartialToString(), + ] +) +start_scan_request.insert(0, len(start_scan_request)) +await manager.client.write_gatt_char(GoProUuid.NETWORK_MANAGEMENT_REQ_UUID.value, start_scan_request, response=True) +while response := await manager.get_next_response_as_protobuf(): + ... + elif response.action_id == 0x0B: # Scan Notifications + scan_notification: proto.NotifStartScanning = response.data # type: ignore + logger.info(f"Received scan notification: {scan_notification}") + if scan_notification.scanning_state == proto.EnumScanning.SCANNING_SUCCESS: + return scan_notification.scan_id +``` + +This will log as such: + +```console +Scanning for available Wifi Networks +Writing: 02:02:02 +Received response at GoProUuid.NETWORK_MANAGEMENT_RSP_UUID: 06:02:82:08:01:10:02 +Received response at GoProUuid.NETWORK_MANAGEMENT_RSP_UUID: 0a:02:0b:08:05:10:01:18:05:20:01 +Received scan notification: scanning_state: SCANNING_SUCCESS + scan_id: 1 + total_entries: 5 + total_configured_ssid: 1 +``` + +{% endtab %} +{% tab scan_for_networks kotlin %} +TODO +{% endtab %} +{% endlinkedTabs %} + +Next we must request the GoPro to +[return the Scan Results]({{site.baseurl}}/ble/features/access_points.html#get-ap-scan-results). +Using the `scan_id` from above, let's send the +[Get AP Scan Results]({{site.baseurl}}/ble/features/access_points.html#get-ap-scan-results) request, then +retrieve and parse the response: + +{% linkedTabs scan_for_networks %} +{% tab scan_for_networks python %} + +```python +results_request = bytearray( + [ + 0x02, # Feature ID + 0x03, # Action ID + *proto.RequestGetApEntries(start_index=0, max_entries=100, scan_id=scan_id).SerializePartialToString(), + ] +) +results_request.insert(0, len(results_request)) +await manager.client.write_gatt_char(GoProUuid.NETWORK_MANAGEMENT_REQ_UUID.value, results_request, response=True) +response := await manager.get_next_response_as_protobuf(): +entries_response: proto.ResponseGetApEntries = response.data # type: ignore +logger.info("Found the following networks:") +for entry in entries_response.entries: + logger.info(str(entry)) +return list(entries_response.entries) +``` + +This will log as such: + +```console +Getting the scanned networks. +Writing: 08:02:03:08:00:10:64:18:01 +Received response at GoProUuid.NETWORK_MANAGEMENT_RSP_UUID: 20:76:02:83:08:01:10:01:1a:13:0a:0a:64:61:62:75:67:64:61:62 +Received response at GoProUuid.NETWORK_MANAGEMENT_RSP_UUID: 80:75:67:10:03:20:e4:28:28:2f:1a:13:0a:0a:41:54:54:54:70:34 +Received response at GoProUuid.NETWORK_MANAGEMENT_RSP_UUID: 81:72:36:46:69:10:02:20:f1:2c:28:01:1a:13:0a:0a:41:54:54:62 +Received response at GoProUuid.NETWORK_MANAGEMENT_RSP_UUID: 82:37:4a:67:41:77:61:10:02:20:99:2d:28:01:1a:16:0a:0d:52:69 +Received response at GoProUuid.NETWORK_MANAGEMENT_RSP_UUID: 83:6e:67:20:53:65:74:75:70:20:65:37:10:01:20:ec:12:28:00:1a +Received response at GoProUuid.NETWORK_MANAGEMENT_RSP_UUID: 84:17:0a:0e:48:6f:6d:65:79:6e:65:74:5f:32:47:45:58:54:10:01 +Received response at GoProUuid.NETWORK_MANAGEMENT_RSP_UUID: 85:20:85:13:28:01 +Found the following networks: + ssid: "dabugdabug" + signal_strength_bars: 3 + signal_frequency_mhz: 5220 + scan_entry_flags: 47 + ssid: "ATTTp4r6Fi" + signal_strength_bars: 2 + signal_frequency_mhz: 5745 + scan_entry_flags: 1 + ssid: "ATTb7JgAwa" + signal_strength_bars: 2 + signal_frequency_mhz: 5785 + scan_entry_flags: 1 + ssid: "Ring Setup e7" + signal_strength_bars: 1 + signal_frequency_mhz: 2412 + scan_entry_flags: 0 + ssid: "Homeynet_2GEXT" + signal_strength_bars: 1 + signal_frequency_mhz: 2437 + scan_entry_flags: 1 +``` + +{% endtab %} +{% tab scan_for_networks kotlin %} +TODO +{% endtab %} +{% endlinkedTabs %} + +At this point we have all of the discovered networks. Continue on to see how to use this information. + +## Connect to Network + +Depending on whether the GoPro has already connected to the desired network, we must next perform either the +[Connect]({{site.baseurl}}/ble/features/access_points.html#connect-to-provisioned-access-point) or +[Connect New]({{site.baseurl}}/ble/features/access_points.html#connect-to-a-new-access-point) operation. +This will be described below but first, a note on fragmentation: + +### GATT Write Fragmentation + +Up to this point in the tutorials, all of the operations we have been performing have resulted in GATT write requests +guaranteed to be less than maximum BLE packet size of 20 bytes. However, depending on the SSID and password used in +the Connect New operation, this maximum size might be surpassed. Therefore, it is necessary to fragment the payload. This +is essentially the inverse of the +[accumulation algorithm]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}#parsing-multiple-packet-tlv-responses). +We accomplish this as follows: + +{% linkedTabs fragment %} +{% tab fragment python %} + +Let's create a generator to yield fragmented packets (`yield_fragmented_packets`) from a monolithic payload. First, +depending on the length of the payload, we create the +[header]({{site.baseurl}}/ble/protocol/data_protocol.html#packet-headers) for the first packet that specifies the +total payload length: + +```python +if length < (2**5 - 1): + header = bytearray([length]) +elif length < (2**13 - 1): + header = bytearray((length | 0x2000).to_bytes(2, "big", signed=False)) +elif length < (2**16 - 1): + header = bytearray((length | 0x6400).to_bytes(2, "big", signed=False)) +``` + +Then we chunk through the payload, prepending either the above header for the first packet or the continuation header +for subsequent packets: + +```python +byte_index = 0 +while bytes_remaining := length - byte_index: + # If this is the first packet, use the appropriate header. Else use the continuation header + if is_first_packet: + packet = bytearray(header) + is_first_packet = False + else: + packet = bytearray(CONTINUATION_HEADER) + # Build the current packet + packet_size = min(MAX_PACKET_SIZE - len(packet), bytes_remaining) + packet.extend(bytearray(payload[byte_index : byte_index + packet_size])) + yield bytes(packet) + # Increment byte_index for continued processing + byte_index += packet_size +``` + +Finally we create a helper method that we can reuse throughout the tutorials to use this generator to send GATT Writes +using a given Bleak client: + +```python +async def fragment_and_write_gatt_char(client: BleakClient, char_specifier: str, data: bytes): + for packet in yield_fragmented_packets(data): + await client.write_gatt_char(char_specifier, packet, response=True) +``` + +{% endtab %} + +{% tab fragment kotlin %} +TODO +{% endtab %} +{% endlinkedTabs %} + +{% tip %} +The safest solution would be to always use the above fragmentation method. For the sake of simplicity in these tutorials, +we are only using this where there is a possibility of exceeding the maximum BLE packet size. +{% endtip %} + +### Connect Example + +In order to proceed, we must first inspect the scan result gathered from the previous section to see which +connect operation to use. Specifically we are checking the +[scan_entry_flags]({{site.baseurl}}/ble/protocol/protobuf.html#responsegetapentries-scanentry) to see if the +[SCAN_FLAG_CONFIGURED]({{site.baseurl}}/ble/protocol/protobuf.html#proto-enumscanentryflags) bit is set. If the +bit is set (and thus we have already provisioned this network) then we must use +[Connect]({{site.baseurl}}/ble/features/access_points.html#connect-to-provisioned-access-point) . Otherwise we must use +[Connect New]({{site.baseurl}}/ble/features/access_points.html#connect-to-a-new-access-point): + +{% linkedTabs inspect_scan_result %} +{% tab inspect_scan_result python %} + +```python +if entry.scan_entry_flags & proto.EnumScanEntryFlags.SCAN_FLAG_CONFIGURED: + connect_request = bytearray( + [ + 0x02, # Feature ID + 0x04, # Action ID + *proto.RequestConnect(ssid=entry.ssid).SerializePartialToString(), + ] + ) +else: + connect_request = bytearray( + [ + 0x02, # Feature ID + 0x05, # Action ID + *proto.RequestConnectNew(ssid=entry.ssid, password=password).SerializePartialToString(), + ] + ) +``` + +{% endtab %} +{% tab inspect_scan_result kotlin %} +TODO +{% endtab %} +{% endlinkedTabs %} + +Now that we have the correct request built, we can send it (using our newly created fragmentation method) we can send it. +Then we will continuously receive +[Provisioning Notifications]({{site.baseurl}}/ble/protocol/protobuf.html#notifprovisioningstate) which should be checked until +the `provisioning_state` is set to +[PROVISIONING_SUCCESS_NEW_AP]({{site.baseurl}}/ble/protocol/protobuf.html#proto-enumprovisioning). + +{% warning %} +The final `provisioning_state` that we are looking for is always `PROVISIONING_SUCCESS_NEW_AP` both in the Connect and +Connect New use cases. +{% endwarning %} + +The procedure is summarized here: + +{% include figure image_path="/assets/images/plantuml_ble_connect_ap.png" alt="connect_ap" size="60%" caption="Connect to Already Configured Network" %} + +{% linkedTabs send_Connect %} +{% tab send_Connect python %} + +```python +await fragment_and_write_gatt_char(manager.client, GoProUuid.NETWORK_MANAGEMENT_REQ_UUID.value, connect_request) +while response := await manager.get_next_response_as_protobuf(): + ... + elif response.action_id == 0x0C: # NotifProvisioningState Notifications + provisioning_notification: proto.NotifProvisioningState = response.data # type: ignore + if provisioning_notification.provisioning_state == proto.EnumProvisioning.PROVISIONING_SUCCESS_NEW_AP: + return +``` + +{% endtab %} +{% tab send_Connect kotlin %} +TODO +{% endtab %} +{% endlinkedTabs %} + +At this point, the GoPro is connect to the desired network in Station Mode! + +**Quiz time! 📚 ✏️** + +{% quiz + question="True or False: When the GoPro is in Station Mode, it can be communicated with via both BLE and HTTP." + option="A:::True" + option="B:::False" + correct="B" + info="When the GoPro is in station mode, it is connected via WiFi to another Access Point; not connected via Wifi + to you (the client). However, it is possible to maintain the BLE connection in STA mode so that you can still control + the GoPro." +%} + +# Troubleshooting + +See the first tutorial's +[BLE troubleshooting section]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#troubleshooting) to troubleshoot +BLE problems. + +# Good Job! + +{% success %} +Congratulations 🤙 +{% endsuccess %} + +You have now connected the GoPro to a WiFi network in either AP or STA mode. + +To see how to make use of AP mode, continue to the next tutorial. + +To see how make use of STA mode, continue to the +[camera on the home network tutorial]({% link _tutorials/tutorial_9_cohn/tutorial.md %}). diff --git a/docs/_tutorials/tutorial_6_send_wifi_commands/tutorial.md b/docs/_tutorials/tutorial_7_send_wifi_commands/tutorial.md similarity index 87% rename from docs/_tutorials/tutorial_6_send_wifi_commands/tutorial.md rename to docs/_tutorials/tutorial_7_send_wifi_commands/tutorial.md index d45c244a..3f5022b3 100644 --- a/docs/_tutorials/tutorial_6_send_wifi_commands/tutorial.md +++ b/docs/_tutorials/tutorial_7_send_wifi_commands/tutorial.md @@ -2,17 +2,17 @@ permalink: '/tutorials/send-wifi-commands' sidebar: nav: 'tutorials' -lesson: 6 +lesson: 7 --- -# Tutorial 6: Send WiFi Commands +# Tutorial 7: Send WiFi Commands -This document will provide a walk-through tutorial to send Open GoPro -[HTTP commands](/http) to the GoPro. +This document will provide a walk-through tutorial to perform Open GoPro [HTTP Operations]({{site.baseurl}}/http) +with the GoPro. {% tip %} It is suggested that you have first completed the -[Connecting to Wifi]({% link _tutorials/tutorial_5_connect_wifi/tutorial.md %}) tutorial. +[Connecting to Wifi]({% link _tutorials/tutorial_6_connect_wifi/tutorial.md %}) tutorial. {% endtip %} This tutorial only considers sending these commands as one-off commands. That is, it does not consider state management / @@ -20,35 +20,38 @@ synchronization when sending multiple commands. This will be discussed in a futu There are two types of responses that can be received from the HTTP commands: JSON and binary. This section will deal with commands that return JSON responses. For commands with binary responses (as well as commands with -JSON responses that work with the media list), see the [next tutorial]({% link _tutorials/tutorial_7_camera_media_list/tutorial.md %}). +JSON responses that work with the media list), see the +[next tutorial]({% link _tutorials/tutorial_8_camera_media_list/tutorial.md %}). # Requirements -It is assumed that the hardware and software requirements from the [connect tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#requirements) +It is assumed that the hardware and software requirements from the +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#requirements) are present and configured correctly. The scripts that will be used for this tutorial can be found in the -[Tutorial 6 Folder](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands). +[Tutorial 7 Folder](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands). # Just Show me the Demo(s)!! {% linkedTabs demo %} {% tab demo python %} -Each of the scripts for this tutorial can be found in the Tutorial 2 -[directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_6_send_wifi_commands/). +Each of the scripts for this tutorial can be found in the Tutorial 7 +[directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_7_send_wifi_commands/). {% warning %} -Python >= 3.8.x must be used as specified in the requirements +Python >= 3.9 and < 3.12 must be used as specified in the requirements {% endwarning %} {% warning %} You must be connected to the camera via WiFi as stated in -[Tutorial 5]({% link _tutorials/tutorial_5_connect_wifi/tutorial.md %}#Establish Connection to WiFi APPermalink). +[Tutorial 5]({% link _tutorials/tutorial_6_connect_wifi/tutorial.md %}#Establish Connection to WiFi APPermalink). {% endwarning %} -{% accordion Get State %} +{% accordion Get Camera State %} You can test querying the state of your camera with HTTP over WiFi using the following script: + ```console $ python wifi_command_get_state.py ``` @@ -64,12 +67,13 @@ Get the state of the GoPro (status and settings). optional arguments: -h, --help show this help message and exit ``` -{% endaccordion %} +{% endaccordion %} {% accordion Preview Stream %} You can test enabling the UDP preview stream with HTTP over WiFi using the following script: + ```console $ python wifi_command_preview_stream.py ``` @@ -87,13 +91,13 @@ optional arguments: ``` Once enabled the stream can be viewed at `udp://@:8554` (For more details see the View Stream tab in the -[Preview Stream]({% link _tutorials/tutorial_6_send_wifi_commands/tutorial.md %}#preview-stream) section below. +[Preview Stream]({% link _tutorials/tutorial_7_send_wifi_commands/tutorial.md %}#preview-stream) section below. {% endaccordion %} - {% accordion Load Preset Group %} You can test sending the load preset group command with HTTP over WiFi using the following script: + ```console $ python wifi_command_load_group.py ``` @@ -109,11 +113,13 @@ Load the video preset group. optional arguments: -h, --help show this help message and exit ``` + {% endaccordion %} {% accordion Set Shutter %} You can test sending the Set Shutter command with HTTP over WiFi using the following script: + ```console $ python wifi_command_set_shutter.py ``` @@ -129,12 +135,13 @@ Take a 3 second video. optional arguments: -h, --help show this help message and exit ``` -{% endaccordion %} +{% endaccordion %} {% accordion Set Setting %} You can test setting the resolution setting with HTTP over WiFi using the following script: + ```console $ python wifi_command_set_resolution.py ``` @@ -150,6 +157,7 @@ Set the video resolution to 1080. optional arguments: -h, --help show this help message and exit ``` + {% endaccordion %} {% endtab %} @@ -157,14 +165,15 @@ optional arguments: The Kotlin file for this tutorial can be found on [Github](https://github.com/gopro/OpenGoPro/tree/main/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/tutorials/Tutorial6SendWifiCommands.kt). -To perform the tutorial, run the Android Studio project, select "Tutorial 6" from the dropdown and click on "Perform." +To perform the tutorial, run the Android Studio project, select "Tutorial 7" from the dropdown and click on "Perform." This requires: -- a GoPro is already connected via BLE, i.e. that Tutorial 1 was already run. -- a GoPro is already connected via Wifi, i.e. that Tutorial 5 was already run. + +- a GoPro is already connected via BLE, i.e. that Tutorial 1 was already run. +- a GoPro is already connected via Wifi, i.e. that Tutorial 5 was already run. You can check the BLE and Wifi statuses at the top of the app. -{% include figure image_path="/assets/images/tutorials/kotlin/tutorial_6.png" alt="kotlin_tutorial_6" size="40%" caption="Perform Tutorial 6" %} +{% include figure image_path="/assets/images/tutorials/kotlin/tutorial_7.png" alt="kotlin_tutorial_7" size="40%" caption="Perform Tutorial 7" %} This will start the tutorial and log to the screen as it executes. When the tutorial is complete, click "Exit Tutorial" to return to the Tutorial selection screen. @@ -175,7 +184,7 @@ This will start the tutorial and log to the screen as it executes. When the tuto # Setup We must first connect to The GoPro's WiFi Access Point (AP) as was discussed in the -[Connecting to Wifi]({% link _tutorials/tutorial_5_connect_wifi/tutorial.md %}) tutorial. +[Connecting to Wifi]({% link _tutorials/tutorial_6_connect_wifi/tutorial.md %}) tutorial. # Sending HTTP Commands with JSON Responses @@ -211,6 +220,7 @@ suspend fun get(endpoint: String, timeoutMs: Long = 5000L): JsonObject { return prettyJson.parseToJsonElement(bodyAsString).jsonObject } ``` + {% endtab %} {% endlinkedTabs %} @@ -237,13 +247,13 @@ sequenceDiagram deactivate GoPro ``` -## Get State +## Get Camera State The first command we will be sending is -[Get State](/http#commands-quick-reference). This command will +[Get Camera State]({{site.baseurl}}/http#tag/Query/operation/OGP_GET_STATE). This command will return all of the current settings and values. It is basically a combination of the -[Get All Settings]({% link _tutorials/tutorial_4_ble_queries/tutorial.md %}#query-all) and -[Get All Statuses]({% link _tutorials/tutorial_4_ble_queries/tutorial.md %}#query-all) +[Get All Settings]({{site.baseurl}}/ble/features/query.html#get-setting-values) and +[Get All Statuses]({{site.baseurl}}/ble/features/query.html#get-status-values) commands that were sent via BLE. Since there is no way to query individual settings / statuses via WiFi (or register for asynchronous notifications when they change), this is the only option to query setting / status information via WiFi. @@ -252,11 +262,12 @@ The command writes to the following endpoint: `/gopro/camera/state` -Let's build the endpoint then send the GET request and check the response for errors. +Let's build the endpoint then perform the GET operation and check the response for errors. Any errors will raise an exception. {% linkedTabs get_state_send %} {% tab get_state_send python %} + ```python url = GOPRO_BASE_URL + "/gopro/camera/state" ``` @@ -265,11 +276,14 @@ url = GOPRO_BASE_URL + "/gopro/camera/state" response = requests.get(url) response.raise_for_status() ``` + {% endtab %} {% tab get_state_send kotlin %} + ```kotlin var response = wifi.get(GOPRO_BASE_URL + "gopro/camera/state") ``` + {% endtab %} {% endlinkedTabs %} @@ -277,6 +291,7 @@ Lastly, we print the response's JSON data: {% linkedTabs get_state_print %} {% tab get_state_print python %} + ```python logger.info(f"Response: {json.dumps(response.json(), indent=4)}") ``` @@ -317,8 +332,10 @@ INFO:root:Response: { "41": 9, "42": 5, ``` + {% endtab %} {% tab get_state_print kotlin %} + ```kotlin Timber.i(prettyJson.encodeToString(response)) ``` @@ -366,8 +383,8 @@ GET request to: http://10.5.5.9:8080/gopro/camera/state {% endtab %} {% endlinkedTabs %} -We can see what each of these values mean by looking at the -[Open GoPro Interface](/ble/index.html#settings-quick-reference). +We can see what each of these values mean by looking at relevant documentation in the `settings` or `status` object of the +[State]({{site.baseurl}}/http#schema/State) schema. For example (for settings): @@ -377,7 +394,7 @@ For example (for settings): ## Load Preset Group The next command we will be sending is -[Load Preset Group](/ble/index.html#commands-quick-reference), which is used +[Load Preset Group]({{site.baseurl}}/http#tag/Presets/operation/OGP_PRESET_SET_GROUP), which is used to toggle between the 3 groups of presets (video, photo, and timelapse). The preset groups ID's are: | Command | Bytes | @@ -386,14 +403,9 @@ to toggle between the 3 groups of presets (video, photo, and timelapse). The pre | Load Photo Preset Group | 1001 | | Load Timelapse Preset Group | 1002 | -{% note %} -It is possible that the preset GroupID values will vary in future cameras. The only absolutely correct way to know -the preset ID is to read them from the "Get Preset Status" protobuf command. A future lab will discuss protobuf -commands. -{% endnote %} - {% linkedTabs load_preset_group_send %} {% tab load_preset_group_send python %} + ```python url = GOPRO_BASE_URL + "/gopro/camera/presets/set_group?id=1000" ``` @@ -402,11 +414,14 @@ url = GOPRO_BASE_URL + "/gopro/camera/presets/set_group?id=1000" response = requests.get(url) response.raise_for_status() ``` + {% endtab %} {% tab load_preset_group_send kotlin %} + ```kotlin response = wifi.get(GOPRO_BASE_URL + "gopro/camera/presets/load?id=1000") ``` + {% endtab %} {% endlinkedTabs %} @@ -414,6 +429,7 @@ Lastly, we print the response's JSON data: {% linkedTabs load_preset_group_print %} {% tab load_preset_group_print python %} + ```python logger.info(f"Response: {json.dumps(response.json(), indent=4)}") ``` @@ -425,8 +441,10 @@ INFO:root:Loading the video preset group: sending http://10.5.5.9:8080/gopro/cam INFO:root:Command sent successfully INFO:root:Response: {} ``` + {% endtab %} {% tab load_preset_group_print kotlin %} + ```kotlin Timber.i(prettyJson.encodeToString(response)) ``` @@ -456,12 +474,12 @@ this by seeing the preset name in the pill at bottom middle of the screen. ## Set Shutter -The next command we will be sending is -[Set Shutter](/http#commands-quick-reference). which is +The next command we will be sending is [Set Shutter]({{site.baseurl}}/http#tag/Control/operation/OGP_SHUTTER). which is used to start and stop encoding. {% linkedTabs set_shutter_send %} {% tab set_shutter_send python %} + ```python url = GOPRO_BASE_URL + f"/gopro/camera/shutter/start" ``` @@ -470,11 +488,14 @@ url = GOPRO_BASE_URL + f"/gopro/camera/shutter/start" response = requests.get(url) response.raise_for_status() ``` + {% endtab %} {% tab set_shutter_send kotlin %} + ```kotlin response = wifi.get(GOPRO_BASE_URL + "gopro/camera/shutter/start") ``` + {% endtab %} {% endlinkedTabs %} @@ -488,12 +509,15 @@ This will log as such: {% linkedTabs set_shutter_print %} {% tab set_shutter_print python %} + ```console INFO:root:Turning the shutter on: sending http://10.5.5.9:8080/gopro/camera/shutter/start INFO:root:Command sent successfully ``` + {% endtab %} {% tab set_shutter_print kotlin %} + ```kotlin Timber.i(prettyJson.encodeToString(response)) ``` @@ -519,13 +543,13 @@ attempt to do so will result in an error response. ## Set Setting -The next command will be sending is [Set Setting](/http#settings-quick-reference). +The next command will be sending is [Set Setting]({{site.baseurl}}/http#tag/settings). This end point is used to update all of the settings on the camera. It is analogous to BLE commands like [Set Video Resolution]({% link _tutorials/tutorial_2_send_ble_commands/tutorial.md %}#set-the-video-resolution). It is important to note that many settings are dependent on the video resolution (and other settings). For example, certain FPS values are not valid with certain resolutions. In general, higher resolutions -only allow lower FPS values. Check the [camera capabilities](/ble/index.html#camera-capabilities) +only allow lower FPS values. Check the [camera capabilities]({{site.baseurl}}/http#tag/settings/Capabilities) to see which settings are valid for given use cases. Let's build the endpoint first to set the Video Resolution to 1080 (the setting_id and option value comes from @@ -533,6 +557,7 @@ the command table linked above). {% linkedTabs set_setting_send %} {% tab set_setting_send python %} + ```python url = GOPRO_BASE_URL + f"/gopro/camera/setting?setting=2&option=9" ``` @@ -541,11 +566,14 @@ url = GOPRO_BASE_URL + f"/gopro/camera/setting?setting=2&option=9" response = requests.get(url) response.raise_for_status() ``` + {% endtab %} {% tab set_setting_send kotlin %} + ```kotlin response = wifi.get(GOPRO_BASE_URL + "gopro/camera/setting?setting=2&option=9") ``` + {% endtab %} {% endlinkedTabs %} @@ -553,6 +581,7 @@ Lastly, we print the response's JSON data: {% linkedTabs set_setting_print %} {% tab set_setting_print python %} + ```python logger.info(f"Response: {json.dumps(response.json(), indent=4)}") ``` @@ -567,6 +596,7 @@ INFO:root:Response: {} {% endtab %} {% tab set_setting_print kotlin %} + ```kotlin Timber.i(prettyJson.encodeToString(response)) ``` @@ -592,12 +622,12 @@ screen: {% include figure image_path="/assets/images/tutorials/video_resolution.png" alt="Video Resolution" size="50%" caption="Video Resolution" %} -As a reader exercise, try using the [Get State] command to verify that the resolution has changed. +As a reader exercise, try using the [Get Camera State](#get-camera-state) command to verify that the resolution has changed. ## Preview Stream The next command we will be sending is -[Preview Stream](/http#commands-quick-reference). This command will +[Start Preview Stream]({{site.baseurl}}/http#tag/Preview-Stream/operation/OGP_PREVIEW_STREAM_START). This command will enable (or disable) the preview stream . It is then possible to view the preview stream from a media player. The commands write to the following endpoints: @@ -612,6 +642,7 @@ Any errors will raise an exception. {% linkedTabs preview_stream_send %} {% tab preview_stream_send python %} + ```python url = GOPRO_BASE_URL + "/gopro/camera/stream/start" ``` @@ -620,6 +651,7 @@ url = GOPRO_BASE_URL + "/gopro/camera/stream/start" response = requests.get(url) response.raise_for_status() ``` + {% endtab %} {% tab preview_stream_send kotlin %} TODO @@ -642,6 +674,7 @@ INFO:root:Starting the preview stream: sending http://10.5.5.9:8080/gopro/camera INFO:root:Command sent successfully INFO:root:Response: {} ``` + {% endtab %} {% tab preview_stream_print kotlin %} TODO @@ -720,6 +753,6 @@ Congratulations 🤙 {% endsuccess %} You can now send any of the HTTP commands defined in the -[Open GoPro Interface](/http) that return JSON responses. You +[Open GoPro Interface]({{site.baseurl}}/http) that return JSON responses. You may have noted that we did not discuss one of these (Get Media List) in this tutorial. Proceed to the next tutorial to see how to get and perform operations using the media list. diff --git a/docs/_tutorials/tutorial_7_camera_media_list/tutorial.md b/docs/_tutorials/tutorial_8_camera_media_list/tutorial.md similarity index 85% rename from docs/_tutorials/tutorial_7_camera_media_list/tutorial.md rename to docs/_tutorials/tutorial_8_camera_media_list/tutorial.md index b7b933b7..68a1f223 100644 --- a/docs/_tutorials/tutorial_7_camera_media_list/tutorial.md +++ b/docs/_tutorials/tutorial_8_camera_media_list/tutorial.md @@ -2,19 +2,18 @@ permalink: '/tutorials/camera-media-list' sidebar: nav: 'tutorials' -lesson: 7 +lesson: 8 --- -# Tutorial 7: Camera Media List +# Tutorial 8: Camera Media List -This document will provide a walk-through tutorial to send Open GoPro -[HTTP commands](/http) to the GoPro, specifically to get the media list -and perform operations on it (downloading pictures, videos, etc.) +This document will provide a walk-through tutorial to send Open GoPro [HTTP commands]({{site.baseurl}}/http) to the GoPro, +specifically to get the media list and perform operations on it (downloading pictures, videos, etc.) {% tip %} It is suggested that you have first completed the -[Connecting to Wifi]({% link _tutorials/tutorial_5_connect_wifi/tutorial.md %}) -and [Sending WiFi Commands]({% link _tutorials/tutorial_6_send_wifi_commands/tutorial.md %}) tutorials. +[Connecting to Wifi]({% link _tutorials/tutorial_6_connect_wifi/tutorial.md %}) +and [Sending WiFi Commands]({% link _tutorials/tutorial_7_send_wifi_commands/tutorial.md %}) tutorials. {% endtip %} This tutorial only considers sending these commands as one-off commands. That is, it does not consider state @@ -23,32 +22,34 @@ management / synchronization when sending multiple commands. This will be discus # Requirements It is assumed that the hardware and software requirements from the -[connect tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#requirements) are present and +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#requirements) are present and configured correctly. The scripts that will be used for this tutorial can be found in the -[Tutorial 7 Folder](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list). +[Tutorial 8 Folder](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list). # Just Show me the Demo(s)!! {% linkedTabs demo %} {% tab demo python %} -Each of the scripts for this tutorial can be found in the Tutorial 2 -[directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_7_camera_media_list/). +Each of the scripts for this tutorial can be found in the Tutorial 8 +[directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_8_camera_media_list/). {% warning %} -Python >= 3.8.x must be used as specified in the requirements +Python >= 3.9 and < 3.12 must be used as specified in the requirements {% endwarning %} {% warning %} You must be connected to the camera via WiFi in order to run these scripts. You can do this by manually to the SSID and password listed on your camera or by leaving the -`Establish Connection to WiFi AP` script from [Tutorial 5]({% link _tutorials/tutorial_5_connect_wifi/tutorial.md %}#just-show-me-the-demos) running in the background. +`Establish Connection to WiFi AP` script from +[Tutorial 5]({% link _tutorials/tutorial_6_connect_wifi/tutorial.md %}#just-show-me-the-demos) running in the background. {% endwarning %} {% accordion Download Media File %} You can downloading a file from your camera with HTTP over WiFi using the following script: + ```console $ python wifi_media_download_file.py ``` @@ -64,11 +65,13 @@ Find a photo on the camera and download it to the computer. optional arguments: -h, --help show this help message and exit ``` + {% endaccordion %} {% accordion Get Media Thumbnail %} You can downloading the thumbnail for a media file from your camera with HTTP over WiFi using the following script: + ```console $ python wifi_media_get_thumbnail.py ``` @@ -84,20 +87,22 @@ Get the thumbnail for a media file. optional arguments: -h, --help show this help message and exit ``` + {% endaccordion %} {% endtab %} {% tab demo kotlin %} The Kotlin file for this tutorial can be found on [Github](https://github.com/gopro/OpenGoPro/tree/main/demos/kotlin/tutorial/app/src/main/java/com/example/open_gopro_tutorial/tutorials/Tutorial7CameraMediaList.kt). -To perform the tutorial, run the Android Studio project, select "Tutorial 7" from the dropdown and click on "Perform." +To perform the tutorial, run the Android Studio project, select "Tutorial 8" from the dropdown and click on "Perform." This requires: -- a GoPro is already connected via BLE, i.e. that Tutorial 1 was already run. -- a GoPro is already connected via Wifi, i.e. that Tutorial 5 was already run. + +- a GoPro is already connected via BLE, i.e. that Tutorial 1 was already run. +- a GoPro is already connected via Wifi, i.e. that Tutorial 5 was already run. You can check the BLE and Wifi statuses at the top of the app. -{% include figure image_path="/assets/images/tutorials/kotlin/tutorial_7.png" alt="kotlin_tutorial_7" size="40%" caption="Perform Tutorial 7" %} +{% include figure image_path="/assets/images/tutorials/kotlin/tutorial_8.png" alt="kotlin_tutorial_8" size="40%" caption="Perform Tutorial 8" %} This will start the tutorial and log to the screen as it executes. When the tutorial is complete, click "Exit Tutorial" to return to the Tutorial selection screen. @@ -108,17 +113,16 @@ This will start the tutorial and log to the screen as it executes. When the tuto # Setup We must first connect to The GoPro's WiFi Access Point (AP) as was discussed in the -[Connecting to Wifi]({% link _tutorials/tutorial_5_connect_wifi/tutorial.md %}) tutorial. +[Connecting to Wifi]({% link _tutorials/tutorial_6_connect_wifi/tutorial.md %}) tutorial. # Get Media List Now that we are are connected via WiFi, we will get the media list using the same procedure to send HTTP commands as in the -[previous tutorial]({% link _tutorials/tutorial_6_send_wifi_commands/tutorial.md %}). +[previous tutorial]({% link _tutorials/tutorial_7_send_wifi_commands/tutorial.md %}). -We get the media list via the -[Get Media List command](/http#commands-quick-reference). -This command will return a JSON structure of all of the media files (pictures, videos) on the camera with +We get the media list via [Get Media List]({{site.baseurl}}/http#tag/Media/operation/OGP_MEDIA_LIST). +This will return a JSON structure of all of the media files (pictures, videos) on the camera with corresponding information about each media file. Let's build the endpoint, send the GET request, and check the response for errors. Any errors will raise @@ -126,6 +130,7 @@ an exception. {% linkedTabs media_list_send %} {% tab media_list_send python %} + ```python url = GOPRO_BASE_URL + "/gopro/media/list" ``` @@ -134,11 +139,14 @@ url = GOPRO_BASE_URL + "/gopro/media/list" response = requests.get(url) response.raise_for_status() ``` + {% endtab %} {% tab media_list_send kotlin %} + ```python val response = wifi.get(GOPRO_BASE_URL + "gopro/media/list") ``` + {% endtab %} {% endlinkedTabs %} @@ -146,6 +154,7 @@ Lastly, we print the response's JSON data: {% linkedTabs media_list_print %} {% tab media_list_print python %} + ```python logger.info(f"Response: {json.dumps(response.json(), indent=4)}") ``` @@ -188,8 +197,10 @@ INFO:root:Response: { "s": "10725219" }, ``` + {% endtab %} {% tab media_list_print kotlin %} + ```kotlin Timber.i("Files in media list: ${prettyJson.encodeToString(fileList)}") ``` @@ -230,17 +241,18 @@ Complete media list: { ] } ``` + {% endtab %} {% endlinkedTabs %} -The media list format is defined in the -[Open GoPro Specification](/http#media-list-format). +The media list format is defined in the [Media Model]({{site.baseurl}}/http#schema/MediaList). We won't be rehashing that here but will provide examples below of using the media list. One common functionality is to get the list of media file names, which can be done as such: {% linkedTabs media_list_get_files %} {% tab media_list_get_files python %} + ```python print([x["n"] for x in media_list["media"][0]["fs"]]) ``` @@ -250,6 +262,7 @@ make a list of all of the names (**n** tag of each element) in the **fs** list. {% endtab %} {% tab media_list_get_files kotlin %} + ```kotlin val fileList = response["media"]?.jsonArray?.first()?.jsonObject?.get("fs")?.jsonArray?.map { mediaEntry -> @@ -258,12 +271,12 @@ val fileList = ``` That is: + 1. Access the JSON array at the **fs** tag at the first element of the **media** tag -1. Make a list of all of the names (**n** tag of each element) in the **fs** list. -2. Map this list to string and remove backslashes -3. -{% endtab %} -{% endlinkedTabs %} +2. Make a list of all of the names (**n** tag of each element) in the **fs** list. +3. Map this list to string and remove backslashes +4. {% endtab %} + {% endlinkedTabs %} # Media List Operations @@ -293,18 +306,20 @@ sequenceDiagram ## Download Media File +TODO Handle directory in media list. + The next command we will be sending is -[Download Media](/http#downloading-media). Specifically, we -will be downloading a photo. The camera must have at least one photo in its media list in order for this to -work. +[Download Media]({{site.baseurl}}/http#tag/Media/operation/OGP_DOWNLOAD_MEDIA). Specifically, we +will be downloading a photo. The camera must have at least one photo in its media list in order for this to work. First, we get the media list as in -[Get Media List]({% link _tutorials/tutorial_7_camera_media_list/tutorial.md %}#get-media-list) . +[Get Media List]({% link _tutorials/tutorial_8_camera_media_list/tutorial.md %}#get-media-list) . Then we search through the list of file names in the media list looking for a photo (i.e. a file whose name ends in **.jpg**). Once we find a photo, we proceed: {% linkedTabs download_media_find_jpg %} {% tab download_media_find_jpg python %} + ```python media_list = get_media_list() @@ -318,11 +333,13 @@ for media_file in [x["n"] for x in media_list["media"][0]["fs"]]: {% endtab %} {% tab download_media_find_jpg kotlin %} + ```kotlin val photo = fileList?.firstOrNull { it.endsWith(ignoreCase = true, suffix = "jpg") } ?: throw Exception("Not able to find a .jpg in the media list") Timber.i("Found a photo: $photo") ``` + {% endtab %} {% endlinkedTabs %} @@ -335,6 +352,7 @@ The endpoint will start with "videos" for both photos and videos {% linkedTabs download_media_send %} {% tab download_media_send python %} + ```python url = GOPRO_BASE_URL + f"videos/DCIM/100GOPRO/{photo}" ``` @@ -356,6 +374,7 @@ with open(file, "wb") as f: {% endtab %} {% tab download_media_send kotlin %} + ```kotlin return wifi.getFile( GOPRO_BASE_URL + "videos/DCIM/100GOPRO/$photo", appContainer.applicationContext @@ -371,6 +390,7 @@ This will log as such: {% linkedTabs download_media_print %} {% tab download_media_print python %} + ```console INFO:root:found a photo: GOPR0987.JPG INFO:root:Downloading GOPR0987.JPG @@ -381,6 +401,7 @@ INFO:root:receiving binary stream to GOPR0987.jpg... Once complete, the `GOPR0987_thumbnail.jpg` file will be available from where the demo script was called. {% endtab %} {% tab download_media_print kotlin %} + ```console Found a photo: GOPR0232.JPG Downloading photo: GOPR0232.JPG... @@ -393,8 +414,7 @@ Once complete, the photo will display in the tutorial window. ## Get Media Thumbnail -The next command we will be sending is -[Get Media thumbnail ](/http#downloading-media). +The next command we will be sending is [Get Media thumbnail ]({{site.baseurl}}/http#tag/Media/operation/OGP_MEDIA_THUMBNAIL). Specifically, we will be getting the thumbnail for a photo. The camera must have at least one photo in its media list in order for this to work. @@ -403,12 +423,13 @@ There is a separate commandto get a media "screennail" {% endnote %} First, we get the media list as in -[Get Media List]({% link _tutorials/tutorial_7_camera_media_list/tutorial.md %}#get-media-list) . +[Get Media List]({% link _tutorials/tutorial_8_camera_media_list/tutorial.md %}#get-media-list) . Then we search through the list of file names in the media list looking for a photo (i.e. a file whose name ends in **.jpg**). Once we find a photo, we proceed: {% linkedTabs thumbnail_find_jpg %} {% tab thumbnail_find_jpg python %} + ```python media_list = get_media_list() @@ -431,6 +452,7 @@ an exception. {% linkedTabs thumbnail_send %} {% tab thumbnail_send python %} + ```python url = GOPRO_BASE_URL + f"/gopro/media/thumbnail?path=100GOPRO/{photo}" ``` @@ -449,6 +471,7 @@ with open(file, "wb") as f: for chunk in request.iter_content(chunk_size=8192): f.write(chunk) ``` + {% endtab %} {% tab thumbnail_send kotlin %} TODO @@ -459,12 +482,14 @@ This will log as such: {% linkedTabs thumbnail_print %} {% tab thumbnail_print python %} + ```console INFO:root:found a photo: GOPR0987.JPG INFO:root:Getting the thumbnail for GOPR0987.JPG INFO:root:Sending: http://10.5.5.9:8080/gopro/media/thumbnail?path=100GOPRO/GOPR0987.JPG INFO:root:receiving binary stream to GOPR0987_thumbnail.jpg... ``` + {% endtab %} {% tab thumbnail_print kotlin %} TODO @@ -474,7 +499,7 @@ TODO # Troubleshooting See the previous tutorial's -[troubleshooting section]({% link _tutorials/tutorial_6_send_wifi_commands/tutorial.md %}#troubleshooting). +[troubleshooting section]({% link _tutorials/tutorial_7_send_wifi_commands/tutorial.md %}#troubleshooting). # Good Job! diff --git a/docs/_tutorials/tutorial_9_cohn/tutorial.md b/docs/_tutorials/tutorial_9_cohn/tutorial.md new file mode 100644 index 00000000..59d8a28c --- /dev/null +++ b/docs/_tutorials/tutorial_9_cohn/tutorial.md @@ -0,0 +1,514 @@ +--- +permalink: '/tutorials/cohn' +sidebar: + nav: 'tutorials' +lesson: 9 +--- + +# Tutorial 9: Camera on the Home Network + +This document will provide a walk-through tutorial to use the Open GoPro Interface to configure and demonstrate +the [Camera on the Home Network]({{site.baseurl}}/ble/features/cohn.html) (COHN) feature. + +{% tip %} +It is recommended that you have first completed the +[connecting BLE]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}), +[sending commands]({% link _tutorials/tutorial_2_send_ble_commands/tutorial.md %}), +[parsing responses]({% link _tutorials/tutorial_3_parse_ble_tlv_responses/tutorial.md %}), +[protobuf]({% link _tutorials/tutorial_5_ble_protobuf/tutorial.md %}), and +[connecting WiFi]({% link _tutorials/tutorial_6_connect_wifi/tutorial.md %}) +tutorials before proceeding. +{% endtip %} + +# Requirements + +It is assumed that the hardware and software requirements from the +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#requirements) +are present and configured correctly. + +The scripts that will be used for this tutorial can be found in the +[Tutorial 9 Folder](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi). + +# Just Show me the Demo(s)!! + +{% linkedTabs demo %} +{% tab demo python %} +Each of the scripts for this tutorial can be found in the Tutorial 9 +[directory](https://github.com/gopro/OpenGoPro/tree/main/demos/python/tutorial/tutorial_modules/tutorial_6_connect_wifi/). + +{% warning %} +Python >= 3.9 and < 3.12 must be used as specified in the requirements +{% endwarning %} + +{% accordion Provision COHN %} + +You can provision the GoPro for COHN to communicate via a network via: + +```console +$ python provision_cohn.py +``` + +See the help for parameter definitions: + +```console +$ python provision_cohn.py --help +usage: provision_cohn.py [-h] [-i IDENTIFIER] [-c CERTIFICATE] ssid password + +Provision COHN via BLE to be ready for communication. + +positional arguments: + ssid SSID of network to connect to + password Password of network to connect to + +options: + -h, --help show this help message and exit + -i IDENTIFIER, --identifier IDENTIFIER + Last 4 digits of GoPro serial number, which is the last 4 digits of the default camera + SSID. If not used, first discovered GoPro will be connected to + -c CERTIFICATE, --certificate CERTIFICATE + Path to write retrieved COHN certificate. +``` + +{% endaccordion %} + +{% accordion Communicate via COHN %} + +You can see an example of communicating HTTPS via COHN (assuming it has already been provisioned) via: + +```console +$ python communicate_via_cohn.py +``` + +See the help for parameter definitions: + +```console +$ python communicate_via_cohn.py --help +usage: communicate_via_cohn.py [-h] ip_address username password certificate + +Demonstrate HTTPS communication via COHN. + +positional arguments: + ip_address IP Address of camera on the home network + username COHN username + password COHN password + certificate Path to read COHN cert from. + +options: + -h, --help show this help message and exit +``` + +{% endaccordion %} + +{% endtab %} +{% tab demo kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +# Setup + +We must first connect to BLE as was discussed in the +[connecting BLE tutorial]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}). +The GoPro must then be connected to an access point as was discussed in the +[Connecting WiFi Tutorial]({% link _tutorials/tutorial_6_connect_wifi/tutorial.md %}#station-sta-mode). +For all of the BLE operations, we are using the same `ResponseManager` class that was defined in the +[Protobuf tutorial]({% link _tutorials/tutorial_5_ble_protobuf/tutorial.md %}#response-manager). + +# COHN Overview + +The Camera on the Home Network feature allows the GoPro to connect (in +[Station Mode]({% link _tutorials/tutorial_6_connect_wifi/tutorial.md %}#station-sta-mode)) to an Access Point (AP) +such as a router in order to be controlled over a local network via the [HTTP API]({{site.baseurl}}/http). + +In order to protect users who connect to a network that includes Bad Actors, COHN uses +[SSL/TLS](https://www.websecurity.digicert.com/security-topics/what-is-ssl-tls-https) so that command and responses are +sent securely encrypted via `https://` rather than `http://`. + +{% tip %} +Once COHN is provisioned it is possible to control the GoPro without a BLE connection by communicating via HTTPS over the +provisioned network. +{% endtip %} + +# Provisioning + +In order to use the COHN capability, the GoPro must first be provisioned for COHN via BLE. At a high level, the +provisioning process is as follows: + +- [Connect the GoPro to an access point]({% link _tutorials/tutorial_6_connect_wifi/tutorial.md %}#station-sta-mode) +- Instruct the GoPro to create a COHN Certificate +- Get the created COHN certificate +- Get the COHN status to retrieve and store COHN credentials for future use + +A summary of this process is shown here and will be expanded upon in the following sections: + +{% include figure image_path="/assets/images/plantuml_ble_cohn_provision.png" alt="provision_cohn" size="70%" caption="Provision COHN" %} + +## Set Date Time + +While not explicitly part of of the provisioning process, it is important that the GoPro's date and time are correct +so that it generates a valid SSL certificate. This can be done manually through the camera UI or programatically +using the [Set Local Datetime]({{site.baseurl}}/ble/features/control.html#set-local-date-time) command. + +For the provisioning demo discussed in this tutorial, this is done programatically: + +{% linkedTabs set_date_time %} +{% tab set_date_time python %} + +{% note %} +The code shown here can be found in `provision_cohn.py` +{% endnote %} + +We're using the [pytz](https://pypi.org/project/pytz/) and [tzlocal](https://pypi.org/project/tzlocal/) libraries to +find the timezone offset and daylight savings time status. In the `set_date_time` method, we send the request and wait to +receive the successful response: + +```python +datetime_request = bytearray( + [ + 0x0F, # Command ID + 10, # Length of following datetime parameter + *now.year.to_bytes(2, "big", signed=False), # uint16 year + now.month, + now.day, + now.hour, + now.minute, + now.second, + *offset.to_bytes(2, "big", signed=True), # int16 offset in minutes + is_dst, + ] +) +datetime_request.insert(0, len(datetime_request)) +await manager.client.write_gatt_char(GoProUuid.COMMAND_REQ_UUID.value, datetime_request, response=True) +response = await manager.get_next_response_as_tlv() +``` + +which logs as: + +```console +Setting the camera's date and time to 2024-04-04 13:00:05.097305-07:00:-420 is_dst=True +Writing: 0c:0f:0a:07:e8:04:04:0d:00:05:fe:5c:01 +Received response at GoProUuid.COMMAND_RSP_UUID: 02:0f:00 +Successfully set the date time. +``` + +{% endtab %} +{% tab set_date_time kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +## Create the COHN Certificate + +Now that the GoPro's date and time are valid and it has been +[connected to an Access Point]({% link _tutorials/tutorial_6_connect_wifi/tutorial.md %}#station-sta-mode), we can +continue to provision COHN. + +Let's instruct the GoPro to [Create a COHN certificate]({{site.baseurl}}/ble/features/cohn.html#create-cohn-certificate). + +{% linkedTabs get_ssid %} +{% tab get_ssid python %} + +```python +create_request = bytearray( + [ + 0xF1, # Feature ID + 0x67, # Action ID + *proto.RequestCreateCOHNCert().SerializePartialToString(), + ] +) +create_request.insert(0, len(create_request)) +await manager.client.write_gatt_char(GoProUuid.COMMAND_REQ_UUID.value, create_request, response=True) +response := await manager.get_next_response_as_protobuf() +``` + +which logs as: + +```console +Creating a new COHN certificate. +Writing: 02:f1:67 +Received response at GoProUuid.COMMAND_RSP_UUID: 04:f1:e7:08:01 +COHN certificate successfully created +``` + +{% endtab %} +{% tab get_ssid kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +{% tip %} +You may notice that the provisioning demo first +[Clears the COHN Certificate]({{site.baseurl}}/ble/features/cohn.html#clear-cohn-certificate). This is is only to +ensure a consistent starting state in the case that COHN has already been provisioned. It is not necessary to clear +the certificate if COHN has not yet been provisioned. +{% endtip %} + +## Get the COHN Credentials + +At this point the GoPro has created the certificate and is in the process of provisioning COHN. We now need to get +the COHN credentials that will be used for HTTPS communication. These are: + +- COHN certificate +- Basic auth [username](https://en.wikipedia.org/wiki/Basic_access_authentication) +- Baisc auth [password](https://en.wikipedia.org/wiki/Basic_access_authentication) +- IP Address of COHN network + +We can immediately get the COHN certificate as such: + +{% linkedTabs get_ssid %} +{% tab get_ssid python %} + +```python +cert_request = bytearray( + [ + 0xF5, # Feature ID + 0x6E, # Action ID + *proto.RequestCOHNCert().SerializePartialToString(), + ] +) +cert_request.insert(0, len(cert_request)) +await manager.client.write_gatt_char(GoProUuid.QUERY_REQ_UUID.value, cert_request, response=True) +response := await manager.get_next_response_as_protobuf(): +cert_response: proto.ResponseCOHNCert = response.data # type: ignore +return cert_response.cert +``` + +{% endtab %} +{% tab get_ssid kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +For the remaining credentials, we need to wait until the COHN network is connected. That is, we need to +[Get COHN Status]({{site.baseurl}}/ble/features/cohn.html#get-cohn-status) until we receive a status where the +[state]({{site.baseurl}}/ble/protocol/protobuf.html#notifycohnstatus) is set to +[COHN_STATE_NetworkConnected]({{site.baseurl}}/ble/protocol/protobuf.html#proto-enumcohnnetworkstate). +This final status contains the remaining credentials: username, password, and IP Address. + +To do this, we first register to receive asynchronous COHN status updates: + +{% linkedTabs get_ssid %} +{% tab get_ssid python %} + +```python +status_request = bytearray( + [ + 0xF5, # Feature ID + 0x6F, # Action ID + *proto.RequestGetCOHNStatus(register_cohn_status=True).SerializePartialToString(), + ] +) +status_request.insert(0, len(status_request)) +await manager.client.write_gatt_char(GoProUuid.QUERY_REQ_UUID.value, status_request, response=True) +``` + +{% endtab %} +{% tab get_ssid kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +Then we continuously receive and check the updates until we receive the desired status: + +{% linkedTabs get_ssid %} +{% tab get_ssid python %} + +```python +while response := await manager.get_next_response_as_protobuf(): + cohn_status: proto.NotifyCOHNStatus = response.data # type: ignore + if cohn_status.state == proto.EnumCOHNNetworkState.COHN_STATE_NetworkConnected: + return cohn_status +``` + +This will all display in the log as such: + +```console +Checking COHN status until provisioning is complete +Writing: 04:f5:6f:08:01 +... +Received response at GoProUuid.QUERY_RSP_UUID: 20:47:f5:ef:08:01:10:1b:1a:05:67:6f:70:72:6f:22:0c:47:7a:74 +Received response at GoProUuid.QUERY_RSP_UUID: 80:32:6d:36:59:4d:76:4c:41:6f:2a:0e:31:39:32:2e:31:36:38:2e +Received response at GoProUuid.QUERY_RSP_UUID: 81:35:30:2e:31:30:33:30:01:3a:0a:64:61:62:75:67:64:61:62:75 +Received response at GoProUuid.QUERY_RSP_UUID: 82:67:42:0c:32:34:37:34:66:37:66:36:36:31:30:34 +Received COHN Status: + status: COHN_PROVISIONED + state: COHN_STATE_NetworkConnected + username: "gopro" + password: "Gzt2m6YMvLAo" + ipaddress: "192.168.50.103" + enabled: true + ssid: "dabugdabug" + macaddress: "2474f7f66104" +Successfully provisioned COHN. +``` + +{% endtab %} +{% tab get_ssid kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +Finally we accumulate all of the credentials and log them, also storing the certificate to a `cohn.crt` file: + +{% linkedTabs get_ssid %} +{% tab get_ssid python %} + +```python +credentials = await provision_cohn(manager) +with open(certificate, "w") as fp: + fp.write(credentials.certificate) + logger.info(f"Certificate written to {certificate.resolve()}") +``` + +```console +{ + "certificate": "-----BEGIN + CERTIFICATE-----\nMIIDnzCCAoegAwIBAgIUC7DGLtJJ61TzRY/mYQyhOegnz6cwDQYJKoZIhvcNAQ + EL\nBQAwaTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQHDAlTYW4gTWF0\nZW8xDjAMBg + NVBAoMBUdvUHJvMQ0wCwYDVQQLDARIZXJvMRowGAYDVQQDDBFHb1By\nbyBDYW1lcmEgUm9vdDAeFw0y + NDA0MDQyMDAwMTJaFw0zNDA0MDIyMDAwMTJaMGkx\nCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMB + AGA1UEBwwJU2FuIE1hdGVvMQ4w\nDAYDVQQKDAVHb1BybzENMAsGA1UECwwESGVybzEaMBgGA1UEAwwR + R29Qcm8gQ2Ft\nZXJhIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC05o1QIN5r\n + PmtTntzpzBQvfq64OM1j/tjdNCJsyB9/ipPrPcKdItOy+5gZZF8iOFiw8cG8O2nA\nvLSIJkpQ6d3cuE + 48nAQpc1+jJzskM7Vgqc/i43OqnB8iTKjtNJgj+lJtreQBNJw7\nf00a0GbbUJMo6DhaW58ZIsOJKu3i + +w8w+LNEZECfDN6RMSmkYoLXaHeKAlvhlRYv\nxkNO7pB2OwhbD9awgzKVTiKvZ8Hrxl6lGlH5SHHimU + uo2O1yiNKDWv+MhirCVnup\nVvP/N5S+230KpXreEnHmo65fsHmdM11qYu8WJXGzOViCnQi24wgCuoMx + np9hAeKs\nVj4vxhyCu8gZAgMBAAGjPzA9MA8GA1UdEwQIMAYBAf8CAQAwCwYDVR0PBAQDAgGG\nMB0G + A1UdDgQWBBTYDT4QXVDsi23ukLr2ohJk5+8+gDANBgkqhkiG9w0BAQsFAAOC\nAQEAU4Z9120CGtRGo3 + QfWEy66BGdqI6ohdudmb/3qag0viXag2FyWar18lRFiEWc\nZcsqw6i0CM6lKNVUluEsSBiGGVAbAHKu + +fcpId5NLEI7G1XY5MFRHMIMi4PNKbJr\nVi0ks/biMy7u9++FOBgmCXGAdbMJBfe2gxEJNdyU6wjgGs + 2o402/parrWN8x9J+k\ndBgYqiKpZK0Fad/qM4ivbgkMijXhGFODhWs/GlQWnPeaLusRnn3T/w2CsFzM + kf0i\n6fFT3FAQBU5LCZs1Fp/XFRrnFMp+sNhbmdfnI9EDyZOXzlRS4O48k/AW/nSkCozk\nugYW+61H + /RYPVEgF4VNxRqn+uA==\n-----END CERTIFICATE-----\n", + "username": "gopro", + "password": "Gzt2m6YMvLAo", + "ip_address": "192.168.50.103" +} +Certificate written to C:\Users\user\gopro\OpenGoPro\demos\python\tutorial\tutorial_modules\tutorial_9_cohn\cohn.crt +``` + +{% endtab %} +{% tab get_ssid kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +{% success %} +Make sure to keep these credentials for use in the next section. +{% endsuccess %} + +# Communicating via COHN + +Once the GoPro has provisioned for COHN, we can use the stored credentials for HTTPS communication. + +For the setup of this demo, there is no pre-existing BLE or WiFi connection to the GoPro. We are only going to be using +HTTPS over the provisioned home network for communication. + +In order to demonstrate COHN communication we are going to +[Get the Camera State]({{site.baseurl}}/http#tag/Query/operation/OGP_GET_STATE). + +{% linkedTabs get_ssid %} +{% tab get_ssid python %} + +{% note %} +The code shown below is taken from `communicate_via_cohn.py`. The credentials logged and stored from the previous demo +must be passed in as command line arguments to this script. Run `python communicate_via_cohn.py --help` for usage. +{% endnote %} + +We're going to use the [requests](https://pypi.org/project/requests/) library to perform the HTTPS request. First let's +build the url using the `ip_address` CLI argument: + +```python +url = f"https://{ip_address}" + "/gopro/camera/state" +``` + +Then let's build the [basic auth token](https://www.debugbear.com/basic-auth-header-generator) from the `username` and +`password` CLI arguments: + +```python +token = b64encode(f"{username}:{password}".encode("utf-8")).decode("ascii") +``` + +Lastly we build and send the request using the above endpoint and token combined with the path to the certificate +from the CLI `certificate` argument: + +```python +response = requests.get( + url, + timeout=10, + headers={"Authorization": f"Basic {token}"}, + verify=str(certificate), +) +logger.info(f"Response: {json.dumps(response.json(), indent=4)}") +``` + +{% endtab %} +{% tab get_ssid kotlin %} + +TODO + +{% endtab %} +{% endlinkedTabs %} + +This should result in logging the complete cameras state, truncated here for brevity: + +```console +Sending: https://192.168.50.103/gopro/camera/state +Command sent successfully +Response: { + "status": { + "1": 1, + "2": 4, + "3": 0, + "4": 255, + "6": 0, + "8": 0, + "9": 0, + ... + "settings": { + "2": 1, + "3": 0, + "5": 0, + "6": 0, + "13": 0, + ... +``` + +See the +[sending Wifi commands tutorial]({% link _tutorials/tutorial_7_send_wifi_commands/tutorial.md %}) for more information +on this and other HTTP(S) functionality. + +**Quiz time! 📚 ✏️** + +# Troubleshooting + +See the first tutorial's +[troubleshooting section]({% link _tutorials/tutorial_1_connect_ble/tutorial.md %}#troubleshooting) to troubleshoot +any BLE problems. + +See the Sending Wifi Command tutorial's +[troubleshooting section]({% link _tutorials/tutorial_7_send_wifi_commands/tutorial.md %}#troubleshooting) to +troubleshoot HTTP communication. + +# Good Job! + +{% success %} +Congratulations 🤙 +{% endsuccess %} + +You have now provisioned COHN and performed an HTTPS operation. In the future, you can now communicate with the GoPro +over your home network without needing a direct BLE or WiFi connection. diff --git a/docs/assets/css/custom.css b/docs/assets/css/custom.css index b471e6c5..33b56bbb 100644 --- a/docs/assets/css/custom.css +++ b/docs/assets/css/custom.css @@ -147,6 +147,10 @@ img.mermaid { .md_column { display: flex; + + * { + max-width: none !important; + } } /* Github button for demo layout */ diff --git a/docs/assets/images/tutorials/complex_response_doc.png b/docs/assets/images/tutorials/complex_response_doc.png new file mode 100644 index 00000000..0cbc58db Binary files /dev/null and b/docs/assets/images/tutorials/complex_response_doc.png differ diff --git a/docs/assets/images/tutorials/kotlin/tutorial_6.png b/docs/assets/images/tutorials/kotlin/tutorial_6.png deleted file mode 100644 index 1e3ff937..00000000 Binary files a/docs/assets/images/tutorials/kotlin/tutorial_6.png and /dev/null differ diff --git a/docs/assets/images/tutorials/kotlin/tutorial_7.png b/docs/assets/images/tutorials/kotlin/tutorial_7.png index 0a120544..1e3ff937 100644 Binary files a/docs/assets/images/tutorials/kotlin/tutorial_7.png and b/docs/assets/images/tutorials/kotlin/tutorial_7.png differ diff --git a/docs/assets/images/tutorials/kotlin/tutorial_8.png b/docs/assets/images/tutorials/kotlin/tutorial_8.png new file mode 100644 index 00000000..0a120544 Binary files /dev/null and b/docs/assets/images/tutorials/kotlin/tutorial_8.png differ diff --git a/docs/assets/images/tutorials/protobuf_doc.png b/docs/assets/images/tutorials/protobuf_doc.png new file mode 100644 index 00000000..7507b1ca Binary files /dev/null and b/docs/assets/images/tutorials/protobuf_doc.png differ diff --git a/docs/assets/images/tutorials/protobuf_message_doc.png b/docs/assets/images/tutorials/protobuf_message_doc.png new file mode 100644 index 00000000..b219c479 Binary files /dev/null and b/docs/assets/images/tutorials/protobuf_message_doc.png differ diff --git a/docs/ble/_static/css/badge_only.css b/docs/ble/_static/css/badge_only.css index 7c789fcd..9cf316b6 100644 --- a/docs/ble/_static/css/badge_only.css +++ b/docs/ble/_static/css/badge_only.css @@ -1,4 +1,4 @@ /* badge_only.css/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). */ -/* This copyright was auto-generated on Tue Mar 5 22:34:21 UTC 2024 */ +/* This copyright was auto-generated on Tue Apr 9 19:25:33 UTC 2024 */ .clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/docs/ble/_static/css/rtd_sphinx_search.min.css b/docs/ble/_static/css/rtd_sphinx_search.min.css deleted file mode 100644 index b0391d8f..00000000 --- a/docs/ble/_static/css/rtd_sphinx_search.min.css +++ /dev/null @@ -1,4 +0,0 @@ -/* rtd_sphinx_search.min.css/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). */ -/* This copyright was auto-generated on Tue Mar 5 22:34:21 UTC 2024 */ - -@-webkit-keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.search__backdrop,.search__outer__wrapper{position:fixed;top:0;left:0;width:100%;height:100%;z-index:700}.search__backdrop{z-index:500;display:none;background-color:rgba(0,0,0,.502)}.search__outer{margin:auto;position:absolute;top:0;left:0;right:0;bottom:0;z-index:100000;height:80%;width:80%;max-height:1000px;max-width:1500px;padding:10px;overflow-y:scroll;border:1px solid #e0e0e0;line-height:1.875;background-color:#fcfcfc;-webkit-box-shadow:1px 3px 4px rgba(0,0,0,.09);box-shadow:1px 3px 4px rgba(0,0,0,.09);text-align:left}.search__outer::-webkit-scrollbar-track{border-radius:10px;background-color:#fcfcfc}.search__outer::-webkit-scrollbar{width:7px;height:7px;background-color:#fcfcfc}.search__outer::-webkit-scrollbar-thumb{border-radius:10px;background-color:#8f8f8f}.search__cross__img{width:15px;height:15px;margin:12px}.search__cross{position:absolute;top:0;right:0}.search__cross:hover{cursor:pointer}.search__outer__input{width:90%;height:30px;font-size:19px;outline:0;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#fcfcfc;border:0;border-bottom:1px solid #757575;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgNDUxIDQ1MSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDUxIDQ1MTsiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGc+DQoJPHBhdGggZD0iTTQ0Ny4wNSw0MjhsLTEwOS42LTEwOS42YzI5LjQtMzMuOCw0Ny4yLTc3LjksNDcuMi0xMjYuMUMzODQuNjUsODYuMiwyOTguMzUsMCwxOTIuMzUsMEM4Ni4yNSwwLDAuMDUsODYuMywwLjA1LDE5Mi4zDQoJCXM4Ni4zLDE5Mi4zLDE5Mi4zLDE5Mi4zYzQ4LjIsMCw5Mi4zLTE3LjgsMTI2LjEtNDcuMkw0MjguMDUsNDQ3YzIuNiwyLjYsNi4xLDQsOS41LDRzNi45LTEuMyw5LjUtNA0KCQlDNDUyLjI1LDQ0MS44LDQ1Mi4yNSw0MzMuMiw0NDcuMDUsNDI4eiBNMjYuOTUsMTkyLjNjMC05MS4yLDc0LjItMTY1LjMsMTY1LjMtMTY1LjNjOTEuMiwwLDE2NS4zLDc0LjIsMTY1LjMsMTY1LjMNCgkJcy03NC4xLDE2NS40LTE2NS4zLDE2NS40QzEwMS4xNSwzNTcuNywyNi45NSwyODMuNSwyNi45NSwxOTIuM3oiLz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjwvc3ZnPg0K);background-repeat:no-repeat;background-position:left;background-size:15px 15px;padding-left:25px}.search__outer__input:focus{outline:0}.search__outer .bar{position:relative;display:block;width:90%;margin-bottom:15px}.search__outer .bar:after,.search__outer .bar:before{content:"";height:2px;width:0;bottom:1px;position:absolute;background:#5264ae;-webkit-transition:.2s ease all;-o-transition:.2s ease all;transition:.2s ease all}.search__outer .bar:before{left:50%}.search__outer .bar:after{right:50%}.search__outer__input:focus~.bar:after,.search__outer__input:focus~.bar:before{width:50%}.search__result__box{padding:0 10px}.search__result__single{margin-top:10px;border-bottom:1px solid #e6e6e6}.outer_div_page_results:hover,.search__result__box .active{background-color:#f5f5f5}.search__error__box{color:#000;min-width:300px;font-weight:700}.outer_div_page_results{margin:5px 0;overflow:auto;padding:3px 5px}.search__result__single a{text-decoration:none;cursor:pointer}.search__result__title{display:inline-block;font-weight:500;margin-bottom:15px;margin-top:0;font-size:15px;color:#6ea0ec;border-bottom:1px solid #6ea0ec}.search__result__subheading{color:#000;font-weight:700;float:left;width:20%;font-size:15px;margin-right:10px;word-break:break-all;overflow-x:hidden}.search__result__content{text-decoration:none;color:#000;font-size:15px;display:block;margin:0;line-height:inherit;float:right;width:calc(80% - 15px);text-align:left}.search__outer span{font-style:normal}.search__outer .search__result__title span{background-color:#e5f6ff;padding-bottom:3px;border-bottom-color:#000}.search__outer .search__result__content span{background-color:#e5f6ff;border-bottom:1px solid #000}.search__result__subheading span{border-bottom:1px solid #000}.br-for-hits{display:block;content:"";margin-top:10px}.rtd_ui_search_subtitle{all:unset;color:inherit;font-size:85%}.rtd__search__credits{margin:auto;position:absolute;top:0;left:0;right:0;bottom:calc(-80% - 20px);width:80%;max-width:1500px;height:30px;overflow:hidden;background:#eee;z-index:100000;border:1px solid #eee;padding:5px 10px;text-align:center;color:#000}.rtd__search__credits a{color:#000;text-decoration:underline}.search__domain_role_name{font-size:80%;letter-spacing:1px}.search__filters{padding:0 10px}.search__filters li,.search__filters ul{display:-webkit-box;display:-ms-flexbox;display:flex}.search__filters ul{list-style:none;padding:0;margin:0}.search__filters li{-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-right:15px}.search__filters label{margin:auto}.search__filters .search__filters__title,.search__filters label{color:#000;font-size:15px}@media (max-width:670px){.rtd__search__credits{height:50px;bottom:calc(-80% - 40px);overflow:hidden}}@media (min-height:1250px){.rtd__search__credits{bottom:calc(-1000px - 30px)}}@media (max-width:630px){.search__result__content,.search__result__subheading{float:none;width:90%}} \ No newline at end of file diff --git a/docs/ble/_static/documentation_options.js b/docs/ble/_static/documentation_options.js index b9e0a3b4..38dc7ee0 100644 --- a/docs/ble/_static/documentation_options.js +++ b/docs/ble/_static/documentation_options.js @@ -1,5 +1,5 @@ /* documentation_options.js/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). */ -/* This copyright was auto-generated on Tue Mar 5 22:34:21 UTC 2024 */ +/* This copyright was auto-generated on Tue Apr 9 19:25:34 UTC 2024 */ const DOCUMENTATION_OPTIONS = { VERSION: '0.0.1', diff --git a/docs/ble/_static/jquery.js b/docs/ble/_static/jquery.js index 98a739b8..0b386427 100644 --- a/docs/ble/_static/jquery.js +++ b/docs/ble/_static/jquery.js @@ -1,5 +1,5 @@ /* jquery.js/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). */ -/* This copyright was auto-generated on Tue Mar 5 22:34:21 UTC 2024 */ +/* This copyright was auto-generated on Tue Apr 9 19:25:33 UTC 2024 */ /*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0=e.length?{done:!0}:{done:!1,value:e[n++]}},e:function(e){throw e},f:t}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,o=!0,l=!1;return{s:function(){r=e[Symbol.iterator]()},n:function(){var e=r.next();return o=e.done,e},e:function(e){l=!0,a=e},f:function(){try{o||null==r.return||r.return()}finally{if(l)throw a}}}}function _slicedToArray(e,t){return _arrayWithHoles(e)||_iterableToArrayLimit(e,t)||_unsupportedIterableToArray(e,t)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(e,t){if(e){if("string"==typeof e)return _arrayLikeToArray(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Map"===(r="Object"===r&&e.constructor?e.constructor.name:r)||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?_arrayLikeToArray(e,t):void 0}}function _arrayLikeToArray(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);rSearching ....",a.appendChild(e);return debounce(function(){updateUrl(),updateSearchBar();var e=t+"?"+new URLSearchParams(r).toString();fetch(e,{method:"GET"}).then(function(e){if(!e.ok)throw new Error;return e.json()}).then(function(e){var t;0
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t
  • Control
  • Operations
  • Setting IDs
  • diff --git a/docs/ble/features/query.html b/docs/ble/features/query.html index f9ced167..70ec8647 100644 --- a/docs/ble/features/query.html +++ b/docs/ble/features/query.html @@ -152,14 +152,14 @@
    - - - - - - - - - - \ No newline at end of file diff --git a/docs/ble/features/statuses.html b/docs/ble/features/statuses.html index facb4fbb..8adb3c5a 100644 --- a/docs/ble/features/statuses.html +++ b/docs/ble/features/statuses.html @@ -151,14 +151,14 @@
    • Control
    • Operations
    • Setting IDs
        @@ -253,6 +254,7 @@
      • Frames Per Second (3)
      • FOV (43)
      • Auto Off (59)
      • +
      • GPS (83)
      • Aspect Ratio (108)
      • Lens (121)
      • Lens (122)
      • @@ -291,12 +293,15 @@
      • Status IDs
        • Is the system’s internal battery present? (1)
        • Rough approximation of internal battery level in bars (or charging) (2)
        • +
        • Is an external battery connected? (3)
        • +
        • External battery power level in percent (4)
        • Is the system currently overheating? (6)
        • Is the camera busy? (8)
        • Is Quick Capture feature enabled? (9)
        • Is the system encoding right now? (10)
        • Is LCD lock active? (11)
        • When encoding video, this is the duration (seconds) of the video so far; 0 otherwise (13)
        • +
        • When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise (14)
        • Are Wireless Connections enabled? (17)
        • The pairing state of the camera (19)
        • The last type of pairing in which the camera was engaged (20)
        • @@ -314,6 +319,8 @@
        • Primary Storage Status (33)
        • How many photos can be taken with current settings before sdcard is full (34)
        • How many minutes of video can be captured with current settings before sdcard is full (35)
        • +
        • Total number of group photos on sdcard (36)
        • +
        • Total number of group videos on sdcard (37)
        • Total number of photos on sdcard (38)
        • Total number of videos on sdcard (39)
        • The current status of Over The Air (OTA) update (41)
        • @@ -326,6 +333,9 @@
        • The number of hilights in currently-encoding video (value is set to 0 when encoding stops) (58)
        • Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops) (59)
        • The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this (60)
        • +
        • The current state of camera analytics (61)
        • +
        • The size (units??) of the analytics file (62)
        • +
        • Is the camera currently in a contextual menu (e.g. Preferences)? (63)
        • How many minutes of Time Lapse Video can be captured with current settings before sdcard is full (64)
        • Liveview Exposure Select Mode (65)
        • Liveview Exposure Select: y-coordinate (percent) (66)
        • @@ -346,6 +356,8 @@
        • Rotational orientation of the camera (86)
        • Is this camera model capable of zooming while encoding? (88)
        • Current Flatmode ID (89)
        • +
        • Are current flatmode’s Protune settings factory default? (90)
        • +
        • Are system logs ready to be downloaded? (91)
        • Current Video Preset (ID) (93)
        • Current Photo Preset (ID) (94)
        • Current Time Lapse Preset (ID) (95)
        • @@ -362,6 +374,7 @@
        • Is Video Hindsight Capture Active? (106)
        • Scheduled Capture Preset ID (107)
        • Is Scheduled Capture set? (108)
        • +
        • Is the camera in the process of creating a custom preset? (109)
        • Display Mod Status (bitmasked) (110)
        • Does sdcard meet specified minimum write speed? (111)
        • Number of sdcard write speed errors since device booted (112)
        • @@ -407,11 +420,11 @@

          Statuses

          Status IDs

          Is the system’s internal battery present? (1)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b @@ -430,11 +443,11 @@

          Status IDs

          Rough approximation of internal battery level in bars (or charging) (2)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -460,13 +473,43 @@

          Status IDs +

          Is an external battery connected? (3)

          +https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11Black-ffe119 +https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b +

          ID

          + + + + + + + + + + + + + +

          ID

          Option Name

          0

          False

          1

          True

          +
          +
          +

          External battery power level in percent (4)

          +https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11Black-ffe119 +https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b +

          This is a percent value from 0-100.

          +

          Is the system currently overheating? (6)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b @@ -485,11 +528,11 @@

          Status IDs

          Is the camera busy? (8)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -508,11 +551,11 @@

          Status IDs

          Is Quick Capture feature enabled? (9)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -531,11 +574,11 @@

          Status IDs

          Is the system encoding right now? (10)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -554,11 +597,11 @@

          Status IDs

          Is LCD lock active? (11)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -577,19 +620,26 @@

          Status IDs

          When encoding video, this is the duration (seconds) of the video so far; 0 otherwise (13)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 +https://img.shields.io/badge/HERO11Black-ffe119 +https://img.shields.io/badge/HERO10Black-3cb44b https://img.shields.io/badge/HERO9Black-e6194b + +
          +

          When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise (14)

          +https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Are Wireless Connections enabled? (17)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -608,11 +658,11 @@

          Status IDs

          The pairing state of the camera (19)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -640,11 +690,11 @@

          Status IDs

          The last type of pairing in which the camera was engaged (20)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -669,18 +719,18 @@

          Status IDs

          Time since boot (milliseconds) of last successful pairing complete action (21)

          -https://img.shields.io/badge/HERO9Black-e6194b -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO11BlackMini-f58231 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          State of current scan for WiFi Access Points (22)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -708,19 +758,19 @@

          Status IDs

          Time since boot (milliseconds) that the WiFi Access Point scan completed (23)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          WiFi AP provisioning state (24)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -748,18 +798,18 @@

          Status IDs

          Wireless remote control version (26)

          -https://img.shields.io/badge/HERO9Black-e6194b -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO11BlackMini-f58231 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Is a wireless remote control connected? (27)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -778,44 +828,44 @@

          Status IDs

          Wireless Pairing State. Each bit contains state information (see WirelessPairingStateFlags) (28)

          -https://img.shields.io/badge/HERO9Black-e6194b -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO11BlackMini-f58231 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          SSID of the AP the camera is currently connected to. On BLE connection, value is big-endian byte-encoded int32 (29)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b -

          This is a string vlaue.

          +https://img.shields.io/badge/HERO9Black-e6194b +

          This is a string value.

          The camera’s WiFi SSID. On BLE connection, value is big-endian byte-encoded int32 (30)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b -

          This is a string vlaue.

          +https://img.shields.io/badge/HERO9Black-e6194b +

          This is a string value.

          The number of wireless devices connected to the camera (31)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Is Preview Stream enabled? (32)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -834,11 +884,11 @@

          Status IDs

          Primary Storage Status (33)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -872,42 +922,55 @@

          Status IDs

          How many photos can be taken with current settings before sdcard is full (34)

          -https://img.shields.io/badge/HERO9Black-e6194b -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          How many minutes of video can be captured with current settings before sdcard is full (35)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 +https://img.shields.io/badge/HERO11Black-ffe119 +https://img.shields.io/badge/HERO10Black-3cb44b https://img.shields.io/badge/HERO9Black-e6194b +
          +
          +

          Total number of group photos on sdcard (36)

          +https://img.shields.io/badge/HERO11Black-ffe119 +https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b +
          +
          +

          Total number of group videos on sdcard (37)

          +https://img.shields.io/badge/HERO11BlackMini-f58231 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Total number of photos on sdcard (38)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Total number of videos on sdcard (39)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          The current status of Over The Air (OTA) update (41)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -953,11 +1016,11 @@

          Status IDs

          Is there a pending request to cancel a firmware update download? (42)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -976,11 +1039,11 @@

          Status IDs

          Is locate camera feature active? (45)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -999,27 +1062,27 @@

          Status IDs

          The current timelapse interval countdown value (e.g. 5…4…3…2…1…) (49)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Remaining space on the sdcard in Kilobytes (54)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Is preview stream supported in current recording/mode/secondary-stream? (55)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1038,50 +1101,117 @@

          Status IDs

          WiFi signal strength in bars (56)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          The number of hilights in currently-encoding video (value is set to 0 when encoding stops) (58)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops) (59)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this (60)

          +https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11BlackMini-f58231 https://img.shields.io/badge/HERO11Black-ffe119 +https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b +
          +
          +

          The current state of camera analytics (61)

          https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 +https://img.shields.io/badge/HERO11Black-ffe119 +https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b +

          ID

          + + + + + + + + + + + + + + + + +

          ID

          Option Name

          0

          Not ready

          1

          Ready

          2

          On connect

          +
          +
          +

          The size (units??) of the analytics file (62)

          +https://img.shields.io/badge/HERO11BlackMini-f58231 +https://img.shields.io/badge/HERO11Black-ffe119 +https://img.shields.io/badge/HERO10Black-3cb44b https://img.shields.io/badge/HERO9Black-e6194b + + + + + + + + + + + +

          ID

          Option Name

          0

          Value hard-coded by BOSS in libgpCtrlD/src/camera_status.cpp

          +
          +
          +

          Is the camera currently in a contextual menu (e.g. Preferences)? (63)

          +https://img.shields.io/badge/HERO11BlackMini-f58231 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b + + + + + + + + + + + + + + +

          ID

          Option Name

          0

          False

          1

          True

          How many minutes of Time Lapse Video can be captured with current settings before sdcard is full (64)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Liveview Exposure Select Mode (65)

          -https://img.shields.io/badge/HERO9Black-e6194b -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b @@ -1106,27 +1236,27 @@

          Status IDs

          Liveview Exposure Select: y-coordinate (percent) (66)

          -https://img.shields.io/badge/HERO9Black-e6194b -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          This is a percent value from 0-100.

          Liveview Exposure Select: y-coordinate (percent) (67)

          -https://img.shields.io/badge/HERO9Black-e6194b -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          This is a percent value from 0-100.

          Does the camera currently have a GPS lock? (68)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1145,11 +1275,11 @@

          Status IDs

          Is the camera in AP Mode? (69)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1168,20 +1298,20 @@

          Status IDs

          Internal battery level (percent) (70)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          This is a percent value from 0-100.

          Microphone Accessory status (74)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1203,20 +1333,20 @@

          Status IDs

          Digital Zoom level (percent) (75)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          This is a percent value from 0-100.

          Wireless Band (76)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1235,11 +1365,11 @@

          Status IDs

          Is Digital Zoom feature available? (77)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1258,11 +1388,11 @@

          Status IDs

          Are current video settings mobile friendly? (related to video compression and frame rate) (78)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1281,8 +1411,8 @@

          Status IDs

          Is the camera currently in First Time Use (FTU) UI flow? (79)

          -https://img.shields.io/badge/HERO9Black-e6194b https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1301,11 +1431,11 @@

          Status IDs

          Is 5GHz wireless band available? (81)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1324,11 +1454,11 @@

          Status IDs

          Is the system fully booted and ready to accept commands? (82)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1347,11 +1477,11 @@

          Status IDs

          Is the internal battery charged sufficiently to start Over The Air (OTA) update? (83)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1370,11 +1500,11 @@

          Status IDs

          Is the camera getting too cold to continue recording? (85)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1393,11 +1523,11 @@

          Status IDs

          Rotational orientation of the camera (86)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1422,11 +1552,11 @@

          Status IDs

          Is this camera model capable of zooming while encoding? (88)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1445,78 +1575,124 @@

          Status IDs

          Current Flatmode ID (89)

          +https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11BlackMini-f58231 https://img.shields.io/badge/HERO11Black-ffe119 +https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b + +
          +

          Are current flatmode’s Protune settings factory default? (90)

          https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 +https://img.shields.io/badge/HERO11Black-ffe119 +https://img.shields.io/badge/HERO10Black-3cb44b https://img.shields.io/badge/HERO9Black-e6194b +

          ID

          + + + + + + + + + + + + + +

          ID

          Option Name

          0

          False

          1

          True

          +
          +
          +

          Are system logs ready to be downloaded? (91)

          +https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11BlackMini-f58231 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b + + + + + + + + + + + + + + +

          ID

          Option Name

          0

          False

          1

          True

          Current Video Preset (ID) (93)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Current Photo Preset (ID) (94)

          -https://img.shields.io/badge/HERO9Black-e6194b -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Current Time Lapse Preset (ID) (95)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Current Preset Group (ID) (corresponds to ui_mode_groups in settings.json) (96)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Current Preset (ID) (97)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Preset Modified Status, which contains an event ID and a Preset (Group) ID (98)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          The number of Live Bursts can be captured with current settings before sdcard is full (99)

          -https://img.shields.io/badge/HERO9Black-e6194b https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Total number of Live Bursts on sdcard (100)

          -https://img.shields.io/badge/HERO9Black-e6194b https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Is Capture Delay currently active (i.e. counting down)? (101)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b @@ -1535,11 +1711,11 @@

          Status IDs

          Media Mod state (102)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1561,11 +1737,11 @@

          Status IDs

          Time Warp Speed (103)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1617,8 +1793,8 @@

          Status IDs

          Is the system’s Linux core active? (104)

          -https://img.shields.io/badge/HERO9Black-e6194b https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1637,11 +1813,11 @@

          Status IDs

          Camera lens type (reflects changes to setting 162 or setting 189) (105)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1663,10 +1839,10 @@

          Status IDs

          Is Video Hindsight Capture Active? (106)

          -https://img.shields.io/badge/HERO9Black-e6194b -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1685,17 +1861,39 @@

          Status IDs

          Scheduled Capture Preset ID (107)

          -https://img.shields.io/badge/HERO9Black-e6194b -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          Is Scheduled Capture set? (108)

          -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11Black-ffe119 +https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b +

          ID

          + + + + + + + + + + + + + +

          ID

          Option Name

          0

          False

          1

          True

          +
          +
          +

          Is the camera in the process of creating a custom preset? (109)

          https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b @@ -1714,10 +1912,10 @@

          Status IDs

          Display Mod Status (bitmasked) (110)

          -https://img.shields.io/badge/HERO9Black-e6194b -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          ID

          @@ -1754,9 +1952,9 @@

          Status IDs

          Does sdcard meet specified minimum write speed? (111)

          +https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 https://img.shields.io/badge/HERO11Black-ffe119 -https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO10Black-3cb44b

          ID

          @@ -1776,18 +1974,18 @@

          Status IDs

          Number of sdcard write speed errors since device booted (112)

          +https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 https://img.shields.io/badge/HERO11Black-ffe119 -https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO10Black-3cb44b

          Is Turbo Transfer active? (113)

          -https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 -https://img.shields.io/badge/HERO9Black-e6194b +https://img.shields.io/badge/HERO11Black-ffe119 https://img.shields.io/badge/HERO10Black-3cb44b +https://img.shields.io/badge/HERO9Black-e6194b

          @@ -1806,9 +2004,9 @@

          Status IDs

          Camera control status ID (114)

          +https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 https://img.shields.io/badge/HERO11Black-ffe119 -https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO10Black-3cb44b

          ID

          @@ -1831,9 +2029,9 @@

          Status IDs

          Is the camera connected to a PC via USB? (115)

          +https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 https://img.shields.io/badge/HERO11Black-ffe119 -https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO10Black-3cb44b

          @@ -1853,9 +2051,9 @@

          Status IDs

          Camera control over USB state (116)

          +https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 https://img.shields.io/badge/HERO11Black-ffe119 -https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO10Black-3cb44b

          @@ -1875,9 +2073,9 @@

          Status IDs

          Total SD card capacity in Kilobytes (117)

          +https://img.shields.io/badge/HERO12Black-911eb4 https://img.shields.io/badge/HERO11BlackMini-f58231 https://img.shields.io/badge/HERO11Black-ffe119 -https://img.shields.io/badge/HERO12Black-911eb4 diff --git a/docs/ble/genindex.html b/docs/ble/genindex.html index 630df429..561e18c9 100644 --- a/docs/ble/genindex.html +++ b/docs/ble/genindex.html @@ -149,14 +149,14 @@

          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Setting 3 (Frames Per Second)(features/settings) + Setting 123 (Time Lapse Digital Lenses)(features/settings) + Setting 167 (HindSight)(features/settings) + Setting 2 (Resolution)(features/settings) + Setting 190 (Max Lens Mod Enable)(features/settings) + Setting 171 (Interval)(features/settings) + Setting 135 (Hypersmooth)(features/settings) + Setting 182 (Bit Rate)(features/settings) + Setting 172 (Duration)(features/settings) + Setting 183 (Bit Depth)(features/settings) + Setting 191 (Photo Mode)(features/settings) + Setting 179 (Trail Length)(features/settings) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          - Connect to Provisioned Access Point (features/access_points) + connect to provisioned access point (features/access_points) Operation
          - Connect to a New Access Point (features/access_points) + connect to a new access point (features/access_points) Operation
          - Clear COHN Certificate (features/cohn) + clear cohn certificate (features/cohn) Operation
          - Create COHN Certificate (features/cohn) + create cohn certificate (features/cohn) Operation
           
          + e
          + EnumCOHNStatus (protocol/protobuf) + Proto
          + EnumCOHNNetworkState (protocol/protobuf) + Proto
          + EnumLens (protocol/protobuf) + Proto
          + EnumLiveStreamError (protocol/protobuf) + Proto
          + EnumLiveStreamStatus (protocol/protobuf) + Proto
          + EnumRegisterLiveStreamStatus (protocol/protobuf) + Proto
          + EnumWindowSize (protocol/protobuf) + Proto
          + EnumProvisioning (protocol/protobuf) + Proto
          + EnumScanning (protocol/protobuf) + Proto
          + EnumScanEntryFlags (protocol/protobuf) + Proto
          + EnumFlatMode (protocol/protobuf) + Proto
          + EnumPresetGroup (protocol/protobuf) + Proto
          + EnumPresetGroupIcon (protocol/protobuf) + Proto
          + EnumPresetIcon (protocol/protobuf) + Proto
          + EnumPresetTitle (protocol/protobuf) + Proto
          + EnumRegisterPresetStatus (protocol/protobuf) + Proto
          + EnumResultGeneric (protocol/protobuf) + Proto
          + EnumCameraControlStatus (protocol/protobuf) + Proto
           
          g
          - Get AP Scan Results (features/access_points) + get ap scan results (features/access_points) Operation
          - Get COHN Certificate (features/cohn) + get cohn certificate (features/cohn) Operation
          - Get COHN Status (features/cohn) + get cohn status (features/cohn) Operation
          - Get Livestream Status (features/live_streaming) + get livestream status (features/live_streaming) Operation
          - Get Available Presets (features/presets) + get available presets (features/presets) Operation
          - Get Open GoPro Version (features/query) + get date time (features/query) Operation
          - Get Date Time (features/query) + get hardware info (features/query) Operation
          - Get Hardware Info (features/query) + get local date time (features/query) Operation
          - Get Local Date Time (features/query) + get last captured media (features/query) Operation
          - Get Last Captured Media (features/query) + get open gopro version (features/query) Operation
          - Get Setting Values (features/query) + get setting values (features/query) Operation
          - Get Status Values (features/query) + get status values (features/query) Operation
          - Get Setting Capabilities (features/query) + get setting capabilities (features/query) Operation
           
          @@ -516,7 +626,7 @@

          operation index

          - Hilight Moment (features/hilights) + hilight moment (features/hilights) Operation
           
          @@ -524,7 +634,7 @@

          operation index

          - Keep Alive (features/control) + keep alive (features/control) Operation
           
          @@ -532,116 +642,1055 @@

          operation index

          - Load Preset (features/presets) + load preset (features/presets) Operation
          - Load Preset Group (features/presets) + load preset group (features/presets) Operation
           
          + m
          + Media (protocol/protobuf) + Proto
           
          + n
          + NotifyCOHNStatus (protocol/protobuf) + Proto
          + NotifyLiveStreamStatus (protocol/protobuf) + Proto
          + NotifProvisioningState (protocol/protobuf) + Proto
          + NotifStartScanning (protocol/protobuf) + Proto
          + NotifyPresetStatus (protocol/protobuf) + Proto
           
          + p
          + Preset (protocol/protobuf) + Proto
          + PresetGroup (protocol/protobuf) + Proto
          + PresetSetting (protocol/protobuf) + Proto
           
          r
          - Register for Setting Value Updates (features/query) + register for setting value updates (features/query) Operation
          - Register for Status Value Updates (features/query) + register for status value updates (features/query) Operation
          - Register for Setting Capability Updates (features/query) + register for setting capability updates (features/query) Operation
          + RequestGetCOHNStatus (protocol/protobuf) + Proto
          + RequestCreateCOHNCert (protocol/protobuf) + Proto
          + RequestClearCOHNCert (protocol/protobuf) + Proto
          + RequestCOHNCert (protocol/protobuf) + Proto
          + ResponseCOHNCert (protocol/protobuf) + Proto
          + RequestSetCOHNSetting (protocol/protobuf) + Proto
          + RequestGetLiveStreamStatus (protocol/protobuf) + Proto
          + RequestSetLiveStreamMode (protocol/protobuf) + Proto
          + RequestGetLastCapturedMedia (protocol/protobuf) + Proto
          + ResponseLastCapturedMedia (protocol/protobuf) + Proto
          + RequestConnect (protocol/protobuf) + Proto
          + RequestConnectNew (protocol/protobuf) + Proto
          + RequestGetApEntries (protocol/protobuf) + Proto
          + RequestReleaseNetwork (protocol/protobuf) + Proto
          + RequestStartScan (protocol/protobuf) + Proto
          + ResponseConnect (protocol/protobuf) + Proto
          + ResponseConnectNew (protocol/protobuf) + Proto
          + ResponseGetApEntries (protocol/protobuf) + Proto
          + ResponseStartScanning (protocol/protobuf) + Proto
          + RequestCustomPresetUpdate (protocol/protobuf) + Proto
          + RequestGetPresetStatus (protocol/protobuf) + Proto
          + ResponseGeneric (protocol/protobuf) + Proto
          + RequestSetCameraControlStatus (protocol/protobuf) + Proto
          + RequestSetTurboActive (protocol/protobuf) + Proto
           
          s
          - Scan for Access Points (features/access_points) - Operation
          + Setting
          - Set COHN Setting (features/cohn) - Operation
          + Setting
          - Set Analytics (features/control) - Operation
          + Setting
          - Set AP Control (features/control) - Operation
          + Setting
          - Set Camera Control (features/control) - Operation
          + Setting
          - Set Date Time (features/control) - Operation
          + Setting
          - Set Local Date Time (features/control) - Operation
          + Setting
          - Set Shutter (features/control) - Operation
          + Setting
          - Set Turbo Transfer (features/control) - Operation
          + Setting
          - Sleep (features/control) - Operation
          + Setting
          - Set Livestream Mode (features/live_streaming) - Operation
          + Setting
          - Set Setting (features/settings) - Operation
          + Setting
          + Setting 192 (Aspect Ratio) (features/settings) + Setting
          + Setting 43 (Webcam Digital Lenses) (features/settings) + Setting
          + Setting 128 (Media Format) (features/settings) + Setting
          + Setting 186 (Video Mode) (features/settings) + Setting
          + Setting 150 (Horizon Leveling) (features/settings) + Setting
          + Setting 59 (Auto Power Down) (features/settings) + Setting
          + Setting 184 (Profiles) (features/settings) + Setting
          + Setting 122 (Lens) (features/settings) + Setting
          + Setting 134 (Anti-Flicker) (features/settings) + Setting
          + Setting 108 (Aspect Ratio) (features/settings) + Setting
          + Setting 151 (Horizon Leveling) (features/settings) + Setting
          + Setting 162 (Max Lens) (features/settings) + Setting
          + Setting 180 (Video Mode) (features/settings) + Setting
          + Setting 193 (Framing) (features/settings) + Setting
          + Setting 189 (Max Lens Mod) (features/settings) + Setting
          + Setting 187 (Lapse Mode) (features/settings) + Setting
          + Setting 121 (Lens) (features/settings) + Setting
          + Setting 176 (Easy Mode Speed) (features/settings) + Setting
          + Setting 178 (Wireless Band) (features/settings) + Setting
          + Setting 177 (Enable Night Photo) (features/settings) + Setting
          + Setting 173 (Video Performance Mode) (features/settings) + Setting
          + Setting 83 (GPS) (features/settings) + Setting
          + Setting 175 (Controls) (features/settings) + Setting
          + Status 2 (Rough approximation of internal battery level in bars (or charging)) (features/statuses) + Status
          + Status 98 (Preset Modified Status, which contains an event ID and a Preset (Group) ID) (features/statuses) + Status
          + Status 32 (Is Preview Stream enabled?) (features/statuses) + Status
          + Status 99 (The number of Live Bursts can be captured with current settings before sdcard is full) (features/statuses) + Status
          + Status 30 (The camera's WiFi SSID. On BLE connection, value is big-endian byte-encoded int32) (features/statuses) + Status
          + Status 49 (The current timelapse interval countdown value (e.g. 5...4...3...2...1...)) (features/statuses) + Status
          + Status 100 (Total number of Live Bursts on sdcard) (features/statuses) + Status
          + Status 14 (When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise) (features/statuses) + Status
          + Status 65 (Liveview Exposure Select Mode) (features/statuses) + Status
          + Status 84 (Current Capture Delay value (HERO7 only)) (features/statuses) + Status
          + Status 105 (Camera lens type (reflects changes to setting 162 or setting 189)) (features/statuses) + Status
          + Status 107 (Scheduled Capture Preset ID) (features/statuses) + Status
          + Status 31 (The number of wireless devices connected to the camera) (features/statuses) + Status
          + Status 35 (How many minutes of video can be captured with current settings before sdcard is full) (features/statuses) + Status
          + Status 23 (Time since boot (milliseconds) that the WiFi Access Point scan completed) (features/statuses) + Status
          + Status 67 (Liveview Exposure Select: y-coordinate (percent)) (features/statuses) + Status
          + Status 10 (Is the system encoding right now?) (features/statuses) + Status
          + Status 46 (Are Video Protune settings currently factory default?) (features/statuses) + Status
          + Status 28 (Wireless Pairing State. Each bit contains state information (see WirelessPairingStateFlags)) (features/statuses) + Status
          + Status 78 (Are current video settings mobile friendly? (related to video compression and frame rate)) (features/statuses) + Status
          + Status 64 (How many minutes of Time Lapse Video can be captured with current settings before sdcard is full) (features/statuses) + Status
          + Status 5 (Unused) (features/statuses) + Status
          + Status 68 (Does the camera currently have a GPS lock?) (features/statuses) + Status
          + Status 6 (Is the system currently overheating?) (features/statuses) + Status
          + Status 18 (Unused) (features/statuses) + Status
          + Status 63 (Is the camera currently in a contextual menu (e.g. Preferences)?) (features/statuses) + Status
          + Status 72 (The current photo group flatmode (id)) (features/statuses) + Status
          + Status 114 (Camera control status ID) (features/statuses) + Status
          + Status 29 (SSID of the AP the camera is currently connected to. On BLE connection, value is big-endian byte-encoded int32) (features/statuses) + Status
          + Status 96 (Current Preset Group (ID) (corresponds to ui_mode_groups in settings.json)) (features/statuses) + Status
          + Status 92 (Is Timewarp 1x active?) (features/statuses) + Status
          + Status 19 (The pairing state of the camera) (features/statuses) + Status
          + Status 95 (Current Time Lapse Preset (ID)) (features/statuses) + Status
          + Status 60 (The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this) (features/statuses) + Status
          + Status 58 (The number of hilights in currently-encoding video (value is set to 0 when encoding stops)) (features/statuses) + Status
          + Status 73 (The current timelapse group flatmode (id)) (features/statuses) + Status
          + Status 83 (Is the internal battery charged sufficiently to start Over The Air (OTA) update?) (features/statuses) + Status
          + Status 81 (Is 5GHz wireless band available?) (features/statuses) + Status
          + Status 110 (Display Mod Status (bitmasked)) (features/statuses) + Status
          + Status 116 (Camera control over USB state) (features/statuses) + Status
          + Status 50 (Unused) (features/statuses) + Status
          + Status 56 (WiFi signal strength in bars) (features/statuses) + Status
          + Status 85 (Is the camera getting too cold to continue recording?) (features/statuses) + Status
          + Status 69 (Is the camera in AP Mode?) (features/statuses) + Status
          + Status 93 (Current Video Preset (ID)) (features/statuses) + Status
          + Status 76 (Wireless Band) (features/statuses) + Status
          + Status 111 (Does sdcard meet specified minimum write speed?) (features/statuses) + Status
          + Status 117 (Total SD card capacity in Kilobytes) (features/statuses) + Status
          + Status 16 ((DEPRECATED) Broadcast B-Status) (features/statuses) + Status
          + Status 87 (Can camera use high resolution/fps (based on temperature)? (HERO7 Silver/White only)) (features/statuses) + Status
          + Status 86 (Rotational orientation of the camera) (features/statuses) + Status
          + Status 61 (The current state of camera analytics) (features/statuses) + Status
          + Status 101 (Is Capture Delay currently active (i.e. counting down)?) (features/statuses) + Status
          + Status 27 (Is a wireless remote control connected?) (features/statuses) + Status
          + Status 80 (Secondary Storage Status (exclusive to Superbank)) (features/statuses) + Status
          + Status 22 (State of current scan for WiFi Access Points) (features/statuses) + Status
          + Status 44 (Current submode (deprecated in HERO8)) (features/statuses) + Status
          + Status 108 (Is Scheduled Capture set?) (features/statuses) + Status
          + Status 75 (Digital Zoom level (percent)) (features/statuses) + Status
          + Status 103 (Time Warp Speed) (features/statuses) + Status
          + Status 51 (Unused) (features/statuses) + Status
          + Status 25 (Unused) (features/statuses) + Status
          + Status 13 (When encoding video, this is the duration (seconds) of the video so far; 0 otherwise) (features/statuses) + Status
          + Status 89 (Current Flatmode ID) (features/statuses) + Status
          + Status 4 (External battery power level in percent) (features/statuses) + Status
          + Status 91 (Are system logs ready to be downloaded?) (features/statuses) + Status
          + Status 88 (Is this camera model capable of zooming while encoding?) (features/statuses) + Status
          + Status 37 (Total number of group videos on sdcard) (features/statuses) + Status
          + Status 113 (Is Turbo Transfer active?) (features/statuses) + Status
          + Status 39 (Total number of videos on sdcard) (features/statuses) + Status
          + Status 41 (The current status of Over The Air (OTA) update) (features/statuses) + Status
          + Status 15 ((DEPRECATED) Number of Broadcast viewers) (features/statuses) + Status
          + Status 104 (Is the system's Linux core active?) (features/statuses) + Status
          + Status 34 (How many photos can be taken with current settings before sdcard is full) (features/statuses) + Status
          + Status 8 (Is the camera busy?) (features/statuses) + Status
          + Status 20 (The last type of pairing in which the camera was engaged) (features/statuses) + Status
          + Status 21 (Time since boot (milliseconds) of last successful pairing complete action) (features/statuses) + Status
          + Status 38 (Total number of photos on sdcard) (features/statuses) + Status
          + Status 24 (WiFi AP provisioning state) (features/statuses) + Status
          + Status 71 (The current video group flatmode (id)) (features/statuses) + Status
          + Status 47 (Are Photo Protune settings currently factory default?) (features/statuses) + Status
          + Status 17 (Are Wireless Connections enabled?) (features/statuses) + Status
          + Status 48 (Are Multishot Protune settings currently factory default?) (features/statuses) + Status
          + Status 106 (Is Video Hindsight Capture Active?) (features/statuses) + Status
          + Status 94 (Current Photo Preset (ID)) (features/statuses) + Status
          + Status 74 (Microphone Accessory status) (features/statuses) + Status
          + Status 3 (Is an external battery connected?) (features/statuses) + Status
          + Status 26 (Wireless remote control version) (features/statuses) + Status
          + Status 55 (Is preview stream supported in current recording/mode/secondary-stream?) (features/statuses) + Status
          + Status 45 (Is locate camera feature active?) (features/statuses) + Status
          + Status 90 (Are current flatmode's Protune settings factory default?) (features/statuses) + Status
          + Status 33 (Primary Storage Status) (features/statuses) + Status
          + Status 109 (Is the camera in the process of creating a custom preset?) (features/statuses) + Status
          + Status 112 (Number of sdcard write speed errors since device booted) (features/statuses) + Status
          + Status 97 (Current Preset (ID)) (features/statuses) + Status
          + Status 77 (Is Digital Zoom feature available?) (features/statuses) + Status
          + Status 7 (Unused) (features/statuses) + Status
          + Status 1 (Is the system's internal battery present?) (features/statuses) + Status
          + Status 52 (Unused) (features/statuses) + Status
          + Status 66 (Liveview Exposure Select: y-coordinate (percent)) (features/statuses) + Status
          + Status 70 (Internal battery level (percent)) (features/statuses) + Status
          + Status 102 (Media Mod state) (features/statuses) + Status
          + Status 40 (Current date/time (format: %YY%mm%dd%HH%MM%SS, all values in hex)) (features/statuses) + Status
          + Status 53 (Unused) (features/statuses) + Status
          + Status 79 (Is the camera currently in First Time Use (FTU) UI flow?) (features/statuses) + Status
          + Status 12 (Unused) (features/statuses) + Status
          + Status 57 (Time in milliseconds since system was booted) (features/statuses) + Status
          + Status 43 (Current mode group (deprecated in HERO8)) (features/statuses) + Status
          + Status 62 (The size (units??) of the analytics file) (features/statuses) + Status
          + Status 115 (Is the camera connected to a PC via USB?) (features/statuses) + Status
          + Status 11 (Is LCD lock active?) (features/statuses) + Status
          + Status 54 (Remaining space on the sdcard in Kilobytes) (features/statuses) + Status
          + Status 36 (Total number of group photos on sdcard) (features/statuses) + Status
          + Status 82 (Is the system fully booted and ready to accept commands?) (features/statuses) + Status
          + Status 9 (Is Quick Capture feature enabled?) (features/statuses) + Status
          + Status 59 (Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops)) (features/statuses) + Status
          + Status 42 (Is there a pending request to cancel a firmware update download?) (features/statuses) + Status
          + scan for access points (features/access_points) + Operation
          + set cohn setting (features/cohn) + Operation
          + set analytics (features/control) + Operation
          + set ap control (features/control) + Operation
          + set camera control (features/control) + Operation
          + set date time (features/control) + Operation
          + set local date time (features/control) + Operation
          + set shutter (features/control) + Operation
          + set turbo transfer (features/control) + Operation
          + sleep (features/control) + Operation
          + set livestream mode (features/live_streaming) + Operation
          + set setting (features/settings) + Operation
          + ScanEntry (protocol/protobuf) + Proto
           
          u
          - Update Custom Preset (features/presets) + update custom preset (features/presets) Operation
          - Unregister for Setting Value Updates (features/query) + unregister for setting value updates (features/query) Operation
          - Unregister for Status Value Updates (features/query) + unregister for status value updates (features/query) Operation
          - Unregister for Setting Capability Updates (features/query) + unregister for setting capability updates (features/query) Operation
          diff --git a/docs/ble/protocol.html b/docs/ble/protocol.html index da40f548..c28c200f 100644 --- a/docs/ble/protocol.html +++ b/docs/ble/protocol.html @@ -152,14 +152,14 @@
          • Control
          • Operations
          • Setting IDs
              @@ -254,6 +255,7 @@
            • Frames Per Second (3)
            • FOV (43)
            • Auto Off (59)
            • +
            • GPS (83)
            • Aspect Ratio (108)
            • Lens (121)
            • Lens (122)
            • @@ -292,12 +294,15 @@
            • Status IDs
              • Is the system’s internal battery present? (1)
              • Rough approximation of internal battery level in bars (or charging) (2)
              • +
              • Is an external battery connected? (3)
              • +
              • External battery power level in percent (4)
              • Is the system currently overheating? (6)
              • Is the camera busy? (8)
              • Is Quick Capture feature enabled? (9)
              • Is the system encoding right now? (10)
              • Is LCD lock active? (11)
              • When encoding video, this is the duration (seconds) of the video so far; 0 otherwise (13)
              • +
              • When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise (14)
              • Are Wireless Connections enabled? (17)
              • The pairing state of the camera (19)
              • The last type of pairing in which the camera was engaged (20)
              • @@ -315,6 +320,8 @@
              • Primary Storage Status (33)
              • How many photos can be taken with current settings before sdcard is full (34)
              • How many minutes of video can be captured with current settings before sdcard is full (35)
              • +
              • Total number of group photos on sdcard (36)
              • +
              • Total number of group videos on sdcard (37)
              • Total number of photos on sdcard (38)
              • Total number of videos on sdcard (39)
              • The current status of Over The Air (OTA) update (41)
              • @@ -327,6 +334,9 @@
              • The number of hilights in currently-encoding video (value is set to 0 when encoding stops) (58)
              • Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops) (59)
              • The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this (60)
              • +
              • The current state of camera analytics (61)
              • +
              • The size (units??) of the analytics file (62)
              • +
              • Is the camera currently in a contextual menu (e.g. Preferences)? (63)
              • How many minutes of Time Lapse Video can be captured with current settings before sdcard is full (64)
              • Liveview Exposure Select Mode (65)
              • Liveview Exposure Select: y-coordinate (percent) (66)
              • @@ -347,6 +357,8 @@
              • Rotational orientation of the camera (86)
              • Is this camera model capable of zooming while encoding? (88)
              • Current Flatmode ID (89)
              • +
              • Are current flatmode’s Protune settings factory default? (90)
              • +
              • Are system logs ready to be downloaded? (91)
              • Current Video Preset (ID) (93)
              • Current Photo Preset (ID) (94)
              • Current Time Lapse Preset (ID) (95)
              • @@ -363,6 +375,7 @@
              • Is Video Hindsight Capture Active? (106)
              • Scheduled Capture Preset ID (107)
              • Is Scheduled Capture set? (108)
              • +
              • Is the camera in the process of creating a custom preset? (109)
              • Display Mod Status (bitmasked) (110)
              • Does sdcard meet specified minimum write speed? (111)
              • Number of sdcard write speed errors since device booted (112)
              • diff --git a/docs/ble/protocol/ble_setup.html b/docs/ble/protocol/ble_setup.html index 0d59c878..f39b316c 100644 --- a/docs/ble/protocol/ble_setup.html +++ b/docs/ble/protocol/ble_setup.html @@ -152,14 +152,14 @@
                • Control
                • Operations
                • Setting IDs
                    @@ -254,6 +255,7 @@
                  • Frames Per Second (3)
                  • FOV (43)
                  • Auto Off (59)
                  • +
                  • GPS (83)
                  • Aspect Ratio (108)
                  • Lens (121)
                  • Lens (122)
                  • @@ -292,12 +294,15 @@
                  • Status IDs
                    • Is the system’s internal battery present? (1)
                    • Rough approximation of internal battery level in bars (or charging) (2)
                    • +
                    • Is an external battery connected? (3)
                    • +
                    • External battery power level in percent (4)
                    • Is the system currently overheating? (6)
                    • Is the camera busy? (8)
                    • Is Quick Capture feature enabled? (9)
                    • Is the system encoding right now? (10)
                    • Is LCD lock active? (11)
                    • When encoding video, this is the duration (seconds) of the video so far; 0 otherwise (13)
                    • +
                    • When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise (14)
                    • Are Wireless Connections enabled? (17)
                    • The pairing state of the camera (19)
                    • The last type of pairing in which the camera was engaged (20)
                    • @@ -315,6 +320,8 @@
                    • Primary Storage Status (33)
                    • How many photos can be taken with current settings before sdcard is full (34)
                    • How many minutes of video can be captured with current settings before sdcard is full (35)
                    • +
                    • Total number of group photos on sdcard (36)
                    • +
                    • Total number of group videos on sdcard (37)
                    • Total number of photos on sdcard (38)
                    • Total number of videos on sdcard (39)
                    • The current status of Over The Air (OTA) update (41)
                    • @@ -327,6 +334,9 @@
                    • The number of hilights in currently-encoding video (value is set to 0 when encoding stops) (58)
                    • Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops) (59)
                    • The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this (60)
                    • +
                    • The current state of camera analytics (61)
                    • +
                    • The size (units??) of the analytics file (62)
                    • +
                    • Is the camera currently in a contextual menu (e.g. Preferences)? (63)
                    • How many minutes of Time Lapse Video can be captured with current settings before sdcard is full (64)
                    • Liveview Exposure Select Mode (65)
                    • Liveview Exposure Select: y-coordinate (percent) (66)
                    • @@ -347,6 +357,8 @@
                    • Rotational orientation of the camera (86)
                    • Is this camera model capable of zooming while encoding? (88)
                    • Current Flatmode ID (89)
                    • +
                    • Are current flatmode’s Protune settings factory default? (90)
                    • +
                    • Are system logs ready to be downloaded? (91)
                    • Current Video Preset (ID) (93)
                    • Current Photo Preset (ID) (94)
                    • Current Time Lapse Preset (ID) (95)
                    • @@ -363,6 +375,7 @@
                    • Is Video Hindsight Capture Active? (106)
                    • Scheduled Capture Preset ID (107)
                    • Is Scheduled Capture set? (108)
                    • +
                    • Is the camera in the process of creating a custom preset? (109)
                    • Display Mod Status (bitmasked) (110)
                    • Does sdcard meet specified minimum write speed? (111)
                    • Number of sdcard write speed errors since device booted (112)
                    • diff --git a/docs/ble/protocol/data_protocol.html b/docs/ble/protocol/data_protocol.html index 38c9548b..77eada66 100644 --- a/docs/ble/protocol/data_protocol.html +++ b/docs/ble/protocol/data_protocol.html @@ -152,14 +152,14 @@
                      • Control
                      • Operations
                      • Setting IDs
                          @@ -254,6 +255,7 @@
                        • Frames Per Second (3)
                        • FOV (43)
                        • Auto Off (59)
                        • +
                        • GPS (83)
                        • Aspect Ratio (108)
                        • Lens (121)
                        • Lens (122)
                        • @@ -292,12 +294,15 @@
                        • Status IDs
                          • Is the system’s internal battery present? (1)
                          • Rough approximation of internal battery level in bars (or charging) (2)
                          • +
                          • Is an external battery connected? (3)
                          • +
                          • External battery power level in percent (4)
                          • Is the system currently overheating? (6)
                          • Is the camera busy? (8)
                          • Is Quick Capture feature enabled? (9)
                          • Is the system encoding right now? (10)
                          • Is LCD lock active? (11)
                          • When encoding video, this is the duration (seconds) of the video so far; 0 otherwise (13)
                          • +
                          • When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise (14)
                          • Are Wireless Connections enabled? (17)
                          • The pairing state of the camera (19)
                          • The last type of pairing in which the camera was engaged (20)
                          • @@ -315,6 +320,8 @@
                          • Primary Storage Status (33)
                          • How many photos can be taken with current settings before sdcard is full (34)
                          • How many minutes of video can be captured with current settings before sdcard is full (35)
                          • +
                          • Total number of group photos on sdcard (36)
                          • +
                          • Total number of group videos on sdcard (37)
                          • Total number of photos on sdcard (38)
                          • Total number of videos on sdcard (39)
                          • The current status of Over The Air (OTA) update (41)
                          • @@ -327,6 +334,9 @@
                          • The number of hilights in currently-encoding video (value is set to 0 when encoding stops) (58)
                          • Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops) (59)
                          • The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this (60)
                          • +
                          • The current state of camera analytics (61)
                          • +
                          • The size (units??) of the analytics file (62)
                          • +
                          • Is the camera currently in a contextual menu (e.g. Preferences)? (63)
                          • How many minutes of Time Lapse Video can be captured with current settings before sdcard is full (64)
                          • Liveview Exposure Select Mode (65)
                          • Liveview Exposure Select: y-coordinate (percent) (66)
                          • @@ -347,6 +357,8 @@
                          • Rotational orientation of the camera (86)
                          • Is this camera model capable of zooming while encoding? (88)
                          • Current Flatmode ID (89)
                          • +
                          • Are current flatmode’s Protune settings factory default? (90)
                          • +
                          • Are system logs ready to be downloaded? (91)
                          • Current Video Preset (ID) (93)
                          • Current Photo Preset (ID) (94)
                          • Current Time Lapse Preset (ID) (95)
                          • @@ -363,6 +375,7 @@
                          • Is Video Hindsight Capture Active? (106)
                          • Scheduled Capture Preset ID (107)
                          • Is Scheduled Capture set? (108)
                          • +
                          • Is the camera in the process of creating a custom preset? (109)
                          • Display Mod Status (bitmasked) (110)
                          • Does sdcard meet specified minimum write speed? (111)
                          • Number of sdcard write speed errors since device booted (112)
                          • diff --git a/docs/ble/protocol/id_tables.html b/docs/ble/protocol/id_tables.html index e9ea1434..3cbf2ee8 100644 --- a/docs/ble/protocol/id_tables.html +++ b/docs/ble/protocol/id_tables.html @@ -152,14 +152,14 @@
                            • Control
                            • Operations
                            • Setting IDs
                                @@ -254,6 +255,7 @@
                              • Frames Per Second (3)
                              • FOV (43)
                              • Auto Off (59)
                              • +
                              • GPS (83)
                              • Aspect Ratio (108)
                              • Lens (121)
                              • Lens (122)
                              • @@ -292,12 +294,15 @@
                              • Status IDs
                                • Is the system’s internal battery present? (1)
                                • Rough approximation of internal battery level in bars (or charging) (2)
                                • +
                                • Is an external battery connected? (3)
                                • +
                                • External battery power level in percent (4)
                                • Is the system currently overheating? (6)
                                • Is the camera busy? (8)
                                • Is Quick Capture feature enabled? (9)
                                • Is the system encoding right now? (10)
                                • Is LCD lock active? (11)
                                • When encoding video, this is the duration (seconds) of the video so far; 0 otherwise (13)
                                • +
                                • When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise (14)
                                • Are Wireless Connections enabled? (17)
                                • The pairing state of the camera (19)
                                • The last type of pairing in which the camera was engaged (20)
                                • @@ -315,6 +320,8 @@
                                • Primary Storage Status (33)
                                • How many photos can be taken with current settings before sdcard is full (34)
                                • How many minutes of video can be captured with current settings before sdcard is full (35)
                                • +
                                • Total number of group photos on sdcard (36)
                                • +
                                • Total number of group videos on sdcard (37)
                                • Total number of photos on sdcard (38)
                                • Total number of videos on sdcard (39)
                                • The current status of Over The Air (OTA) update (41)
                                • @@ -327,6 +334,9 @@
                                • The number of hilights in currently-encoding video (value is set to 0 when encoding stops) (58)
                                • Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops) (59)
                                • The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this (60)
                                • +
                                • The current state of camera analytics (61)
                                • +
                                • The size (units??) of the analytics file (62)
                                • +
                                • Is the camera currently in a contextual menu (e.g. Preferences)? (63)
                                • How many minutes of Time Lapse Video can be captured with current settings before sdcard is full (64)
                                • Liveview Exposure Select Mode (65)
                                • Liveview Exposure Select: y-coordinate (percent) (66)
                                • @@ -347,6 +357,8 @@
                                • Rotational orientation of the camera (86)
                                • Is this camera model capable of zooming while encoding? (88)
                                • Current Flatmode ID (89)
                                • +
                                • Are current flatmode’s Protune settings factory default? (90)
                                • +
                                • Are system logs ready to be downloaded? (91)
                                • Current Video Preset (ID) (93)
                                • Current Photo Preset (ID) (94)
                                • Current Time Lapse Preset (ID) (95)
                                • @@ -363,6 +375,7 @@
                                • Is Video Hindsight Capture Active? (106)
                                • Scheduled Capture Preset ID (107)
                                • Is Scheduled Capture set? (108)
                                • +
                                • Is the camera in the process of creating a custom preset? (109)
                                • Display Mod Status (bitmasked) (110)
                                • Does sdcard meet specified minimum write speed? (111)
                                • Number of sdcard write speed errors since device booted (112)
                                • @@ -422,13 +435,13 @@

                                  Command IDsSet Date Time

                                  0x0E

                                  -

                                  Get Date Time

                                  +

                                  Get Date Time

                                  0x0F

                                  Set Local Date Time

                                  0x10

                                  -

                                  Get Local Date Time

                                  +

                                  Get Local Date Time

                                  0x17

                                  Set AP Control

                                  @@ -437,7 +450,7 @@

                                  Command IDsHilight Moment

                                  0x3C

                                  -

                                  Get Hardware Info

                                  +

                                  Get Hardware Info

                                  0x3E

                                  Load Preset Group

                                  @@ -449,7 +462,7 @@

                                  Command IDsSet Analytics

                                  0x51

                                  -

                                  Get Open GoPro Version

                                  +

                                  Get Open GoPro Version

                                  0x5B

                                  Keep Alive

                                  @@ -470,40 +483,40 @@

                                  Query IDs

                                  0x12

                                  -

                                  Get Setting Values

                                  +

                                  Get Setting Values

                                  0x13

                                  -

                                  Get Status Values

                                  +

                                  Get Status Values

                                  0x32

                                  -

                                  Get Setting Capabilities

                                  +

                                  Get Setting Capabilities

                                  0x52

                                  -

                                  Register for Setting Value Updates

                                  +

                                  Register for Setting Value Updates

                                  0x53

                                  -

                                  Register for Status Value Updates

                                  +

                                  Register for Status Value Updates

                                  0x62

                                  -

                                  Register for Setting Capability Updates

                                  +

                                  Register for Setting Capability Updates

                                  0x72

                                  -

                                  Unregister for Setting Value Updates

                                  +

                                  Unregister for Setting Value Updates

                                  0x73

                                  -

                                  Unregister for Status Value Updates

                                  +

                                  Unregister for Status Value Updates

                                  0x82

                                  -

                                  Unregister for Setting Capability Updates

                                  +

                                  Unregister for Setting Capability Updates

                                  0x92

                                  -

                                  Asynchronous setting value Notification

                                  +

                                  Asynchronous setting value Notification

                                  0x93

                                  -

                                  Asynchronous status value Notification

                                  +

                                  Asynchronous status value Notification

                                  0xA2

                                  -

                                  Asynchronous setting capability Notification

                                  +

                                  Asynchronous setting capability Notification

                                  @@ -522,192 +535,192 @@

                                  Protobuf IDs

                                  0x02

                                  0x02

                                  "Scan for Access Points" Request

                                  -

                                  RequestStartScan

                                  +

                                  RequestStartScan

                                  0x02

                                  -

                                  0x04

                                  +

                                  0x03

                                  "Get AP Scan Results" Request

                                  -

                                  RequestGetApEntries

                                  +

                                  RequestGetApEntries

                                  0x02

                                  0x04

                                  "Connect to Provisioned Access Point" Request

                                  -

                                  RequestConnect

                                  +

                                  RequestConnect

                                  0x02

                                  0x05

                                  "Connect to a New Access Point" Request

                                  -

                                  RequestConnectNew

                                  +

                                  RequestConnectNew

                                  0x02

                                  0x0B

                                  "Scan for Access Points" Notification

                                  -

                                  NotifStartScanning

                                  +

                                  NotifStartScanning

                                  0x02

                                  0x0C

                                  "Connect to Provisioned Access Point" Notification

                                  -

                                  NotifProvisioningState

                                  +

                                  NotifProvisioningState

                                  0x02

                                  0x0C

                                  "Connect to a New Access Point" Notification

                                  -

                                  NotifProvisioningState

                                  +

                                  NotifProvisioningState

                                  0x02

                                  0x82

                                  "Scan for Access Points" Response

                                  -

                                  ResponseStartScanning

                                  +

                                  ResponseStartScanning

                                  0x02

                                  -

                                  0x84

                                  +

                                  0x83

                                  "Get AP Scan Results" Response

                                  -

                                  ResponseGetApEntries

                                  +

                                  ResponseGetApEntries

                                  0x02

                                  0x84

                                  "Connect to Provisioned Access Point" Response

                                  -

                                  ResponseConnect

                                  +

                                  ResponseConnect

                                  0x02

                                  0x85

                                  "Connect to a New Access Point" Response

                                  -

                                  ResponseConnectNew

                                  +

                                  ResponseConnectNew

                                  0xF1

                                  0x64

                                  "Update Custom Preset" Request

                                  -

                                  RequestCustomPresetUpdate

                                  +

                                  RequestCustomPresetUpdate

                                  0xF1

                                  0x65

                                  "Set COHN Setting" Request

                                  -

                                  RequestSetCOHNSetting

                                  +

                                  RequestSetCOHNSetting

                                  0xF1

                                  0x66

                                  "Clear COHN Certificate" Request

                                  -

                                  RequestClearCOHNCert

                                  +

                                  RequestClearCOHNCert

                                  0xF1

                                  0x67

                                  "Create COHN Certificate" Request

                                  -

                                  RequestCreateCOHNCert

                                  +

                                  RequestCreateCOHNCert

                                  0xF1

                                  0x69

                                  "Set Camera Control" Request

                                  -

                                  RequestSetCameraControlStatus

                                  +

                                  RequestSetCameraControlStatus

                                  0xF1

                                  0x6B

                                  "Set Turbo Transfer" Request

                                  -

                                  RequestSetTurboActive

                                  +

                                  RequestSetTurboActive

                                  0xF1

                                  0x79

                                  "Set Livestream Mode" Request

                                  -

                                  RequestSetLiveStreamMode

                                  +

                                  RequestSetLiveStreamMode

                                  0xF1

                                  0xE4

                                  "Update Custom Preset" Response

                                  -

                                  ResponseGeneric

                                  +

                                  ResponseGeneric

                                  0xF1

                                  0xE5

                                  "Set COHN Setting" Response

                                  -

                                  ResponseGeneric

                                  +

                                  ResponseGeneric

                                  0xF1

                                  0xE6

                                  "Clear COHN Certificate" Response

                                  -

                                  ResponseGeneric

                                  +

                                  ResponseGeneric

                                  0xF1

                                  0xE7

                                  "Create COHN Certificate" Response

                                  -

                                  ResponseGeneric

                                  +

                                  ResponseGeneric

                                  0xF1

                                  0xE9

                                  "Set Camera Control" Response

                                  -

                                  ResponseGeneric

                                  +

                                  ResponseGeneric

                                  0xF1

                                  0xEB

                                  "Set Turbo Transfer" Response

                                  -

                                  ResponseGeneric

                                  +

                                  ResponseGeneric

                                  0xF1

                                  0xF9

                                  "Set Livestream Mode" Response

                                  -

                                  ResponseGeneric

                                  +

                                  ResponseGeneric

                                  0xF5

                                  0x6D

                                  "Get Last Captured Media" Request

                                  -

                                  RequestGetLastCapturedMedia

                                  +

                                  RequestGetLastCapturedMedia

                                  0xF5

                                  0x6E

                                  "Get COHN Certificate" Request

                                  -

                                  RequestCOHNCert

                                  +

                                  RequestCOHNCert

                                  0xF5

                                  0x6F

                                  "Get COHN Status" Request

                                  -

                                  RequestGetCOHNStatus

                                  +

                                  RequestGetCOHNStatus

                                  0xF5

                                  0x72

                                  "Get Available Presets" Request

                                  -

                                  RequestGetPresetStatus

                                  +

                                  RequestGetPresetStatus

                                  0xF5

                                  0x74

                                  "Get Livestream Status" Request

                                  -

                                  RequestGetLiveStreamStatus

                                  +

                                  RequestGetLiveStreamStatus

                                  0xF5

                                  0xED

                                  "Get Last Captured Media" Response

                                  -

                                  ResponseLastCapturedMedia

                                  +

                                  ResponseLastCapturedMedia

                                  0xF5

                                  0xEE

                                  "Get COHN Certificate" Response

                                  -

                                  ResponseCOHNCert

                                  +

                                  ResponseCOHNCert

                                  0xF5

                                  0xEF

                                  "Get COHN Status" Response

                                  -

                                  NotifyCOHNStatus

                                  +

                                  NotifyCOHNStatus

                                  0xF5

                                  0xEF

                                  "Get COHN Status" Notification

                                  -

                                  NotifyCOHNStatus

                                  +

                                  NotifyCOHNStatus

                                  0xF5

                                  0xF2

                                  "Get Available Presets" Response

                                  -

                                  NotifyPresetStatus

                                  +

                                  NotifyPresetStatus

                                  0xF5

                                  0xF3

                                  "Get Available Presets" Notification

                                  -

                                  NotifyPresetStatus

                                  +

                                  NotifyPresetStatus

                                  0xF5

                                  0xF4

                                  "Get Livestream Status" Response

                                  -

                                  NotifyLiveStreamStatus

                                  +

                                  NotifyLiveStreamStatus

                                  0xF5

                                  0xF5

                                  "Get Livestream Status" Notification

                                  -

                                  NotifyLiveStreamStatus

                                  +

                                  NotifyLiveStreamStatus

                                  @@ -733,94 +746,97 @@

                                  Setting IDs

                                  59

                                  Auto Power Down

                                  -

                                  108

                                  +

                                  83

                                  +

                                  GPS

                                  + +

                                  108

                                  Aspect Ratio

                                  -

                                  121

                                  +

                                  121

                                  Lens

                                  -

                                  122

                                  +

                                  122

                                  Lens

                                  -

                                  123

                                  +

                                  123

                                  Time Lapse Digital Lenses

                                  -

                                  128

                                  +

                                  128

                                  Media Format

                                  -

                                  134

                                  +

                                  134

                                  Anti-Flicker

                                  -

                                  135

                                  +

                                  135

                                  Hypersmooth

                                  -

                                  150

                                  +

                                  150

                                  Horizon Leveling

                                  -

                                  151

                                  +

                                  151

                                  Horizon Leveling

                                  -

                                  162

                                  +

                                  162

                                  Max Lens

                                  -

                                  167

                                  +

                                  167

                                  HindSight

                                  -

                                  171

                                  +

                                  171

                                  Interval

                                  -

                                  172

                                  +

                                  172

                                  Duration

                                  -

                                  173

                                  +

                                  173

                                  Video Performance Mode

                                  -

                                  175

                                  +

                                  175

                                  Controls

                                  -

                                  176

                                  +

                                  176

                                  Easy Mode Speed

                                  -

                                  177

                                  +

                                  177

                                  Enable Night Photo

                                  -

                                  178

                                  +

                                  178

                                  Wireless Band

                                  -

                                  179

                                  +

                                  179

                                  Trail Length

                                  -

                                  180

                                  +

                                  180

                                  Video Mode

                                  -

                                  182

                                  +

                                  182

                                  Bit Rate

                                  -

                                  183

                                  +

                                  183

                                  Bit Depth

                                  -

                                  184

                                  +

                                  184

                                  Profiles

                                  -

                                  186

                                  +

                                  186

                                  Video Mode

                                  -

                                  187

                                  +

                                  187

                                  Lapse Mode

                                  -

                                  189

                                  +

                                  189

                                  Max Lens Mod

                                  -

                                  190

                                  +

                                  190

                                  Max Lens Mod Enable

                                  -

                                  191

                                  +

                                  191

                                  Photo Mode

                                  -

                                  192

                                  +

                                  192

                                  Aspect Ratio

                                  -

                                  193

                                  +

                                  193

                                  Framing

                                  @@ -836,247 +852,355 @@

                                  Status IDs

                                  1

                                  -

                                  Is the system's internal battery present?

                                  +

                                  Is the system's internal battery present?

                                  2

                                  -

                                  Rough approximation of internal battery level in bars (or charging)

                                  +

                                  Rough approximation of internal battery level in bars (or charging)

                                  + +

                                  3

                                  +

                                  Is an external battery connected?

                                  + +

                                  4

                                  +

                                  External battery power level in percent

                                  -

                                  6

                                  -

                                  Is the system currently overheating?

                                  +

                                  5

                                  +

                                  Unused

                                  + +

                                  6

                                  +

                                  Is the system currently overheating?

                                  + +

                                  7

                                  +

                                  Unused

                                  8

                                  -

                                  Is the camera busy?

                                  +

                                  Is the camera busy?

                                  9

                                  -

                                  Is Quick Capture feature enabled?

                                  +

                                  Is Quick Capture feature enabled?

                                  10

                                  -

                                  Is the system encoding right now?

                                  +

                                  Is the system encoding right now?

                                  11

                                  -

                                  Is LCD lock active?

                                  +

                                  Is LCD lock active?

                                  + +

                                  12

                                  +

                                  Unused

                                  + +

                                  13

                                  +

                                  When encoding video, this is the duration (seconds) of the video so far; 0 otherwise

                                  + +

                                  14

                                  +

                                  When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise

                                  -

                                  13

                                  -

                                  When encoding video, this is the duration (seconds) of the video so far; 0 otherwise

                                  +

                                  15

                                  +

                                  (DEPRECATED) Number of Broadcast viewers

                                  + +

                                  16

                                  +

                                  (DEPRECATED) Broadcast B-Status

                                  17

                                  -

                                  Are Wireless Connections enabled?

                                  +

                                  Are Wireless Connections enabled?

                                  + +

                                  18

                                  +

                                  Unused

                                  + +

                                  19

                                  +

                                  The pairing state of the camera

                                  -

                                  19

                                  -

                                  The pairing state of the camera

                                  +

                                  20

                                  +

                                  The last type of pairing in which the camera was engaged

                                  -

                                  20

                                  -

                                  The last type of pairing in which the camera was engaged

                                  +

                                  21

                                  +

                                  Time since boot (milliseconds) of last successful pairing complete action

                                  -

                                  21

                                  -

                                  Time since boot (milliseconds) of last successful pairing complete action

                                  +

                                  22

                                  +

                                  State of current scan for WiFi Access Points

                                  -

                                  22

                                  -

                                  State of current scan for WiFi Access Points

                                  +

                                  23

                                  +

                                  Time since boot (milliseconds) that the WiFi Access Point scan completed

                                  -

                                  23

                                  -

                                  Time since boot (milliseconds) that the WiFi Access Point scan completed

                                  +

                                  24

                                  +

                                  WiFi AP provisioning state

                                  -

                                  24

                                  -

                                  WiFi AP provisioning state

                                  +

                                  25

                                  +

                                  Unused

                                  26

                                  -

                                  Wireless remote control version

                                  +

                                  Wireless remote control version

                                  27

                                  -

                                  Is a wireless remote control connected?

                                  +

                                  Is a wireless remote control connected?

                                  28

                                  -

                                  Wireless Pairing State. Each bit contains state information (see WirelessPairingStateFlags)

                                  +

                                  Wireless Pairing State. Each bit contains state information (see WirelessPairingStateFlags)

                                  29

                                  -

                                  SSID of the AP the camera is currently connected to. On BLE connection, value is big-endian byte-encoded int32

                                  +

                                  SSID of the AP the camera is currently connected to. On BLE connection, value is big-endian byte-encoded int32

                                  30

                                  -

                                  The camera's WiFi SSID. On BLE connection, value is big-endian byte-encoded int32

                                  +

                                  The camera's WiFi SSID. On BLE connection, value is big-endian byte-encoded int32

                                  31

                                  -

                                  The number of wireless devices connected to the camera

                                  +

                                  The number of wireless devices connected to the camera

                                  32

                                  -

                                  Is Preview Stream enabled?

                                  +

                                  Is Preview Stream enabled?

                                  33

                                  -

                                  Primary Storage Status

                                  +

                                  Primary Storage Status

                                  34

                                  -

                                  How many photos can be taken with current settings before sdcard is full

                                  +

                                  How many photos can be taken with current settings before sdcard is full

                                  35

                                  -

                                  How many minutes of video can be captured with current settings before sdcard is full

                                  +

                                  How many minutes of video can be captured with current settings before sdcard is full

                                  + +

                                  36

                                  +

                                  Total number of group photos on sdcard

                                  + +

                                  37

                                  +

                                  Total number of group videos on sdcard

                                  38

                                  -

                                  Total number of photos on sdcard

                                  +

                                  Total number of photos on sdcard

                                  39

                                  -

                                  Total number of videos on sdcard

                                  +

                                  Total number of videos on sdcard

                                  + +

                                  40

                                  +

                                  Current date/time (format: %YY%mm%dd%HH%MM%SS, all values in hex)

                                  + +

                                  41

                                  +

                                  The current status of Over The Air (OTA) update

                                  + +

                                  42

                                  +

                                  Is there a pending request to cancel a firmware update download?

                                  + +

                                  43

                                  +

                                  Current mode group (deprecated in HERO8)

                                  -

                                  41

                                  -

                                  The current status of Over The Air (OTA) update

                                  +

                                  44

                                  +

                                  Current submode (deprecated in HERO8)

                                  -

                                  42

                                  -

                                  Is there a pending request to cancel a firmware update download?

                                  +

                                  45

                                  +

                                  Is locate camera feature active?

                                  -

                                  45

                                  -

                                  Is locate camera feature active?

                                  +

                                  46

                                  +

                                  Are Video Protune settings currently factory default?

                                  + +

                                  47

                                  +

                                  Are Photo Protune settings currently factory default?

                                  + +

                                  48

                                  +

                                  Are Multishot Protune settings currently factory default?

                                  49

                                  -

                                  The current timelapse interval countdown value (e.g. 5...4...3...2...1...)

                                  +

                                  The current timelapse interval countdown value (e.g. 5...4...3...2...1...)

                                  + +

                                  50

                                  +

                                  Unused

                                  + +

                                  51

                                  +

                                  Unused

                                  + +

                                  52

                                  +

                                  Unused

                                  + +

                                  53

                                  +

                                  Unused

                                  54

                                  -

                                  Remaining space on the sdcard in Kilobytes

                                  +

                                  Remaining space on the sdcard in Kilobytes

                                  55

                                  -

                                  Is preview stream supported in current recording/mode/secondary-stream?

                                  +

                                  Is preview stream supported in current recording/mode/secondary-stream?

                                  56

                                  -

                                  WiFi signal strength in bars

                                  +

                                  WiFi signal strength in bars

                                  -

                                  58

                                  -

                                  The number of hilights in currently-encoding video (value is set to 0 when encoding stops)

                                  +

                                  57

                                  +

                                  Time in milliseconds since system was booted

                                  -

                                  59

                                  -

                                  Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops)

                                  +

                                  58

                                  +

                                  The number of hilights in currently-encoding video (value is set to 0 when encoding stops)

                                  + +

                                  59

                                  +

                                  Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops)

                                  + +

                                  60

                                  +

                                  The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this

                                  + +

                                  61

                                  +

                                  The current state of camera analytics

                                  + +

                                  62

                                  +

                                  The size (units??) of the analytics file

                                  -

                                  60

                                  -

                                  The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this

                                  +

                                  63

                                  +

                                  Is the camera currently in a contextual menu (e.g. Preferences)?

                                  64

                                  -

                                  How many minutes of Time Lapse Video can be captured with current settings before sdcard is full

                                  +

                                  How many minutes of Time Lapse Video can be captured with current settings before sdcard is full

                                  65

                                  -

                                  Liveview Exposure Select Mode

                                  +

                                  Liveview Exposure Select Mode

                                  66

                                  -

                                  Liveview Exposure Select: y-coordinate (percent)

                                  +

                                  Liveview Exposure Select: y-coordinate (percent)

                                  67

                                  -

                                  Liveview Exposure Select: y-coordinate (percent)

                                  +

                                  Liveview Exposure Select: y-coordinate (percent)

                                  68

                                  -

                                  Does the camera currently have a GPS lock?

                                  +

                                  Does the camera currently have a GPS lock?

                                  69

                                  -

                                  Is the camera in AP Mode?

                                  +

                                  Is the camera in AP Mode?

                                  70

                                  -

                                  Internal battery level (percent)

                                  +

                                  Internal battery level (percent)

                                  -

                                  74

                                  -

                                  Microphone Accessory status

                                  +

                                  71

                                  +

                                  The current video group flatmode (id)

                                  -

                                  75

                                  -

                                  Digital Zoom level (percent)

                                  +

                                  72

                                  +

                                  The current photo group flatmode (id)

                                  -

                                  76

                                  -

                                  Wireless Band

                                  +

                                  73

                                  +

                                  The current timelapse group flatmode (id)

                                  -

                                  77

                                  -

                                  Is Digital Zoom feature available?

                                  +

                                  74

                                  +

                                  Microphone Accessory status

                                  -

                                  78

                                  -

                                  Are current video settings mobile friendly? (related to video compression and frame rate)

                                  +

                                  75

                                  +

                                  Digital Zoom level (percent)

                                  -

                                  79

                                  -

                                  Is the camera currently in First Time Use (FTU) UI flow?

                                  +

                                  76

                                  +

                                  Wireless Band

                                  + +

                                  77

                                  +

                                  Is Digital Zoom feature available?

                                  + +

                                  78

                                  +

                                  Are current video settings mobile friendly? (related to video compression and frame rate)

                                  + +

                                  79

                                  +

                                  Is the camera currently in First Time Use (FTU) UI flow?

                                  + +

                                  80

                                  +

                                  Secondary Storage Status (exclusive to Superbank)

                                  81

                                  -

                                  Is 5GHz wireless band available?

                                  +

                                  Is 5GHz wireless band available?

                                  82

                                  -

                                  Is the system fully booted and ready to accept commands?

                                  +

                                  Is the system fully booted and ready to accept commands?

                                  83

                                  -

                                  Is the internal battery charged sufficiently to start Over The Air (OTA) update?

                                  +

                                  Is the internal battery charged sufficiently to start Over The Air (OTA) update?

                                  + +

                                  84

                                  +

                                  Current Capture Delay value (HERO7 only)

                                  -

                                  85

                                  -

                                  Is the camera getting too cold to continue recording?

                                  +

                                  85

                                  +

                                  Is the camera getting too cold to continue recording?

                                  -

                                  86

                                  -

                                  Rotational orientation of the camera

                                  +

                                  86

                                  +

                                  Rotational orientation of the camera

                                  + +

                                  87

                                  +

                                  Can camera use high resolution/fps (based on temperature)? (HERO7 Silver/White only)

                                  88

                                  -

                                  Is this camera model capable of zooming while encoding?

                                  +

                                  Is this camera model capable of zooming while encoding?

                                  89

                                  -

                                  Current Flatmode ID

                                  +

                                  Current Flatmode ID

                                  + +

                                  90

                                  +

                                  Are current flatmode's Protune settings factory default?

                                  + +

                                  91

                                  +

                                  Are system logs ready to be downloaded?

                                  + +

                                  92

                                  +

                                  Is Timewarp 1x active?

                                  + +

                                  93

                                  +

                                  Current Video Preset (ID)

                                  -

                                  93

                                  -

                                  Current Video Preset (ID)

                                  +

                                  94

                                  +

                                  Current Photo Preset (ID)

                                  -

                                  94

                                  -

                                  Current Photo Preset (ID)

                                  +

                                  95

                                  +

                                  Current Time Lapse Preset (ID)

                                  -

                                  95

                                  -

                                  Current Time Lapse Preset (ID)

                                  +

                                  96

                                  +

                                  Current Preset Group (ID) (corresponds to ui_mode_groups in settings.json)

                                  -

                                  96

                                  -

                                  Current Preset Group (ID) (corresponds to ui_mode_groups in settings.json)

                                  +

                                  97

                                  +

                                  Current Preset (ID)

                                  -

                                  97

                                  -

                                  Current Preset (ID)

                                  +

                                  98

                                  +

                                  Preset Modified Status, which contains an event ID and a Preset (Group) ID

                                  -

                                  98

                                  -

                                  Preset Modified Status, which contains an event ID and a Preset (Group) ID

                                  +

                                  99

                                  +

                                  The number of Live Bursts can be captured with current settings before sdcard is full

                                  -

                                  99

                                  -

                                  The number of Live Bursts can be captured with current settings before sdcard is full

                                  +

                                  100

                                  +

                                  Total number of Live Bursts on sdcard

                                  -

                                  100

                                  -

                                  Total number of Live Bursts on sdcard

                                  +

                                  101

                                  +

                                  Is Capture Delay currently active (i.e. counting down)?

                                  -

                                  101

                                  -

                                  Is Capture Delay currently active (i.e. counting down)?

                                  +

                                  102

                                  +

                                  Media Mod state

                                  -

                                  102

                                  -

                                  Media Mod state

                                  +

                                  103

                                  +

                                  Time Warp Speed

                                  -

                                  103

                                  -

                                  Time Warp Speed

                                  +

                                  104

                                  +

                                  Is the system's Linux core active?

                                  -

                                  104

                                  -

                                  Is the system's Linux core active?

                                  +

                                  105

                                  +

                                  Camera lens type (reflects changes to setting 162 or setting 189)

                                  -

                                  105

                                  -

                                  Camera lens type (reflects changes to setting 162 or setting 189)

                                  +

                                  106

                                  +

                                  Is Video Hindsight Capture Active?

                                  -

                                  106

                                  -

                                  Is Video Hindsight Capture Active?

                                  +

                                  107

                                  +

                                  Scheduled Capture Preset ID

                                  -

                                  107

                                  -

                                  Scheduled Capture Preset ID

                                  +

                                  108

                                  +

                                  Is Scheduled Capture set?

                                  -

                                  108

                                  -

                                  Is Scheduled Capture set?

                                  +

                                  109

                                  +

                                  Is the camera in the process of creating a custom preset?

                                  110

                                  -

                                  Display Mod Status (bitmasked)

                                  +

                                  Display Mod Status (bitmasked)

                                  111

                                  -

                                  Does sdcard meet specified minimum write speed?

                                  +

                                  Does sdcard meet specified minimum write speed?

                                  112

                                  -

                                  Number of sdcard write speed errors since device booted

                                  +

                                  Number of sdcard write speed errors since device booted

                                  113

                                  -

                                  Is Turbo Transfer active?

                                  +

                                  Is Turbo Transfer active?

                                  114

                                  -

                                  Camera control status ID

                                  +

                                  Camera control status ID

                                  115

                                  -

                                  Is the camera connected to a PC via USB?

                                  +

                                  Is the camera connected to a PC via USB?

                                  116

                                  -

                                  Camera control over USB state

                                  +

                                  Camera control over USB state

                                  117

                                  -

                                  Total SD card capacity in Kilobytes

                                  +

                                  Total SD card capacity in Kilobytes

                                  diff --git a/docs/ble/protocol/protobuf.html b/docs/ble/protocol/protobuf.html index c77aefc1..f272d930 100644 --- a/docs/ble/protocol/protobuf.html +++ b/docs/ble/protocol/protobuf.html @@ -152,14 +152,14 @@
                                  • Control
                                  • Operations
                                  • Setting IDs
                                      @@ -254,6 +255,7 @@
                                    • Frames Per Second (3)
                                    • FOV (43)
                                    • Auto Off (59)
                                    • +
                                    • GPS (83)
                                    • Aspect Ratio (108)
                                    • Lens (121)
                                    • Lens (122)
                                    • @@ -292,12 +294,15 @@
                                    • Status IDs
                                      • Is the system’s internal battery present? (1)
                                      • Rough approximation of internal battery level in bars (or charging) (2)
                                      • +
                                      • Is an external battery connected? (3)
                                      • +
                                      • External battery power level in percent (4)
                                      • Is the system currently overheating? (6)
                                      • Is the camera busy? (8)
                                      • Is Quick Capture feature enabled? (9)
                                      • Is the system encoding right now? (10)
                                      • Is LCD lock active? (11)
                                      • When encoding video, this is the duration (seconds) of the video so far; 0 otherwise (13)
                                      • +
                                      • When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise (14)
                                      • Are Wireless Connections enabled? (17)
                                      • The pairing state of the camera (19)
                                      • The last type of pairing in which the camera was engaged (20)
                                      • @@ -315,6 +320,8 @@
                                      • Primary Storage Status (33)
                                      • How many photos can be taken with current settings before sdcard is full (34)
                                      • How many minutes of video can be captured with current settings before sdcard is full (35)
                                      • +
                                      • Total number of group photos on sdcard (36)
                                      • +
                                      • Total number of group videos on sdcard (37)
                                      • Total number of photos on sdcard (38)
                                      • Total number of videos on sdcard (39)
                                      • The current status of Over The Air (OTA) update (41)
                                      • @@ -327,6 +334,9 @@
                                      • The number of hilights in currently-encoding video (value is set to 0 when encoding stops) (58)
                                      • Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops) (59)
                                      • The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this (60)
                                      • +
                                      • The current state of camera analytics (61)
                                      • +
                                      • The size (units??) of the analytics file (62)
                                      • +
                                      • Is the camera currently in a contextual menu (e.g. Preferences)? (63)
                                      • How many minutes of Time Lapse Video can be captured with current settings before sdcard is full (64)
                                      • Liveview Exposure Select Mode (65)
                                      • Liveview Exposure Select: y-coordinate (percent) (66)
                                      • @@ -347,6 +357,8 @@
                                      • Rotational orientation of the camera (86)
                                      • Is this camera model capable of zooming while encoding? (88)
                                      • Current Flatmode ID (89)
                                      • +
                                      • Are current flatmode’s Protune settings factory default? (90)
                                      • +
                                      • Are system logs ready to be downloaded? (91)
                                      • Current Video Preset (ID) (93)
                                      • Current Photo Preset (ID) (94)
                                      • Current Time Lapse Preset (ID) (95)
                                      • @@ -363,6 +375,7 @@
                                      • Is Video Hindsight Capture Active? (106)
                                      • Scheduled Capture Preset ID (107)
                                      • Is Scheduled Capture set? (108)
                                      • +
                                      • Is the camera in the process of creating a custom preset? (109)
                                      • Display Mod Status (bitmasked) (110)
                                      • Does sdcard meet specified minimum write speed? (111)
                                      • Number of sdcard write speed errors since device booted (112)
                                      • @@ -2580,9 +2593,15 @@

                                        EnumsSee also

                                        Source Protobuf File

                                        -

                                        Get preset status (and optionally register to be notified when it changes)

                                        +

                                        Get the set of currently available presets and optionally register to be notified when it changes.

                                        Response: NotifyPresetStatus sent immediately

                                        Notification: NotifyPresetStatus sent periodically as preset status changes, if registered.

                                        +

                                        The preset status changes when:

                                        +
                                          +
                                        • A client changes one of a preset’s captioned settings via the API

                                        • +
                                        • The user exits from a preset’s settings UI on the camera (e.g. long-press the preset pill and then press the back arrow)

                                        • +
                                        • The user creates/deletes/reorders a preset within a group

                                        • +
                                        diff --git a/docs/ble/protocol/state_management.html b/docs/ble/protocol/state_management.html index f2ae0f4d..b9fb7e67 100644 --- a/docs/ble/protocol/state_management.html +++ b/docs/ble/protocol/state_management.html @@ -152,14 +152,14 @@
                                        • Control
                                        • Operations
                                        • Setting IDs
                                            @@ -254,6 +255,7 @@
                                          • Frames Per Second (3)
                                          • FOV (43)
                                          • Auto Off (59)
                                          • +
                                          • GPS (83)
                                          • Aspect Ratio (108)
                                          • Lens (121)
                                          • Lens (122)
                                          • @@ -292,12 +294,15 @@
                                          • Status IDs
                                            • Is the system’s internal battery present? (1)
                                            • Rough approximation of internal battery level in bars (or charging) (2)
                                            • +
                                            • Is an external battery connected? (3)
                                            • +
                                            • External battery power level in percent (4)
                                            • Is the system currently overheating? (6)
                                            • Is the camera busy? (8)
                                            • Is Quick Capture feature enabled? (9)
                                            • Is the system encoding right now? (10)
                                            • Is LCD lock active? (11)
                                            • When encoding video, this is the duration (seconds) of the video so far; 0 otherwise (13)
                                            • +
                                            • When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise (14)
                                            • Are Wireless Connections enabled? (17)
                                            • The pairing state of the camera (19)
                                            • The last type of pairing in which the camera was engaged (20)
                                            • @@ -315,6 +320,8 @@
                                            • Primary Storage Status (33)
                                            • How many photos can be taken with current settings before sdcard is full (34)
                                            • How many minutes of video can be captured with current settings before sdcard is full (35)
                                            • +
                                            • Total number of group photos on sdcard (36)
                                            • +
                                            • Total number of group videos on sdcard (37)
                                            • Total number of photos on sdcard (38)
                                            • Total number of videos on sdcard (39)
                                            • The current status of Over The Air (OTA) update (41)
                                            • @@ -327,6 +334,9 @@
                                            • The number of hilights in currently-encoding video (value is set to 0 when encoding stops) (58)
                                            • Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops) (59)
                                            • The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this (60)
                                            • +
                                            • The current state of camera analytics (61)
                                            • +
                                            • The size (units??) of the analytics file (62)
                                            • +
                                            • Is the camera currently in a contextual menu (e.g. Preferences)? (63)
                                            • How many minutes of Time Lapse Video can be captured with current settings before sdcard is full (64)
                                            • Liveview Exposure Select Mode (65)
                                            • Liveview Exposure Select: y-coordinate (percent) (66)
                                            • @@ -347,6 +357,8 @@
                                            • Rotational orientation of the camera (86)
                                            • Is this camera model capable of zooming while encoding? (88)
                                            • Current Flatmode ID (89)
                                            • +
                                            • Are current flatmode’s Protune settings factory default? (90)
                                            • +
                                            • Are system logs ready to be downloaded? (91)
                                            • Current Video Preset (ID) (93)
                                            • Current Photo Preset (ID) (94)
                                            • Current Time Lapse Preset (ID) (95)
                                            • @@ -363,6 +375,7 @@
                                            • Is Video Hindsight Capture Active? (106)
                                            • Scheduled Capture Preset ID (107)
                                            • Is Scheduled Capture set? (108)
                                            • +
                                            • Is the camera in the process of creating a custom preset? (109)
                                            • Display Mod Status (bitmasked) (110)
                                            • Does sdcard meet specified minimum write speed? (111)
                                            • Number of sdcard write speed errors since device booted (112)
                                            • @@ -406,8 +419,7 @@

                                              State Management

                                              Camera Readiness

                                              Depending on the camera’s state, it may not be ready to accept specific commands. This ready state is dependent on the -System Busy -and Encoding Active status flags. For example:

                                              +System Busy and Encoding Active status flags. For example:

                                              • System Busy flag is set while loading presets, changing settings, formatting sdcard, …

                                              • Encoding Active flag is set while capturing photo/video media

                                              • @@ -418,14 +430,13 @@

                                                Camera Readiness

                                                Keep Alive

                                                Unless changed by the user, GoPro cameras will automatically power off after some time (e.g. 5min, 15min, 30min). -Therefore, it is necessary to periodically send a keep alive signal to maintain the connection.

                                                +Therefore, it is necessary to periodically send a Keep Alive signal to maintain the connection.

                                                Camera Control

                                                In order to prevent undefined behavior between the camera and a connected app, simultaneous use of the camera and a -connected app is discouraged. A third party client should use -Set Camera Control -to tell the camera that the client wishes to claim control of the camera.

                                                +connected app is discouraged. A third party client should use Set Camera Control to tell the camera +that the client wishes to claim control of the camera.

                                                diff --git a/docs/ble/search.html b/docs/ble/search.html index 869d8f9d..3231f133 100644 --- a/docs/ble/search.html +++ b/docs/ble/search.html @@ -152,14 +152,14 @@
                                                • Control
                                                • Operations
                                                • Setting IDs
                                                    @@ -254,6 +255,7 @@
                                                  • Frames Per Second (3)
                                                  • FOV (43)
                                                  • Auto Off (59)
                                                  • +
                                                  • GPS (83)
                                                  • Aspect Ratio (108)
                                                  • Lens (121)
                                                  • Lens (122)
                                                  • @@ -292,12 +294,15 @@
                                                  • Status IDs
                                                    • Is the system’s internal battery present? (1)
                                                    • Rough approximation of internal battery level in bars (or charging) (2)
                                                    • +
                                                    • Is an external battery connected? (3)
                                                    • +
                                                    • External battery power level in percent (4)
                                                    • Is the system currently overheating? (6)
                                                    • Is the camera busy? (8)
                                                    • Is Quick Capture feature enabled? (9)
                                                    • Is the system encoding right now? (10)
                                                    • Is LCD lock active? (11)
                                                    • When encoding video, this is the duration (seconds) of the video so far; 0 otherwise (13)
                                                    • +
                                                    • When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise (14)
                                                    • Are Wireless Connections enabled? (17)
                                                    • The pairing state of the camera (19)
                                                    • The last type of pairing in which the camera was engaged (20)
                                                    • @@ -315,6 +320,8 @@
                                                    • Primary Storage Status (33)
                                                    • How many photos can be taken with current settings before sdcard is full (34)
                                                    • How many minutes of video can be captured with current settings before sdcard is full (35)
                                                    • +
                                                    • Total number of group photos on sdcard (36)
                                                    • +
                                                    • Total number of group videos on sdcard (37)
                                                    • Total number of photos on sdcard (38)
                                                    • Total number of videos on sdcard (39)
                                                    • The current status of Over The Air (OTA) update (41)
                                                    • @@ -327,6 +334,9 @@
                                                    • The number of hilights in currently-encoding video (value is set to 0 when encoding stops) (58)
                                                    • Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops) (59)
                                                    • The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this (60)
                                                    • +
                                                    • The current state of camera analytics (61)
                                                    • +
                                                    • The size (units??) of the analytics file (62)
                                                    • +
                                                    • Is the camera currently in a contextual menu (e.g. Preferences)? (63)
                                                    • How many minutes of Time Lapse Video can be captured with current settings before sdcard is full (64)
                                                    • Liveview Exposure Select Mode (65)
                                                    • Liveview Exposure Select: y-coordinate (percent) (66)
                                                    • @@ -347,6 +357,8 @@
                                                    • Rotational orientation of the camera (86)
                                                    • Is this camera model capable of zooming while encoding? (88)
                                                    • Current Flatmode ID (89)
                                                    • +
                                                    • Are current flatmode’s Protune settings factory default? (90)
                                                    • +
                                                    • Are system logs ready to be downloaded? (91)
                                                    • Current Video Preset (ID) (93)
                                                    • Current Photo Preset (ID) (94)
                                                    • Current Time Lapse Preset (ID) (95)
                                                    • @@ -363,6 +375,7 @@
                                                    • Is Video Hindsight Capture Active? (106)
                                                    • Scheduled Capture Preset ID (107)
                                                    • Is Scheduled Capture set? (108)
                                                    • +
                                                    • Is the camera in the process of creating a custom preset? (109)
                                                    • Display Mod Status (bitmasked) (110)
                                                    • Does sdcard meet specified minimum write speed? (111)
                                                    • Number of sdcard write speed errors since device booted (112)
                                                    • diff --git a/docs/ble/searchindex.js b/docs/ble/searchindex.js index 9a590d66..1c736b53 100644 --- a/docs/ble/searchindex.js +++ b/docs/ble/searchindex.js @@ -1,4 +1,4 @@ /* searchindex.js/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro). */ -/* This copyright was auto-generated on Tue Mar 5 22:34:20 UTC 2024 */ +/* This copyright was auto-generated on Tue Apr 9 19:25:34 UTC 2024 */ -Search.setIndex({"docnames": ["features/access_points", "features/cohn", "features/control", "features/hilights", "features/live_streaming", "features/presets", "features/query", "features/settings", "features/statuses", "index", "protocol", "protocol/ble_setup", "protocol/data_protocol", "protocol/id_tables", "protocol/protobuf", "protocol/state_management"], "filenames": ["features/access_points.rst", "features/cohn.rst", "features/control.rst", "features/hilights.rst", "features/live_streaming.rst", "features/presets.rst", "features/query.rst", "features/settings.rst", "features/statuses.rst", "index.rst", "protocol.rst", "protocol/ble_setup.rst", "protocol/data_protocol.rst", "protocol/id_tables.rst", "protocol/protobuf.rst", "protocol/state_management.rst"], "titles": ["Access Point", "Camera on the Home Network", "Control", "Hilights", "Live Streaming", "Presets", "Query", "Settings", "Statuses", "Welcome to Open GoPro BLE API\u2019s documentation!", "Protocol", "BLE Setup", "Data Protocol", "ID Tables", "Protobuf Documentation", "State Management"], "terms": {"The": [0, 1, 2, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14], "camera": [0, 2, 4, 5, 6, 10, 11, 12, 13, 14], "support": [0, 1, 2, 4, 6, 7, 11, 13, 14], "connect": [0, 1, 2, 4, 11, 13, 14, 15], "station": [0, 4, 14], "mode": [0, 2, 4, 5, 9, 10, 13, 14], "sta": [0, 14], "thi": [0, 1, 2, 3, 5, 6, 7, 9, 11, 12, 13, 14, 15], "i": [0, 1, 2, 4, 5, 6, 7, 9, 11, 12, 13, 14, 15], "necessari": [0, 7, 11, 12, 15], "featur": [0, 1, 2, 4, 5, 6, 9, 10, 11, 12, 13, 14], "live": [0, 9, 13, 14], "stream": [0, 9, 13, 14], "where": [0, 9, 12], "need": [0, 1, 9, 11], "an": [0, 1, 4, 6, 7, 9, 11, 12, 13, 14, 15], "internet": [0, 14], "while": [0, 3, 9, 11, 13, 14, 15], "http": [0, 1, 14], "command": [0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 14, 15], "control": [0, 1, 5, 9, 10, 11, 13, 14], "avail": [0, 5, 9, 13, 14], "some": [0, 1, 2, 12, 15], "scan": [0, 11, 13, 14], "type": [0, 1, 2, 3, 4, 5, 6, 7, 10, 13, 14], "protobuf": [0, 1, 2, 4, 5, 6, 9, 10], "hero": 7, "hero12": [1, 6, 9], "black": [1, 6, 7, 9], "hero11": [1, 9], "mini": [1, 9], "hero10": [1, 9], "hero9": [1, 9], "request": [0, 1, 2, 3, 4, 5, 6, 7, 9, 12, 13, 14], "start": [0, 2, 4, 6, 12, 13, 14], "serial": [0, 2, 12, 14], "object": [0, 7, 12, 14], "zero": [0, 2, 8, 14], "byte": [0, 2, 6, 12, 13, 14], "respons": [0, 1, 2, 3, 4, 5, 6, 7, 11, 12, 13, 14], "responsestartscan": [0, 13], "ar": [0, 1, 5, 6, 7, 9, 10, 11, 12, 13, 14], "sent": [0, 4, 5, 6, 11, 12, 14], "immedi": [0, 2, 5, 14], "after": [0, 2, 11, 12, 14, 15], "receiv": [0, 6, 9, 11, 12, 14], "notif": [0, 1, 2, 4, 5, 6, 11, 13, 14], "notifstartscan": [0, 13], "period": [0, 5, 14, 15], "state": [0, 5, 6, 7, 9, 10, 11, 12, 13, 14], "chang": [0, 1, 4, 5, 6, 7, 9, 13, 14, 15], "us": [0, 1, 2, 3, 4, 5, 9, 10, 12, 13, 14, 15], "detect": [0, 14], "complet": [0, 9, 13, 14], "uuid": [0, 1, 2, 3, 4, 5, 6, 7, 11, 12], "network": [0, 9, 11, 14], "manag": [0, 9, 10, 11], "id": [0, 1, 2, 3, 4, 5, 6, 9, 10, 12, 14], "0x02": [0, 13], "action": [0, 1, 2, 4, 5, 6, 12, 13], "messag": [0, 1, 2, 4, 5, 6, 9, 10, 13, 14, 15], "requeststartscan": [0, 13], "doc": [0, 1, 2, 4, 5, 6], "sourc": [0, 1, 2, 4, 5, 6, 14], "current": [0, 1, 2, 4, 5, 6, 7, 9, 12, 13, 14], "initi": [0, 4, 5, 6, 10, 14], "0x82": [0, 6, 13], "trigger": [0, 1, 14], "via": [0, 1, 2, 4, 5, 6, 7, 9, 11, 13, 14], "0x0b": [0, 13], "get": [0, 1, 4, 5, 6, 7, 13, 14, 15], "ap": [0, 2, 11, 13, 14], "result": [0, 6, 7, 9, 12, 13, 14], "list": [0, 7, 9, 14], "found": [0, 5, 6, 7, 14], "dure": [0, 3, 11, 14], "responsegetapentri": [0, 13], "0x04": [0, 13], "requestgetapentri": [0, 13], "A": [0, 1, 7, 12, 14, 15], "entri": [0, 14], "describ": [0, 6, 8, 9, 12, 14], "0x84": [0, 13], "provis": [0, 13, 14], "do": [0, 11, 12, 14], "authent": [0, 14], "intend": [0, 14], "previous": [0, 7, 14], "responseconnect": [0, 13], "notifprovisioningst": [0, 13], "requestconnect": [0, 13], "statu": [0, 1, 2, 4, 5, 6, 10, 12, 14, 15], "attempt": [0, 8, 14], "requestconnectnew": [0, 13], "0x0c": [0, 13], "new": [0, 1, 11, 13, 14], "should": [0, 9, 11, 15], "onli": [0, 3, 5, 6, 7, 8, 12, 14], "done": [0, 11], "onc": [0, 1, 11, 12], "subsequ": [0, 9, 11, 12], "responseconnectnew": [0, 13], "0x05": [0, 2, 13], "0x85": [0, 13], "To": [0, 5, 8, 12], "return": [0, 1, 2, 5, 6, 14], "set": [0, 1, 2, 4, 5, 6, 9, 10, 11, 12, 14, 15], "ON": [0, 7, 11], "which": [0, 1, 2, 5, 11, 13, 14], "disabl": [0, 2, 8, 14], "On": [1, 2, 7, 13, 14], "cohn": [1, 13, 14], "capabl": [1, 6, 9, 13], "allow": [1, 11], "client": [1, 2, 11, 15], "perform": [1, 5, 9, 13, 14], "indirectli": 1, "through": [1, 9, 10], "access": [1, 2, 4, 9, 11, 13, 14], "point": [1, 2, 4, 9, 11, 13, 14], "router": 1, "For": [1, 2, 4, 7, 9, 11, 12, 15], "secur": 1, "purpos": 1, "all": [1, 2, 6, 11, 12], "commun": [1, 9, 10, 11], "over": [1, 13], "requir": [1, 11, 14], "two": [1, 8, 11, 12], "thing": 1, "trust": 1, "ssl": [1, 14], "tl": [1, 14], "basic": [1, 7, 9, 14], "auth": [1, 14], "usernam": [1, 14], "password": [1, 11, 14], "header": [1, 14], "ha": [1, 8, 12, 14], "root": [1, 14], "ca": [1, 14], "cert": [1, 14], "provid": 1, "1": [1, 2, 6, 7, 12, 13, 14], "year": [1, 2, 6], "lifespan": 1, "contain": [1, 6, 7, 12, 13, 14], "": [1, 2, 4, 5, 6, 7, 11, 12, 13, 14, 15], "ip": [1, 14], "address": [1, 14], "local": [1, 2, 6, 13, 14], "sign": 1, "chain": 1, "e": [1, 2, 6, 13, 14, 15], "g": [1, 13, 14, 15], "when": [1, 2, 5, 6, 12, 13, 14], "dhcp": 1, "leas": 1, "expir": 1, "reset": [1, 2, 11, 12], "replac": 1, "without": [1, 2, 6], "download": [1, 13], "instal": 1, "act": 1, "author": 1, "creat": [1, 13, 14], "can": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14], "valid": [1, 7, 11, 14], "util": 1, "openssl": 1, "cafil": 1, "path": [1, 6, 14], "goprorootca": 1, "crt": 1, "ok": [1, 8], "most": [1, 2, 9, 13, 14], "system": [1, 13, 14, 15], "have": [1, 11, 12, 13], "about": [1, 2, 4, 6, 14], "maco": 1, "right": [1, 13], "mous": 1, "click": 1, "quick": [1, 13], "look": 1, "window": 1, "properti": [1, 14], "ubuntu": 1, "open": [1, 6, 10, 12, 13], "file": [1, 7, 14], "x509": 1, "noout": 1, "text": [1, 14], "In": [1, 2, 7, 11, 12, 15], "order": [1, 2, 7, 10, 11, 12, 15], "must": [1, 5, 8, 11, 12, 14], "first": [1, 6, 7, 9, 11, 12, 13, 14], "At": 1, "high": [1, 7], "level": [1, 12, 13, 14], "process": [1, 11], "follow": [1, 4, 7, 10, 11, 12, 14], "instruct": 1, "gopro": [1, 2, 6, 8, 10, 11, 12, 13, 15], "credenti": 1, "depend": [1, 5, 6, 7, 12, 14, 15], "case": [1, 5, 9, 14], "step": [1, 11], "nearli": 1, "function": [1, 9], "doe": [1, 11, 13, 14], "more": [1, 6, 7, 11, 12, 13, 14], "see": [1, 4, 6, 7, 9, 11, 12, 13], "specif": [1, 15], "clear": [1, 13, 14], "responsegener": [1, 2, 4, 5, 13], "0xf1": [1, 2, 4, 5, 13], "0x66": [1, 13], "requestclearcohncert": [1, 13], "gener": [1, 2, 4, 5, 14], "across": [1, 2, 4, 5, 14], "mani": [1, 2, 4, 5, 13, 14], "0xe6": [1, 13], "creation": [1, 14], "0x67": [1, 13], "requestcreatecohncert": [1, 13], "0xe7": [1, 13], "responsecohncert": [1, 13], "0xf5": [1, 4, 5, 6, 13], "0x6e": [1, 13], "requestcohncert": [1, 13], "0xee": [1, 13], "notifycohnstatu": [1, 13], "addition": [1, 9, 14], "asynchron": [1, 4, 5, 11, 13, 14], "updat": [1, 2, 5, 6, 9, 13, 14], "also": [1, 14], "regist": [1, 4, 5, 6, 13, 14], "valu": [1, 2, 5, 6, 7, 9, 13, 14], "0x6f": [1, 13], "requestgetcohnstatu": [1, 13], "0xef": [1, 13], "configur": [1, 2, 4, 10, 14], "0x65": [1, 13], "requestsetcohnset": [1, 13], "0xe5": [1, 13], "page": [2, 14], "detail": [2, 4, 7, 14], "keep": [2, 10, 13], "aliv": [2, 10, 13], "tlv": [2, 3, 5, 6, 7, 12], "0x5b": [2, 13], "maxim": [2, 12], "batteri": [2, 7, 13], "life": 2, "automat": [2, 14, 15], "go": 2, "sleep": [2, 11, 13], "time": [2, 6, 11, 13, 14, 15], "logic": 2, "handl": 2, "combin": 2, "auto": [2, 8, 13], "power": [2, 11, 13, 15], "down": [2, 13], "user": [2, 7, 9, 14, 15], "regularli": 2, "send": [2, 9, 12, 14, 15], "both": 2, "timer": 2, "reach": 2, "tap": 2, "lcd": [2, 13], "screen": [2, 14], "press": 2, "button": [2, 14], "programmat": 2, "un": 2, "shutter": [2, 4, 13], "load": [2, 5, 13, 15], "preset": [2, 7, 9, 13, 15], "best": [2, 11, 13, 15], "practic": [2, 11, 13, 15], "prevent": [2, 15], "from": [2, 5, 6, 7, 8, 11, 12, 14], "inadvert": 2, "everi": [2, 7], "3": [2, 12, 13, 14], "0": [2, 6, 7, 12, 13, 14], "second": [2, 6, 13, 14], "establish": 2, "paramet": [2, 5, 6, 7, 12], "keep_al": 2, "uint8": [2, 6, 7], "hard": 2, "code": [2, 9], "data": [2, 6, 9, 10, 11], "0x42": 2, "analyt": [2, 13], "0x50": [2, 13], "third": [2, 14, 15], "parti": [2, 14, 15], "track": 2, "0x17": [2, 13], "enabl": [2, 5, 11, 13, 14], "wifi": [2, 11, 13, 14], "part": [2, 6, 14], "global": [2, 14], "behavior": [2, 14, 15], "tell": [2, 14, 15], "app": [2, 8, 14, 15], "extern": [2, 8, 14], "wish": [2, 14, 15], "claim": [2, 14, 15], "caus": [2, 11, 14], "exit": [2, 12, 14], "contextu": [2, 14], "menu": [2, 8, 14], "idl": [2, 8, 14], "ani": [2, 4, 9, 14], "interact": [2, 14], "physic": [2, 14], "reclaim": [2, 14], "accordingli": [2, 14], "If": [2, 6, 7, 11, 12, 14, 15], "ui": [2, 11, 13, 14], "entiti": [2, 8, 14], "advertis": [2, 10, 14], "114": [2, 7, 13, 14], "inform": [2, 6, 7, 11, 13, 14], "whether": [2, 11, 12, 14], "63": [2, 14], "0x69": [2, 13], "requestsetcameracontrolstatu": [2, 13], "0xe9": [2, 13], "date": [2, 6, 13], "0x0d": [2, 13], "timezon": [2, 6], "daylight": [2, 6], "save": [2, 6, 14], "date_tim": 2, "7": [2, 7, 8, 12, 14], "defin": [2, 6, 7, 12, 14], "uint16": [2, 6], "month": [2, 6], "12": [2, 6, 7, 8, 14], "dai": [2, 6], "31": [2, 6, 12, 13, 14], "hour": [2, 6, 7, 11], "23": [2, 6, 7, 13, 14], "minut": [2, 6, 7, 13], "59": [2, 6, 13, 14], "exampl": [2, 7, 9, 11, 12, 15], "2023": 2, "01": [2, 6, 9, 12], "03": [2, 9], "04": 2, "05": 2, "07": 2, "e7": 2, "1f": 2, "abov": [2, 6, 7, 9], "0x0f": [2, 13], "10": [2, 7, 9, 12, 13, 14], "int16": [2, 6], "utc": [2, 6], "offset": [2, 6], "is_dst": [2, 6], "otherwis": [2, 12, 13], "02": 2, "00": [2, 9, 12], "dst": 2, "ff": 2, "88": [2, 13], "0x01": [2, 13], "off": [2, 15], "turbo": [2, 13, 14], "transfer": [2, 13, 14], "displai": [2, 13, 14], "media": [2, 4, 6, 13, 15], "0x6b": [2, 13], "requestsetturboact": [2, 13], "0xeb": [2, 13], "put": [2, 4, 11], "still": 2, "ble": [2, 10, 12, 13], "moment": [3, 13], "0x18": [3, 13], "add": [3, 14], "record": [3, 13], "encod": [3, 9, 13, 14, 15], "abil": 4, "social": 4, "platform": 4, "twitch": 4, "youtub": 4, "facebook": 4, "other": [4, 15], "site": 4, "accept": [4, 13, 14, 15], "rtmp": [4, 14], "url": [4, 14], "addit": [4, 14], "how": [4, 9, 12, 13], "accomplish": [4, 12], "livestream": [4, 13, 14], "poll": [4, 13], "until": 4, "indic": [4, 11, 14], "readi": [4, 10, 13, 14], "begin": 4, "unset": [4, 15], "stop": [4, 13, 14], "queri": [4, 5, 7, 8, 9, 10, 11, 15], "0x79": [4, 13], "requestsetlivestreammod": [4, 13], "0xf9": [4, 13], "option": [4, 5, 6, 7, 8, 12, 14], "futur": [4, 14], "notifylivestreamstatu": [4, 13], "0x74": [4, 13], "requestgetlivestreamstatu": [4, 13], "either": [4, 5, 12, 14], "As": [4, 14], "synchron": [4, 5, 14], "0xf4": [4, 13], "organ": 5, "differ": [5, 12], "collect": 5, "below": [5, 7, 9, 11, 12], "tabl": [5, 9, 10, 11, 12], "affect": 5, "therebi": 5, "162": [5, 13], "max": [5, 8, 13, 14], "len": [5, 13, 14], "173": [5, 13], "video": [5, 6, 9, 13, 14, 15], "175": [5, 13], "177": [5, 13], "night": [5, 13], "photo": [5, 6, 9, 13, 14, 15], "180": [5, 8, 13], "186": [5, 13], "187": [5, 13], "laps": [5, 13], "189": [5, 13], "mod": [5, 13], "190": [5, 13], "191": [5, 13], "find": 5, "notifi": [5, 11, 14], "notifypresetstatu": [5, 13], "0x72": [5, 6, 13], "requestgetpresetstatu": [5, 13], "0xf2": [5, 13], "0xf3": [5, 13], "0x40": [5, 13], "uint32": 5, "0x3e": [5, 13], "custom": [5, 13, 14], "titl": [5, 14], "icon": [5, 14], "activ": [5, 9, 13, 14, 15], "fail": [5, 7, 8, 14], "icon_id": [5, 14], "alwai": [5, 7, 9, 12, 14, 15], "pass": [5, 14], "factori": [5, 11, 14], "title_id": [5, 14], "non": [5, 14], "preset_title_user_defined_custom_nam": [5, 14], "94": [5, 13, 14], "name": [5, 7, 8, 9, 14], "specifi": [5, 12, 13, 14], "custom_nam": [5, 14], "0x64": [5, 13], "requestcustompresetupd": [5, 13], "0xe4": [5, 13], "section": [6, 8, 9, 10, 11, 12], "variou": [6, 9, 10], "version": [6, 7, 9, 12, 13], "0x51": [6, 13], "api": 6, "major_length": 6, "length": [6, 13], "major": 6, "unsign": 6, "number": [6, 13, 14], "minor_length": 6, "minor": 6, "0x0e": [6, 13], "response_length": 6, "payload": [6, 10], "weekdai": 6, "sundai": 6, "saturdai": 6, "6": [6, 7, 12, 13, 14], "hardwar": [6, 13], "info": [6, 13, 14], "0x3c": [6, 13], "firmwar": [6, 7, 9, 13], "note": [6, 12], "model": [6, 9, 13, 14], "under": 6, "model_number_length": 6, "model_numb": 6, "model_name_length": 6, "model_nam": 6, "string": [6, 8, 12, 14], "deprecated_length": 6, "deprec": 6, "firmware_version_length": 6, "firmware_vers": 6, "h23": [6, 9], "99": [6, 13], "56": [6, 13], "serial_number_length": 6, "serial_numb": 6, "c1234567812345": 6, "ap_ssid_length": 6, "ap_ssid": 6, "gp12345678": 6, "ap_mac_address_length": 6, "ap_mac_address": 6, "2674f7f65f78": 6, "reserv": [6, 12], "11": [6, 7, 13, 14], "0x10": [6, 13], "ye": 6, "last": [6, 13, 14], "captur": [6, 13, 14, 15], "filenam": [6, 14], "responselastcapturedmedia": [6, 13], "0x6d": [6, 13], "requestgetlastcapturedmedia": [6, 13], "rel": [6, 14], "dcim": [6, 14], "directori": [6, 14], "sdcard": [6, 13, 14, 15], "singl": [6, 12, 14], "group": [6, 13, 14], "0xed": [6, 13], "associ": [6, 9, 14], "one": [6, 7, 8, 12], "element": [6, 12, 13], "arrai": [6, 12, 14], "empti": 6, "0x12": [6, 13], "field": [6, 14], "individu": [6, 7, 12, 14], "document": [6, 7, 10, 12], "status": [6, 9, 14], "0x13": [6, 13], "report": 6, "those": 6, "0x32": [6, 13], "whenev": 6, "0x52": [6, 13], "0x92": [6, 13], "0x53": [6, 13], "0x93": [6, 13], "0x62": [6, 13], "0xa2": [6, 13], "unregist": [6, 13, 14], "cancel": [6, 13], "ongo": 6, "0x73": [6, 13], "usual": [7, 14], "anoth": 7, "often": [7, 13], "releas": 7, "next": 7, "whitelist": 7, "These": 7, "each": [7, 11, 12, 13], "compris": [7, 12, 14], "present": [7, 13], "mean": [7, 14], "guarante": 7, "attain": 7, "failur": 7, "adher": 7, "mai": [7, 14, 15], "blacklist": 7, "rule": 7, "reject": [7, 9, 14, 15], "4": [7, 12, 13, 14], "5": [7, 13, 14], "re": [7, 11, 14], "1080": 7, "60": [7, 9, 13, 14], "hz": 7, "240": 7, "wide": 7, "work": [7, 12], "standard": 7, "suppos": 7, "wa": [7, 11, 13, 14], "4k": 7, "tri": 7, "becaus": [7, 14], "240fp": 7, "here": [7, 12], "spreadsheet": 7, "worksheet": 7, "row": [7, 12], "repres": [7, 14], "outlin": 7, "construct": 7, "given": [7, 14], "schema": 7, "settingid": [7, 13], "superset": 7, "per": [12, 13], "altern": [7, 11, 12], "dynam": [7, 11], "value_length": 7, "variabl": [7, 12], "7k": 7, "4by3": [], "1440": 7, "9": [7, 13, 14], "18": [7, 14], "24": [7, 13, 14], "5k": 7, "25": [7, 14], "26": [7, 13, 14], "3k": 7, "8by7": [], "27": [7, 13, 14], "28": [7, 13, 14], "100": [7, 13], "107": [7, 13], "v2": [], "109": 7, "9by16": [], "110": [7, 13], "111": [7, 13], "120": 7, "50": 7, "8": [7, 11, 13, 14], "30": [7, 13, 14], "13": [7, 13, 14], "200": 7, "narrow": [7, 11], "superview": 7, "linear": 7, "never": [7, 8], "min": 7, "15": [7, 14], "16by9": [], "plu": [], "hyperview": 7, "lock": [7, 13], "19": [7, 13, 14], "101": [7, 13], "102": [7, 13], "20": [7, 12, 13, 14], "21": [7, 13, 14], "boost": 7, "maximum": [7, 14], "extend": 7, "tripod": 7, "stationari": 7, "pro": 7, "8x": 7, "ultra": 7, "slo": 7, "mo": 7, "4x": 7, "super": 7, "2x": [7, 8], "1x": [7, 8], "low": [7, 9, 14], "light": 7, "eb": [], "50hz": 7, "14": [7, 14], "16": [7, 14], "lb": [], "17": [7, 13, 14], "22": [7, 13, 14], "103": [7, 13], "104": [7, 13], "105": [7, 13], "106": [7, 13], "112": [7, 13], "113": [7, 13], "115": [7, 13], "116": [7, 13], "117": [7, 13], "118": 7, "mobil": 13, "119": 7, "univers": [], "124": 7, "125": 7, "126": 7, "127": 7, "129": 7, "130": 7, "131": 7, "132": 7, "133": 7, "136": 7, "137": 7, "ghz": 8, "short": 7, "long": 7, "highest": 7, "qualiti": 7, "green": [], "longest": 7, "8bit": [], "10bit": [], "hdr": 7, "log": 7, "warp": 13, "star": 7, "paint": 7, "vehicl": 7, "none": 7, "widescreen": 7, "vertic": 7, "full": [7, 13, 14], "its": [8, 12], "oper": [8, 10, 13, 14], "fals": [8, 14], "true": 8, "One": 8, "three": 8, "abort": 8, "bluetooth": [8, 9], "unknown": [8, 14], "remov": [8, 14], "format": [8, 9, 12, 13, 14, 15], "swap": 8, "verifi": 8, "iso": 8, "hemispher": 8, "percentag": [], "plug": 8, "degre": 8, "upright": 8, "upsid": 8, "90": 8, "lai": 8, "side": 8, "270": 8, "left": 8, "15x": 8, "30x": 8, "60x": 8, "150x": 8, "300x": 8, "900x": 8, "1800x": 8, "5x": 8, "10x": 8, "realtim": 8, "slow": 8, "motion": 8, "default": [8, 14], "000": 8, "hdmi": 8, "001": 8, "010": 8, "011": 8, "No": [8, 14], "interven": 8, "outsid": [8, 14], "energi": 9, "pertain": 9, "public": 9, "market": 9, "minim": 9, "62": [9, 14], "v01": 9, "h22": 9, "58": [9, 13, 14], "57": 9, "h21": 9, "55": [9, 13], "hd9": 9, "70": [9, 13, 14], "mininum": 9, "assum": 9, "recent": [9, 13], "relev": [9, 11, 12], "between": [9, 13, 14, 15], "read": [9, 10, 11], "protocol": [9, 11], "understand": 9, "setup": [9, 10], "Then": 9, "desir": [9, 14], "home": [9, 14], "hilight": [9, 13], "walk": 9, "tutori": [9, 12], "demonstr": 9, "well": 9, "demo": 9, "program": 9, "languag": [9, 14], "hindsight": [9, 13], "core": [9, 13], "undefin": [9, 15], "try": 9, "digit": [9, 13], "lens": [9, 13, 14], "fov": [9, 14], "base": 9, "pair": [10, 12, 13], "finish": [10, 14], "gatt": [10, 12], "characterist": [10, 12], "packet": 10, "deciph": 10, "refer": 10, "befor": [11, 12, 13, 14, 15], "overview": 11, "up": 11, "ensur": 11, "discov": [11, 14], "peripher": 11, "devic": [11, 13], "limit": [11, 12], "servic": 11, "0xfea6": 11, "subscrib": 11, "flag": [11, 15], "discover": 11, "wake": 11, "boot": [11, 13], "procedur": [11, 12], "again": 11, "store": 11, "so": [11, 13], "wai": 11, "cach": 11, "subscript": 11, "upon": 11, "gp": [11, 12, 13], "xxxx": 11, "shorthand": 11, "128": [11, 13], "bit": [11, 13], "b5f9xxxx": 11, "aa8d": 11, "11e3": 11, "9046": 11, "0002a5d5c51b": 11, "descript": 11, "permiss": 11, "0001": 11, "0002": 11, "ssid": [11, 13, 14], "write": [11, 13], "0003": 11, "0004": 11, "0005": 11, "0090": 11, "0091": 11, "0092": 11, "fea6": 11, "0072": [11, 12], "0073": 11, "0074": [11, 12], "0075": 11, "0076": [11, 12], "0077": 11, "wait": [11, 14, 15], "correspond": [11, 13, 14], "build": 11, "pars": [11, 12], "terminologi": 12, "includ": [12, 14], "accumul": 12, "depacket": 12, "extract": 12, "identifi": 12, "big": [12, 13], "endian": [12, 13], "unless": [12, 15], "v4": 12, "2": [12, 13, 14], "size": 12, "accommod": 12, "larger": 12, "less": 12, "than": [12, 13, 15], "split": 12, "multipl": 12, "prepend": 12, "onto": 12, "fewer": 12, "8191": 12, "avoid": 12, "8192": 12, "longer": 12, "respond": 12, "It": 12, "n": 12, "counter": 12, "0x0": 12, "0xf": 12, "been": [12, 14], "determin": 12, "appropri": 12, "pseudocod": 12, "u": 12, "p": 12, "f": 12, "int": 12, "match": 12, "structur": 12, "nope": 12, "scheme": 12, "els": 12, "map": 12, "flowchart": 12, "form": 12, "had": 12, "top": 12, "thei": 12, "consid": 12, "There": 12, "summar": 12, "throughout": 12, "respect": 12, "triplet": 12, "bandwidth": 12, "googl": 12, "buffer": 12, "deseri": 12, "certif": [13, 14], "resolut": [13, 14], "fp": 7, "43": 13, "broadcast": [], "108": 13, "aspect": 13, "ratio": 13, "121": 13, "122": 13, "123": 13, "multi": [], "shot": [], "134": 13, "anti": 13, "flicker": 13, "135": 13, "hypersmooth": 13, "150": 13, "horizon": 13, "151": 13, "167": 13, "171": 13, "interv": 13, "172": 13, "durat": 13, "profil": 13, "ux": [], "176": 13, "easi": [7, 13], "speed": 13, "178": 13, "wireless": 13, "band": 13, "179": 13, "trail": 13, "182": 13, "rate": 13, "183": 13, "depth": 13, "184": 13, "addon": [], "192": 13, "nlv": [], "193": 13, "frame": 13, "intern": 13, "rough": 13, "approxim": 13, "bar": [13, 14], "charg": 13, "overh": 13, "busi": [13, 15], "now": 13, "far": 13, "engag": 13, "sinc": 13, "millisecond": 13, "success": [13, 14], "remot": 13, "wirelesspairingstateflag": 13, "29": [13, 14], "int32": [13, 14], "32": [13, 14], "preview": 13, "33": [13, 14], "primari": [13, 14], "storag": 13, "34": [13, 14], "taken": 13, "35": [13, 14], "38": [13, 14], "total": [13, 14], "39": [13, 14], "41": [13, 14], "air": 13, "ota": 13, "42": [13, 14], "pend": 13, "45": 13, "locat": 13, "49": 13, "timelaps": 13, "countdown": 13, "54": 13, "remain": 13, "space": 13, "kilobyt": 13, "secondari": [13, 14], "signal": [13, 14, 15], "strength": [13, 14], "minimum": [13, 14], "64": [13, 14], "65": [13, 14], "liveview": 13, "exposur": 13, "select": 13, "66": [13, 14], "y": 13, "coordin": 13, "percent": 13, "67": [13, 14], "68": [13, 14], "69": [13, 14], "74": [13, 14], "microphon": 13, "accessori": 13, "75": [13, 14], "zoom": 13, "76": [13, 14], "77": [13, 14], "78": [13, 14], "friendli": 13, "relat": 13, "compress": 13, "79": [13, 14], "ftu": 13, "flow": 13, "81": 13, "5ghz": [7, 13], "82": [13, 14], "fulli": 13, "83": [13, 14], "suffici": 13, "85": [13, 14], "too": 13, "cold": 13, "continu": 13, "86": 13, "rotat": 13, "orient": 13, "89": 13, "flatmod": [13, 14], "93": [13, 14], "95": 13, "96": 13, "ui_mode_group": 13, "json": 13, "97": 13, "98": 13, "modifi": [13, 14], "event": 13, "burst": 13, "delai": 13, "count": [13, 14], "linux": [13, 14], "reflect": 13, "schedul": 13, "bitmask": [13, 14], "meet": 13, "error": [13, 14], "pc": 13, "usb": 13, "sd": [13, 14], "card": [13, 14], "capac": 13, "summari": 14, "cohn_state_init": 14, "cohn_state_error": 14, "cohn_state_exit": 14, "cohn_state_idl": 14, "cohn_state_networkconnect": 14, "cohn_state_networkdisconnect": 14, "cohn_state_connectingtonetwork": 14, "cohn_state_invalid": 14, "cohn_unprovis": 14, "cohn_provis": 14, "camera_idl": 14, "camera_control": 14, "camera_external_control": 14, "flat_mode_unknown": 14, "flat_mode_playback": 14, "flat_mode_setup": 14, "flat_mode_video": 14, "flat_mode_time_lapse_video": 14, "flat_mode_loop": 14, "flat_mode_photo_singl": 14, "flat_mode_photo": 14, "flat_mode_photo_night": 14, "flat_mode_photo_burst": 14, "flat_mode_time_lapse_photo": 14, "flat_mode_night_lapse_photo": 14, "flat_mode_broadcast_record": 14, "flat_mode_broadcast_broadcast": 14, "flat_mode_time_warp_video": 14, "flat_mode_live_burst": 14, "flat_mode_night_lapse_video": 14, "flat_mode_slomo": 14, "flat_mode_idl": 14, "flat_mode_video_star_trail": 14, "flat_mode_video_light_paint": 14, "flat_mode_video_light_trail": 14, "lens_wid": 14, "lens_superview": 14, "lens_linear": 14, "live_stream_error_non": 14, "live_stream_error_network": 14, "live_stream_error_createstream": 14, "startup": 14, "bad": 14, "server": 14, "live_stream_error_outofmemori": 14, "Not": [8, 14], "enough": 14, "memori": 14, "task": 14, "live_stream_error_inputstream": 14, "live_stream_error_internet": 14, "streamer": 14, "live_stream_error_osnetwork": 14, "occur": 14, "stack": 14, "close": 14, "live_stream_error_selectednetworktimeout": 14, "out": 14, "attemp": 14, "live_stream_error_ssl_handshak": 14, "handshak": 14, "commonli": 14, "due": 14, "incorrect": 14, "zone": 14, "live_stream_error_camera_block": 14, "live_stream_error_unknown": 14, "live_stream_error_sd_card_ful": 14, "40": 14, "live_stream_error_sd_card_remov": 14, "live_stream_state_idl": 14, "yet": 14, "live_stream_state_config": 14, "being": 14, "live_stream_state_readi": 14, "live_stream_state_stream": 14, "live_stream_state_complete_stay_on": 14, "live_stream_state_failed_stay_on": 14, "live_stream_state_reconnect": 14, "reconnect": 14, "preset_group_id_video": 14, "1000": 14, "preset_group_id_photo": 14, "1001": 14, "preset_group_id_timelaps": 14, "1002": 14, "preset_group_video_icon_id": 14, "preset_group_photo_icon_id": 14, "preset_group_timelapse_icon_id": 14, "preset_group_long_bat_video_icon_id": 14, "preset_group_endurance_video_icon_id": 14, "preset_group_max_video_icon_id": 14, "preset_group_max_photo_icon_id": 14, "preset_group_max_timelapse_icon_id": 14, "preset_icon_video": 14, "preset_icon_act": 14, "preset_icon_cinemat": 14, "preset_icon_photo": 14, "preset_icon_live_burst": 14, "preset_icon_burst": 14, "preset_icon_photo_night": 14, "preset_icon_timewarp": 14, "preset_icon_timelaps": 14, "preset_icon_nightlaps": 14, "preset_icon_snail": 14, "preset_icon_video_2": 14, "preset_icon_360_video": [], "preset_icon_photo_2": 14, "preset_icon_panorama": 14, "preset_icon_burst_2": 14, "preset_icon_timewarp_2": 14, "preset_icon_timelapse_2": 14, "preset_icon_custom": 14, "preset_icon_air": 14, "preset_icon_bik": 14, "preset_icon_ep": 14, "preset_icon_indoor": 14, "preset_icon_motor": 14, "preset_icon_mount": 14, "preset_icon_outdoor": 14, "preset_icon_pov": 14, "preset_icon_selfi": 14, "preset_icon_sk": 14, "preset_icon_snow": 14, "preset_icon_trail": 14, "preset_icon_travel": 14, "preset_icon_wat": 14, "preset_icon_loop": 14, "preset_icon_star": 14, "preset_icon_follow_cam": 14, "36": 14, "preset_icon_surf": 14, "37": 14, "preset_icon_c": 14, "preset_icon_shaki": 14, "preset_icon_chesti": 14, "preset_icon_helmet": 14, "preset_icon_bit": 14, "preset_icon_max_video": [], "preset_icon_max_photo": [], "preset_icon_max_timewarp": [], "preset_icon_bas": 14, "preset_icon_ultra_slo_mo": 14, "preset_icon_standard_endur": 14, "preset_icon_activity_endur": 14, "61": 14, "preset_icon_cinematic_endur": 14, "preset_icon_slomo_endur": 14, "preset_icon_stationary_1": 14, "preset_icon_stationary_2": 14, "preset_icon_stationary_3": 14, "preset_icon_stationary_4": 14, "preset_icon_simple_super_photo": 14, "preset_icon_simple_night_photo": 14, "71": 14, "preset_icon_highest_quality_video": 14, "73": 14, "preset_icon_standard_quality_video": 14, "preset_icon_basic_quality_video": 14, "preset_icon_star_trail": 14, "preset_icon_light_paint": 14, "preset_icon_light_trail": 14, "preset_icon_full_fram": 14, "preset_icon_easy_max_video": [], "80": [], "preset_icon_easy_max_photo": [], "preset_icon_easy_max_timewarp": [], "preset_icon_easy_max_star_trail": [], "preset_icon_easy_max_light_paint": [], "84": [], "preset_icon_easy_max_light_trail": [], "preset_icon_max_star_trail": [], "preset_icon_max_light_paint": [], "preset_icon_max_light_trail": [], "91": [], "preset_icon_360_burst": [], "92": [], "preset_icon_360_photo_night": [], "preset_icon_360_nightlaps": [], "preset_icon_360_timelapse_photo": [], "preset_icon_360_nightlapse_photo": [], "preset_icon_360_photo": [], "preset_icon_360_timelaps": [], "preset_icon_360_timewarp": [], "preset_icon_timelapse_photo": 14, "preset_icon_nightlapse_photo": 14, "preset_icon_max": [], "preset_title_act": 14, "preset_title_standard": 14, "preset_title_cinemat": 14, "preset_title_photo": 14, "preset_title_live_burst": 14, "preset_title_burst": 14, "preset_title_night": 14, "preset_title_time_warp": 14, "preset_title_time_laps": 14, "preset_title_night_laps": 14, "preset_title_video": 14, "preset_title_slomo": 14, "preset_title_360_video": [], "preset_title_photo_2": 14, "preset_title_panorama": 14, "preset_title_360_photo": [], "preset_title_time_warp_2": 14, "preset_title_360_time_warp": [], "preset_title_custom": 14, "preset_title_air": 14, "preset_title_bik": 14, "preset_title_ep": 14, "preset_title_indoor": 14, "preset_title_motor": 14, "preset_title_mount": 14, "preset_title_outdoor": 14, "preset_title_pov": 14, "preset_title_selfi": 14, "preset_title_sk": 14, "preset_title_snow": 14, "preset_title_trail": 14, "preset_title_travel": 14, "preset_title_wat": 14, "preset_title_loop": 14, "preset_title_star": 14, "preset_title_follow_cam": 14, "preset_title_surf": 14, "preset_title_c": 14, "preset_title_shaki": 14, "preset_title_chesti": 14, "preset_title_helmet": 14, "preset_title_bit": 14, "preset_title_360_timelaps": [], "51": [], "preset_title_360_night_laps": [], "52": [], "preset_title_360_night_photo": [], "53": [], "preset_title_pano_time_laps": [], "preset_title_max_video": [], "preset_title_max_photo": [], "preset_title_max_timewarp": [], "preset_title_bas": 14, "preset_title_ultra_slo_mo": 14, "preset_title_standard_endur": 14, "preset_title_activity_endur": 14, "preset_title_cinematic_endur": 14, "preset_title_slomo_endur": 14, "preset_title_stationary_1": 14, "preset_title_stationary_2": 14, "preset_title_stationary_3": 14, "preset_title_stationary_4": 14, "preset_title_simple_video": 14, "preset_title_simple_time_warp": 14, "preset_title_simple_super_photo": 14, "preset_title_simple_night_photo": 14, "preset_title_simple_video_endur": 14, "72": 14, "preset_title_highest_qu": 14, "preset_title_extended_batteri": 14, "preset_title_longest_batteri": 14, "preset_title_star_trail": 14, "preset_title_light_paint": 14, "preset_title_light_trail": 14, "preset_title_full_fram": 14, "preset_title_max_lens_video": [], "preset_title_max_lens_timewarp": [], "preset_title_standard_quality_video": 14, "preset_title_basic_quality_video": 14, "preset_title_easy_max_video": [], "preset_title_easy_max_photo": [], "preset_title_easy_max_timewarp": [], "preset_title_easy_max_star_trail": [], "87": [], "preset_title_easy_max_light_paint": [], "preset_title_easy_max_light_trail": [], "preset_title_max_star_trail": [], "preset_title_max_light_paint": [], "preset_title_max_light_trail": [], "preset_title_highest_quality_video": 14, "preset_title_360_burst": [], "preset_title_360_night": [], "preset_title_360_time_lapse_photo": [], "preset_title_360_night_lapse_photo": [], "preset_title_max": [], "provisioning_unknown": 14, "provisioning_never_start": 14, "provisioning_start": 14, "provisioning_aborted_by_system": 14, "provisioning_cancelled_by_us": 14, "provisioning_success_new_ap": 14, "provisioning_success_old_ap": 14, "provisioning_error_failed_to_associ": 14, "provisioning_error_password_auth": 14, "provisioning_error_eula_block": 14, "provisioning_error_no_internet": 14, "provisioning_error_unsupported_typ": 14, "register_live_stream_status_statu": 14, "register_live_stream_status_error": 14, "register_live_stream_status_mod": 14, "register_live_stream_status_bitr": 14, "register_preset_status_preset": 14, "register_preset_status_preset_group_arrai": 14, "result_unknown": 14, "result_success": 14, "result_ill_form": 14, "result_not_support": 14, "result_argument_out_of_bound": 14, "result_argument_invalid": 14, "result_resource_not_avail": 14, "scan_flag_open": 14, "scan_flag_authent": 14, "scan_flag_configur": 14, "scan_flag_best_ssid": 14, "scan_flag_associ": 14, "scan_flag_unsupported_typ": 14, "scanning_unknown": 14, "scanning_never_start": 14, "scanning_start": 14, "scanning_aborted_by_system": 14, "scanning_cancelled_by_us": 14, "scanning_success": 14, "window_size_480": 14, "window_size_720": 14, "window_size_1080": 14, "common": 14, "typespec": 14, "folder": 14, "provisioning_st": 14, "scanning_st": 14, "scan_id": 14, "total_entri": 14, "total_configured_ssid": 14, "ipaddress": 14, "bool": 14, "macaddress": 14, "mac": 14, "adapt": 14, "live_stream_statu": 14, "live_stream_error": 14, "live_stream_encod": 14, "live_stream_bitr": 14, "bitrat": 14, "kbp": 14, "live_stream_window_size_supported_arrai": 14, "live_stream_encode_support": 14, "live_stream_max_lens_unsupport": 14, "NOT": 14, "live_stream_minimum_stream_bitr": 14, "static": 14, "live_stream_maximum_stream_bitr": 14, "live_stream_lens_support": 14, "live_stream_lens_supported_arrai": 14, "preset_group_arrai": 14, "custom_icon_id": [], "custom_title_id": [], "title_numb": 14, "custom1": 14, "custom2": 14, "custom3": 14, "user_defin": 14, "setting_arrai": 14, "is_modifi": 14, "is_fix": 14, "mutabl": 14, "meta": 14, "preset_arrai": 14, "can_add_preset": 14, "room": 14, "represent": 14, "is_capt": 14, "appear": 14, "pill": 14, "contigu": [], "integ": [], "index": [], "static_ip": 14, "gatewai": 14, "subnet": 14, "mask": 14, "dns_primari": 14, "dn": 14, "dns_secondari": 14, "overrid": 14, "utf": 14, "obei": 14, "charact": 14, "inclus": 14, "special": 14, "english": 14, "french": 14, "italian": 14, "german": 14, "spanish": 14, "portugues": 14, "swedish": 14, "russian": 14, "start_index": 14, "max_entri": 14, "register_cohn_statu": 14, "register_live_stream_statu": 14, "unregister_live_stream_statu": 14, "register_preset_statu": 14, "unregister_preset_statu": 14, "disconnect": 14, "drop": 14, "cohn_act": 14, "camera_control_statu": 14, "declar": 14, "who": 14, "take": 14, "window_s": 14, "pem": 14, "minimum_bitr": 14, "honor": 14, "maximum_bitr": 14, "starting_bitr": 14, "ascii": 14, "timeout_second": 14, "timeout": 14, "batch": 14, "invalid": 14, "result_resource_not_availbl": 14, "scan_entry_flag": 14, "alreadi": 14, "signal_strength_bar": 14, "dbm": 14, "signal_frequency_mhz": 14, "frequenc": 14, "mhz": 14, "incom": 15, "howev": 15, "5min": 15, "15min": 15, "30min": 15, "therefor": 15, "maintain": 15, "simultan": 15, "discourag": 15, "todo": [], "rang": 14, "60hz": 7, "ext": [], "batt": [], "4ghz": 7, "timewarp": 7, "webcam": 13, "hero13": [], "wsdk_requestclearcohncert": [], "wsdk_requestcreatecohncert": [], "wsdk_responsecohncert": [], "wsdk_requestcohncert": [], "wsdk_notifycohnstatu": [], "wsdk_requestgetcohnstatu": [], "wsdk_requestsetcohnset": [], "wsdk_requestsetcameracontrolstatu": [], "wsdk_requestsetturboact": [], "wsdk_requestsetlivestreammod": [], "wsdk_notifylivestreamstatu": [], "wsdk_requestgetlivestreamstatu": [], "wsdk_notifypresetstatu": [], "wsdk_requestgetpresetstatu": [], "wsdk_preset_title_user_defined_custom_nam": [], "wsdk_requestcustompresetupd": [], "wsdk_responselastcapturedmedia": [], "wsdk_requestgetlastcapturedmedia": [], "720": [], "6k": [], "8k": [], "900": [], "400": [], "300": [], "480": [], "6400": [], "1600": [], "3200": [], "800": [], "1800": [], "3600": [], "3601": [], "ask": [], "hidden": [], "250000": [], "250": [], "400000": [], "600000": [], "600": [], "700000": [], "700": [], "800000": [], "1000000": [], "mbp": [], "1200000": [], "1600000": [], "2000000": [], "2400000": [], "2500000": [], "4000000": [], "subsampl": [], "squar": [], "chines": [], "japanes": [], "korean": [], "tradit": [], "uk": [], "au": [], "na": [], "ind": [], "mute": [], "medium": [], "hevc": [], "h": [], "264": [], "landscap": [], "255": [], "5500k": [], "6500k": [], "nativ": [], "4000k": [], "6000k": [], "2300k": [], "2800k": [], "3200k": [], "4500k": [], "5000k": [], "flat": [], "natur": [], "vibrant": [], "superphoto": [], "loop": [], "8mp": [], "12mp": [], "stereo": [], "back": [], "960": [], "1920": [], "384": [], "3840": [], "768": [], "1536": [], "3072": [], "288": [], "576": [], "1152": [], "2304": [], "4608": [], "6144": [], "46": [], "1200": [], "2400": [], "4800": [], "2880": [], "5760": [], "7680": [], "cinemat": [], "500": [], "2000": [], "actual": [], "view": [], "real": [], "half": [], "line": [], "macro": [], "anamorph": [], "nd": [], "filter": [], "jpg": [], "36p": [], "boss": [], "libgpctrld": [], "src": [], "camera_statu": [], "cpp": [], "44": [], "bnr": [], "47": [], "48": [], "privaci": [], "gop": [], "idr": [], "audio": [], "protun": [], "voic": [], "beep": [], "bright": [], "led": [], "white": [], "balanc": [], "color": [], "sharp": [], "ev": [], "comp": [], "output": [], "lower": [], "upper": [], "megapixel": [], "mic": [], "138": [], "360": [], "139": [], "raw": [], "141": [], "quikcaptur": [], "143": [], "144": [], "145": [], "146": [], "147": [], "148": [], "149": [], "wind": [], "153": [], "154": [], "front": [], "155": [], "ramp": [], "156": [], "157": [], "158": [], "saver": [], "159": [], "rear": [], "160": [], "161": [], "163": [], "164": [], "165": [], "166": [], "168": [], "169": [], "174": [], "181": [], "194": [], "195": [], "region": [], "196": [], "extens": [], "197": [], "198": [], "denois": [], "199": [], "hlg": [], "unus": [], "viewer": [], "b": [], "yy": [], "mm": [], "dd": [], "hh": [], "ss": [], "hex": [], "hero8": [], "submod": [], "multishot": [], "unit": [], "prefer": [], "exclus": [], "superbank": [], "hero7": [], "temperatur": [], "silver": [], "wsdk_cohn_state_init": [], "wsdk_cohn_state_error": [], "wsdk_cohn_state_exit": [], "wsdk_cohn_state_csisubscrib": [], "wsdk_cohn_state_csiunsubscrib": [], "wsdk_cohn_state_idl": [], "wsdk_cohn_state_networkconnect": [], "wsdk_cohn_state_networkdisconnect": [], "wsdk_cohn_state_connectingtonetwork": [], "wsdk_cohn_state_invalid": [], "wsdk_cohn_unprovis": [], "wsdk_cohn_provis": [], "connect_btc_connect": [], "connect_btc_disconnect": [], "connect_btc_success": [], "connect_btc_fail": [], "connect_btc_never_pair": [], "ping": [], "cmd": [], "proto": [], "get_cap": [], "start_scan": [], "get_ap_entri": [], "connect_new": [], "delete_singl": [], "delete_al": [], "take_ownership": [], "relinquish_ownership": [], "stop_network_featur": [], "event_notif_start_scan": [], "evt": [], "event_notif_provis_st": [], "connect_mfi": [], "generic_rsp": [], "get_capabilities_rsp": [], "start_scan_rsp": [], "get_ap_entries_rsp": [], "connect_rsp": [], "connect_new_rsp": [], "delete_single_rsp": [], "delete_all_rsp": [], "take_ownership_rsp": [], "relinquish_ownership_rsp": [], "stop_network_features_rsp": [], "event_notif_start_scan_rsp": [], "event_notif_provis_state_rsp": [], "140": [], "connect_mfi_rsp": [], "http_proxi": [], "ip_v6": [], "network_own": [], "network_purpos": [], "owner_non": [], "owner_offload_to_supertub": [], "owner_offload_to_cloud": [], "owner_offload_to_supertubes_or_cloud": [], "owner_smarty_over_network": [], "owner_test": [], "owner_live_stream": [], "do_not_drop": [], "pair_btc_start": [], "pair_btc_stop": [], "pair_btc_success": [], "pair_btc_timeout": [], "ble_sta_ap": [], "ble_sta": [], "quickboot_off": [], "register_a": [], "register_b": [], "register_c": [], "if_battery_percent_gt_c": [], "if_battery_percent_lt_c": [], "if_rc_off_button_press": [], "if_app_off_button_press": [], "if_ble_off_button_press": [], "if_camera_off_button_press": [], "if_external_power_not_suppli": [], "if_external_power_suppli": [], "pwr_restore_ble_sta_ap": [], "if_ap_assoc": [], "if_act": [], "if_quick_off": [], "if_not_cold_silent_boot": [], "if_not_cold_boot": [], "if_not_warm_silent_boot": [], "if_not_warm_boot": [], "continue_previous_sequ": [], "pwr_ap_if_associ": [], "set_mtim": [], "scan_flag_cah_cloud": [], "scan_flag_livestream": [], "timeunit_unknown": [], "timeunit_minut": [], "timeunit_hour": [], "timeunit_dai": [], "timeunit_second": [], "timeunit_jump": [], "timeunit_skip": [], "timeunit_decrement_jump_not_zero": [], "timeunit_decrement_skip_not_zero": [], "timeunit_set_regist": [], "timeunit_set_ble_slow_advertis": [], "timeunit_set_mtim": [], "timeunit_test_jump_not_zero": [], "pairing_finish": [], "set_suspend_sequ": [], "set_resume_sequ": [], "set_coldboot_sequ": [], "pair_btc": [], "event_notif_pair_btc": [], "connect_btc": [], "event_notif_connect_btc": [], "pairing_finish_rsp": [], "set_suspend_sequence_rsp": [], "set_resume_sequence_rsp": [], "set_coldboot_sequence_rsp": [], "pair_btc_rsp": [], "event_notif_pair_btc_rsp": [], "connect_btc_rsp": [], "event_notif_connect_btc_rsp": [], "mappingunknown": [], "readwrit": [], "wsdk_association_state_not_associ": [], "wsdk_association_state_associ": [], "wsdk_association_state_associated_another_us": [], "wsdk_auth_state_unknown": [], "wsdk_auth_state_author": [], "wsdk_auth_state_not_author": [], "wsdk_auth_state_busi": [], "wsdk_auth_state_err_network": [], "wsdk_auth_state_err_cloud": [], "wsdk_auth_state_err_auth_fail": [], "wsdk_auth_state_waiting_confirm": [], "wsdk_band_select_2_4ghz": [], "band_select_5ghz": [], "band_select_max": [], "wsdk_caha_cat_0": [], "wsdk_caha_cat_1": [], "wsdk_caha_cat_2": [], "wsdk_caha_cat_3": [], "wsdk_caha_cat_4": [], "wsdk_caha_cat_csi_err": [], "wsdk_caha_err_0": [], "wsdk_caha_err_1": [], "wsdk_caha_err_2": [], "wsdk_caha_err_3": [], "wsdk_caha_err_4": [], "wsdk_caha_err_csi_err": [], "wsdk_caha_state_inact": [], "wsdk_caha_state_internet_check": [], "wsdk_caha_state_internet_connect": [], "wsdk_caha_state_credential_check": [], "wsdk_caha_state_entitlement_ok": [], "wsdk_caha_state_upload": [], "wsdk_caha_state_uploading_complet": [], "wsdk_caha_state_shutting_down": [], "wsdk_caha_state_error": [], "wsdk_caha_state_csi_err": [], "wsdk_caha_sub_0": [], "wsdk_caha_sub_1": [], "wsdk_caha_sub_2": [], "wsdk_caha_sub_3": [], "wsdk_caha_sub_4": [], "wsdk_caha_sub_csi_err": [], "wsdk_cah_auto_clear_off": [], "wsdk_cah_auto_clear_on": [], "wsdk_cah_server_product": [], "wsdk_cah_server_stag": [], "wsdk_cah_server_qa": [], "wsdk_camera_idl": [], "wsdk_camera_control": [], "wsdk_camera_external_control": [], "wsdk_boot_reason_power_on_from_scratch": [], "transit": [], "least": [], "wsdk_boot_reason_reset": [], "jtag": [], "edb": [], "frw_power_reset": [], "wsdk_boot_reason_power_button": [], "wsdk_boot_reason_shutter_button": [], "shutton": [], "wsdk_boot_reason_settings_button": [], "wsdk_boot_reason_herobus_wak": [], "herobu": [], "wsdk_boot_reason_rtc_alarm": [], "rtc": [], "alarm": [], "fire": [], "wsdk_boot_reason_sdcard_insert": [], "insert": [], "wsdk_boot_reason_wireless_wak": [], "wsdk_boot_reason_ble_wak": [], "wsdk_boot_reason_usb1_insert": [], "usb1": [], "wsdk_boot_reason_usb1_remov": [], "wsdk_boot_reason_usb2_insert": [], "usb2": [], "wsdk_boot_reason_usb2_remov": [], "wsdk_boot_reason_depleted_bombie_attach": [], "deepli": [], "deplet": [], "bombi": [], "attach": [], "wsdk_boot_reason_ibat_insert": [], "unexpect": [], "ibat": [], "wsdk_boot_reason_ibat_remov": [], "wsdk_boot_reason_ibat_end_of_charg": [], "end": [], "wsdk_boot_reason_ibat_charging_resum": [], "resum": [], "wsdk_boot_reason_bombie_attach": [], "wsdk_boot_reason_lowpower_in_standbi": [], "standbi": [], "wsdk_boot_reason_overtemp": [], "temp": [], "wsdk_boot_reason_unknown": [], "reason": [], "wsdk_boot_reason_sdcard_remov": [], "wsdk_boot_reason_ibat_temp_state_chang": [], "wsdk_boot_reason_wake_on_voic": [], "wsdk_boot_reason_charger_fault": [], "charger": [], "fault": [], "wsdk_boot_reason_heartbeat_timeout": [], "heartbeat": [], "wsdk_boot_reason_mode_button_4s_pwrup_push": [], "powerup": [], "push": [], "wsdk_boot_reason_mode_button_8s_pwrup_push": [], "wsdk_boot_reason_mode_button_4s_pwrdn_push": [], "powerdown": [], "wsdk_boot_reason_mode_button_8s_pwrdn_push": [], "wsdk_boot_reason_warm_reboot": [], "warm": [], "reboot": [], "wsdk_boot_reason_core_resum": [], "four": [], "wsdk_boot_reason_reset_fwupd": [], "fwupdat": [], "wsdk_boot_reason_shutter_button_no_qc": [], "qc": [], "wsdk_boot_reason_usb_insert_pwroff_reject": [], "poweroff": [], "wsdk_boot_reason_max": [], "wsdk_boot_reason_error": [], "someth": [], "gone": [], "terribli": [], "wrong": [], "wsdk_cmd_id_invalid": [], "wsdk_cmd_id_request_set_shutt": [], "wsdk_cmd_id_request_set_mod": [], "wsdk_cmd_id_request_preset_update_custom": [], "wsdk_cmd_id_request_cohn_set": [], "wsdk_cmd_id_request_clear_cohn_cert": [], "wsdk_cmd_id_request_create_cohn_cert": [], "wsdk_cmd_id_request_set_cah_start": [], "cah": [], "upload": [], "wsdk_cmd_id_request_set_camera_control_statu": [], "wsdk_cmd_id_request_set_in_contextual_menu": [], "wsdk_cmd_id_request_set_turbo_act": [], "wsdk_cmd_id_request_set_timewarp_speed_ramp_act": [], "wsdk_cmd_id_request_set_timewarp_speed_ramp": [], "wsdk_cmd_id_request_preset_remov": [], "wsdk_cmd_id_request_shortcuts_reset": [], "shortcut": [], "wsdk_cmd_id_request_set_lens_mod": [], "spheric": [], "wsdk_cmd_id_request_set_timewarp_speed_1x": [], "wsdk_cmd_id_request_preset_edit_start": [], "edit": [], "wsdk_cmd_id_request_preset_edit_cancel": [], "revert": [], "progress": [], "wsdk_cmd_id_request_preset_edit_stor": [], "wsdk_cmd_id_request_preset_factory_reset": [], "wsdk_cmd_id_request_preset_cr": [], "wsdk_cmd_id_request_preset_ord": [], "wsdk_cmd_id_request_release_network": [], "ownership": [], "wsdk_cmd_id_request_set_live_stream": [], "wsdk_cmd_id_request_set_ota_upd": [], "wsdk_cmd_id_request_set_band_select": [], "8ghz": [], "wsdk_cmd_id_request_clear_new_media_flag": [], "wsdk_cmd_id_request_set_system_notify_ev": [], "geneirc": [], "softub": [], "wsdk_cmd_id_request_set_client_info": [], "dev": [], "prog": [], "wsdk_cmd_id_request_set_cah_setup_mod": [], "enter": [], "wsdk_cmd_id_response_set_shutt": [], "wsdk_cmd_id_response_set_mod": [], "wsdk_cmd_id_response_preset_update_custom": [], "228": [], "wsdk_cmd_id_response_cohn_set": [], "229": [], "wsdk_cmd_id_response_clear_cohn_cert": [], "230": [], "wsdk_cmd_id_response_create_cohn_cert": [], "231": [], "wsdk_cmd_id_response_set_cah_start": [], "232": [], "wsdk_cmd_id_response_set_camera_control_statu": [], "233": [], "wsdk_cmd_id_response_set_in_contextual_menu": [], "234": [], "wsdk_cmd_id_response_set_turbo_act": [], "235": [], "wsdk_cmd_id_response_set_timewarp_speed_ramp_act": [], "236": [], "wsdk_cmd_id_response_set_timewarp_speed_ramp": [], "237": [], "wsdk_cmd_id_response_preset_remov": [], "238": [], "wsdk_cmd_id_response_shortcuts_reset": [], "239": [], "wsdk_cmd_id_response_set_lens_mod": [], "wsdk_cmd_id_response_set_timewarp_speed_1x": [], "241": [], "wsdk_cmd_id_response_preset_edit_start": [], "242": [], "wsdk_cmd_id_response_preset_edit_cancel": [], "243": [], "wsdk_cmd_id_response_preset_edit_stor": [], "244": [], "wsdk_cmd_id_response_preset_factory_reset": [], "245": [], "wsdk_cmd_id_response_preset_cr": [], "246": [], "wsdk_cmd_id_response_preset_ord": [], "247": [], "wsdk_cmd_id_response_release_network": [], "248": [], "wsdk_cmd_id_response_set_live_stream": [], "249": [], "wsdk_cmd_id_response_set_ota_upd": [], "wsdk_cmd_id_response_set_band_select": [], "251": [], "wsdk_cmd_id_response_clear_new_media_flag": [], "252": [], "wsdk_cmd_id_response_set_system_notify_ev": [], "253": [], "wsdk_cmd_id_response_set_client_info": [], "254": [], "wsdk_cmd_id_response_set_cah_setup_mod": [], "wsdk_device_mgr_cat_0": [], "wsdk_device_mgr_cat_1": [], "wsdk_device_mgr_cat_2": [], "wsdk_device_mgr_cat_3": [], "wsdk_device_mgr_cat_4": [], "wsdk_device_mgr_cat_csi_err": [], "wsdk_device_mgr_err_0": [], "wsdk_device_mgr_err_1": [], "wsdk_device_mgr_err_2": [], "wsdk_device_mgr_err_3": [], "wsdk_device_mgr_err_4": [], "wsdk_device_mgr_err_csi_err": [], "wsdk_device_mgr_state_inact": [], "wsdk_device_mgr_state_check_device_token": [], "wsdk_device_mgr_state_provision_devic": [], "wsdk_device_mgr_state_store_device_token": [], "wsdk_device_mgr_state_check_for_auth_cod": [], "wsdk_device_mgr_state_convert_auth_cod": [], "wsdk_device_mgr_state_link_device_token_with_auth_cod": [], "wsdk_device_mgr_state_retrieve_access_token": [], "wsdk_device_mgr_state_complet": [], "wsdk_device_mgr_state_csi_err": [], "wsdk_device_mgr_sub_0": [], "wsdk_device_mgr_sub_1": [], "wsdk_device_mgr_sub_2": [], "wsdk_device_mgr_sub_3": [], "wsdk_device_mgr_sub_4": [], "wsdk_device_mgr_sub_csi_err": [], "wsdk_fid_command_low": [], "wsdk_fid_command_high": [], "wsdk_fid_setting_low": [], "wsdk_fid_setting_high": [], "wsdk_fid_query_low": [], "wsdk_fid_query_high": [], "wsdk_flat_mode_unknown": [], "wsdk_flat_mode_playback": [], "wsdk_flat_mode_setup": [], "wsdk_flat_mode_video": [], "wsdk_flat_mode_time_lapse_video": [], "wsdk_flat_mode_loop": [], "wsdk_flat_mode_photo_singl": [], "wsdk_flat_mode_photo": [], "wsdk_flat_mode_photo_night": [], "wsdk_flat_mode_photo_burst": [], "wsdk_flat_mode_time_lapse_photo": [], "wsdk_flat_mode_night_lapse_photo": [], "wsdk_flat_mode_broadcast_record": [], "wsdk_flat_mode_broadcast_broadcast": [], "wsdk_flat_mode_time_warp_video": [], "wsdk_flat_mode_live_burst": [], "wsdk_flat_mode_night_lapse_video": [], "wsdk_flat_mode_slomo": [], "wsdk_flat_mode_idl": [], "wsdk_flat_mode_video_star_trail": [], "wsdk_flat_mode_video_light_paint": [], "wsdk_flat_mode_video_light_trail": [], "wsdk_lens_wid": [], "wsdk_lens_superview": [], "wsdk_lens_linear": [], "wsdk_live_stream_error_non": [], "wsdk_live_stream_error_network": [], "wsdk_live_stream_error_createstream": [], "wsdk_live_stream_error_outofmemori": [], "wsdk_live_stream_error_inputstream": [], "wsdk_live_stream_error_internet": [], "wsdk_live_stream_error_osnetwork": [], "wsdk_live_stream_error_selectednetworktimeout": [], "wsdk_live_stream_error_ssl_handshak": [], "wsdk_live_stream_error_camera_block": [], "wsdk_live_stream_error_unknown": [], "wsdk_live_stream_error_sd_card_ful": [], "wsdk_live_stream_error_sd_card_remov": [], "wsdk_live_stream_state_idl": [], "wsdk_live_stream_state_config": [], "wsdk_live_stream_state_readi": [], "wsdk_live_stream_state_stream": [], "wsdk_live_stream_state_complete_stay_on": [], "wsdk_live_stream_state_failed_stay_on": [], "wsdk_live_stream_state_reconnect": [], "wsdk_ota_cancel": [], "wms_request_ux_cancel": [], "wsdk_ota_start": [], "wms_request_ota": [], "wsdk_ota_start_forc": [], "wms_request_ota_forc": [], "wsdk_ota_error_non": [], "wsdk_ota_error_csifail": [], "wsdk_ota_error_unzipfail": [], "wsdk_ota_error_headrequestfail": [], "wsdk_ota_error_downloadfail": [], "wsdk_ota_error_networkfail": [], "wsdk_ota_error_gopropingfail": [], "wsdk_ota_error_curlinitfail": [], "wsdk_ota_error_sha_failur": [], "wsdk_ota_error_files": [], "wsdk_ota_error_thread": [], "wsdk_ota_error_nofirmwarefound": [], "wsdk_ota_error_firmwaredidntmatch": [], "wsdk_ota_state_idl": [], "wsdk_ota_state_download": [], "wsdk_ota_state_verifi": [], "wsdk_ota_state_download_fail": [], "wsdk_ota_state_verify_fail": [], "wsdk_ota_state_readi": [], "wsdk_ota_state_smarty_download": [], "wsdk_ota_state_smarty_verifi": [], "wsdk_ota_state_smarty_download_fail": [], "wsdk_ota_state_smarty_verify_fail": [], "wsdk_ota_state_smarty_readi": [], "wsdk_ota_state_soft_readi": [], "wsdk_ota_state_resum": [], "wsdk_preset_group_id_video": [], "wsdk_preset_group_id_photo": [], "wsdk_preset_group_id_timelaps": [], "wsdk_preset_group_video_icon_id": [], "wsdk_preset_group_photo_icon_id": [], "wsdk_preset_group_timelapse_icon_id": [], "wsdk_preset_group_long_bat_video_icon_id": [], "wsdk_preset_group_endurance_video_icon_id": [], "wsdk_preset_group_max_video_icon_id": [], "wsdk_preset_group_max_photo_icon_id": [], "wsdk_preset_group_max_timelapse_icon_id": [], "wsdk_preset_icon_video": [], "wsdk_preset_icon_act": [], "wsdk_preset_icon_cinemat": [], "wsdk_preset_icon_photo": [], "wsdk_preset_icon_live_burst": [], "wsdk_preset_icon_burst": [], "wsdk_preset_icon_photo_night": [], "wsdk_preset_icon_timewarp": [], "wsdk_preset_icon_timelaps": [], "wsdk_preset_icon_nightlaps": [], "wsdk_preset_icon_snail": [], "wsdk_preset_icon_video_2": [], "wsdk_preset_icon_360_video": [], "unreleas": [], "wsdk_preset_icon_photo_2": [], "wsdk_preset_icon_panorama": [], "wsdk_preset_icon_burst_2": [], "wsdk_preset_icon_timewarp_2": [], "wsdk_preset_icon_timelapse_2": [], "wsdk_preset_icon_custom": [], "wsdk_preset_icon_air": [], "wsdk_preset_icon_bik": [], "wsdk_preset_icon_ep": [], "wsdk_preset_icon_indoor": [], "wsdk_preset_icon_motor": [], "wsdk_preset_icon_mount": [], "wsdk_preset_icon_outdoor": [], "wsdk_preset_icon_pov": [], "wsdk_preset_icon_selfi": [], "wsdk_preset_icon_sk": [], "wsdk_preset_icon_snow": [], "wsdk_preset_icon_trail": [], "wsdk_preset_icon_travel": [], "wsdk_preset_icon_wat": [], "wsdk_preset_icon_loop": [], "wsdk_preset_icon_star": [], "wsdk_preset_icon_follow_cam": [], "wsdk_preset_icon_surf": [], "wsdk_preset_icon_c": [], "wsdk_preset_icon_shaki": [], "wsdk_preset_icon_chesti": [], "wsdk_preset_icon_helmet": [], "wsdk_preset_icon_bit": [], "wsdk_preset_icon_max_video": [], "wsdk_preset_icon_max_photo": [], "wsdk_preset_icon_max_timewarp": [], "wsdk_preset_icon_bas": [], "wsdk_preset_icon_ultra_slo_mo": [], "wsdk_preset_icon_standard_endur": [], "wsdk_preset_icon_activity_endur": [], "wsdk_preset_icon_cinematic_endur": [], "wsdk_preset_icon_slomo_endur": [], "wsdk_preset_icon_stationary_1": [], "wsdk_preset_icon_stationary_2": [], "wsdk_preset_icon_stationary_3": [], "wsdk_preset_icon_stationary_4": [], "wsdk_preset_icon_simple_super_photo": [], "wsdk_preset_icon_simple_night_photo": [], "wsdk_preset_icon_highest_quality_video": [], "wsdk_preset_icon_standard_quality_video": [], "wsdk_preset_icon_basic_quality_video": [], "wsdk_preset_icon_star_trail": [], "wsdk_preset_icon_light_paint": [], "wsdk_preset_icon_light_trail": [], "wsdk_preset_icon_full_fram": [], "wsdk_preset_icon_easy_max_video": [], "wsdk_preset_icon_easy_max_photo": [], "wsdk_preset_icon_easy_max_timewarp": [], "wsdk_preset_icon_easy_max_star_trail": [], "wsdk_preset_icon_easy_max_light_paint": [], "wsdk_preset_icon_easy_max_light_trail": [], "wsdk_preset_icon_max_star_trail": [], "wsdk_preset_icon_max_light_paint": [], "wsdk_preset_icon_max_light_trail": [], "wsdk_preset_icon_360_burst": [], "wsdk_preset_icon_360_photo_night": [], "wsdk_preset_icon_360_nightlaps": [], "wsdk_preset_icon_360_timelapse_photo": [], "wsdk_preset_icon_360_nightlapse_photo": [], "wsdk_preset_icon_360_photo": [], "wsdk_preset_icon_360_timelaps": [], "wsdk_preset_icon_360_timewarp": [], "wsdk_preset_icon_timelapse_photo": [], "wsdk_preset_icon_nightlapse_photo": [], "wsdk_preset_icon_max": [], "wsdk_preset_title_act": [], "wsdk_preset_title_standard": [], "wsdk_preset_title_cinemat": [], "wsdk_preset_title_photo": [], "wsdk_preset_title_live_burst": [], "wsdk_preset_title_burst": [], "wsdk_preset_title_night": [], "wsdk_preset_title_time_warp": [], "wsdk_preset_title_time_laps": [], "wsdk_preset_title_night_laps": [], "wsdk_preset_title_video": [], "wsdk_preset_title_slomo": [], "wsdk_preset_title_360_video": [], "wsdk_preset_title_photo_2": [], "wsdk_preset_title_panorama": [], "wsdk_preset_title_360_photo": [], "wsdk_preset_title_time_warp_2": [], "wsdk_preset_title_360_time_warp": [], "wsdk_preset_title_custom": [], "wsdk_preset_title_air": [], "wsdk_preset_title_bik": [], "wsdk_preset_title_ep": [], "wsdk_preset_title_indoor": [], "wsdk_preset_title_motor": [], "wsdk_preset_title_mount": [], "wsdk_preset_title_outdoor": [], "wsdk_preset_title_pov": [], "wsdk_preset_title_selfi": [], "wsdk_preset_title_sk": [], "wsdk_preset_title_snow": [], "wsdk_preset_title_trail": [], "wsdk_preset_title_travel": [], "wsdk_preset_title_wat": [], "wsdk_preset_title_loop": [], "wsdk_preset_title_star": [], "wsdk_preset_title_follow_cam": [], "wsdk_preset_title_surf": [], "wsdk_preset_title_c": [], "wsdk_preset_title_shaki": [], "wsdk_preset_title_chesti": [], "wsdk_preset_title_helmet": [], "wsdk_preset_title_bit": [], "wsdk_preset_title_360_timelaps": [], "wsdk_preset_title_360_night_laps": [], "wsdk_preset_title_360_night_photo": [], "wsdk_preset_title_pano_time_laps": [], "wsdk_preset_title_max_video": [], "wsdk_preset_title_max_photo": [], "wsdk_preset_title_max_timewarp": [], "wsdk_preset_title_bas": [], "wsdk_preset_title_ultra_slo_mo": [], "wsdk_preset_title_standard_endur": [], "wsdk_preset_title_activity_endur": [], "wsdk_preset_title_cinematic_endur": [], "wsdk_preset_title_slomo_endur": [], "wsdk_preset_title_stationary_1": [], "wsdk_preset_title_stationary_2": [], "wsdk_preset_title_stationary_3": [], "wsdk_preset_title_stationary_4": [], "wsdk_preset_title_simple_video": [], "wsdk_preset_title_simple_time_warp": [], "wsdk_preset_title_simple_super_photo": [], "wsdk_preset_title_simple_night_photo": [], "wsdk_preset_title_simple_video_endur": [], "wsdk_preset_title_highest_qu": [], "wsdk_preset_title_extended_batteri": [], "wsdk_preset_title_longest_batteri": [], "wsdk_preset_title_star_trail": [], "wsdk_preset_title_light_paint": [], "wsdk_preset_title_light_trail": [], "wsdk_preset_title_full_fram": [], "wsdk_preset_title_max_lens_video": [], "wsdk_preset_title_max_lens_timewarp": [], "wsdk_preset_title_standard_quality_video": [], "wsdk_preset_title_basic_quality_video": [], "wsdk_preset_title_easy_max_video": [], "wsdk_preset_title_easy_max_photo": [], "wsdk_preset_title_easy_max_timewarp": [], "wsdk_preset_title_easy_max_star_trail": [], "wsdk_preset_title_easy_max_light_paint": [], "wsdk_preset_title_easy_max_light_trail": [], "wsdk_preset_title_max_star_trail": [], "wsdk_preset_title_max_light_paint": [], "wsdk_preset_title_max_light_trail": [], "wsdk_preset_title_highest_quality_video": [], "wsdk_preset_title_360_burst": [], "wsdk_preset_title_360_night": [], "wsdk_preset_title_360_time_lapse_photo": [], "wsdk_preset_title_360_night_lapse_photo": [], "wsdk_preset_title_max": [], "wsdk_query_id_invalid": [], "fid": [], "wsdk_query_id_request_get_last_media": [], "fid_high": [], "wsdk_query_id_request_get_cohn_cert": [], "wsdk_query_id_request_cohn_statu": [], "wsdk_query_id_request_set_shutt": [], "test": [], "wsdk_query_id_request_get_preset_statu": [], "wsdk_query_id_register_preset_statu": [], "wsdk_query_id_request_get_live_stream_statu": [], "wsdk_query_id_register_live_stream_statu": [], "wsdk_query_id_request_get_ota_statu": [], "wsdk_query_id_register_ota_statu": [], "wsdk_query_id_request_get_mobile_offload_st": [], "wsdk_query_id_request_get_system_beacon": [], "wsdk_query_id_request_get_cah_sticki": [], "wsdk_query_id_request_get_csi_valu": [], "wsdk_query_id_request_get_association_st": [], "wsdk_query_id_request_get_client_id": [], "wsdk_query_id_request_get_cah_statu": [], "wsdk_query_id_register_cah_statu": [], "wsdk_query_id_response_get_last_media": [], "fid_high_respons": [], "0x80": [], "wsdk_query_id_response_get_cohn_cert": [], "wsdk_query_id_response_cohn_statu": [], "wsdk_query_id_response_get_preset_statu": [], "wsdk_query_id_notify_preset_statu": [], "wsdk_query_id_response_get_live_stream_statu": [], "wsdk_query_id_notify_live_stream_statu": [], "wsdk_query_id_response_get_ota_statu": [], "wsdk_query_id_notify_ota_statu": [], "wsdk_query_id_response_get_mobile_offload_st": [], "wsdk_query_id_response_get_system_beacon": [], "wsdk_query_id_response_get_cah_sticki": [], "wsdk_query_id_response_get_csi_valu": [], "wsdk_query_id_response_get_association_st": [], "wsdk_query_id_response_get_client_id": [], "wsdk_query_id_response_get_cah_statu": [], "wsdk_query_id_notify_cah_statu": [], "wsdk_register_cah_status_dev_mgr": [], "wsdk_register_cah_status_wom": [], "wsdk_register_cah_status_caha": [], "wsdk_register_cah_status_featture_en": [], "wsdk_register_cah_status_act": [], "wsdk_register_cah_status_associ": [], "wsdk_register_cah_status_author": [], "wsdk_register_live_stream_status_statu": [], "wsdk_register_live_stream_status_error": [], "wsdk_register_live_stream_status_mod": [], "wsdk_register_live_stream_status_bitr": [], "wsdk_register_ota_status_st": [], "wsdk_register_ota_status_percentag": [], "wsdk_register_preset_status_preset": [], "wsdk_register_preset_status_preset_group_arrai": [], "wsdk_setting_id_invalid": [], "wsdk_setting_id_request_set_shutt": [], "wsdk_setting_id_request_set_cah_short_provis": [], "wsdk_setting_id_request_set_cah_auto_clear": [], "wsdk_setting_id_request_set_system_enable_beacon": [], "turn": [], "beacon": [], "session": [], "wsdk_setting_id_request_set_system_beacon": [], "wsdk_setting_id_request_set_cah_log": [], "wsdk_setting_id_request_set_csi_valu": [], "wsdk_setting_id_request_set_cah_serv": [], "wsdk_setting_id_request_set_cah_en": [], "wsdk_setting_id_request_set_auth_cod": [], "wsdk_setting_id_request_set_association_st": [], "wsdk_setting_id_response_set_shutt": [], "wsdk_setting_id_response_set_cah_short_provis": [], "wsdk_setting_id_response_set_cah_auto_clear": [], "wsdk_setting_id_response_set_system_enable_beacon": [], "wsdk_setting_id_response_set_system_beacon": [], "wsdk_setting_id_response_set_cah_log": [], "wsdk_setting_id_response_set_csi_valu": [], "wsdk_setting_id_response_set_cah_serv": [], "wsdk_setting_id_response_set_cah_en": [], "wsdk_setting_id_response_set_auth_cod": [], "wsdk_setting_id_response_set_association_st": [], "wsdk_shutter_off": [], "wsdk_shutter_on": [], "wsdk_activity_unknown": [], "wsdk_activity_st_start": [], "prior": [], "offload": [], "wsdk_activity_st_power_on": [], "woke": [], "wsdk_activity_st_stop": [], "wsdk_activity_app_power_up": [], "wsdk_timewarp_speed_ramp_1x": [], "wsdk_timewarp_speed_ramp_1_2x": [], "wsdk_wom_cat_unknown": [], "wsdk_wom_cat_info": [], "wsdk_wom_cat_warn": [], "wsdk_wom_cat_error": [], "wsdk_wom_cat_failur": [], "wsdk_wom_cat_retri": [], "wsdk_wom_cat_csi_err": [], "wsdk_wom_err_no_err": [], "wsdk_wom_err_mq_open": [], "wsdk_wom_err_alloc": [], "wsdk_wom_err_mq_rec": [], "wsdk_wom_err_message_pars": [], "wsdk_wom_err_csi": [], "wsdk_wom_err_invalid_ev": [], "wsdk_wom_err_start_fail": [], "wsdk_wom_err_nra_nack": [], "wsdk_wom_err_nra_ownership": [], "wsdk_wom_err_nra_timeout": [], "wsdk_wom_err_lost_network": [], "wsdk_wom_err_sd_card": [], "wsdk_wom_err_sd_card_spac": [], "wsdk_wom_err_no_new_media": [], "wsdk_wom_err_space_check_fail": [], "wsdk_wom_err_new_media_check_fail": [], "wsdk_wom_err_csi_err": [], "wsdk_wom_state_init": [], "wsdk_wom_state_error": [], "wsdk_wom_state_exit": [], "wsdk_wom_state_csi_subscrib": [], "wsdk_wom_state_csi_unsubscrib": [], "wsdk_wom_state_not_trigg": [], "wsdk_wom_state_ev": [], "wsdk_wom_state_ent": [], "wsdk_wom_state_not_ent": [], "wsdk_wom_state_nra_ack": [], "wsdk_wom_state_cancel_ok_stay_on": [], "wsdk_wom_state_connecting_to_sink": [], "wsdk_wom_state_failed_stay_on": [], "wsdk_wom_state_offloading_cah": [], "wsdk_wom_state_offloading_st": [], "wsdk_wom_state_complete_stay_on": [], "wsdk_wom_state_complete_turn_off": [], "wsdk_wom_state_paus": [], "wsdk_wom_state_connectingtocloud": [], "wsdk_wom_state_enumeratingmedia": [], "wsdk_wom_state_ota": [], "wsdk_wom_state_livestreamconfigur": [], "wsdk_wom_state_livestreamreadi": [], "wsdk_wom_state_livestream": [], "wsdk_wom_state_connectingtosinkl": [], "wsdk_wom_state_livestreamreconnect": [], "wsdk_wom_state_waitingforautoclear": [], "wsdk_wom_state_network_connect": [], "wsdk_wom_state_network_disconnect": [], "wsdk_wom_state_connecting_to_network": [], "wsdk_wom_state_invalid": [], "wsdk_wom_state_csi_err": [], "wsdk_wom_sub_unknown": [], "wsdk_wom_sub_control": [], "wsdk_wom_sub_devicemanag": [], "wsdk_wom_sub_wom": [], "wsdk_wom_sub_shareservic": [], "wsdk_wom_sub_transcod": [], "wsdk_wom_sub_medialist": [], "wsdk_wom_sub_csi_err": [], "wsdk_window_size_480": [], "wsdk_window_size_720": [], "wsdk_window_size_1080": [], "webview": [], "edittext": [], "readonli": [], "child": [], "slider": [], "toggl": [], "modeunknown": [], "videotimelaps": [], "videoplusphoto": [], "continuousshot": [], "nightlaps": [], "timewarpvideo": [], "groupunknown": [], "groupvideo": [], "groupphoto": [], "groupmultishot": [], "possibl": [], "setting_id": [], "setting_valu": [], "kei": [], "display_nam": [], "widget_typ": [], "network_typ": [], "transport": [], "hint": [], "command_kei": [], "preced": [], "v5": [], "activated_bi": [], "group_id": [], "flat_mod": [], "preset_icon": [], "preset_nam": [], "preset_name_iter": [], "prest": [], "preset_id": [], "newli": [], "include_info": [], "theoret": [], "c3501324645504": [], "board_typ": [], "ap_mac": [], "065747046ceb": [], "gp24645504": [], "ap_has_default_credenti": [], "git_sha1": [], "path_seg": [], "mapping_typ": [], "mode_valu": [], "sub_mode_valu": [], "wsdk_mode_group": [], "wsdk_mode": [], "btc": [], "exist": [], "human": [], "readabl": [], "predefined_preset": [], "mfi": [], "made": [], "iphon": [], "mfi_timeout_second": [], "test_request": [], "test_ssid": [], "test_password": [], "force_permiss": [], "owner_purpos": [], "delet": [], "sake": [], "consist": [], "requset": [], "pairi": [], "colloqui": [], "phonenam": [], "phone": [], "give": [], "ownership_handl": [], "relinquish": [], "owner_typ": [], "owner": [], "ap_enable_st": [], "ap_timeout_second": [], "owner_nam": [], "polici": [], "polic": [], "version_major": [], "version_minor": [], "schema_vers": [], "time_unit": [], "power_st": [], "time_valu": [], "displaynam": [], "modegroup": [], "hub": [], "device_mgr_st": [], "device_mgr_cat": [], "device_mgr_sub": [], "device_mgr_err": [], "wom_stat": [], "wom_cat": [], "wom_sub": [], "wom_err": [], "caha_st": [], "caha_cat": [], "caha_sub": [], "caha_err": [], "cah_act": [], "cah_feature_en": [], "cah_auth_st": [], "cah_busi": [], "issu": [], "cah_current_fil": [], "cah_total_fil": [], "cah_percentag": [], "item": [], "cah_auto_clear_en": [], "user_cod": [], "cloud": [], "simplifi": [], "verification_url": [], "syncrhon": [], "ota_st": [], "ota_percentag": [], "ota_error": [], "mirror": [], "mobile_offload": [], "clear_new_media_flag": [], "softtub": [], "associatino": [], "gopro_user_id": [], "register_cah_statu": [], "unregister_cah_statu": [], "sticki": [], "csi": [], "csi_kei": [], "obtain": [], "jakarta": [], "register_ota_statu": [], "unregister_ota_statu": [], "association_st": [], "auth_cod": [], "what": [], "band_select": [], "osd": [], "cah_auto_clear": [], "cah_en": [], "csi_cah_activate_log": [], "0x7d": [], "activate_log_display_on": [], "you": [], "want": [], "activate_log_upload_on": [], "loglogg": [], "treveiscorp": [], "com": [], "develop": [], "pw": [], "radmagix": [], "activate_log_syslog_on": [], "syslog": [], "activate_log_jakarta_on": [], "0x08": [], "call": [], "activate_log_dev_on": [], "activate_log_wom_on": [], "0x20": [], "wom": [], "activate_log_cah_on": [], "activate_log_backup_on": [], "backup": [], "crash": [], "lost": [], "copi": [], "activate_log_display_ex_on": [], "0x100": [], "consol": [], "tmp": [], "fuse_d": [], "misc": [], "sys_log": [], "txt": [], "backup_log": [], "cah_log": [], "qa": [], "stage": [], "product": [], "cah_serv": [], "cah_upload_start": [], "csi_str": [], "csi_int": [], "developer_prog_accessori": [], "in_menu": [], "reserved1": [], "reserved2": [], "reserved3": [], "ota_cmd": [], "prset": [], "whose": [], "preset_ord": [], "repsons": [], "wifo": [], "enable_beacon": [], "ibeacon": [], "notify_ev": [], "dsiabl": [], "timewarp_speed_ramp": [], "resppons": [], "stick": [], "cah_sticki": [], "client_id": [], "successfl": [], "mobile_offload_st": [], "new_media_avail": [], "battery_ok": [], "sd_card_ok": [], "camera_busi": [], "thu": [], "st_paus": [], "alta": [], "paus": [], "cnt_this_boot_bt": [], "cnt_this_boot_rc": [], "cnt_this_boot_ap": [], "camera_wakeup_reason": [], "wakeup": [], "st_activ": [], "st_beacon_uuid": [], "st_beacon_uuid_major": [], "compon": [], "chees": [], "imag": [], "img": [], "shield": [], "io": [], "badg": [], "8a2be2": [], "head": [], "column": [], "vlaue": 8, "flat_mode_video_burst_slomo": 14, "preset_group_video_single_len": [], "preset_group_photo_single_len": [], "preset_group_timelapse_single_len": [], "preset_group_video_hemi_len": [], "hemi": [], "preset_group_photo_hemi_len": [], "preset_group_timelapse_hemi_len": [], "preset_group_speci": [], "preset_group_special_hemi": [], "preset_group_video_endurance_single_len": [], "endur": [], "preset_group_video_longest_battery_single_len": [], "preset_group_easy_video_single_len": [], "preset_group_easy_video_endurance_single_len": [], "preset_group_easy_photo_single_len": [], "preset_group_easy_timelapse_single_len": [], "preset_group_easy_video_longest_battery_single_len": [], "preset_group_video_hemi_lens_2": [], "preset_group_photo_hemi_lens_2": [], "preset_group_timelapse_hemi_lens_2": [], "preset_group_special_hemi_lens_2": [], "preset_group_easy_video_hemi_len": [], "preset_group_easy_photo_hemi_len": [], "preset_group_easy_timelapse_hemi_len": [], "preset_group_easy_video_hemi_lens_2": [], "preset_group_easy_photo_hemi_lens_2": [], "preset_group_easy_timelapse_hemi_lens_2": [], "preset_group_video_single_lens_standard": [], "switch": [], "preset_group_video_single_lens_hdr": [], "preset_group_video_single_lens_log": [], "preset_group_video_spherical_len": [], "preset_group_photo_spherical_len": [], "preset_group_timelapse_spherical_len": [], "preset_group_special_spher": [], "preset_group_video_spherical_lens_standard": [], "preset_group_video_spherical_lens_log": [], "presets_group_video_hemi_lens_2_standard": [], "presets_group_video_hemi_lens_2_log": [], "presets_group_video_macro_len": [], "presets_group_photo_macro_len": [], "presets_group_timelapse_macro_len": [], "presets_group_easy_video_macro_len": [], "presets_group_easy_photo_macro_len": [], "presets_group_easy_timelapse_macro_len": [], "presets_group_video_macro_lens_standard": [], "presets_group_video_macro_lens_log": [], "presets_group_video_anamorphic_len": [], "presets_group_photo_anamorphic_len": [], "presets_group_timelapse_anamorphic_len": [], "presets_group_easy_video_anamorphic_len": [], "presets_group_easy_photo_anamorphic_len": [], "presets_group_easy_timelapse_anamorphic_len": [], "presets_group_video_anamorphic_lens_standard": [], "presets_group_video_anamorphic_lens_log": [], "preset_icon_easy_standard_profil": [], "preset_icon_easy_hdr_profil": [], "preset_title_easy_standard_profil": [], "preset_title_easy_hdr_profil": [], "regardless": []}, "objects": {"": [[1, 0, 0, "operation-Clear COHN Certificate", "Clear COHN Certificate"], [0, 0, 0, "operation-Connect to Provisioned Access Point", "Connect to Provisioned Access Point"], [0, 0, 0, "operation-Connect to a New Access Point", "Connect to a New Access Point"], [1, 0, 0, "operation-Create COHN Certificate", "Create COHN Certificate"], [0, 0, 0, "operation-Get AP Scan Results", "Get AP Scan Results"], [5, 0, 0, "operation-Get Available Presets", "Get Available Presets"], [1, 0, 0, "operation-Get COHN Certificate", "Get COHN Certificate"], [1, 0, 0, "operation-Get COHN Status", "Get COHN Status"], [6, 0, 0, "operation-Get Date Time", "Get Date Time"], [6, 0, 0, "operation-Get Hardware Info", "Get Hardware Info"], [6, 0, 0, "operation-Get Last Captured Media", "Get Last Captured Media"], [4, 0, 0, "operation-Get Livestream Status", "Get Livestream Status"], [6, 0, 0, "operation-Get Local Date Time", "Get Local Date Time"], [6, 0, 0, "operation-Get Open GoPro Version", "Get Open GoPro Version"], [6, 0, 0, "operation-Get Setting Capabilities", "Get Setting Capabilities"], [6, 0, 0, "operation-Get Setting Values", "Get Setting Values"], [6, 0, 0, "operation-Get Status Values", "Get Status Values"], [3, 0, 0, "operation-Hilight Moment", "Hilight Moment"], [2, 0, 0, "operation-Keep Alive", "Keep Alive"], [5, 0, 0, "operation-Load Preset", "Load Preset"], [5, 0, 0, "operation-Load Preset Group", "Load Preset Group"], [6, 0, 0, "operation-Register for Setting Capability Updates", "Register for Setting Capability Updates"], [6, 0, 0, "operation-Register for Setting Value Updates", "Register for Setting Value Updates"], [6, 0, 0, "operation-Register for Status Value Updates", "Register for Status Value Updates"], [0, 0, 0, "operation-Scan for Access Points", "Scan for Access Points"], [2, 0, 0, "operation-Set AP Control", "Set AP Control"], [2, 0, 0, "operation-Set Analytics", "Set Analytics"], [1, 0, 0, "operation-Set COHN Setting", "Set COHN Setting"], [2, 0, 0, "operation-Set Camera Control", "Set Camera Control"], [2, 0, 0, "operation-Set Date Time", "Set Date Time"], [4, 0, 0, "operation-Set Livestream Mode", "Set Livestream Mode"], [2, 0, 0, "operation-Set Local Date Time", "Set Local Date Time"], [7, 0, 0, "operation-Set Setting", "Set Setting"], [2, 0, 0, "operation-Set Shutter", "Set Shutter"], [2, 0, 0, "operation-Set Turbo Transfer", "Set Turbo Transfer"], [2, 0, 0, "operation-Sleep", "Sleep"], [6, 0, 0, "operation-Unregister for Setting Capability Updates", "Unregister for Setting Capability Updates"], [6, 0, 0, "operation-Unregister for Setting Value Updates", "Unregister for Setting Value Updates"], [6, 0, 0, "operation-Unregister for Status Value Updates", "Unregister for Status Value Updates"], [5, 0, 0, "operation-Update Custom Preset", "Update Custom Preset"]]}, "objtypes": {"0": "operation:Operation"}, "objnames": {"0": ["operation", "Operation", "Operation"]}, "titleterms": {"access": [0, 8], "point": [0, 8], "oper": [0, 1, 2, 3, 4, 5, 6, 7], "disconnect": 0, "from": 0, "camera": [1, 7, 8, 9, 15], "home": 1, "network": 1, "certif": 1, "verifi": 1, "view": 1, "detail": 1, "provis": [1, 8], "procedur": 1, "control": [2, 7, 8, 15], "hilight": [3, 8], "live": [4, 8], "stream": [4, 8], "preset": [5, 8, 14], "group": [5, 8], "queri": [6, 12, 13], "set": [7, 8, 13], "capabl": [7, 8], "xlsx": 7, "json": [7, 8], "id": [7, 8, 13], "video": [7, 8], "resolut": 7, "2": [7, 8], "fp": [], "3": [7, 8], "broadcast": [], "fov": 7, "43": 7, "setup": 11, "auto": 7, "power": [], "down": 8, "59": [7, 8], "aspect": 7, "ratio": 7, "108": [7, 8], "digit": 8, "lens": [], "121": 7, "photo": [7, 8], "122": 7, "multi": [], "shot": [], "123": 7, "gener": [9, 12], "format": 7, "128": 7, "anti": 7, "flicker": 7, "134": 7, "hypersmooth": 7, "135": 7, "horizon": 7, "level": [7, 8], "150": 7, "151": 7, "mod": [7, 8], "max": 7, "len": [7, 8], "enabl": [7, 8], "162": [7, 8], "hindsight": [7, 8], "length": [7, 12], "167": 7, "singl": [], "interv": [7, 8], "171": 7, "durat": [7, 8], "172": 7, "system": 8, "profil": 7, "173": 7, "ux": [], "mode": [7, 8, 11], "175": 7, "easi": [], "speed": [7, 8], "176": 7, "night": 7, "177": 7, "wireless": 8, "band": [7, 8], "178": 7, "trail": 7, "179": 7, "180": 7, "bit": [7, 8, 12], "rate": [7, 8], "182": 7, "depth": 7, "183": 7, "184": 7, "186": 7, "187": 7, "addon": [], "activ": 8, "189": [7, 8], "statu": [8, 13], "190": 7, "191": 7, "nlv": [], "192": 7, "frame": [7, 8], "193": 7, "status": 8, "i": 8, "The": 8, "": [8, 9], "intern": 8, "batteri": 8, "present": 8, "1": 8, "rough": 8, "approxim": 8, "Of": [], "In": [], "bar": 8, "Or": [], "charg": 8, "current": 8, "overh": 8, "6": 8, "busi": 8, "8": 8, "quick": 8, "captur": 8, "featur": 8, "9": 8, "encod": 8, "right": 8, "now": 8, "10": 8, "lcd": 8, "lock": 8, "11": 8, "when": 8, "thi": 8, "second": [7, 8], "so": 8, "far": 8, "0": 8, "otherwis": 8, "13": [8, 12], "ar": 8, "connect": 8, "17": 8, "pair": [8, 11], "state": [8, 15], "19": 8, "last": 8, "type": [8, 12], "which": 8, "wa": 8, "engag": 8, "20": 8, "time": 8, "sinc": 8, "boot": 8, "millisecond": 8, "success": 8, "complet": 8, "action": 8, "21": 8, "scan": 8, "For": [], "wifi": 8, "22": 8, "That": [], "23": 8, "ap": 8, "24": 8, "remot": 8, "version": 8, "26": 8, "A": [], "27": 8, "each": 8, "contain": 8, "inform": 8, "see": 8, "wirelesspairingstateflag": 8, "28": 8, "ssid": 8, "To": [], "On": 8, "ble": [8, 9, 11], "valu": [8, 12], "big": 8, "endian": 8, "byte": 8, "int32": 8, "29": 8, "30": 8, "number": 8, "devic": 8, "31": 8, "preview": 8, "32": 8, "primari": 8, "storag": 8, "33": 8, "how": 8, "mani": 8, "can": 8, "Be": [], "taken": 8, "With": [], "befor": 8, "sdcard": 8, "full": 8, "34": 8, "minut": 8, "35": 8, "total": 8, "38": 8, "39": 8, "over": 8, "air": 8, "ota": 8, "updat": 8, "41": 8, "There": [], "pend": 8, "request": 8, "cancel": 8, "firmwar": 8, "download": 8, "42": 8, "locat": 8, "45": 8, "timelaps": 8, "countdown": 8, "e": 8, "g": 8, "5": [8, 12], "4": 8, "49": 8, "remain": 8, "space": 8, "kilobyt": 8, "54": 8, "support": [8, 9], "record": 8, "secondari": 8, "55": 8, "signal": 8, "strength": 8, "56": 8, "stop": 8, "58": 8, "most": 8, "recent": 8, "minimum": 8, "between": 8, "best": 8, "practic": 8, "Not": [], "poll": 8, "more": 8, "often": 8, "than": 8, "60": 8, "laps": [7, 8], "64": 8, "liveview": 8, "exposur": 8, "select": 8, "65": 8, "y": 8, "coordin": 8, "percent": 8, "66": 8, "67": 8, "doe": 8, "have": 8, "gp": 8, "68": 8, "69": 8, "70": 8, "microphon": 8, "accessori": 8, "74": 8, "zoom": 8, "75": 8, "76": 8, "avail": 8, "77": 8, "mobil": 8, "friendli": 8, "relat": 8, "compress": 8, "And": [], "78": 8, "first": 8, "us": 8, "ftu": 8, "ui": 8, "flow": 8, "79": 8, "5ghz": 8, "81": 8, "fulli": 8, "readi": [8, 15], "accept": 8, "command": [8, 12, 13], "82": 8, "suffici": 8, "start": [8, 9], "83": 8, "get": [8, 9], "too": 8, "cold": 8, "continu": [8, 12], "85": 8, "rotat": 8, "orient": 8, "86": 8, "model": 8, "while": 8, "88": 8, "flatmod": 8, "89": 8, "93": 8, "94": 8, "95": 8, "correspond": 8, "ui_mode_group": 8, "96": 8, "97": 8, "modifi": 8, "an": 8, "event": 8, "98": 8, "burst": 8, "99": 8, "100": 8, "delai": 8, "count": 8, "101": 8, "media": [8, 14], "102": 8, "warp": 8, "103": 8, "linux": 8, "core": 8, "104": 8, "reflect": 8, "chang": 8, "105": 8, "106": 8, "schedul": 8, "107": 8, "displai": 8, "bitmask": 8, "110": 8, "meet": 8, "specifi": 8, "write": 8, "111": 8, "error": 8, "112": 8, "turbo": 8, "transfer": 8, "113": 8, "114": 8, "pc": 8, "via": 8, "usb": 8, "115": 8, "116": 8, "sd": 8, "card": 8, "capac": 8, "117": 8, "welcom": 9, "open": 9, "gopro": 9, "api": 9, "document": [9, 14], "limit": 9, "protocol": [10, 12], "advertis": 11, "finish": 11, "configur": 11, "gatt": 11, "characterist": 11, "send": 11, "messag": [11, 12], "data": 12, "packet": 12, "header": 12, "extend": 12, "16": 12, "deciph": 12, "payload": 12, "protobuf": [12, 13, 14], "tabl": 13, "enum": 14, "enumcohnnetworkst": 14, "enumcohnstatu": 14, "enumcameracontrolstatu": 14, "enumflatmod": 14, "enumlen": 14, "enumlivestreamerror": 14, "enumlivestreamstatu": 14, "enumpresetgroup": 14, "enumpresetgroupicon": 14, "enumpreseticon": 14, "enumpresettitl": 14, "enumprovis": 14, "enumregisterlivestreamstatu": 14, "enumregisterpresetstatu": 14, "enumresultgener": 14, "enumscanentryflag": 14, "enumscan": 14, "enumwindows": 14, "notifprovisioningst": 14, "notifstartscan": 14, "notifycohnstatu": 14, "notifylivestreamstatu": 14, "notifypresetstatu": 14, "presetgroup": 14, "presetset": 14, "rang": [], "requestcohncert": 14, "requestclearcohncert": 14, "requestconnect": 14, "requestconnectnew": 14, "requestcreatecohncert": 14, "requestcustompresetupd": 14, "requestgetapentri": 14, "requestgetcohnstatu": 14, "requestgetlastcapturedmedia": 14, "requestgetlivestreamstatu": 14, "requestgetpresetstatu": 14, "requestreleasenetwork": 14, "requestsetcohnset": 14, "requestsetcameracontrolstatu": 14, "requestsetlivestreammod": 14, "requestsetturboact": 14, "requeststartscan": 14, "responsecohncert": 14, "responseconnect": 14, "responseconnectnew": 14, "responsegener": 14, "responsegetapentri": 14, "responselastcapturedmedia": 14, "responsestartscan": 14, "scanentri": 14, "manag": 15, "keep": 15, "aliv": 15, "per": 7, "webcam": [], "perform": 7, "iso": [], "shutter": [], "37": [], "bnr": [], "44": [], "47": [], "privaci": [], "48": [], "gop": [], "size": [], "idr": [], "61": [], "62": [], "window": [], "min": [], "audio": [], "protun": [], "languag": [], "84": [], "voic": [], "beep": [], "87": [], "bright": [], "led": [], "91": [], "No": [], "track": [], "wake": [], "timer": [], "white": [], "balanc": [], "color": [], "sharp": [], "ev": [], "comp": [], "118": [], "124": [], "output": [], "125": [], "126": [], "lower": [], "left": [], "129": [], "130": [], "upper": [], "131": [], "132": [], "megapixel": [], "133": [], "mic": [], "137": [], "360": [], "138": [], "raw": [], "139": [], "quikcaptur": [], "default": [], "141": [], "143": [], "144": [], "145": [], "146": [], "147": [], "148": [], "wind": [], "149": [], "button": [], "153": [], "front": [], "154": [], "ramp": [], "155": [], "156": [], "157": [], "screen": [], "saver": [], "158": [], "rear": [], "159": [], "160": [], "161": [], "163": [], "164": [], "165": [], "166": [], "168": [], "169": [], "174": [], "181": [], "194": [], "region": [], "195": [], "file": [], "extens": [], "196": [], "197": [], "denois": [], "198": [], "hlg": [], "hdr": [], "199": [], "extern": [], "14": [], "36": [], "analyt": [], "unit": [], "contextu": [], "menu": [], "prefer": [], "63": [], "factori": [], "90": [], "log": [], "process": [], "creat": [], "custom": [], "109": [], "enumconnectbtcrequest": [], "enumconnectbtcstatu": [], "enumnetworkcommand": [], "enumnetworkopt": [], "enumnetworkown": [], "enumnetworkpolici": [], "enumpairbtcrequest": [], "enumpairbtcstatu": [], "enumpairingfinishst": [], "enumpowerst": [], "enumtimeunit": [], "enumwirelessmanagementcommand": [], "modemap": [], "map": [], "wsdk_enumassociationst": [], "wsdk_enumauthst": [], "wsdk_enumbandselect": [], "wsdk_enumcahacat": [], "wsdk_enumcahaerr": [], "wsdk_enumcahast": [], "wsdk_enumcahasub": [], "wsdk_enumcahautoclear": [], "wsdk_enumcahserv": [], "wsdk_enumcameracontrolstatu": [], "wsdk_enumcamerawakeupreason": [], "wsdk_enumcmdid": [], "wsdk_enumdevicemgrcat": [], "wsdk_enumdevicemgrerr": [], "wsdk_enumdevicemgrst": [], "wsdk_enumdevicemgrsub": [], "wsdk_enumfeatureid": [], "wsdk_enumflatmod": [], "wsdk_enumlen": [], "wsdk_enumlivestreamerror": [], "wsdk_enumlivestreamstatu": [], "wsdk_enumotacmd": [], "wsdk_enumotaerror": [], "wsdk_enumotast": [], "wsdk_enumpresetgroup": [], "wsdk_enumpresetgroupicon": [], "wsdk_enumpreseticon": [], "wsdk_enumpresettitl": [], "wsdk_enumqueryid": [], "wsdk_enumregistercahstatu": [], "wsdk_enumregisterlivestreamstatu": [], "wsdk_enumregisterotastatu": [], "wsdk_enumregisterpresetstatu": [], "wsdk_enumsettingid": [], "wsdk_enumshutt": [], "wsdk_enumsystemnotifyev": [], "wsdk_enumtimewarpspeedramp": [], "wsdk_enumwomcat": [], "wsdk_enumwomerr": [], "wsdk_enumwomst": [], "wsdk_enumwomsub": [], "wsdk_enumwindows": [], "widgettyp": [], "wsdkmode": [], "wsdkmodegroup": [], "filter": [], "activatedbi": [], "blacklist": [], "displayhint": [], "commandhint": [], "gpc_custom_preset_upd": [], "gpc_preset_custom_create_req": [], "gpc_preset_custom_create_resp": [], "gpc_preset_custom_remove_req": [], "gpc_preset_edit_start_req": [], "gpc_preset_factory_reset_req": [], "gpc_preset_get_presets_resp": [], "gpc_preset_group_list_resp": [], "gpc_preset_info_req": [], "gpc_preset_info_resp": [], "gpc_preset_list_req": [], "gpc_preset_list_resp": [], "gpc_preset_load_req": [], "gpc_preset_set_order_req": [], "gpc_preset_set_title_icon_req": [], "gpc_preset_switch_flatmode_req": [], "info": [], "notifconnectbtc": [], "notifpairbtc": [], "preset_group": [], "preset_info": [], "requestconnectbtc": [], "requestconnectmfi": [], "requestdeleteallap": [], "requestdeletesingleap": [], "requestgetnetworkcap": [], "requestpairbtc": [], "requestpairingfinish": [], "requestrelinquishownership": [], "requestsetsuspendsequ": [], "requeststopnetworkfeatur": [], "requesttakeownership": [], "responsecap": [], "responseconnectmfi": [], "responsetakeownership": [], "settinghint": [], "settingopt": [], "suspendinstructionentri": [], "uimodegroup": [], "wsdk_notifycahstatu": [], "wsdk_notifycohnstatu": [], "wsdk_notifylivestreamstatu": [], "wsdk_notifyotastatu": [], "wsdk_notifypresetstatu": [], "wsdk_preset": [], "wsdk_presetgroup": [], "wsdk_presetset": [], "wsdk_requestcohncert": [], "wsdk_requestclearcohncert": [], "wsdk_requestclearnewmediaflag": [], "wsdk_requestcreatecohncert": [], "wsdk_requestcreatecustompreset": [], "wsdk_requestcustompresetupd": [], "wsdk_requestgetassociationst": [], "wsdk_requestgetcahstatu": [], "wsdk_requestgetcahsticki": [], "wsdk_requestgetcohnstatu": [], "wsdk_requestgetcsivalu": [], "wsdk_requestgetclientid": [], "wsdk_requestgetlastcapturedmedia": [], "wsdk_requestgetlivestreamstatu": [], "wsdk_requestgetmobileoffloadst": [], "wsdk_requestgetotastatu": [], "wsdk_requestgetpresetstatu": [], "wsdk_requestgetsystembeacon": [], "wsdk_requestreleasenetwork": [], "wsdk_requestsetassociationst": [], "wsdk_requestsetauthcod": [], "wsdk_requestsetbandselect": [], "wsdk_requestsetcahautoclear": [], "wsdk_requestsetcahen": [], "wsdk_requestsetcahlog": [], "wsdk_requestsetcahserv": [], "wsdk_requestsetcahstart": [], "wsdk_requestsetcohnset": [], "wsdk_requestsetcsivalu": [], "wsdk_requestsetcameracontrolstatu": [], "wsdk_requestsetclientinfo": [], "wsdk_requestsetincontextualmenu": [], "wsdk_requestsetlivestreammod": [], "wsdk_requestsetotaupd": [], "wsdk_requestsetpresetcr": [], "wsdk_requestsetpreseteditcancel": [], "wsdk_requestsetpreseteditstart": [], "wsdk_requestsetpreseteditstor": [], "wsdk_requestsetpresetfactoryreset": [], "wsdk_requestsetpresetord": [], "wsdk_requestsetpresetremov": [], "wsdk_requestsetshutt": [], "wsdk_requestsetsystemenablebeacon": [], "wsdk_requestsetsystemnotifyev": [], "wsdk_requestsettimewarpspeed1x": [], "wsdk_requestsettimewarpspeedramp": [], "wsdk_requestsettimewarpspeedrampact": [], "wsdk_requestsetturboact": [], "wsdk_requestshortcutsreset": [], "wsdk_requeststartsimplecahprovis": [], "wsdk_responsecohncert": [], "wsdk_responsecreatecustompreset": [], "wsdk_responsegetassociationst": [], "wsdk_responsegetcahsticki": [], "wsdk_responsegetcsivalu": [], "wsdk_responsegetclientid": [], "wsdk_responsegetmobileoffloadst": [], "wsdk_responsegetsystembeacon": [], "wsdk_responselastcapturedmedia": [], "titl": [], "off": 7, "wi": 7, "fi": 7, "unus": [], "7": [], "12": [], "deprec": [], "viewer": [], "15": [], "b": [], "18": [], "25": [], "date": [], "yy": [], "mm": [], "dd": [], "hh": [], "ss": [], "all": [], "hex": [], "40": [], "hero8": [], "submod": [], "46": [], "multishot": [], "50": [], "51": [], "52": [], "53": [], "57": [], "71": [], "72": [], "73": [], "exclus": [], "superbank": [], "80": [], "hero7": [], "onli": [], "high": [], "base": [], "temperatur": [], "silver": [], "timewarp": [], "1x": [], "92": [], "requestgetallpresetstatu": []}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 60}, "alltitles": {"Access Point": [[0, "access-point"]], "Operations": [[0, "operations"], [1, "operations"], [2, "operations"], [3, "operations"], [4, "operations"], [5, "operations"], [6, "operations"], [7, "operations"]], "Disconnect from Access Point": [[0, "disconnect-from-access-point"]], "Camera on the Home Network": [[1, "camera-on-the-home-network"]], "Certificates": [[1, "certificates"]], "Verifying Certificate": [[1, "verifying-certificate"]], "View Certificate Details": [[1, "view-certificate-details"]], "Provisioning Procedure": [[1, "provisioning-procedure"]], "Control": [[2, "control"]], "Hilights": [[3, "hilights"]], "Live Streaming": [[4, "live-streaming"]], "Presets": [[5, "presets"]], "Preset Groups": [[5, "preset-groups"]], "Query": [[6, "query"]], "Settings": [[7, "settings"]], "Camera Capabilities": [[7, "camera-capabilities"]], "XLSX": [[7, "xlsx"]], "JSON": [[7, "json"]], "Setting IDs": [[7, "setting-ids"], [13, "setting-ids"]], "Resolution (2)": [[7, "resolution-2"]], "Frames Per Second (3)": [[7, "frames-per-second-3"]], "FOV (43)": [[7, "fov-43"]], "Auto Off (59)": [[7, "auto-off-59"]], "Aspect Ratio (108)": [[7, "aspect-ratio-108"]], "Lens (121)": [[7, "lens-121"]], "Lens (122)": [[7, "lens-122"]], "Lens (123)": [[7, "lens-123"]], "Format (128)": [[7, "format-128"]], "Anti-Flicker (134)": [[7, "anti-flicker-134"]], "Hypersmooth (135)": [[7, "hypersmooth-135"]], "Horizon Leveling (150)": [[7, "horizon-leveling-150"]], "Horizon Leveling (151)": [[7, "horizon-leveling-151"]], "Max Lens Mod Enable (162)": [[7, "max-lens-mod-enable-162"]], "HindSight (167)": [[7, "hindsight-167"]], "Interval (171)": [[7, "interval-171"]], "Duration (172)": [[7, "duration-172"]], "Video Performance Modes (173)": [[7, "video-performance-modes-173"]], "Controls (175)": [[7, "controls-175"]], "Speed (176)": [[7, "speed-176"]], "Night Photo (177)": [[7, "night-photo-177"]], "Wi-fi Band (178)": [[7, "wi-fi-band-178"]], "Trail Length (179)": [[7, "trail-length-179"]], "Video Mode (180)": [[7, "video-mode-180"]], "Bit Rate (182)": [[7, "bit-rate-182"]], "Bit Depth (183)": [[7, "bit-depth-183"]], "Profiles (184)": [[7, "profiles-184"]], "Video Mode (186)": [[7, "video-mode-186"]], "Lapse Mode (187)": [[7, "lapse-mode-187"]], "Max Lens Mod (189)": [[7, "max-lens-mod-189"]], "Max Lens Mod Enable (190)": [[7, "max-lens-mod-enable-190"]], "Photo Mode (191)": [[7, "photo-mode-191"]], "Aspect Ratio (192)": [[7, "aspect-ratio-192"]], "Framing (193)": [[7, "framing-193"]], "Statuses": [[8, "statuses"]], "Status IDs": [[8, "status-ids"], [13, "status-ids"]], "Is the system\u2019s internal battery present? (1)": [[8, "is-the-system-s-internal-battery-present-1"]], "Rough approximation of internal battery level in bars (or charging) (2)": [[8, "rough-approximation-of-internal-battery-level-in-bars-or-charging-2"]], "Is the system currently overheating? (6)": [[8, "is-the-system-currently-overheating-6"]], "Is the camera busy? (8)": [[8, "is-the-camera-busy-8"]], "Is Quick Capture feature enabled? (9)": [[8, "is-quick-capture-feature-enabled-9"]], "Is the system encoding right now? (10)": [[8, "is-the-system-encoding-right-now-10"]], "Is LCD lock active? (11)": [[8, "is-lcd-lock-active-11"]], "When encoding video, this is the duration (seconds) of the video so far; 0 otherwise (13)": [[8, "when-encoding-video-this-is-the-duration-seconds-of-the-video-so-far-0-otherwise-13"]], "Are Wireless Connections enabled? (17)": [[8, "are-wireless-connections-enabled-17"]], "The pairing state of the camera (19)": [[8, "the-pairing-state-of-the-camera-19"]], "The last type of pairing in which the camera was engaged (20)": [[8, "the-last-type-of-pairing-in-which-the-camera-was-engaged-20"]], "Time since boot (milliseconds) of last successful pairing complete action (21)": [[8, "time-since-boot-milliseconds-of-last-successful-pairing-complete-action-21"]], "State of current scan for WiFi Access Points (22)": [[8, "state-of-current-scan-for-wifi-access-points-22"]], "Time since boot (milliseconds) that the WiFi Access Point scan completed (23)": [[8, "time-since-boot-milliseconds-that-the-wifi-access-point-scan-completed-23"]], "WiFi AP provisioning state (24)": [[8, "wifi-ap-provisioning-state-24"]], "Wireless remote control version (26)": [[8, "wireless-remote-control-version-26"]], "Is a wireless remote control connected? (27)": [[8, "is-a-wireless-remote-control-connected-27"]], "Wireless Pairing State. Each bit contains state information (see WirelessPairingStateFlags) (28)": [[8, "wireless-pairing-state-each-bit-contains-state-information-see-wirelesspairingstateflags-28"]], "SSID of the AP the camera is currently connected to. On BLE connection, value is big-endian byte-encoded int32 (29)": [[8, "ssid-of-the-ap-the-camera-is-currently-connected-to-on-ble-connection-value-is-big-endian-byte-encoded-int32-29"]], "The camera\u2019s WiFi SSID. On BLE connection, value is big-endian byte-encoded int32 (30)": [[8, "the-camera-s-wifi-ssid-on-ble-connection-value-is-big-endian-byte-encoded-int32-30"]], "The number of wireless devices connected to the camera (31)": [[8, "the-number-of-wireless-devices-connected-to-the-camera-31"]], "Is Preview Stream enabled? (32)": [[8, "is-preview-stream-enabled-32"]], "Primary Storage Status (33)": [[8, "primary-storage-status-33"]], "How many photos can be taken with current settings before sdcard is full (34)": [[8, "how-many-photos-can-be-taken-with-current-settings-before-sdcard-is-full-34"]], "How many minutes of video can be captured with current settings before sdcard is full (35)": [[8, "how-many-minutes-of-video-can-be-captured-with-current-settings-before-sdcard-is-full-35"]], "Total number of photos on sdcard (38)": [[8, "total-number-of-photos-on-sdcard-38"]], "Total number of videos on sdcard (39)": [[8, "total-number-of-videos-on-sdcard-39"]], "The current status of Over The Air (OTA) update (41)": [[8, "the-current-status-of-over-the-air-ota-update-41"]], "Is there a pending request to cancel a firmware update download? (42)": [[8, "is-there-a-pending-request-to-cancel-a-firmware-update-download-42"]], "Is locate camera feature active? (45)": [[8, "is-locate-camera-feature-active-45"]], "The current timelapse interval countdown value (e.g. 5\u20264\u20263\u20262\u20261\u2026) (49)": [[8, "the-current-timelapse-interval-countdown-value-e-g-5-4-3-2-1-49"]], "Remaining space on the sdcard in Kilobytes (54)": [[8, "remaining-space-on-the-sdcard-in-kilobytes-54"]], "Is preview stream supported in current recording/mode/secondary-stream? (55)": [[8, "is-preview-stream-supported-in-current-recording-mode-secondary-stream-55"]], "WiFi signal strength in bars (56)": [[8, "wifi-signal-strength-in-bars-56"]], "The number of hilights in currently-encoding video (value is set to 0 when encoding stops) (58)": [[8, "the-number-of-hilights-in-currently-encoding-video-value-is-set-to-0-when-encoding-stops-58"]], "Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops) (59)": [[8, "time-since-boot-milliseconds-of-most-recent-hilight-in-encoding-video-set-to-0-when-encoding-stops-59"]], "The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this (60)": [[8, "the-minimum-time-between-camera-status-updates-milliseconds-best-practice-is-to-not-poll-for-status-more-often-than-this-60"]], "How many minutes of Time Lapse Video can be captured with current settings before sdcard is full (64)": [[8, "how-many-minutes-of-time-lapse-video-can-be-captured-with-current-settings-before-sdcard-is-full-64"]], "Liveview Exposure Select Mode (65)": [[8, "liveview-exposure-select-mode-65"]], "Liveview Exposure Select: y-coordinate (percent) (66)": [[8, "liveview-exposure-select-y-coordinate-percent-66"]], "Liveview Exposure Select: y-coordinate (percent) (67)": [[8, "liveview-exposure-select-y-coordinate-percent-67"]], "Does the camera currently have a GPS lock? (68)": [[8, "does-the-camera-currently-have-a-gps-lock-68"]], "Is the camera in AP Mode? (69)": [[8, "is-the-camera-in-ap-mode-69"]], "Internal battery level (percent) (70)": [[8, "internal-battery-level-percent-70"]], "Microphone Accessory status (74)": [[8, "microphone-accessory-status-74"]], "Digital Zoom level (percent) (75)": [[8, "digital-zoom-level-percent-75"]], "Wireless Band (76)": [[8, "wireless-band-76"]], "Is Digital Zoom feature available? (77)": [[8, "is-digital-zoom-feature-available-77"]], "Are current video settings mobile friendly? (related to video compression and frame rate) (78)": [[8, "are-current-video-settings-mobile-friendly-related-to-video-compression-and-frame-rate-78"]], "Is the camera currently in First Time Use (FTU) UI flow? (79)": [[8, "is-the-camera-currently-in-first-time-use-ftu-ui-flow-79"]], "Is 5GHz wireless band available? (81)": [[8, "is-5ghz-wireless-band-available-81"]], "Is the system fully booted and ready to accept commands? (82)": [[8, "is-the-system-fully-booted-and-ready-to-accept-commands-82"]], "Is the internal battery charged sufficiently to start Over The Air (OTA) update? (83)": [[8, "is-the-internal-battery-charged-sufficiently-to-start-over-the-air-ota-update-83"]], "Is the camera getting too cold to continue recording? (85)": [[8, "is-the-camera-getting-too-cold-to-continue-recording-85"]], "Rotational orientation of the camera (86)": [[8, "rotational-orientation-of-the-camera-86"]], "Is this camera model capable of zooming while encoding? (88)": [[8, "is-this-camera-model-capable-of-zooming-while-encoding-88"]], "Current Flatmode ID (89)": [[8, "current-flatmode-id-89"]], "Current Video Preset (ID) (93)": [[8, "current-video-preset-id-93"]], "Current Photo Preset (ID) (94)": [[8, "current-photo-preset-id-94"]], "Current Time Lapse Preset (ID) (95)": [[8, "current-time-lapse-preset-id-95"]], "Current Preset Group (ID) (corresponds to ui_mode_groups in settings.json) (96)": [[8, "current-preset-group-id-corresponds-to-ui-mode-groups-in-settings-json-96"]], "Current Preset (ID) (97)": [[8, "current-preset-id-97"]], "Preset Modified Status, which contains an event ID and a Preset (Group) ID (98)": [[8, "preset-modified-status-which-contains-an-event-id-and-a-preset-group-id-98"]], "The number of Live Bursts can be captured with current settings before sdcard is full (99)": [[8, "the-number-of-live-bursts-can-be-captured-with-current-settings-before-sdcard-is-full-99"]], "Total number of Live Bursts on sdcard (100)": [[8, "total-number-of-live-bursts-on-sdcard-100"]], "Is Capture Delay currently active (i.e. counting down)? (101)": [[8, "is-capture-delay-currently-active-i-e-counting-down-101"]], "Media Mod state (102)": [[8, "media-mod-state-102"]], "Time Warp Speed (103)": [[8, "time-warp-speed-103"]], "Is the system\u2019s Linux core active? (104)": [[8, "is-the-system-s-linux-core-active-104"]], "Camera lens type (reflects changes to setting 162 or setting 189) (105)": [[8, "camera-lens-type-reflects-changes-to-setting-162-or-setting-189-105"]], "Is Video Hindsight Capture Active? (106)": [[8, "is-video-hindsight-capture-active-106"]], "Scheduled Capture Preset ID (107)": [[8, "scheduled-capture-preset-id-107"]], "Is Scheduled Capture set? (108)": [[8, "is-scheduled-capture-set-108"]], "Display Mod Status (bitmasked) (110)": [[8, "display-mod-status-bitmasked-110"]], "Does sdcard meet specified minimum write speed? (111)": [[8, "does-sdcard-meet-specified-minimum-write-speed-111"]], "Number of sdcard write speed errors since device booted (112)": [[8, "number-of-sdcard-write-speed-errors-since-device-booted-112"]], "Is Turbo Transfer active? (113)": [[8, "is-turbo-transfer-active-113"]], "Camera control status ID (114)": [[8, "camera-control-status-id-114"]], "Is the camera connected to a PC via USB? (115)": [[8, "is-the-camera-connected-to-a-pc-via-usb-115"]], "Camera control over USB state (116)": [[8, "camera-control-over-usb-state-116"]], "Total SD card capacity in Kilobytes (117)": [[8, "total-sd-card-capacity-in-kilobytes-117"]], "Welcome to Open GoPro BLE API\u2019s documentation!": [[9, "welcome-to-open-gopro-ble-api-s-documentation"]], "Supported Cameras": [[9, "supported-cameras"]], "Getting Started": [[9, "getting-started"]], "Limitations": [[9, "limitations"]], "General": [[9, "general"]], "Protocol": [[10, "protocol"]], "BLE Setup": [[11, "ble-setup"]], "Pairing Mode": [[11, "pairing-mode"]], "Advertisements": [[11, "advertisements"]], "Finish Pairing": [[11, "finish-pairing"]], "Configure GATT Characteristics": [[11, "configure-gatt-characteristics"]], "BLE Characteristics": [[11, "ble-characteristics"]], "Send Messages": [[11, "send-messages"]], "Data Protocol": [[12, "data-protocol"]], "Packetization": [[12, "packetization"]], "Packet Headers": [[12, "packet-headers"]], "General (5-bit) Packets": [[12, "general-5-bit-packets"]], "Extended (13-bit) Packets": [[12, "extended-13-bit-packets"]], "Extended (16-bit) Packets": [[12, "extended-16-bit-packets"]], "Continuation Packets": [[12, "continuation-packets"]], "Decipher Message Payload Type": [[12, "decipher-message-payload-type"]], "Message Payload": [[12, "message-payload"]], "Type Length Value": [[12, "type-length-value"]], "Commands": [[12, "commands"]], "Queries": [[12, "queries"]], "Protobuf": [[12, "protobuf"]], "ID Tables": [[13, "id-tables"]], "Command IDs": [[13, "command-ids"]], "Query IDs": [[13, "query-ids"]], "Protobuf IDs": [[13, "protobuf-ids"]], "Protobuf Documentation": [[14, "protobuf-documentation"]], "Enums": [[14, "enums"]], "EnumCOHNNetworkState": [[14, "enumcohnnetworkstate"]], "EnumCOHNStatus": [[14, "enumcohnstatus"]], "EnumCameraControlStatus": [[14, "enumcameracontrolstatus"]], "EnumFlatMode": [[14, "enumflatmode"]], "EnumLens": [[14, "enumlens"]], "EnumLiveStreamError": [[14, "enumlivestreamerror"]], "EnumLiveStreamStatus": [[14, "enumlivestreamstatus"]], "EnumPresetGroup": [[14, "enumpresetgroup"]], "EnumPresetGroupIcon": [[14, "enumpresetgroupicon"]], "EnumPresetIcon": [[14, "enumpreseticon"]], "EnumPresetTitle": [[14, "enumpresettitle"]], "EnumProvisioning": [[14, "enumprovisioning"]], "EnumRegisterLiveStreamStatus": [[14, "enumregisterlivestreamstatus"]], "EnumRegisterPresetStatus": [[14, "enumregisterpresetstatus"]], "EnumResultGeneric": [[14, "enumresultgeneric"]], "EnumScanEntryFlags": [[14, "enumscanentryflags"]], "EnumScanning": [[14, "enumscanning"]], "EnumWindowSize": [[14, "enumwindowsize"]], "Media": [[14, "media"]], "NotifProvisioningState": [[14, "notifprovisioningstate"]], "NotifStartScanning": [[14, "notifstartscanning"]], "NotifyCOHNStatus": [[14, "notifycohnstatus"]], "NotifyLiveStreamStatus": [[14, "notifylivestreamstatus"]], "NotifyPresetStatus": [[14, "notifypresetstatus"]], "Preset": [[14, "preset"]], "PresetGroup": [[14, "presetgroup"]], "PresetSetting": [[14, "presetsetting"]], "RequestCOHNCert": [[14, "requestcohncert"]], "RequestClearCOHNCert": [[14, "requestclearcohncert"]], "RequestConnect": [[14, "requestconnect"]], "RequestConnectNew": [[14, "requestconnectnew"]], "RequestCreateCOHNCert": [[14, "requestcreatecohncert"]], "RequestCustomPresetUpdate": [[14, "requestcustompresetupdate"]], "RequestGetApEntries": [[14, "requestgetapentries"]], "RequestGetCOHNStatus": [[14, "requestgetcohnstatus"]], "RequestGetLastCapturedMedia": [[14, "requestgetlastcapturedmedia"]], "RequestGetLiveStreamStatus": [[14, "requestgetlivestreamstatus"]], "RequestGetPresetStatus": [[14, "requestgetpresetstatus"]], "RequestReleaseNetwork": [[14, "requestreleasenetwork"]], "RequestSetCOHNSetting": [[14, "requestsetcohnsetting"]], "RequestSetCameraControlStatus": [[14, "requestsetcameracontrolstatus"]], "RequestSetLiveStreamMode": [[14, "requestsetlivestreammode"]], "RequestSetTurboActive": [[14, "requestsetturboactive"]], "RequestStartScan": [[14, "requeststartscan"]], "ResponseCOHNCert": [[14, "responsecohncert"]], "ResponseConnect": [[14, "responseconnect"]], "ResponseConnectNew": [[14, "responseconnectnew"]], "ResponseGeneric": [[14, "responsegeneric"]], "ResponseGetApEntries": [[14, "responsegetapentries"]], "ResponseLastCapturedMedia": [[14, "responselastcapturedmedia"]], "ResponseStartScanning": [[14, "responsestartscanning"]], "ResponseGetApEntries::ScanEntry": [[14, "responsegetapentries-scanentry"]], "State Management": [[15, "state-management"]], "Camera Readiness": [[15, "camera-readiness"]], "Keep Alive": [[15, "keep-alive"]], "Camera Control": [[15, "camera-control"]]}, "indexentries": {}}) \ No newline at end of file +Search.setIndex({"docnames": ["features/access_points", "features/cohn", "features/control", "features/hilights", "features/live_streaming", "features/presets", "features/query", "features/settings", "features/statuses", "index", "protocol", "protocol/ble_setup", "protocol/data_protocol", "protocol/id_tables", "protocol/protobuf", "protocol/state_management"], "filenames": ["features/access_points.rst", "features/cohn.rst", "features/control.rst", "features/hilights.rst", "features/live_streaming.rst", "features/presets.rst", "features/query.rst", "features/settings.rst", "features/statuses.rst", "index.rst", "protocol.rst", "protocol/ble_setup.rst", "protocol/data_protocol.rst", "protocol/id_tables.rst", "protocol/protobuf.rst", "protocol/state_management.rst"], "titles": ["Access Point", "Camera on the Home Network", "Control", "Hilights", "Live Streaming", "Presets", "Query", "Settings", "Statuses", "Welcome to Open GoPro BLE API\u2019s documentation!", "Protocol", "BLE Setup", "Data Protocol", "ID Tables", "Protobuf Documentation", "State Management"], "terms": {"The": [0, 1, 2, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14], "camera": [0, 2, 4, 5, 6, 10, 11, 12, 13, 14], "support": [0, 1, 2, 4, 6, 7, 11, 13, 14], "connect": [0, 1, 2, 4, 11, 13, 14, 15], "station": [0, 4, 14], "mode": [0, 2, 4, 5, 9, 10, 13, 14], "sta": [0, 14], "thi": [0, 1, 2, 3, 5, 6, 7, 9, 11, 12, 13, 14, 15], "i": [0, 1, 2, 4, 5, 6, 7, 9, 11, 12, 13, 14, 15], "necessari": [0, 7, 11, 12, 15], "featur": [0, 1, 2, 4, 5, 6, 9, 10, 11, 12, 13, 14], "live": [0, 9, 13, 14], "stream": [0, 9, 13, 14], "where": [0, 9, 12], "need": [0, 1, 9, 11], "an": [0, 1, 4, 6, 7, 9, 11, 12, 13, 14, 15], "internet": [0, 14], "while": [0, 3, 9, 11, 13, 14, 15], "http": [0, 1, 14], "command": [0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 14, 15], "control": [0, 1, 5, 9, 10, 11, 13, 14], "avail": [0, 5, 9, 13, 14], "some": [0, 1, 2, 12, 15], "scan": [0, 11, 13, 14], "type": [0, 1, 2, 3, 4, 5, 6, 7, 10, 13, 14], "protobuf": [0, 1, 2, 4, 5, 6, 9, 10], "request": [0, 1, 2, 3, 4, 5, 6, 7, 9, 12, 13, 14], "start": [0, 2, 4, 6, 12, 13, 14], "serial": [0, 2, 12, 14], "object": [0, 7, 12, 14], "zero": [0, 2, 5, 8, 14], "byte": [0, 2, 6, 12, 13, 14], "respons": [0, 1, 2, 3, 4, 5, 6, 7, 11, 12, 13, 14], "responsestartscan": [0, 13], "ar": [0, 1, 5, 6, 7, 9, 10, 11, 12, 13, 14], "sent": [0, 4, 5, 6, 11, 12, 14], "immedi": [0, 2, 5, 14], "after": [0, 2, 11, 12, 14, 15], "receiv": [0, 6, 9, 11, 12, 14], "notif": [0, 1, 2, 4, 5, 6, 11, 13, 14], "notifstartscan": [0, 13], "period": [0, 5, 14, 15], "state": [0, 5, 6, 7, 9, 10, 11, 12, 13, 14], "chang": [0, 1, 4, 5, 6, 7, 9, 13, 14, 15], "us": [0, 1, 2, 3, 4, 5, 9, 10, 12, 13, 14, 15], "detect": [0, 14], "complet": [0, 9, 13, 14], "uuid": [0, 1, 2, 3, 4, 5, 6, 7, 11, 12], "network": [0, 9, 11, 14], "manag": [0, 9, 10, 11], "id": [0, 1, 2, 3, 4, 5, 6, 9, 10, 12, 14], "0x02": [0, 13], "action": [0, 1, 2, 4, 5, 6, 12, 13], "messag": [0, 1, 2, 4, 5, 6, 9, 10, 13, 14, 15], "requeststartscan": [0, 13], "doc": [0, 1, 2, 4, 5, 6], "sourc": [0, 1, 2, 4, 5, 6, 14], "current": [0, 1, 2, 4, 5, 6, 7, 9, 12, 13, 14], "initi": [0, 4, 5, 6, 10, 14], "0x82": [0, 6, 13], "trigger": [0, 1, 14], "via": [0, 1, 2, 4, 5, 6, 7, 9, 11, 13, 14], "0x0b": [0, 13], "get": [0, 1, 4, 5, 6, 7, 13, 14, 15], "ap": [0, 2, 11, 13, 14], "result": [0, 6, 7, 9, 12, 13, 14], "list": [0, 7, 9, 14], "found": [0, 5, 6, 7, 14], "dure": [0, 3, 11, 14], "responsegetapentri": [0, 13], "0x03": [0, 13], "requestgetapentri": [0, 13], "A": [0, 1, 5, 7, 12, 14, 15], "entri": [0, 14], "describ": [0, 6, 8, 9, 12, 14], "0x83": [0, 13], "provis": [0, 13, 14], "can": [0, 1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14], "onli": [0, 3, 5, 6, 7, 8, 12, 13, 14], "ha": [0, 1, 8, 12, 14], "been": [0, 12, 14], "previous": [0, 7, 14], "configur": [0, 1, 2, 4, 10, 14], "therefor": [0, 15], "first": [0, 1, 6, 7, 9, 11, 12, 13, 14], "ensur": [0, 11], "relev": [0, 9, 11, 12], "scan_flag_configur": [0, 14], "bit": [0, 11, 13], "set": [0, 1, 2, 4, 5, 6, 9, 10, 11, 12, 14, 15], "do": [0, 11, 12, 14], "authent": [0, 14], "intend": [0, 14], "responseconnect": [0, 13], "notifprovisioningst": [0, 13], "0x04": [0, 13], "requestconnect": [0, 13], "statu": [0, 1, 2, 4, 6, 10, 12, 14, 15], "attempt": [0, 8, 14], "0x84": [0, 13], "requestconnectnew": [0, 13], "0x0c": [0, 13], "new": [0, 1, 5, 11, 13, 14], "doe": [0, 1, 11, 13, 14], "have": [0, 1, 11, 12, 13], "responseconnectnew": [0, 13], "0x05": [0, 2, 13], "0x85": [0, 13], "To": [0, 5, 8, 12], "return": [0, 1, 2, 5, 6, 14], "On": [0, 1, 2, 7, 13, 14], "which": [0, 1, 2, 5, 11, 13, 14], "disabl": [0, 2, 8, 14], "cohn": [1, 13, 14], "capabl": [1, 6, 9, 13], "allow": [1, 11], "client": [1, 2, 5, 11, 14, 15], "perform": [1, 5, 9, 13, 14], "indirectli": 1, "through": [1, 9, 10], "access": [1, 2, 4, 9, 11, 13, 14], "point": [1, 2, 4, 9, 11, 13, 14], "router": 1, "For": [1, 2, 4, 7, 9, 11, 12, 15], "secur": 1, "purpos": 1, "all": [1, 2, 6, 11, 12, 13], "commun": [1, 9, 10, 11], "over": [1, 13], "hero12": [1, 6, 9], "black": [1, 6, 7, 9], "hero11": [1, 9], "mini": [1, 9], "hero10": [1, 9], "hero9": [1, 9], "requir": [1, 11, 14], "two": [1, 8, 11, 12], "thing": 1, "trust": 1, "ssl": [1, 14], "tl": [1, 14], "basic": [1, 7, 9, 14], "auth": [1, 14], "usernam": [1, 14], "password": [1, 11, 14], "header": [1, 14], "root": [1, 14], "ca": [1, 14], "cert": [1, 14], "provid": 1, "1": [1, 2, 6, 7, 12, 13, 14], "year": [1, 2, 6], "lifespan": 1, "contain": [1, 6, 7, 12, 13, 14], "": [1, 2, 4, 5, 6, 7, 11, 12, 13, 14, 15], "ip": [1, 14], "address": [1, 14], "local": [1, 2, 6, 13, 14], "sign": 1, "chain": 1, "e": [1, 2, 5, 6, 13, 14, 15], "g": [1, 5, 13, 14, 15], "when": [1, 2, 5, 6, 12, 13, 14], "dhcp": 1, "leas": 1, "expir": 1, "reset": [1, 2, 5, 11, 12], "replac": 1, "without": [1, 2, 6], "download": [1, 13], "instal": 1, "act": 1, "author": 1, "creat": [1, 5, 13, 14], "valid": [1, 7, 11, 14], "util": 1, "openssl": 1, "cafil": 1, "path": [1, 6, 14], "goprorootca": 1, "crt": 1, "ok": [1, 8], "most": [1, 2, 9, 13, 14], "system": [1, 13, 14, 15], "about": [1, 2, 4, 6, 14], "maco": 1, "right": [1, 13], "mous": 1, "click": 1, "quick": [1, 13], "look": 1, "window": 1, "properti": [1, 14], "ubuntu": 1, "open": [1, 6, 10, 12, 13], "file": [1, 7, 13, 14], "x509": 1, "noout": 1, "text": [1, 14], "In": [1, 2, 7, 11, 12, 15], "order": [1, 2, 5, 7, 10, 11, 12, 15], "must": [1, 5, 8, 11, 12, 14], "At": 1, "high": [1, 7, 13], "level": [1, 12, 13, 14], "process": [1, 11, 13], "follow": [1, 4, 7, 10, 11, 12, 14], "instruct": 1, "gopro": [1, 2, 6, 8, 10, 11, 12, 13, 15], "credenti": 1, "depend": [1, 5, 6, 7, 12, 14, 15], "case": [1, 5, 9, 14], "step": [1, 11], "onc": [1, 11, 12], "nearli": 1, "function": [1, 9], "more": [1, 6, 7, 11, 12, 13, 14], "see": [1, 4, 6, 7, 9, 11, 12, 13], "specif": [1, 15], "clear": [1, 13, 14], "responsegener": [1, 2, 4, 5, 13], "0xf1": [1, 2, 4, 5, 13], "0x66": [1, 13], "requestclearcohncert": [1, 13], "gener": [1, 2, 4, 5, 14], "across": [1, 2, 4, 5, 14], "mani": [1, 2, 4, 5, 13, 14], "0xe6": [1, 13], "creation": [1, 14], "0x67": [1, 13], "requestcreatecohncert": [1, 13], "0xe7": [1, 13], "responsecohncert": [1, 13], "queri": [1, 4, 5, 7, 8, 9, 10, 11, 15], "0xf5": [1, 4, 5, 6, 13], "0x6e": [1, 13], "requestcohncert": [1, 13], "0xee": [1, 13], "notifycohnstatu": [1, 13], "addition": [1, 9, 14], "asynchron": [1, 4, 5, 11, 13, 14], "updat": [1, 2, 5, 6, 9, 13, 14], "also": [1, 14], "regist": [1, 4, 5, 6, 13, 14], "valu": [1, 2, 5, 6, 7, 9, 13, 14], "0x6f": [1, 13], "requestgetcohnstatu": [1, 13], "0xef": [1, 13], "0x65": [1, 13], "requestsetcohnset": [1, 13], "0xe5": [1, 13], "page": [2, 14], "detail": [2, 4, 7, 14], "keep": [2, 10, 13], "aliv": [2, 10, 13], "tlv": [2, 3, 5, 6, 7, 12], "0x5b": [2, 13], "maxim": [2, 12], "batteri": [2, 7, 13], "life": 2, "automat": [2, 14, 15], "go": 2, "sleep": [2, 11, 13], "time": [2, 6, 11, 13, 14, 15], "logic": 2, "handl": 2, "combin": 2, "auto": [2, 8, 13], "off": [2, 15], "user": [2, 5, 7, 9, 14, 15], "regularli": 2, "send": [2, 5, 9, 12, 14, 15], "both": 2, "timer": 2, "reach": 2, "power": [2, 11, 13, 15], "down": [2, 13], "tap": 2, "lcd": [2, 13], "screen": [2, 14], "press": [2, 5, 14], "button": [2, 14], "programmat": 2, "un": 2, "shutter": [2, 4, 13], "load": [2, 5, 13, 15], "preset": [2, 7, 9, 13, 15], "best": [2, 11, 13, 15], "practic": [2, 11, 13, 15], "prevent": [2, 15], "from": [2, 5, 6, 7, 8, 11, 12, 14], "inadvert": 2, "everi": [2, 7], "3": [2, 12, 13, 14], "0": [2, 6, 7, 12, 13, 14], "second": [2, 6, 13, 14], "establish": 2, "paramet": [2, 5, 6, 7, 12], "keep_al": 2, "uint8": [2, 6, 7], "hard": [2, 8], "code": [2, 8, 9], "data": [2, 6, 9, 10, 11], "0x42": 2, "analyt": [2, 13], "0x50": [2, 13], "third": [2, 14, 15], "parti": [2, 14, 15], "track": 2, "0x17": [2, 13], "enabl": [2, 5, 11, 13, 14], "wifi": [2, 11, 13, 14], "part": [2, 6, 14], "global": [2, 14], "behavior": [2, 14, 15], "tell": [2, 14, 15], "app": [2, 8, 14, 15], "extern": [2, 13, 14], "wish": [2, 14, 15], "claim": [2, 14, 15], "caus": [2, 11, 14], "exit": [2, 5, 12, 14], "contextu": [2, 13, 14], "menu": [2, 13, 14], "idl": [2, 8, 14], "ani": [2, 4, 5, 9, 14], "interact": [2, 14], "physic": [2, 14], "reclaim": [2, 14], "accordingli": [2, 14], "If": [2, 6, 7, 11, 12, 14, 15], "ui": [2, 5, 11, 13, 14], "entiti": [2, 8, 14], "advertis": [2, 10, 14], "114": [2, 7, 13, 14], "inform": [2, 6, 7, 11, 13, 14], "whether": [2, 5, 11, 12, 14], "63": [2, 13, 14], "0x69": [2, 13], "requestsetcameracontrolstatu": [2, 13], "0xe9": [2, 13], "date": [2, 6, 13], "0x0d": [2, 13], "timezon": [2, 6], "daylight": [2, 6], "save": [2, 6, 14], "date_tim": 2, "7": [2, 7, 8, 12, 13, 14], "defin": [2, 6, 7, 12, 14], "uint16": [2, 6], "month": [2, 6], "12": [2, 6, 7, 8, 13, 14], "dai": [2, 6], "31": [2, 6, 12, 13, 14], "hour": [2, 6, 7, 11], "23": [2, 6, 7, 13, 14], "minut": [2, 6, 7, 13], "59": [2, 6, 13, 14], "exampl": [2, 7, 9, 11, 12, 15], "2023": 2, "01": [2, 6, 9, 12], "03": [2, 9], "04": 2, "05": 2, "07": 2, "e7": 2, "1f": 2, "abov": [2, 6, 7, 9], "0x0f": [2, 13], "10": [2, 7, 9, 12, 13, 14], "int16": [2, 6], "utc": [2, 6], "offset": [2, 6], "is_dst": [2, 6], "otherwis": [2, 12, 13], "02": 2, "00": [2, 9, 12], "dst": 2, "ff": 2, "88": [2, 13], "0x01": [2, 13], "turbo": [2, 13, 14], "transfer": [2, 13, 14], "displai": [2, 13, 14], "media": [2, 4, 6, 13, 15], "0x6b": [2, 13], "requestsetturboact": [2, 13], "0xeb": [2, 13], "put": [2, 4, 11], "still": 2, "ble": [2, 10, 12, 13], "moment": [3, 13], "0x18": [3, 13], "add": [3, 14], "record": [3, 13], "encod": [3, 9, 13, 14, 15], "abil": 4, "social": 4, "platform": 4, "twitch": 4, "youtub": 4, "facebook": 4, "other": [4, 15], "site": 4, "accept": [4, 13, 14, 15], "rtmp": [4, 14], "url": [4, 14], "addit": [4, 14], "how": [4, 9, 12, 13], "accomplish": [4, 12], "livestream": [4, 13, 14], "poll": [4, 13], "until": 4, "indic": [4, 11, 14], "readi": [4, 10, 13, 14], "begin": 4, "unset": [4, 15], "stop": [4, 13, 14], "0x79": [4, 13], "requestsetlivestreammod": [4, 13], "0xf9": [4, 13], "option": [4, 5, 6, 7, 8, 12, 14], "futur": [4, 14], "notifylivestreamstatu": [4, 13], "0x74": [4, 13], "requestgetlivestreamstatu": [4, 13], "either": [4, 5, 12, 14], "As": [4, 14], "synchron": [4, 5, 14], "0xf4": [4, 13], "organ": 5, "differ": [5, 12], "collect": 5, "below": [5, 7, 9, 11, 12], "tabl": [5, 9, 10, 11, 12], "affect": 5, "therebi": 5, "162": [5, 13], "max": [5, 8, 13, 14], "len": [5, 13, 14], "173": [5, 13], "video": [5, 6, 9, 13, 14, 15], "175": [5, 13], "177": [5, 13], "night": [5, 13], "photo": [5, 6, 9, 13, 14, 15], "180": [5, 8, 13], "186": [5, 13], "187": [5, 13], "laps": [5, 13], "189": [5, 13], "mod": [5, 13], "190": [5, 13], "191": [5, 13], "find": 5, "98": [5, 13], "non": [5, 14], "submenu": 5, "were": 5, "delet": [5, 14], "within": [5, 14], "factori": [5, 11, 13, 14], "default": [5, 13, 14], "notifi": [5, 11, 14], "notifypresetstatu": [5, 13], "one": [5, 6, 7, 8, 12, 14], "caption": [5, 14], "api": [5, 6, 14], "long": [5, 7, 14], "pill": [5, 14], "back": [5, 14], "arrow": [5, 14], "reorder": [5, 14], "0x72": [5, 6, 13], "requestgetpresetstatu": [5, 13], "0xf2": [5, 13], "0xf3": [5, 13], "0x40": [5, 13], "uint32": 5, "0x3e": [5, 13], "enumpresetgroup": 5, "custom": [5, 13, 14], "titl": [5, 14], "icon": [5, 14], "activ": [5, 9, 13, 14, 15], "fail": [5, 7, 8, 14], "icon_id": [5, 14], "alwai": [5, 7, 9, 12, 14, 15], "pass": [5, 14], "title_id": [5, 14], "preset_title_user_defined_custom_nam": [5, 14], "94": [5, 13, 14], "name": [5, 7, 8, 9, 14], "specifi": [5, 12, 13, 14], "custom_nam": [5, 14], "0x64": [5, 13], "requestcustompresetupd": [5, 13], "0xe4": [5, 13], "section": [6, 8, 9, 10, 11, 12], "variou": [6, 9, 10], "0x0e": [6, 13], "response_length": 6, "length": [6, 13], "payload": [6, 10], "weekdai": 6, "sundai": 6, "saturdai": 6, "6": [6, 7, 12, 13, 14], "hardwar": [6, 13], "info": [6, 13, 14], "0x3c": [6, 13], "firmwar": [6, 7, 9, 13], "note": [6, 12], "model": [6, 9, 13, 14], "number": [6, 13, 14], "under": 6, "model_number_length": 6, "model_numb": 6, "unsign": 6, "model_name_length": 6, "model_nam": 6, "string": [6, 8, 12, 14], "deprecated_length": 6, "deprec": [6, 13], "firmware_version_length": 6, "firmware_vers": 6, "h23": [6, 9], "99": [6, 13], "56": [6, 13], "serial_number_length": 6, "serial_numb": 6, "c1234567812345": 6, "ap_ssid_length": 6, "ap_ssid": 6, "gp12345678": 6, "ap_mac_address_length": 6, "ap_mac_address": 6, "2674f7f65f78": 6, "reserv": [6, 12], "11": [6, 7, 13, 14], "0x10": [6, 13], "ye": 6, "last": [6, 13, 14], "captur": [6, 13, 14, 15], "filenam": [6, 14], "responselastcapturedmedia": [6, 13], "0x6d": [6, 13], "requestgetlastcapturedmedia": [6, 13], "rel": [6, 14], "dcim": [6, 14], "directori": [6, 14], "sdcard": [6, 13, 14, 15], "singl": [6, 12, 14], "group": [6, 13, 14], "0xed": [6, 13], "version": [6, 7, 9, 12, 13], "0x51": [6, 13], "major_length": 6, "major": 6, "minor_length": 6, "minor": 6, "associ": [6, 9, 14], "element": [6, 12, 13], "arrai": [6, 12, 14], "empti": 6, "0x12": [6, 13], "field": [6, 14], "individu": [6, 7, 12, 14], "document": [6, 7, 10, 12], "status": [6, 9, 14], "0x13": [6, 13], "report": 6, "those": 6, "0x32": [6, 13], "whenev": 6, "0x52": [6, 13], "0x92": [6, 13], "0x53": [6, 13], "0x93": [6, 13], "0x62": [6, 13], "0xa2": [6, 13], "unregist": [6, 13, 14], "cancel": [6, 13], "ongo": 6, "0x73": [6, 13], "usual": [7, 14], "anoth": 7, "often": [7, 13], "releas": 7, "next": 7, "whitelist": 7, "These": 7, "each": [7, 11, 12, 13], "compris": [7, 12, 14], "present": [7, 13], "mean": [7, 14], "guarante": 7, "attain": 7, "failur": 7, "adher": 7, "mai": [7, 14, 15], "blacklist": 7, "rule": 7, "reject": [7, 9, 14, 15], "4": [7, 12, 13, 14], "5": [7, 13, 14], "hero": 7, "re": [7, 11, 14], "1080": 7, "60": [7, 9, 13, 14], "hz": 7, "fp": [7, 13], "240": 7, "wide": 7, "work": [7, 12], "standard": 7, "suppos": 7, "wa": [7, 11, 13, 14], "4k": 7, "tri": 7, "becaus": [7, 14], "240fp": 7, "here": [7, 12], "spreadsheet": 7, "worksheet": 7, "row": [7, 12], "repres": [7, 14], "outlin": 7, "construct": 7, "given": [7, 14], "schema": 7, "settingid": [7, 13], "superset": 7, "altern": [7, 11, 12], "dynam": [7, 11], "value_length": 7, "variabl": [7, 12], "7k": 7, "1440": 7, "9": [7, 13, 14], "18": [7, 13, 14], "24": [7, 13, 14], "5k": 7, "25": [7, 13, 14], "26": [7, 13, 14], "3k": 7, "8": [7, 11, 13, 14], "27": [7, 13, 14], "28": [7, 13, 14], "100": [7, 13], "107": [7, 13], "109": [7, 13], "110": [7, 13], "111": [7, 13], "120": 7, "50": [7, 13], "30": [7, 13, 14], "13": [7, 13, 14], "200": 7, "narrow": [7, 11], "superview": 7, "linear": 7, "never": [7, 8], "min": 7, "15": [7, 13, 14], "ON": [7, 11], "16": [7, 13, 14], "hyperview": 7, "lock": [7, 13], "19": [7, 13, 14], "101": [7, 13], "102": [7, 13], "20": [7, 12, 13, 14], "21": [7, 13, 14], "60hz": 7, "50hz": 7, "boost": 7, "maximum": [7, 14], "extend": 7, "tripod": 7, "stationari": 7, "easi": [7, 13], "pro": 7, "8x": 7, "ultra": 7, "slo": 7, "mo": 7, "4x": 7, "super": 7, "2x": [7, 8], "1x": [7, 8, 13], "low": [7, 9, 14], "light": 7, "14": [7, 13, 14], "17": [7, 13, 14], "22": [7, 13, 14], "103": [7, 13], "104": [7, 13], "105": [7, 13], "106": [7, 13], "112": [7, 13], "113": [7, 13], "115": [7, 13], "116": [7, 13], "117": [7, 13], "118": 7, "119": 7, "124": 7, "125": 7, "126": 7, "127": 7, "129": 7, "130": 7, "131": 7, "132": 7, "133": 7, "136": 7, "137": 7, "4ghz": 7, "5ghz": [7, 13], "short": 7, "highest": 7, "qualiti": 7, "longest": 7, "hdr": 7, "log": [7, 13], "timewarp": [7, 13], "star": 7, "paint": 7, "vehicl": 7, "none": 7, "widescreen": 7, "vertic": 7, "full": [7, 13, 14], "its": [8, 12], "oper": [8, 10, 13, 14], "fals": [8, 14], "true": 8, "One": 8, "three": 8, "abort": 8, "Not": [8, 14], "bluetooth": [8, 9], "unknown": [8, 14], "remov": [8, 14], "format": [8, 9, 12, 13, 14, 15], "swap": 8, "verifi": 8, "boss": 8, "libgpctrld": 8, "src": 8, "camera_statu": 8, "cpp": 8, "iso": 8, "hemispher": 8, "plug": 8, "ghz": 8, "degre": 8, "upright": 8, "upsid": 8, "lai": 8, "side": 8, "270": 8, "left": 8, "15x": 8, "30x": 8, "60x": 8, "150x": 8, "300x": 8, "900x": 8, "1800x": 8, "5x": 8, "10x": 8, "realtim": 8, "slow": 8, "motion": 8, "000": 8, "hdmi": 8, "001": 8, "010": 8, "011": 8, "No": [8, 14], "interven": 8, "outsid": [8, 14], "energi": 9, "pertain": 9, "public": 9, "market": 9, "minim": 9, "62": [9, 13, 14], "v01": 9, "h22": 9, "58": [9, 13, 14], "57": [9, 13], "h21": 9, "55": [9, 13], "hd9": 9, "70": [9, 13, 14], "minimum": [9, 13, 14], "assum": 9, "recent": [9, 13], "between": [9, 13, 14, 15], "read": [9, 10, 11], "protocol": [9, 11], "understand": 9, "setup": [9, 10], "Then": 9, "subsequ": [9, 11, 12], "desir": [9, 14], "home": [9, 14], "hilight": [9, 13], "walk": 9, "tutori": [9, 12], "demonstr": 9, "well": 9, "demo": 9, "program": 9, "languag": [9, 14], "hindsight": [9, 13], "core": [9, 13], "undefin": [9, 15], "should": [9, 11, 15], "try": 9, "digit": [9, 13], "lens": [9, 13, 14], "fov": [9, 14], "base": [9, 13], "pair": [10, 12, 13], "finish": [10, 14], "gatt": [10, 12], "characterist": [10, 12], "packet": 10, "deciph": 10, "refer": 10, "befor": [11, 12, 13, 14, 15], "overview": 11, "up": 11, "discov": [11, 14], "peripher": 11, "devic": [11, 13], "limit": [11, 12], "servic": 11, "0xfea6": 11, "subscrib": 11, "flag": [11, 15], "discover": 11, "wake": 11, "boot": [11, 13], "procedur": [11, 12], "done": 11, "again": 11, "store": 11, "so": [11, 13], "wai": 11, "cach": 11, "subscript": 11, "upon": 11, "gp": [11, 12, 13], "xxxx": 11, "shorthand": 11, "128": [11, 13], "b5f9xxxx": 11, "aa8d": 11, "11e3": 11, "9046": 11, "0002a5d5c51b": 11, "descript": 11, "permiss": 11, "0001": 11, "0002": 11, "ssid": [11, 13, 14], "write": [11, 13], "0003": 11, "0004": 11, "0005": 11, "0090": 11, "0091": 11, "0092": 11, "fea6": 11, "0072": [11, 12], "0073": 11, "0074": [11, 12], "0075": 11, "0076": [11, 12], "0077": 11, "wait": [11, 14, 15], "correspond": [11, 13, 14], "build": 11, "pars": [11, 12], "terminologi": 12, "includ": [12, 14], "accumul": 12, "depacket": 12, "extract": 12, "per": [12, 13], "identifi": 12, "big": [12, 13], "endian": [12, 13], "unless": [12, 15], "v4": 12, "2": [12, 13, 14], "size": [12, 13], "accommod": 12, "larger": 12, "less": 12, "than": [12, 13, 15], "split": 12, "multipl": 12, "prepend": 12, "onto": 12, "fewer": 12, "8191": 12, "avoid": 12, "8192": 12, "longer": 12, "respond": 12, "It": 12, "n": 12, "counter": 12, "0x0": 12, "0xf": 12, "determin": 12, "appropri": 12, "pseudocod": 12, "u": 12, "p": 12, "f": 12, "int": 12, "match": 12, "structur": 12, "nope": 12, "scheme": 12, "els": 12, "map": 12, "flowchart": 12, "form": 12, "had": 12, "top": 12, "thei": 12, "consid": 12, "There": 12, "summar": 12, "throughout": 12, "respect": 12, "triplet": 12, "bandwidth": 12, "googl": 12, "buffer": 12, "deseri": 12, "certif": [13, 14], "resolut": [13, 14], "frame": 13, "43": 13, "webcam": 13, "83": [13, 14], "108": 13, "aspect": 13, "ratio": 13, "121": 13, "122": 13, "123": 13, "134": 13, "anti": 13, "flicker": 13, "135": 13, "hypersmooth": 13, "150": 13, "horizon": 13, "151": 13, "167": 13, "171": 13, "interv": 13, "172": 13, "durat": 13, "176": 13, "speed": 13, "178": 13, "wireless": 13, "band": 13, "179": 13, "trail": 13, "182": 13, "rate": 13, "183": 13, "depth": 13, "184": 13, "profil": 13, "192": 13, "193": 13, "intern": 13, "rough": 13, "approxim": 13, "bar": [13, 14], "charg": 13, "percent": 13, "unus": 13, "overh": 13, "busi": [13, 15], "now": 13, "far": 13, "broadcast": 13, "viewer": 13, "b": 13, "engag": 13, "sinc": 13, "millisecond": 13, "success": [13, 14], "remot": 13, "wirelesspairingstateflag": 13, "29": [13, 14], "int32": [13, 14], "32": [13, 14], "preview": 13, "33": [13, 14], "primari": [13, 14], "storag": 13, "34": [13, 14], "taken": 13, "35": [13, 14], "36": [13, 14], "total": [13, 14], "37": [13, 14], "38": [13, 14], "39": [13, 14], "40": [13, 14], "yy": 13, "mm": 13, "dd": 13, "hh": 13, "ss": 13, "hex": 13, "41": [13, 14], "air": 13, "ota": 13, "42": [13, 14], "pend": 13, "hero8": 13, "44": 13, "submod": 13, "45": 13, "locat": 13, "46": 13, "protun": 13, "47": 13, "48": 13, "multishot": 13, "49": 13, "timelaps": 13, "countdown": 13, "51": 13, "52": 13, "53": 13, "54": 13, "remain": 13, "space": 13, "kilobyt": 13, "secondari": [13, 14], "signal": [13, 14, 15], "strength": [13, 14], "61": [13, 14], "unit": 13, "prefer": 13, "64": [13, 14], "65": [13, 14], "liveview": 13, "exposur": 13, "select": 13, "66": [13, 14], "y": 13, "coordin": 13, "67": [13, 14], "68": [13, 14], "69": [13, 14], "71": [13, 14], "flatmod": [13, 14], "72": [13, 14], "73": [13, 14], "74": [13, 14], "microphon": 13, "accessori": 13, "75": [13, 14], "zoom": 13, "76": [13, 14], "77": [13, 14], "78": [13, 14], "mobil": 13, "friendli": 13, "relat": 13, "compress": 13, "79": [13, 14], "ftu": 13, "flow": 13, "80": 13, "exclus": 13, "superbank": 13, "81": 13, "82": [13, 14], "fulli": 13, "suffici": 13, "84": 13, "delai": 13, "hero7": 13, "85": [13, 14], "too": 13, "cold": 13, "continu": 13, "86": 13, "rotat": 13, "orient": 13, "87": 13, "temperatur": 13, "silver": 13, "white": 13, "89": 13, "90": 13, "91": 13, "92": 13, "93": [13, 14], "95": 13, "96": 13, "ui_mode_group": 13, "json": 13, "97": 13, "modifi": [13, 14], "event": 13, "burst": 13, "count": [13, 14], "warp": 13, "linux": [13, 14], "reflect": 13, "schedul": 13, "bitmask": [13, 14], "meet": 13, "error": [13, 14], "pc": 13, "usb": 13, "sd": [13, 14], "card": [13, 14], "capac": 13, "summari": 14, "cohn_state_init": 14, "cohn_state_error": 14, "cohn_state_exit": 14, "cohn_state_idl": 14, "cohn_state_networkconnect": 14, "cohn_state_networkdisconnect": 14, "cohn_state_connectingtonetwork": 14, "cohn_state_invalid": 14, "cohn_unprovis": 14, "cohn_provis": 14, "camera_idl": 14, "camera_control": 14, "camera_external_control": 14, "flat_mode_unknown": 14, "flat_mode_playback": 14, "flat_mode_setup": 14, "flat_mode_video": 14, "flat_mode_time_lapse_video": 14, "flat_mode_loop": 14, "flat_mode_photo_singl": 14, "flat_mode_photo": 14, "flat_mode_photo_night": 14, "flat_mode_photo_burst": 14, "flat_mode_time_lapse_photo": 14, "flat_mode_night_lapse_photo": 14, "flat_mode_broadcast_record": 14, "flat_mode_broadcast_broadcast": 14, "flat_mode_time_warp_video": 14, "flat_mode_live_burst": 14, "flat_mode_night_lapse_video": 14, "flat_mode_slomo": 14, "flat_mode_idl": 14, "flat_mode_video_star_trail": 14, "flat_mode_video_light_paint": 14, "flat_mode_video_light_trail": 14, "flat_mode_video_burst_slomo": 14, "lens_wid": 14, "lens_superview": 14, "lens_linear": 14, "live_stream_error_non": 14, "live_stream_error_network": 14, "live_stream_error_createstream": 14, "startup": 14, "bad": 14, "server": 14, "live_stream_error_outofmemori": 14, "enough": 14, "memori": 14, "task": 14, "live_stream_error_inputstream": 14, "live_stream_error_internet": 14, "streamer": 14, "live_stream_error_osnetwork": 14, "occur": 14, "stack": 14, "close": 14, "live_stream_error_selectednetworktimeout": 14, "out": 14, "attemp": 14, "live_stream_error_ssl_handshak": 14, "handshak": 14, "commonli": 14, "due": 14, "incorrect": 14, "zone": 14, "live_stream_error_camera_block": 14, "live_stream_error_unknown": 14, "live_stream_error_sd_card_ful": 14, "live_stream_error_sd_card_remov": 14, "live_stream_state_idl": 14, "yet": 14, "live_stream_state_config": 14, "being": 14, "live_stream_state_readi": 14, "live_stream_state_stream": 14, "live_stream_state_complete_stay_on": 14, "live_stream_state_failed_stay_on": 14, "live_stream_state_reconnect": 14, "reconnect": 14, "preset_group_id_video": 14, "1000": 14, "preset_group_id_photo": 14, "1001": 14, "preset_group_id_timelaps": 14, "1002": 14, "preset_group_video_icon_id": 14, "preset_group_photo_icon_id": 14, "preset_group_timelapse_icon_id": 14, "preset_group_long_bat_video_icon_id": 14, "preset_group_endurance_video_icon_id": 14, "preset_group_max_video_icon_id": 14, "preset_group_max_photo_icon_id": 14, "preset_group_max_timelapse_icon_id": 14, "preset_icon_video": 14, "preset_icon_act": 14, "preset_icon_cinemat": 14, "preset_icon_photo": 14, "preset_icon_live_burst": 14, "preset_icon_burst": 14, "preset_icon_photo_night": 14, "preset_icon_timewarp": 14, "preset_icon_timelaps": 14, "preset_icon_nightlaps": 14, "preset_icon_snail": 14, "preset_icon_video_2": 14, "preset_icon_photo_2": 14, "preset_icon_panorama": 14, "preset_icon_burst_2": 14, "preset_icon_timewarp_2": 14, "preset_icon_timelapse_2": 14, "preset_icon_custom": 14, "preset_icon_air": 14, "preset_icon_bik": 14, "preset_icon_ep": 14, "preset_icon_indoor": 14, "preset_icon_motor": 14, "preset_icon_mount": 14, "preset_icon_outdoor": 14, "preset_icon_pov": 14, "preset_icon_selfi": 14, "preset_icon_sk": 14, "preset_icon_snow": 14, "preset_icon_trail": 14, "preset_icon_travel": 14, "preset_icon_wat": 14, "preset_icon_loop": 14, "preset_icon_star": 14, "preset_icon_follow_cam": 14, "preset_icon_surf": 14, "preset_icon_c": 14, "preset_icon_shaki": 14, "preset_icon_chesti": 14, "preset_icon_helmet": 14, "preset_icon_bit": 14, "preset_icon_bas": 14, "preset_icon_ultra_slo_mo": 14, "preset_icon_standard_endur": 14, "preset_icon_activity_endur": 14, "preset_icon_cinematic_endur": 14, "preset_icon_slomo_endur": 14, "preset_icon_stationary_1": 14, "preset_icon_stationary_2": 14, "preset_icon_stationary_3": 14, "preset_icon_stationary_4": 14, "preset_icon_simple_super_photo": 14, "preset_icon_simple_night_photo": 14, "preset_icon_highest_quality_video": 14, "preset_icon_standard_quality_video": 14, "preset_icon_basic_quality_video": 14, "preset_icon_star_trail": 14, "preset_icon_light_paint": 14, "preset_icon_light_trail": 14, "preset_icon_full_fram": 14, "preset_icon_timelapse_photo": 14, "preset_icon_nightlapse_photo": 14, "preset_title_act": 14, "preset_title_standard": 14, "preset_title_cinemat": 14, "preset_title_photo": 14, "preset_title_live_burst": 14, "preset_title_burst": 14, "preset_title_night": 14, "preset_title_time_warp": 14, "preset_title_time_laps": 14, "preset_title_night_laps": 14, "preset_title_video": 14, "preset_title_slomo": 14, "preset_title_photo_2": 14, "preset_title_panorama": 14, "preset_title_time_warp_2": 14, "preset_title_custom": 14, "preset_title_air": 14, "preset_title_bik": 14, "preset_title_ep": 14, "preset_title_indoor": 14, "preset_title_motor": 14, "preset_title_mount": 14, "preset_title_outdoor": 14, "preset_title_pov": 14, "preset_title_selfi": 14, "preset_title_sk": 14, "preset_title_snow": 14, "preset_title_trail": 14, "preset_title_travel": 14, "preset_title_wat": 14, "preset_title_loop": 14, "preset_title_star": 14, "preset_title_follow_cam": 14, "preset_title_surf": 14, "preset_title_c": 14, "preset_title_shaki": 14, "preset_title_chesti": 14, "preset_title_helmet": 14, "preset_title_bit": 14, "preset_title_bas": 14, "preset_title_ultra_slo_mo": 14, "preset_title_standard_endur": 14, "preset_title_activity_endur": 14, "preset_title_cinematic_endur": 14, "preset_title_slomo_endur": 14, "preset_title_stationary_1": 14, "preset_title_stationary_2": 14, "preset_title_stationary_3": 14, "preset_title_stationary_4": 14, "preset_title_simple_video": 14, "preset_title_simple_time_warp": 14, "preset_title_simple_super_photo": 14, "preset_title_simple_night_photo": 14, "preset_title_simple_video_endur": 14, "preset_title_highest_qu": 14, "preset_title_extended_batteri": 14, "preset_title_longest_batteri": 14, "preset_title_star_trail": 14, "preset_title_light_paint": 14, "preset_title_light_trail": 14, "preset_title_full_fram": 14, "preset_title_standard_quality_video": 14, "preset_title_basic_quality_video": 14, "preset_title_highest_quality_video": 14, "provisioning_unknown": 14, "provisioning_never_start": 14, "provisioning_start": 14, "provisioning_aborted_by_system": 14, "provisioning_cancelled_by_us": 14, "provisioning_success_new_ap": 14, "provisioning_success_old_ap": 14, "provisioning_error_failed_to_associ": 14, "provisioning_error_password_auth": 14, "provisioning_error_eula_block": 14, "provisioning_error_no_internet": 14, "provisioning_error_unsupported_typ": 14, "register_live_stream_status_statu": 14, "register_live_stream_status_error": 14, "register_live_stream_status_mod": 14, "register_live_stream_status_bitr": 14, "register_preset_status_preset": 14, "register_preset_status_preset_group_arrai": 14, "result_unknown": 14, "result_success": 14, "result_ill_form": 14, "result_not_support": 14, "result_argument_out_of_bound": 14, "result_argument_invalid": 14, "result_resource_not_avail": 14, "scan_flag_open": 14, "scan_flag_authent": 14, "scan_flag_best_ssid": 14, "scan_flag_associ": 14, "scan_flag_unsupported_typ": 14, "scanning_unknown": 14, "scanning_never_start": 14, "scanning_start": 14, "scanning_aborted_by_system": 14, "scanning_cancelled_by_us": 14, "scanning_success": 14, "window_size_480": 14, "window_size_720": 14, "window_size_1080": 14, "common": 14, "typespec": 14, "folder": 14, "provisioning_st": 14, "scanning_st": 14, "scan_id": 14, "total_entri": 14, "total_configured_ssid": 14, "ipaddress": 14, "bool": 14, "macaddress": 14, "mac": 14, "adapt": 14, "live_stream_statu": 14, "live_stream_error": 14, "live_stream_encod": 14, "live_stream_bitr": 14, "bitrat": 14, "kbp": 14, "live_stream_window_size_supported_arrai": 14, "live_stream_encode_support": 14, "live_stream_max_lens_unsupport": 14, "NOT": 14, "live_stream_minimum_stream_bitr": 14, "static": 14, "live_stream_maximum_stream_bitr": 14, "live_stream_lens_support": 14, "live_stream_lens_supported_arrai": 14, "preset_group_arrai": 14, "title_numb": 14, "custom1": 14, "custom2": 14, "custom3": 14, "user_defin": 14, "setting_arrai": 14, "is_modifi": 14, "is_fix": 14, "mutabl": 14, "meta": 14, "preset_arrai": 14, "can_add_preset": 14, "room": 14, "represent": 14, "is_capt": 14, "appear": 14, "static_ip": 14, "gatewai": 14, "subnet": 14, "mask": 14, "dns_primari": 14, "dn": 14, "dns_secondari": 14, "overrid": 14, "rang": 14, "utf": 14, "obei": 14, "charact": 14, "inclus": 14, "special": 14, "english": 14, "french": 14, "italian": 14, "german": 14, "spanish": 14, "portugues": 14, "swedish": 14, "russian": 14, "start_index": 14, "max_entri": 14, "register_cohn_statu": 14, "register_live_stream_statu": 14, "unregister_live_stream_statu": 14, "register_preset_statu": 14, "unregister_preset_statu": 14, "disconnect": 14, "drop": 14, "cohn_act": 14, "camera_control_statu": 14, "declar": 14, "who": 14, "take": 14, "window_s": 14, "pem": 14, "minimum_bitr": 14, "honor": 14, "maximum_bitr": 14, "starting_bitr": 14, "ascii": 14, "timeout_second": 14, "timeout": 14, "batch": 14, "invalid": 14, "result_resource_not_availbl": 14, "scan_entry_flag": 14, "alreadi": 14, "signal_strength_bar": 14, "dbm": 14, "signal_frequency_mhz": 14, "frequenc": 14, "mhz": 14, "incom": 15, "howev": 15, "5min": 15, "15min": 15, "30min": 15, "maintain": 15, "simultan": 15, "discourag": 15}, "objects": {"": [[14, 0, 0, "enumcohnnetworkstate", "EnumCOHNNetworkState"], [14, 0, 0, "enumcohnstatus", "EnumCOHNStatus"], [14, 0, 0, "enumcameracontrolstatus", "EnumCameraControlStatus"], [14, 0, 0, "enumflatmode", "EnumFlatMode"], [14, 0, 0, "enumlens", "EnumLens"], [14, 0, 0, "enumlivestreamerror", "EnumLiveStreamError"], [14, 0, 0, "enumlivestreamstatus", "EnumLiveStreamStatus"], [14, 0, 0, "enumpresetgroup", "EnumPresetGroup"], [14, 0, 0, "enumpresetgroupicon", "EnumPresetGroupIcon"], [14, 0, 0, "enumpreseticon", "EnumPresetIcon"], [14, 0, 0, "enumpresettitle", "EnumPresetTitle"], [14, 0, 0, "enumprovisioning", "EnumProvisioning"], [14, 0, 0, "enumregisterlivestreamstatus", "EnumRegisterLiveStreamStatus"], [14, 0, 0, "enumregisterpresetstatus", "EnumRegisterPresetStatus"], [14, 0, 0, "enumresultgeneric", "EnumResultGeneric"], [14, 0, 0, "enumscanentryflags", "EnumScanEntryFlags"], [14, 0, 0, "enumscanning", "EnumScanning"], [14, 0, 0, "enumwindowsize", "EnumWindowSize"], [14, 0, 0, "media", "Media"], [14, 0, 0, "notifprovisioningstate", "NotifProvisioningState"], [14, 0, 0, "notifstartscanning", "NotifStartScanning"], [14, 0, 0, "notifycohnstatus", "NotifyCOHNStatus"], [14, 0, 0, "notifylivestreamstatus", "NotifyLiveStreamStatus"], [14, 0, 0, "notifypresetstatus", "NotifyPresetStatus"], [14, 0, 0, "preset", "Preset"], [14, 0, 0, "presetgroup", "PresetGroup"], [14, 0, 0, "presetsetting", "PresetSetting"], [14, 0, 0, "requestcohncert", "RequestCOHNCert"], [14, 0, 0, "requestclearcohncert", "RequestClearCOHNCert"], [14, 0, 0, "requestconnect", "RequestConnect"], [14, 0, 0, "requestconnectnew", "RequestConnectNew"], [14, 0, 0, "requestcreatecohncert", "RequestCreateCOHNCert"], [14, 0, 0, "requestcustompresetupdate", "RequestCustomPresetUpdate"], [14, 0, 0, "requestgetapentries", "RequestGetApEntries"], [14, 0, 0, "requestgetcohnstatus", "RequestGetCOHNStatus"], [14, 0, 0, "requestgetlastcapturedmedia", "RequestGetLastCapturedMedia"], [14, 0, 0, "requestgetlivestreamstatus", "RequestGetLiveStreamStatus"], [14, 0, 0, "requestgetpresetstatus", "RequestGetPresetStatus"], [14, 0, 0, "requestreleasenetwork", "RequestReleaseNetwork"], [14, 0, 0, "requestsetcohnsetting", "RequestSetCOHNSetting"], [14, 0, 0, "requestsetcameracontrolstatus", "RequestSetCameraControlStatus"], [14, 0, 0, "requestsetlivestreammode", "RequestSetLiveStreamMode"], [14, 0, 0, "requestsetturboactive", "RequestSetTurboActive"], [14, 0, 0, "requeststartscan", "RequestStartScan"], [14, 0, 0, "responsecohncert", "ResponseCOHNCert"], [14, 0, 0, "responseconnect", "ResponseConnect"], [14, 0, 0, "responseconnectnew", "ResponseConnectNew"], [14, 0, 0, "responsegeneric", "ResponseGeneric"], [14, 0, 0, "responsegetapentries", "ResponseGetApEntries"], [14, 0, 0, "responselastcapturedmedia", "ResponseLastCapturedMedia"], [14, 0, 0, "responsestartscanning", "ResponseStartScanning"], [14, 0, 0, "scanentry", "ScanEntry"], [1, 1, 0, "clear-cohn-certificate", "clear cohn certificate"], [0, 1, 0, "connect-to-a-new-access-point", "connect to a new access point"], [0, 1, 0, "connect-to-provisioned-access-point", "connect to provisioned access point"], [1, 1, 0, "create-cohn-certificate", "create cohn certificate"], [0, 1, 0, "get-ap-scan-results", "get ap scan results"], [5, 1, 0, "get-available-presets", "get available presets"], [1, 1, 0, "get-cohn-certificate", "get cohn certificate"], [1, 1, 0, "get-cohn-status", "get cohn status"], [6, 1, 0, "get-date-time", "get date time"], [6, 1, 0, "get-hardware-info", "get hardware info"], [6, 1, 0, "get-last-captured-media", "get last captured media"], [4, 1, 0, "get-livestream-status", "get livestream status"], [6, 1, 0, "get-local-date-time", "get local date time"], [6, 1, 0, "get-open-gopro-version", "get open gopro version"], [6, 1, 0, "get-setting-capabilities", "get setting capabilities"], [6, 1, 0, "get-setting-values", "get setting values"], [6, 1, 0, "get-status-values", "get status values"], [3, 1, 0, "hilight-moment", "hilight moment"], [2, 1, 0, "keep-alive", "keep alive"], [5, 1, 0, "load-preset", "load preset"], [5, 1, 0, "load-preset-group", "load preset group"], [6, 1, 0, "register-for-setting-capability-updates", "register for setting capability updates"], [6, 1, 0, "register-for-setting-value-updates", "register for setting value updates"], [6, 1, 0, "register-for-status-value-updates", "register for status value updates"], [0, 1, 0, "scan-for-access-points", "scan for access points"], [2, 1, 0, "set-analytics", "set analytics"], [2, 1, 0, "set-ap-control", "set ap control"], [2, 1, 0, "set-camera-control", "set camera control"], [1, 1, 0, "set-cohn-setting", "set cohn setting"], [2, 1, 0, "set-date-time", "set date time"], [4, 1, 0, "set-livestream-mode", "set livestream mode"], [2, 1, 0, "set-local-date-time", "set local date time"], [7, 1, 0, "set-setting", "set setting"], [2, 1, 0, "set-shutter", "set shutter"], [2, 1, 0, "set-turbo-transfer", "set turbo transfer"], [2, 1, 0, "sleep", "sleep"], [6, 1, 0, "unregister-for-setting-capability-updates", "unregister for setting capability updates"], [6, 1, 0, "unregister-for-setting-value-updates", "unregister for setting value updates"], [6, 1, 0, "unregister-for-status-value-updates", "unregister for status value updates"], [5, 1, 0, "update-custom-preset", "update custom preset"], [7, 2, 0, "setting-108", "Setting 108 (Aspect Ratio)"], [7, 2, 0, "setting-121", "Setting 121 (Lens)"], [7, 2, 0, "setting-122", "Setting 122 (Lens)"], [7, 2, 0, "setting-123", "Setting 123 (Time Lapse Digital Lenses)"], [7, 2, 0, "setting-128", "Setting 128 (Media Format)"], [7, 2, 0, "setting-134", "Setting 134 (Anti-Flicker)"], [7, 2, 0, "setting-135", "Setting 135 (Hypersmooth)"], [7, 2, 0, "setting-150", "Setting 150 (Horizon Leveling)"], [7, 2, 0, "setting-151", "Setting 151 (Horizon Leveling)"], [7, 2, 0, "setting-162", "Setting 162 (Max Lens)"], [7, 2, 0, "setting-167", "Setting 167 (HindSight)"], [7, 2, 0, "setting-171", "Setting 171 (Interval)"], [7, 2, 0, "setting-172", "Setting 172 (Duration)"], [7, 2, 0, "setting-173", "Setting 173 (Video Performance Mode)"], [7, 2, 0, "setting-175", "Setting 175 (Controls)"], [7, 2, 0, "setting-176", "Setting 176 (Easy Mode Speed)"], [7, 2, 0, "setting-177", "Setting 177 (Enable Night Photo)"], [7, 2, 0, "setting-178", "Setting 178 (Wireless Band)"], [7, 2, 0, "setting-179", "Setting 179 (Trail Length)"], [7, 2, 0, "setting-180", "Setting 180 (Video Mode)"], [7, 2, 0, "setting-182", "Setting 182 (Bit Rate)"], [7, 2, 0, "setting-183", "Setting 183 (Bit Depth)"], [7, 2, 0, "setting-184", "Setting 184 (Profiles)"], [7, 2, 0, "setting-186", "Setting 186 (Video Mode)"], [7, 2, 0, "setting-187", "Setting 187 (Lapse Mode)"], [7, 2, 0, "setting-189", "Setting 189 (Max Lens Mod)"], [7, 2, 0, "setting-190", "Setting 190 (Max Lens Mod Enable)"], [7, 2, 0, "setting-191", "Setting 191 (Photo Mode)"], [7, 2, 0, "setting-192", "Setting 192 (Aspect Ratio)"], [7, 2, 0, "setting-193", "Setting 193 (Framing)"], [7, 2, 0, "setting-2", "Setting 2 (Resolution)"], [7, 2, 0, "setting-3", "Setting 3 (Frames Per Second)"], [7, 2, 0, "setting-43", "Setting 43 (Webcam Digital Lenses)"], [7, 2, 0, "setting-59", "Setting 59 (Auto Power Down)"], [7, 2, 0, "setting-83", "Setting 83 (GPS)"], [8, 3, 0, "status-1", "Status 1 (Is the system's internal battery present?)"], [8, 3, 0, "status-10", "Status 10 (Is the system encoding right now?)"], [8, 3, 0, "status-100", "Status 100 (Total number of Live Bursts on sdcard)"], [8, 3, 0, "status-102", "Status 102 (Media Mod state)"], [8, 3, 0, "status-103", "Status 103 (Time Warp Speed)"], [8, 3, 0, "status-104", "Status 104 (Is the system's Linux core active?)"], [8, 3, 0, "status-105", "Status 105 (Camera lens type (reflects changes to setting 162 or setting 189))"], [8, 3, 0, "status-106", "Status 106 (Is Video Hindsight Capture Active?)"], [8, 3, 0, "status-107", "Status 107 (Scheduled Capture Preset ID)"], [8, 3, 0, "status-108", "Status 108 (Is Scheduled Capture set?)"], [8, 3, 0, "status-109", "Status 109 (Is the camera in the process of creating a custom preset?)"], [8, 3, 0, "status-11", "Status 11 (Is LCD lock active?)"], [8, 3, 0, "status-110", "Status 110 (Display Mod Status (bitmasked))"], [8, 3, 0, "status-111", "Status 111 (Does sdcard meet specified minimum write speed?)"], [8, 3, 0, "status-112", "Status 112 (Number of sdcard write speed errors since device booted)"], [8, 3, 0, "status-113", "Status 113 (Is Turbo Transfer active?)"], [8, 3, 0, "status-114", "Status 114 (Camera control status ID)"], [8, 3, 0, "status-115", "Status 115 (Is the camera connected to a PC via USB?)"], [8, 3, 0, "status-116", "Status 116 (Camera control over USB state)"], [8, 3, 0, "status-117", "Status 117 (Total SD card capacity in Kilobytes)"], [8, 3, 0, "status-12", "Status 12 (Unused)"], [8, 3, 0, "status-13", "Status 13 (When encoding video, this is the duration (seconds) of the video so far; 0 otherwise)"], [8, 3, 0, "status-14", "Status 14 (When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise)"], [8, 3, 0, "status-15", "Status 15 ((DEPRECATED) Number of Broadcast viewers)"], [8, 3, 0, "status-16", "Status 16 ((DEPRECATED) Broadcast B-Status)"], [8, 3, 0, "status-17", "Status 17 (Are Wireless Connections enabled?)"], [8, 3, 0, "status-18", "Status 18 (Unused)"], [8, 3, 0, "status-19", "Status 19 (The pairing state of the camera)"], [8, 3, 0, "status-2", "Status 2 (Rough approximation of internal battery level in bars (or charging))"], [8, 3, 0, "status-20", "Status 20 (The last type of pairing in which the camera was engaged)"], [8, 3, 0, "status-21", "Status 21 (Time since boot (milliseconds) of last successful pairing complete action)"], [8, 3, 0, "status-22", "Status 22 (State of current scan for WiFi Access Points)"], [8, 3, 0, "status-23", "Status 23 (Time since boot (milliseconds) that the WiFi Access Point scan completed)"], [8, 3, 0, "status-24", "Status 24 (WiFi AP provisioning state)"], [8, 3, 0, "status-25", "Status 25 (Unused)"], [8, 3, 0, "status-26", "Status 26 (Wireless remote control version)"], [8, 3, 0, "status-27", "Status 27 (Is a wireless remote control connected?)"], [8, 3, 0, "status-3", "Status 3 (Is an external battery connected?)"], [8, 3, 0, "status-31", "Status 31 (The number of wireless devices connected to the camera)"], [8, 3, 0, "status-32", "Status 32 (Is Preview Stream enabled?)"], [8, 3, 0, "status-33", "Status 33 (Primary Storage Status)"], [8, 3, 0, "status-34", "Status 34 (How many photos can be taken with current settings before sdcard is full)"], [8, 3, 0, "status-35", "Status 35 (How many minutes of video can be captured with current settings before sdcard is full)"], [8, 3, 0, "status-36", "Status 36 (Total number of group photos on sdcard)"], [8, 3, 0, "status-37", "Status 37 (Total number of group videos on sdcard)"], [8, 3, 0, "status-38", "Status 38 (Total number of photos on sdcard)"], [8, 3, 0, "status-39", "Status 39 (Total number of videos on sdcard)"], [8, 3, 0, "status-4", "Status 4 (External battery power level in percent)"], [8, 3, 0, "status-40", "Status 40 (Current date/time (format: %YY%mm%dd%HH%MM%SS, all values in hex))"], [8, 3, 0, "status-41", "Status 41 (The current status of Over The Air (OTA) update)"], [8, 3, 0, "status-42", "Status 42 (Is there a pending request to cancel a firmware update download?)"], [8, 3, 0, "status-43", "Status 43 (Current mode group (deprecated in HERO8))"], [8, 3, 0, "status-44", "Status 44 (Current submode (deprecated in HERO8))"], [8, 3, 0, "status-45", "Status 45 (Is locate camera feature active?)"], [8, 3, 0, "status-46", "Status 46 (Are Video Protune settings currently factory default?)"], [8, 3, 0, "status-47", "Status 47 (Are Photo Protune settings currently factory default?)"], [8, 3, 0, "status-48", "Status 48 (Are Multishot Protune settings currently factory default?)"], [8, 3, 0, "status-5", "Status 5 (Unused)"], [8, 3, 0, "status-50", "Status 50 (Unused)"], [8, 3, 0, "status-51", "Status 51 (Unused)"], [8, 3, 0, "status-52", "Status 52 (Unused)"], [8, 3, 0, "status-53", "Status 53 (Unused)"], [8, 3, 0, "status-54", "Status 54 (Remaining space on the sdcard in Kilobytes)"], [8, 3, 0, "status-55", "Status 55 (Is preview stream supported in current recording/mode/secondary-stream?)"], [8, 3, 0, "status-56", "Status 56 (WiFi signal strength in bars)"], [8, 3, 0, "status-57", "Status 57 (Time in milliseconds since system was booted)"], [8, 3, 0, "status-58", "Status 58 (The number of hilights in currently-encoding video (value is set to 0 when encoding stops))"], [8, 3, 0, "status-59", "Status 59 (Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops))"], [8, 3, 0, "status-6", "Status 6 (Is the system currently overheating?)"], [8, 3, 0, "status-61", "Status 61 (The current state of camera analytics)"], [8, 3, 0, "status-62", "Status 62 (The size (units??) of the analytics file)"], [8, 3, 0, "status-64", "Status 64 (How many minutes of Time Lapse Video can be captured with current settings before sdcard is full)"], [8, 3, 0, "status-65", "Status 65 (Liveview Exposure Select Mode)"], [8, 3, 0, "status-66", "Status 66 (Liveview Exposure Select: y-coordinate (percent))"], [8, 3, 0, "status-67", "Status 67 (Liveview Exposure Select: y-coordinate (percent))"], [8, 3, 0, "status-68", "Status 68 (Does the camera currently have a GPS lock?)"], [8, 3, 0, "status-69", "Status 69 (Is the camera in AP Mode?)"], [8, 3, 0, "status-7", "Status 7 (Unused)"], [8, 3, 0, "status-70", "Status 70 (Internal battery level (percent))"], [8, 3, 0, "status-71", "Status 71 (The current video group flatmode (id))"], [8, 3, 0, "status-72", "Status 72 (The current photo group flatmode (id))"], [8, 3, 0, "status-73", "Status 73 (The current timelapse group flatmode (id))"], [8, 3, 0, "status-74", "Status 74 (Microphone Accessory status)"], [8, 3, 0, "status-75", "Status 75 (Digital Zoom level (percent))"], [8, 3, 0, "status-76", "Status 76 (Wireless Band)"], [8, 3, 0, "status-77", "Status 77 (Is Digital Zoom feature available?)"], [8, 3, 0, "status-78", "Status 78 (Are current video settings mobile friendly? (related to video compression and frame rate))"], [8, 3, 0, "status-79", "Status 79 (Is the camera currently in First Time Use (FTU) UI flow?)"], [8, 3, 0, "status-8", "Status 8 (Is the camera busy?)"], [8, 3, 0, "status-80", "Status 80 (Secondary Storage Status (exclusive to Superbank))"], [8, 3, 0, "status-81", "Status 81 (Is 5GHz wireless band available?)"], [8, 3, 0, "status-82", "Status 82 (Is the system fully booted and ready to accept commands?)"], [8, 3, 0, "status-83", "Status 83 (Is the internal battery charged sufficiently to start Over The Air (OTA) update?)"], [8, 3, 0, "status-84", "Status 84 (Current Capture Delay value (HERO7 only))"], [8, 3, 0, "status-85", "Status 85 (Is the camera getting too cold to continue recording?)"], [8, 3, 0, "status-86", "Status 86 (Rotational orientation of the camera)"], [8, 3, 0, "status-87", "Status 87 (Can camera use high resolution/fps (based on temperature)? (HERO7 Silver/White only))"], [8, 3, 0, "status-88", "Status 88 (Is this camera model capable of zooming while encoding?)"], [8, 3, 0, "status-89", "Status 89 (Current Flatmode ID)"], [8, 3, 0, "status-9", "Status 9 (Is Quick Capture feature enabled?)"], [8, 3, 0, "status-90", "Status 90 (Are current flatmode's Protune settings factory default?)"], [8, 3, 0, "status-91", "Status 91 (Are system logs ready to be downloaded?)"], [8, 3, 0, "status-92", "Status 92 (Is Timewarp 1x active?)"], [8, 3, 0, "status-93", "Status 93 (Current Video Preset (ID))"], [8, 3, 0, "status-94", "Status 94 (Current Photo Preset (ID))"], [8, 3, 0, "status-95", "Status 95 (Current Time Lapse Preset (ID))"], [8, 3, 0, "status-97", "Status 97 (Current Preset (ID))"], [8, 3, 0, "status-98", "Status 98 (Preset Modified Status, which contains an event ID and a Preset (Group) ID)"], [8, 3, 0, "status-99", "Status 99 (The number of Live Bursts can be captured with current settings before sdcard is full)"]], "Status 101 (Is Capture Delay currently active (i.e": [[8, 3, 0, "status-101", " counting down)?)"]], "Status 28 (Wireless Pairing State": [[8, 3, 0, "status-28", " Each bit contains state information (see WirelessPairingStateFlags))"]], "Status 29 (SSID of the AP the camera is currently connected to": [[8, 3, 0, "status-29", " On BLE connection, value is big-endian byte-encoded int32)"]], "Status 30 (The camera's WiFi SSID": [[8, 3, 0, "status-30", " On BLE connection, value is big-endian byte-encoded int32)"]], "Status 49 (The current timelapse interval countdown value (e.g. 5...4...3...2...1..": [[8, 3, 0, "status-49", "))"]], "Status 60 (The minimum time between camera status updates (milliseconds)": [[8, 3, 0, "status-60", " Best practice is to not poll for status more often than this)"]], "Status 63 (Is the camera currently in a contextual menu (e.g": [[8, 3, 0, "status-63", " Preferences)?)"]], "Status 96 (Current Preset Group (ID) (corresponds to ui_mode_groups in settings": [[8, 3, 0, "status-96", "json))"]]}, "objtypes": {"0": "operation:Proto", "1": "operation:Operation", "2": "operation:Setting", "3": "operation:Status"}, "objnames": {"0": ["operation", "Proto", "Proto"], "1": ["operation", "Operation", "Operation"], "2": ["operation", "Setting", "Setting"], "3": ["operation", "Status", "Status"]}, "titleterms": {"access": [0, 8], "point": [0, 8], "oper": [0, 1, 2, 3, 4, 5, 6, 7], "disconnect": 0, "from": 0, "camera": [1, 7, 8, 9, 15], "home": 1, "network": 1, "certif": 1, "verifi": 1, "view": 1, "detail": 1, "provis": [1, 8], "procedur": 1, "control": [2, 7, 8, 15], "hilight": [3, 8], "live": [4, 8], "stream": [4, 8], "preset": [5, 8, 14], "group": [5, 8], "modifi": [5, 8], "statu": [5, 8, 13], "queri": [6, 12, 13], "set": [7, 8, 13], "capabl": [7, 8], "xlsx": 7, "json": [7, 8], "id": [7, 8, 13], "resolut": 7, "2": [7, 8], "frame": [7, 8], "per": 7, "second": [7, 8], "3": [7, 8], "fov": 7, "43": 7, "auto": 7, "off": 7, "59": [7, 8], "gp": [7, 8], "83": [7, 8], "aspect": 7, "ratio": 7, "108": [7, 8], "len": [7, 8], "121": 7, "122": 7, "123": 7, "format": 7, "128": 7, "anti": 7, "flicker": 7, "134": 7, "hypersmooth": 7, "135": 7, "horizon": 7, "level": [7, 8], "150": 7, "151": 7, "max": 7, "mod": [7, 8], "enabl": [7, 8], "162": [7, 8], "hindsight": [7, 8], "167": 7, "interv": [7, 8], "171": 7, "durat": [7, 8], "172": 7, "video": [7, 8], "perform": 7, "mode": [7, 8, 11], "173": 7, "175": 7, "speed": [7, 8], "176": 7, "night": 7, "photo": [7, 8], "177": 7, "wi": 7, "fi": 7, "band": [7, 8], "178": 7, "trail": 7, "length": [7, 12], "179": 7, "180": 7, "bit": [7, 8, 12], "rate": [7, 8], "182": 7, "depth": 7, "183": 7, "profil": 7, "184": 7, "186": 7, "laps": [7, 8], "187": 7, "189": [7, 8], "190": 7, "191": 7, "192": 7, "193": 7, "status": 8, "i": 8, "system": 8, "": [8, 9], "intern": 8, "batteri": 8, "present": 8, "1": 8, "rough": 8, "approxim": 8, "bar": 8, "charg": 8, "an": 8, "extern": 8, "connect": 8, "power": 8, "percent": 8, "4": 8, "current": 8, "overh": 8, "6": 8, "busi": 8, "8": 8, "quick": 8, "captur": 8, "featur": 8, "9": 8, "encod": 8, "right": 8, "now": 8, "10": 8, "lcd": 8, "lock": 8, "activ": 8, "11": 8, "when": 8, "thi": 8, "so": 8, "far": 8, "0": 8, "otherwis": 8, "13": [8, 12], "broadcast": 8, "14": 8, "ar": 8, "wireless": 8, "17": 8, "The": 8, "pair": [8, 11], "state": [8, 15], "19": 8, "last": 8, "type": [8, 12], "which": 8, "wa": 8, "engag": 8, "20": 8, "time": 8, "sinc": 8, "boot": 8, "millisecond": 8, "success": 8, "complet": 8, "action": 8, "21": 8, "scan": 8, "wifi": 8, "22": 8, "23": 8, "ap": 8, "24": 8, "remot": 8, "version": 8, "26": 8, "27": 8, "each": 8, "contain": 8, "inform": 8, "see": 8, "wirelesspairingstateflag": 8, "28": 8, "ssid": 8, "On": 8, "ble": [8, 9, 11], "valu": [8, 12], "big": 8, "endian": 8, "byte": 8, "int32": 8, "29": 8, "30": 8, "number": 8, "devic": 8, "31": 8, "preview": 8, "32": 8, "primari": 8, "storag": 8, "33": 8, "how": 8, "mani": 8, "can": 8, "taken": 8, "befor": 8, "sdcard": 8, "full": 8, "34": 8, "minut": 8, "35": 8, "total": 8, "36": 8, "37": 8, "38": 8, "39": 8, "over": 8, "air": 8, "ota": 8, "updat": 8, "41": 8, "pend": 8, "request": 8, "cancel": 8, "firmwar": 8, "download": 8, "42": 8, "locat": 8, "45": 8, "timelaps": 8, "countdown": 8, "e": 8, "g": 8, "5": [8, 12], "49": 8, "remain": 8, "space": 8, "kilobyt": 8, "54": 8, "support": [8, 9], "record": 8, "secondari": 8, "55": 8, "signal": 8, "strength": 8, "56": 8, "stop": 8, "58": 8, "most": 8, "recent": 8, "minimum": 8, "between": 8, "best": 8, "practic": 8, "poll": 8, "more": 8, "often": 8, "than": 8, "60": 8, "analyt": 8, "61": 8, "size": 8, "unit": 8, "file": 8, "62": 8, "contextu": 8, "menu": 8, "prefer": 8, "63": 8, "64": 8, "liveview": 8, "exposur": 8, "select": 8, "65": 8, "y": 8, "coordin": 8, "66": 8, "67": 8, "doe": 8, "have": 8, "68": 8, "69": 8, "70": 8, "microphon": 8, "accessori": 8, "74": 8, "digit": 8, "zoom": 8, "75": 8, "76": 8, "avail": 8, "77": 8, "mobil": 8, "friendli": 8, "relat": 8, "compress": 8, "78": 8, "first": 8, "us": 8, "ftu": 8, "ui": 8, "flow": 8, "79": 8, "5ghz": 8, "81": 8, "fulli": 8, "readi": [8, 15], "accept": 8, "command": [8, 12, 13], "82": 8, "suffici": 8, "start": [8, 9], "get": [8, 9], "too": 8, "cold": 8, "continu": [8, 12], "85": 8, "rotat": 8, "orient": 8, "86": 8, "model": 8, "while": 8, "88": 8, "flatmod": 8, "89": 8, "protun": 8, "factori": 8, "default": 8, "90": 8, "log": 8, "91": 8, "93": 8, "94": 8, "95": 8, "correspond": 8, "ui_mode_group": 8, "96": 8, "97": 8, "event": 8, "98": 8, "burst": 8, "99": 8, "100": 8, "delai": 8, "count": 8, "down": 8, "101": 8, "media": [8, 14], "102": 8, "warp": 8, "103": 8, "linux": 8, "core": 8, "104": 8, "reflect": 8, "chang": 8, "105": 8, "106": 8, "schedul": 8, "107": 8, "process": 8, "creat": 8, "custom": 8, "109": 8, "displai": 8, "bitmask": 8, "110": 8, "meet": 8, "specifi": 8, "write": 8, "111": 8, "error": 8, "112": 8, "turbo": 8, "transfer": 8, "113": 8, "114": 8, "pc": 8, "via": 8, "usb": 8, "115": 8, "116": 8, "sd": 8, "card": 8, "capac": 8, "117": 8, "welcom": 9, "open": 9, "gopro": 9, "api": 9, "document": [9, 14], "limit": 9, "gener": [9, 12], "protocol": [10, 12], "setup": 11, "advertis": 11, "finish": 11, "configur": 11, "gatt": 11, "characterist": 11, "send": 11, "messag": [11, 12], "data": 12, "packet": 12, "header": 12, "extend": 12, "16": 12, "deciph": 12, "payload": 12, "protobuf": [12, 13, 14], "tabl": 13, "enum": 14, "enumcohnnetworkst": 14, "enumcohnstatu": 14, "enumcameracontrolstatu": 14, "enumflatmod": 14, "enumlen": 14, "enumlivestreamerror": 14, "enumlivestreamstatu": 14, "enumpresetgroup": 14, "enumpresetgroupicon": 14, "enumpreseticon": 14, "enumpresettitl": 14, "enumprovis": 14, "enumregisterlivestreamstatu": 14, "enumregisterpresetstatu": 14, "enumresultgener": 14, "enumscanentryflag": 14, "enumscan": 14, "enumwindows": 14, "notifprovisioningst": 14, "notifstartscan": 14, "notifycohnstatu": 14, "notifylivestreamstatu": 14, "notifypresetstatu": 14, "presetgroup": 14, "presetset": 14, "requestcohncert": 14, "requestclearcohncert": 14, "requestconnect": 14, "requestconnectnew": 14, "requestcreatecohncert": 14, "requestcustompresetupd": 14, "requestgetapentri": 14, "requestgetcohnstatu": 14, "requestgetlastcapturedmedia": 14, "requestgetlivestreamstatu": 14, "requestgetpresetstatu": 14, "requestreleasenetwork": 14, "requestsetcohnset": 14, "requestsetcameracontrolstatu": 14, "requestsetlivestreammod": 14, "requestsetturboact": 14, "requeststartscan": 14, "responsecohncert": 14, "responseconnect": 14, "responseconnectnew": 14, "responsegener": 14, "responsegetapentri": 14, "responselastcapturedmedia": 14, "responsestartscan": 14, "scanentri": 14, "manag": 15, "keep": 15, "aliv": 15}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 60}, "alltitles": {"Access Point": [[0, "access-point"]], "Operations": [[0, "operations"], [1, "operations"], [2, "operations"], [3, "operations"], [4, "operations"], [5, "operations"], [6, "operations"], [7, "operations"]], "Disconnect from Access Point": [[0, "disconnect-from-access-point"]], "Camera on the Home Network": [[1, "camera-on-the-home-network"]], "Certificates": [[1, "certificates"]], "Verifying Certificate": [[1, "verifying-certificate"]], "View Certificate Details": [[1, "view-certificate-details"]], "Provisioning Procedure": [[1, "provisioning-procedure"]], "Control": [[2, "control"]], "Hilights": [[3, "hilights"]], "Live Streaming": [[4, "live-streaming"]], "Presets": [[5, "presets"]], "Preset Groups": [[5, "preset-groups"]], "Preset Modified Status": [[5, "preset-modified-status"]], "Query": [[6, "query"]], "Settings": [[7, "settings"]], "Camera Capabilities": [[7, "camera-capabilities"]], "XLSX": [[7, "xlsx"]], "JSON": [[7, "json"]], "Setting IDs": [[7, "setting-ids"], [13, "setting-ids"]], "Resolution (2)": [[7, "resolution-2"]], "Frames Per Second (3)": [[7, "frames-per-second-3"]], "FOV (43)": [[7, "fov-43"]], "Auto Off (59)": [[7, "auto-off-59"]], "GPS (83)": [[7, "gps-83"]], "Aspect Ratio (108)": [[7, "aspect-ratio-108"]], "Lens (121)": [[7, "lens-121"]], "Lens (122)": [[7, "lens-122"]], "Lens (123)": [[7, "lens-123"]], "Format (128)": [[7, "format-128"]], "Anti-Flicker (134)": [[7, "anti-flicker-134"]], "Hypersmooth (135)": [[7, "hypersmooth-135"]], "Horizon Leveling (150)": [[7, "horizon-leveling-150"]], "Horizon Leveling (151)": [[7, "horizon-leveling-151"]], "Max Lens Mod Enable (162)": [[7, "max-lens-mod-enable-162"]], "HindSight (167)": [[7, "hindsight-167"]], "Interval (171)": [[7, "interval-171"]], "Duration (172)": [[7, "duration-172"]], "Video Performance Modes (173)": [[7, "video-performance-modes-173"]], "Controls (175)": [[7, "controls-175"]], "Speed (176)": [[7, "speed-176"]], "Night Photo (177)": [[7, "night-photo-177"]], "Wi-fi Band (178)": [[7, "wi-fi-band-178"]], "Trail Length (179)": [[7, "trail-length-179"]], "Video Mode (180)": [[7, "video-mode-180"]], "Bit Rate (182)": [[7, "bit-rate-182"]], "Bit Depth (183)": [[7, "bit-depth-183"]], "Profiles (184)": [[7, "profiles-184"]], "Video Mode (186)": [[7, "video-mode-186"]], "Lapse Mode (187)": [[7, "lapse-mode-187"]], "Max Lens Mod (189)": [[7, "max-lens-mod-189"]], "Max Lens Mod Enable (190)": [[7, "max-lens-mod-enable-190"]], "Photo Mode (191)": [[7, "photo-mode-191"]], "Aspect Ratio (192)": [[7, "aspect-ratio-192"]], "Framing (193)": [[7, "framing-193"]], "Statuses": [[8, "statuses"]], "Status IDs": [[8, "status-ids"], [13, "status-ids"]], "Is the system\u2019s internal battery present? (1)": [[8, "is-the-system-s-internal-battery-present-1"]], "Rough approximation of internal battery level in bars (or charging) (2)": [[8, "rough-approximation-of-internal-battery-level-in-bars-or-charging-2"]], "Is an external battery connected? (3)": [[8, "is-an-external-battery-connected-3"]], "External battery power level in percent (4)": [[8, "external-battery-power-level-in-percent-4"]], "Is the system currently overheating? (6)": [[8, "is-the-system-currently-overheating-6"]], "Is the camera busy? (8)": [[8, "is-the-camera-busy-8"]], "Is Quick Capture feature enabled? (9)": [[8, "is-quick-capture-feature-enabled-9"]], "Is the system encoding right now? (10)": [[8, "is-the-system-encoding-right-now-10"]], "Is LCD lock active? (11)": [[8, "is-lcd-lock-active-11"]], "When encoding video, this is the duration (seconds) of the video so far; 0 otherwise (13)": [[8, "when-encoding-video-this-is-the-duration-seconds-of-the-video-so-far-0-otherwise-13"]], "When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise (14)": [[8, "when-broadcasting-live-stream-this-is-the-broadcast-duration-seconds-so-far-0-otherwise-14"]], "Are Wireless Connections enabled? (17)": [[8, "are-wireless-connections-enabled-17"]], "The pairing state of the camera (19)": [[8, "the-pairing-state-of-the-camera-19"]], "The last type of pairing in which the camera was engaged (20)": [[8, "the-last-type-of-pairing-in-which-the-camera-was-engaged-20"]], "Time since boot (milliseconds) of last successful pairing complete action (21)": [[8, "time-since-boot-milliseconds-of-last-successful-pairing-complete-action-21"]], "State of current scan for WiFi Access Points (22)": [[8, "state-of-current-scan-for-wifi-access-points-22"]], "Time since boot (milliseconds) that the WiFi Access Point scan completed (23)": [[8, "time-since-boot-milliseconds-that-the-wifi-access-point-scan-completed-23"]], "WiFi AP provisioning state (24)": [[8, "wifi-ap-provisioning-state-24"]], "Wireless remote control version (26)": [[8, "wireless-remote-control-version-26"]], "Is a wireless remote control connected? (27)": [[8, "is-a-wireless-remote-control-connected-27"]], "Wireless Pairing State. Each bit contains state information (see WirelessPairingStateFlags) (28)": [[8, "wireless-pairing-state-each-bit-contains-state-information-see-wirelesspairingstateflags-28"]], "SSID of the AP the camera is currently connected to. On BLE connection, value is big-endian byte-encoded int32 (29)": [[8, "ssid-of-the-ap-the-camera-is-currently-connected-to-on-ble-connection-value-is-big-endian-byte-encoded-int32-29"]], "The camera\u2019s WiFi SSID. On BLE connection, value is big-endian byte-encoded int32 (30)": [[8, "the-camera-s-wifi-ssid-on-ble-connection-value-is-big-endian-byte-encoded-int32-30"]], "The number of wireless devices connected to the camera (31)": [[8, "the-number-of-wireless-devices-connected-to-the-camera-31"]], "Is Preview Stream enabled? (32)": [[8, "is-preview-stream-enabled-32"]], "Primary Storage Status (33)": [[8, "primary-storage-status-33"]], "How many photos can be taken with current settings before sdcard is full (34)": [[8, "how-many-photos-can-be-taken-with-current-settings-before-sdcard-is-full-34"]], "How many minutes of video can be captured with current settings before sdcard is full (35)": [[8, "how-many-minutes-of-video-can-be-captured-with-current-settings-before-sdcard-is-full-35"]], "Total number of group photos on sdcard (36)": [[8, "total-number-of-group-photos-on-sdcard-36"]], "Total number of group videos on sdcard (37)": [[8, "total-number-of-group-videos-on-sdcard-37"]], "Total number of photos on sdcard (38)": [[8, "total-number-of-photos-on-sdcard-38"]], "Total number of videos on sdcard (39)": [[8, "total-number-of-videos-on-sdcard-39"]], "The current status of Over The Air (OTA) update (41)": [[8, "the-current-status-of-over-the-air-ota-update-41"]], "Is there a pending request to cancel a firmware update download? (42)": [[8, "is-there-a-pending-request-to-cancel-a-firmware-update-download-42"]], "Is locate camera feature active? (45)": [[8, "is-locate-camera-feature-active-45"]], "The current timelapse interval countdown value (e.g. 5\u20264\u20263\u20262\u20261\u2026) (49)": [[8, "the-current-timelapse-interval-countdown-value-e-g-5-4-3-2-1-49"]], "Remaining space on the sdcard in Kilobytes (54)": [[8, "remaining-space-on-the-sdcard-in-kilobytes-54"]], "Is preview stream supported in current recording/mode/secondary-stream? (55)": [[8, "is-preview-stream-supported-in-current-recording-mode-secondary-stream-55"]], "WiFi signal strength in bars (56)": [[8, "wifi-signal-strength-in-bars-56"]], "The number of hilights in currently-encoding video (value is set to 0 when encoding stops) (58)": [[8, "the-number-of-hilights-in-currently-encoding-video-value-is-set-to-0-when-encoding-stops-58"]], "Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops) (59)": [[8, "time-since-boot-milliseconds-of-most-recent-hilight-in-encoding-video-set-to-0-when-encoding-stops-59"]], "The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this (60)": [[8, "the-minimum-time-between-camera-status-updates-milliseconds-best-practice-is-to-not-poll-for-status-more-often-than-this-60"]], "The current state of camera analytics (61)": [[8, "the-current-state-of-camera-analytics-61"]], "The size (units??) of the analytics file (62)": [[8, "the-size-units-of-the-analytics-file-62"]], "Is the camera currently in a contextual menu (e.g. Preferences)? (63)": [[8, "is-the-camera-currently-in-a-contextual-menu-e-g-preferences-63"]], "How many minutes of Time Lapse Video can be captured with current settings before sdcard is full (64)": [[8, "how-many-minutes-of-time-lapse-video-can-be-captured-with-current-settings-before-sdcard-is-full-64"]], "Liveview Exposure Select Mode (65)": [[8, "liveview-exposure-select-mode-65"]], "Liveview Exposure Select: y-coordinate (percent) (66)": [[8, "liveview-exposure-select-y-coordinate-percent-66"]], "Liveview Exposure Select: y-coordinate (percent) (67)": [[8, "liveview-exposure-select-y-coordinate-percent-67"]], "Does the camera currently have a GPS lock? (68)": [[8, "does-the-camera-currently-have-a-gps-lock-68"]], "Is the camera in AP Mode? (69)": [[8, "is-the-camera-in-ap-mode-69"]], "Internal battery level (percent) (70)": [[8, "internal-battery-level-percent-70"]], "Microphone Accessory status (74)": [[8, "microphone-accessory-status-74"]], "Digital Zoom level (percent) (75)": [[8, "digital-zoom-level-percent-75"]], "Wireless Band (76)": [[8, "wireless-band-76"]], "Is Digital Zoom feature available? (77)": [[8, "is-digital-zoom-feature-available-77"]], "Are current video settings mobile friendly? (related to video compression and frame rate) (78)": [[8, "are-current-video-settings-mobile-friendly-related-to-video-compression-and-frame-rate-78"]], "Is the camera currently in First Time Use (FTU) UI flow? (79)": [[8, "is-the-camera-currently-in-first-time-use-ftu-ui-flow-79"]], "Is 5GHz wireless band available? (81)": [[8, "is-5ghz-wireless-band-available-81"]], "Is the system fully booted and ready to accept commands? (82)": [[8, "is-the-system-fully-booted-and-ready-to-accept-commands-82"]], "Is the internal battery charged sufficiently to start Over The Air (OTA) update? (83)": [[8, "is-the-internal-battery-charged-sufficiently-to-start-over-the-air-ota-update-83"]], "Is the camera getting too cold to continue recording? (85)": [[8, "is-the-camera-getting-too-cold-to-continue-recording-85"]], "Rotational orientation of the camera (86)": [[8, "rotational-orientation-of-the-camera-86"]], "Is this camera model capable of zooming while encoding? (88)": [[8, "is-this-camera-model-capable-of-zooming-while-encoding-88"]], "Current Flatmode ID (89)": [[8, "current-flatmode-id-89"]], "Are current flatmode\u2019s Protune settings factory default? (90)": [[8, "are-current-flatmode-s-protune-settings-factory-default-90"]], "Are system logs ready to be downloaded? (91)": [[8, "are-system-logs-ready-to-be-downloaded-91"]], "Current Video Preset (ID) (93)": [[8, "current-video-preset-id-93"]], "Current Photo Preset (ID) (94)": [[8, "current-photo-preset-id-94"]], "Current Time Lapse Preset (ID) (95)": [[8, "current-time-lapse-preset-id-95"]], "Current Preset Group (ID) (corresponds to ui_mode_groups in settings.json) (96)": [[8, "current-preset-group-id-corresponds-to-ui-mode-groups-in-settings-json-96"]], "Current Preset (ID) (97)": [[8, "current-preset-id-97"]], "Preset Modified Status, which contains an event ID and a Preset (Group) ID (98)": [[8, "preset-modified-status-which-contains-an-event-id-and-a-preset-group-id-98"]], "The number of Live Bursts can be captured with current settings before sdcard is full (99)": [[8, "the-number-of-live-bursts-can-be-captured-with-current-settings-before-sdcard-is-full-99"]], "Total number of Live Bursts on sdcard (100)": [[8, "total-number-of-live-bursts-on-sdcard-100"]], "Is Capture Delay currently active (i.e. counting down)? (101)": [[8, "is-capture-delay-currently-active-i-e-counting-down-101"]], "Media Mod state (102)": [[8, "media-mod-state-102"]], "Time Warp Speed (103)": [[8, "time-warp-speed-103"]], "Is the system\u2019s Linux core active? (104)": [[8, "is-the-system-s-linux-core-active-104"]], "Camera lens type (reflects changes to setting 162 or setting 189) (105)": [[8, "camera-lens-type-reflects-changes-to-setting-162-or-setting-189-105"]], "Is Video Hindsight Capture Active? (106)": [[8, "is-video-hindsight-capture-active-106"]], "Scheduled Capture Preset ID (107)": [[8, "scheduled-capture-preset-id-107"]], "Is Scheduled Capture set? (108)": [[8, "is-scheduled-capture-set-108"]], "Is the camera in the process of creating a custom preset? (109)": [[8, "is-the-camera-in-the-process-of-creating-a-custom-preset-109"]], "Display Mod Status (bitmasked) (110)": [[8, "display-mod-status-bitmasked-110"]], "Does sdcard meet specified minimum write speed? (111)": [[8, "does-sdcard-meet-specified-minimum-write-speed-111"]], "Number of sdcard write speed errors since device booted (112)": [[8, "number-of-sdcard-write-speed-errors-since-device-booted-112"]], "Is Turbo Transfer active? (113)": [[8, "is-turbo-transfer-active-113"]], "Camera control status ID (114)": [[8, "camera-control-status-id-114"]], "Is the camera connected to a PC via USB? (115)": [[8, "is-the-camera-connected-to-a-pc-via-usb-115"]], "Camera control over USB state (116)": [[8, "camera-control-over-usb-state-116"]], "Total SD card capacity in Kilobytes (117)": [[8, "total-sd-card-capacity-in-kilobytes-117"]], "Welcome to Open GoPro BLE API\u2019s documentation!": [[9, "welcome-to-open-gopro-ble-api-s-documentation"]], "Supported Cameras": [[9, "supported-cameras"]], "Getting Started": [[9, "getting-started"]], "Limitations": [[9, "limitations"]], "General": [[9, "general"]], "Protocol": [[10, "protocol"]], "BLE Setup": [[11, "ble-setup"]], "Pairing Mode": [[11, "pairing-mode"]], "Advertisements": [[11, "advertisements"]], "Finish Pairing": [[11, "finish-pairing"]], "Configure GATT Characteristics": [[11, "configure-gatt-characteristics"]], "BLE Characteristics": [[11, "ble-characteristics"]], "Send Messages": [[11, "send-messages"]], "Data Protocol": [[12, "data-protocol"]], "Packetization": [[12, "packetization"]], "Packet Headers": [[12, "packet-headers"]], "General (5-bit) Packets": [[12, "general-5-bit-packets"]], "Extended (13-bit) Packets": [[12, "extended-13-bit-packets"]], "Extended (16-bit) Packets": [[12, "extended-16-bit-packets"]], "Continuation Packets": [[12, "continuation-packets"]], "Decipher Message Payload Type": [[12, "decipher-message-payload-type"]], "Message Payload": [[12, "message-payload"]], "Type Length Value": [[12, "type-length-value"]], "Commands": [[12, "commands"]], "Queries": [[12, "queries"]], "Protobuf": [[12, "protobuf"]], "ID Tables": [[13, "id-tables"]], "Command IDs": [[13, "command-ids"]], "Query IDs": [[13, "query-ids"]], "Protobuf IDs": [[13, "protobuf-ids"]], "Protobuf Documentation": [[14, "protobuf-documentation"]], "Enums": [[14, "enums"]], "EnumCOHNNetworkState": [[14, "enumcohnnetworkstate"]], "EnumCOHNStatus": [[14, "enumcohnstatus"]], "EnumCameraControlStatus": [[14, "enumcameracontrolstatus"]], "EnumFlatMode": [[14, "enumflatmode"]], "EnumLens": [[14, "enumlens"]], "EnumLiveStreamError": [[14, "enumlivestreamerror"]], "EnumLiveStreamStatus": [[14, "enumlivestreamstatus"]], "EnumPresetGroup": [[14, "enumpresetgroup"]], "EnumPresetGroupIcon": [[14, "enumpresetgroupicon"]], "EnumPresetIcon": [[14, "enumpreseticon"]], "EnumPresetTitle": [[14, "enumpresettitle"]], "EnumProvisioning": [[14, "enumprovisioning"]], "EnumRegisterLiveStreamStatus": [[14, "enumregisterlivestreamstatus"]], "EnumRegisterPresetStatus": [[14, "enumregisterpresetstatus"]], "EnumResultGeneric": [[14, "enumresultgeneric"]], "EnumScanEntryFlags": [[14, "enumscanentryflags"]], "EnumScanning": [[14, "enumscanning"]], "EnumWindowSize": [[14, "enumwindowsize"]], "Media": [[14, "media"]], "NotifProvisioningState": [[14, "notifprovisioningstate"]], "NotifStartScanning": [[14, "notifstartscanning"]], "NotifyCOHNStatus": [[14, "notifycohnstatus"]], "NotifyLiveStreamStatus": [[14, "notifylivestreamstatus"]], "NotifyPresetStatus": [[14, "notifypresetstatus"]], "Preset": [[14, "preset"]], "PresetGroup": [[14, "presetgroup"]], "PresetSetting": [[14, "presetsetting"]], "RequestCOHNCert": [[14, "requestcohncert"]], "RequestClearCOHNCert": [[14, "requestclearcohncert"]], "RequestConnect": [[14, "requestconnect"]], "RequestConnectNew": [[14, "requestconnectnew"]], "RequestCreateCOHNCert": [[14, "requestcreatecohncert"]], "RequestCustomPresetUpdate": [[14, "requestcustompresetupdate"]], "RequestGetApEntries": [[14, "requestgetapentries"]], "RequestGetCOHNStatus": [[14, "requestgetcohnstatus"]], "RequestGetLastCapturedMedia": [[14, "requestgetlastcapturedmedia"]], "RequestGetLiveStreamStatus": [[14, "requestgetlivestreamstatus"]], "RequestGetPresetStatus": [[14, "requestgetpresetstatus"]], "RequestReleaseNetwork": [[14, "requestreleasenetwork"]], "RequestSetCOHNSetting": [[14, "requestsetcohnsetting"]], "RequestSetCameraControlStatus": [[14, "requestsetcameracontrolstatus"]], "RequestSetLiveStreamMode": [[14, "requestsetlivestreammode"]], "RequestSetTurboActive": [[14, "requestsetturboactive"]], "RequestStartScan": [[14, "requeststartscan"]], "ResponseCOHNCert": [[14, "responsecohncert"]], "ResponseConnect": [[14, "responseconnect"]], "ResponseConnectNew": [[14, "responseconnectnew"]], "ResponseGeneric": [[14, "responsegeneric"]], "ResponseGetApEntries": [[14, "responsegetapentries"]], "ResponseLastCapturedMedia": [[14, "responselastcapturedmedia"]], "ResponseStartScanning": [[14, "responsestartscanning"]], "ResponseGetApEntries::ScanEntry": [[14, "responsegetapentries-scanentry"]], "State Management": [[15, "state-management"]], "Camera Readiness": [[15, "camera-readiness"]], "Keep Alive": [[15, "keep-alive"]], "Camera Control": [[15, "camera-control"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/docs/faq.md b/docs/faq.md index 48a08195..dfc99464 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -8,7 +8,7 @@ read_time: false # Frequently Asked Questions (FAQ) If you have somehow stumbled here first, note that there are specifications, demos, and tutorials which -expand upon much of the information here. These can be found, among other places, from the [home page](/). +expand upon much of the information here. These can be found, among other places, from the [home page]({{site.baseurl}}/). ## Connectivity diff --git a/docs/http.html b/docs/http.html index c939caad..21636aaf 100644 --- a/docs/http.html +++ b/docs/http.html @@ -408,7 +408,7 @@ -
                                                      Supported Cameras

                                        -

                                        While the version listed above are mininum versions needed to support the Open GoPro API, the documentation +

                                        While the version listed above are minimum versions needed to support the Open GoPro API, the documentation assumes that the GoPro is always updated to the most recent version. This is relevant in cases where functionality changes between versions.

                                        @@ -672,36 +672,28 @@

                                        Limitations

                                      Analytics

                                      Query / Configure Analytics

                                      -

                                      Set Client as Third Party

                                      Set Client as Third Party


                                      -

                                      Supported Cameras:

                                      -
                                        -
                                      • HERO12 Black
                                      • -
                                      • HERO11 Black Mini
                                      • -
                                      • HERO11 Black
                                      • -
                                      • HERO10 Black
                                      • -
                                      • HERO9 Black
                                      • -
                                      -
                                      +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                      HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                      Supported Protocols:

                                      • USB
                                      • WIFI
                                      +

                                      Responses

                                      Response Schema: application/json
                                      object

                                  </tr> </thead> <tbody><tr> +<td>HERO</td> +<td>❌</td> +</tr> +<tr> <td>HERO12 Black</td> <td>✔</td> </tr> @@ -750,6 +746,10 @@

                                  Limitations

                                  +HERO +❌ + + HERO12 Black ✔ @@ -784,28 +784,20 @@

                                  Limitations

                                  headers, using the username and password from the COHN status obtained during or after provisioning.</p> ">

                                  All HTTPS messages must contain Basic access authentication headers, using the username and password from the COHN status obtained during or after provisioning.

                                  -

                                  Configure COHN Settings

                                  Configure COHN Settings


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black

                                  Supported Protocols:

                                    -
                                  • WIFI
                                  • USB
                                  • +
                                  • WIFI
                                  +
                                  Request Body schema: application/json
                                  cohn_active
                                  integer
                                  Enum: 0 1
                                  Limitations " class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS sc-ckdEwu LxEPk">

                                  Request was successfully received by the camera

                                  Response Schema: application/json
                                  object

                                  Request samples

                                  Content type
                                  application/json
                                  {
                                  • "cohn_active": 0
                                  }

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Create the COHN SSL/TLS certificates

                                  http://10.5.5.9:8080/gopro/cohn/setting

                                  Request samples

                                  Content type
                                  application/json
                                  {
                                  • "cohn_active": 0
                                  }

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Create the COHN SSL/TLS certificates

                                  This creates the Camera On the Home Network SSL/TLS certs certs. -The created certificate(s) can be obtained via Get COHN Certificate and -used for SSL/TLS communications

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  -
                                  +<hr> +<p>This creates the Camera On the Home Network SSL/TLS certs certs. +The created certificate(s) can be obtained via <a href="#operation/GPCAMERA_GET_HOME_NETWORK_CERT">Get COHN Certificate</a> and +used for SSL/TLS communications</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black

                                  Supported Protocols:

                                    -
                                  • WIFI
                                  • USB
                                  • +
                                  • WIFI
                                  +
                                  +

                                  This creates the Camera On the Home Network SSL/TLS certs certs. +The created certificate(s) can be obtained via Get COHN Certificate and +used for SSL/TLS communications

                                  Request Body schema: application/json
                                  override
                                  integer
                                  Enum: 0 1

                                  If 1, replace existing Root CA cert with a newly-generated one.

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Request samples

                                  Content type
                                  application/json
                                  {
                                  • "override": 0
                                  }

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Delete COHN Certificates

                                  http://10.5.5.9:8080/gopro/cohn/cert/create

                                  Request samples

                                  Content type
                                  application/json
                                  {
                                  • "override": 0
                                  }

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Delete COHN Certificates


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black

                                  Supported Protocols:

                                    -
                                  • WIFI
                                  • USB
                                  • +
                                  • WIFI
                                  +

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Get COHN Certificate

                                  http://10.5.5.9:8080/gopro/cohn/cert/clear

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Get COHN Certificate


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black

                                  Supported Protocols:

                                    -
                                  • WIFI
                                  • USB
                                  • +
                                  • WIFI
                                  +

                                  Responses

                                  Response Schema: text/plain
                                  string

                                  Get COHN Status

                                  Get COHN Status


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black

                                  Supported Protocols:

                                    -
                                  • WIFI
                                  • USB
                                  • +
                                  • WIFI
                                  +

                                  Responses

                                  Response Schema: application/json
                                  enabled
                                  integer
                                  Enum: 0 1
                                  Limitations " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  default camera

                                  http://10.5.5.9:8080/gopro/cohn/status

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "enabled": 0,
                                  • "ipaddress": "123.45.67.890",
                                  • "macaddress": "string",
                                  • "password": "string",
                                  • "ssid": "string",
                                  • "state": 0,
                                  • "status": 0,
                                  • "username": "string"
                                  }

                                  Control

                                  Command and control of the camera

                                  -

                                  Configure Turbo Transfer

                                  Configure Turbo Transfer

                                  Some cameras support Turbo Transfer mode, which allows media to be downloaded over WiFi more rapidly.

                                  -

                                  This special mode should only be used during media offload.

                                  -

                                  It is recommended that the user check for and, if necessary, disable Turbo Transfer on connection.

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +<p>Some cameras support Turbo Transfer mode, which allows media to be downloaded over WiFi more rapidly.</p> +<p>This special mode should only be used during media offload.</p> +<p>It is recommended that the user check for and, if necessary, disable Turbo Transfer on connection.</p> +<p>Note that Disabling / enabling turbo mode willa lso enable / disable the transferring media camera UI.</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Some cameras support Turbo Transfer mode, which allows media to be downloaded over WiFi more rapidly.

                                  +

                                  This special mode should only be used during media offload.

                                  +

                                  It is recommended that the user check for and, if necessary, disable Turbo Transfer on connection.

                                  +

                                  Note that Disabling / enabling turbo mode willa lso enable / disable the transferring media camera UI.

                                  query Parameters
                                  p
                                  integer
                                  Enum: 0 1

                                  0 to disable, 1 to enable

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Enable Wired camera control over USB

                                  http://10.5.5.9:8080/gopro/media/turbo_transfer

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Enable Wired camera control over USB


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  query Parameters
                                  p
                                  integer
                                  Enum: 0 1

                                  If 1, enable wired usb control; If 0, disable usb control

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Keep Alive

                                  http://10.5.5.9:8080/gopro/camera/control/wired_usb

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Keep Alive

                                  In order to maximize battery life, GoPro cameras automatically go to sleep after some time. +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  +

                                  Supported Protocols:

                                  +
                                    +
                                  • USB
                                  • +
                                  • WIFI
                                  • +
                                  +
                                  +

                                  In order to maximize battery life, GoPro cameras automatically go to sleep after some time. This logic is handled by a combination of the Auto Power Down setting which most (but not all) cameras support and a Keep Alive message that the user can regularly send to the camera.

                                  The camera will automatically go to sleep if both timers reach zero.

                                  The Auto Power Down timer is reset when the user taps the LCD screen, presses a button on the camera, -programmatically (un)sets the shutter, sets a setting, or loads a Preset.

                                  + programmatically (un)sets the shutter, sets a setting, or loads a Preset.

                                  The Keep Alive timer is reset when the user sends a keep alive message.

                                  The best practice to prevent the camera from inadvertently going to sleep is to start sending Keep Alive messages every 3.0 seconds after a connection is established.

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  -

                                  Supported Protocols:

                                  -
                                    -
                                  • USB
                                  • -
                                  • WIFI
                                  • -

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Set Camera Control Status

                                  http://10.5.5.9:8080/gopro/camera/keep_alive

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Set Camera Control Status

                                  This command is used to tell the camera that a client (i.e. External Control) wishes to claim control of the camera. +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black

                                  +

                                  Supported Protocols:

                                  +
                                    +
                                  • USB
                                  • +
                                  • WIFI
                                  • +
                                  +
                                  +

                                  This command is used to tell the camera that a client (i.e. External Control) wishes to claim control of the camera. This causes the camera to immediately exit most contextual menus and return to the idle screen. Any interaction with the camera's physical buttons will cause the camera to reclaim control and update control status accordingly. If the user returns the camera UI to the idle screen, the camera updates control status to Idle.

                                  -

                                  Note:

                                  +

                                  Note:

                                  • The entity currently claiming control of the camera is advertised in camera status 114
                                  • Information about whether the camera is in a contextual menu or not is advertised in camera status 63.

                                  See the below diagram for a state diagram of Camera Control:

                                  global behaviors state diagram

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  -
                                  -

                                  Supported Protocols:

                                  -
                                    -
                                  • USB
                                  • -
                                  • WIFI
                                  • -
                                  query Parameters
                                  p
                                  integer (EnumCameraControlStatus)
                                  Enum: 0 1 2
                                  Limitations " class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS sc-ckdEwu LxEPk">

                                  Request was successfully received by the camera

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Set Date / Time

                                  http://10.5.5.9:8080/gopro/camera/control/set_ui_controller

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Set Date / Time


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  query Parameters
                                  date
                                  string
                                  Example: date=2023_12_31

                                  current date in format YYYY_MM_DD

                                  time
                                  string
                                  Example: time=21_12_13
                                  Limitations " class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS sc-ckdEwu LxEPk">

                                  Request was successfully received by the camera

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Set Digital Zoom

                                  http://10.5.5.9:8080/gopro/camera/set_date_time

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Set Digital Zoom


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  query Parameters
                                  percent
                                  integer [ 0 .. 100 ]
                                  Example: percent=50

                                  Zoom Level (0-100)

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Set Shutter

                                  http://10.5.5.9:8080/gopro/camera/digital_zoom

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Set Shutter


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  path Parameters
                                  mode
                                  string
                                  Enum: "start" "stop"

                                  Start / stop encoding.

                                  Responses

                                  Hilight a Media File

                                  Hilight a Media File

                                  Add a hilight / tag to an existing photo or media file.

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +<p>Add a hilight / tag to an existing photo or media file.</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Add a hilight / tag to an existing photo or media file.

                                  query Parameters
                                  path
                                  required
                                  string
                                  Example: path=100GOPRO/GOPR0002.MP4

                                  The path to a file on the camera to HiLight

                                  ms
                                  integer
                                  Example: ms=1
                                  Limitations " class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS sc-ckdEwu LxEPk">

                                  Request was successfully received by the camera

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Hilight While Recording

                                  http://10.5.5.9:8080/gopro/media/hilight/file

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Hilight While Recording

                                  Add hilight at current time while recording video

                                  -

                                  This can only be used during recording.

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  -
                                  +<hr> +<p>Add hilight at current time while recording video</p> +<p>This can only be used during recording.</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Add hilight at current time while recording video

                                  +

                                  This can only be used during recording.

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Remove Hilight

                                  http://10.5.5.9:8080/gopro/media/hilight/moment

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Remove Hilight

                                  Remove an existing hilight from a photo or video file.

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +<p>Remove an existing hilight from a photo or video file.</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Remove an existing hilight from a photo or video file.

                                  query Parameters
                                  path
                                  required
                                  string
                                  Example: path=100GOPRO/GOPR0002.MP4

                                  The path to a file on the camera to remove a HiLight from

                                  ms
                                  integer
                                  Example: ms=1
                                  Limitations -rwxrwxrwx@ 1 gopro 123456789 184517614 Jan 1 00:00 GL030078.LRV -rwxrwxrwx@ 1 gopro 123456789 34877660 Jan 1 00:00 GL040078.LRV -

                                  Download a Media File

                                  Download a Media File

                                  Note that this is the same endpoint for all media (photos, video, etc.).

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +<p>Note that this is the same endpoint for all media (photos, video, etc.).</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Note that this is the same endpoint for all media (photos, video, etc.).

                                  path Parameters
                                  directory
                                  required
                                  string
                                  Example: 100GOPRO

                                  Case sensitive directory that media resides in

                                  filename
                                  required
                                  string
                                  Examples:
                                  • GOPR0001.JPG - Sample photo file
                                  • GH010397.MP4 - Sample video file

                                  Case sensitive media filename

                                  Get Last Captured Media

                                  http://10.5.5.9:8080/videos/DCIM/{directory}/{filename}

                                  Get Last Captured Media

                                  This will return the complete path of the last captured media. Depending on the type of media captured, it will return:

                                  +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black

                                  +

                                  Supported Protocols:

                                    -
                                  • single photo / video: The single media path
                                  • -
                                  • any grouped media: The path to the first captured media in the group
                                  • +
                                  • USB
                                  • +
                                  • WIFI

                                  -

                                  Supported Cameras:

                                  +

                                  This will return the complete path of the last captured media. Depending on the type of media captured, it will return:

                                    -
                                  • HERO12 Black
                                  • -
                                  -
                                  -

                                  Supported Protocols:

                                  -
                                    -
                                  • WIFI
                                  • -
                                  • USB
                                  • +
                                  • single photo / video: The single media path
                                  • +
                                  • any grouped media: The path to the first captured media in the group

                                  Responses

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "file": "GOPR0002.JPG",
                                  • "folder": "100GOPRO"
                                  }

                                  Get Media File GPMF

                                  http://10.5.5.9:8080/gopro/media/last_captured

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "file": "GOPR0002.JPG",
                                  • "folder": "100GOPRO"
                                  }

                                  Get Media File GPMF

                                  None

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +<p>None</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  None

                                  query Parameters
                                  path
                                  string
                                  Example: path=100GOPRO/GOPR0002.JPG

                                  media file name

                                  Responses

                                  Response Schema: application/octet-stream
                                  string <binary>

                                  Get Media File Info

                                  http://10.5.5.9:8080/gopro/media/gpmf

                                  Get Media File Info


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  query Parameters
                                  path
                                  string
                                  Example: path=100GOPRO/GOPR0002.JPG

                                  media file name

                                  Responses

                                  Response samples

                                  Content type
                                  application/json
                                  Example
                                  {
                                  • "ao": "auto",
                                  • "avc_profile": 0,
                                  • "cl": 0,
                                  • "cre": 1692992748,
                                  • "ct": 0,
                                  • "dur": 42,
                                  • "eis": 0,
                                  • "fov": "string",
                                  • "fps": 1001,
                                  • "fps_denom": 30000,
                                  • "gumi": "12345678998765443211234567899875",
                                  • "h": 1080,
                                  • "hc": 99,
                                  • "hi": [
                                    ],
                                  • "lc": 0,
                                  • "ls": -1,
                                  • "mos": [
                                    ],
                                  • "mp": 0,
                                  • "prjn": 0,
                                  • "profile": 255,
                                  • "progr": 0,
                                  • "pta": 0,
                                  • "rot": "string",
                                  • "s": 1234567890,
                                  • "subsample": 0,
                                  • "tr": 0,
                                  • "us": 0,
                                  • "w": 1920
                                  }

                                  Get Media File Screennail

                                  http://10.5.5.9:8080/gopro/media/info

                                  Response samples

                                  Content type
                                  application/json
                                  Example
                                  {
                                  • "ao": "auto",
                                  • "avc_profile": 0,
                                  • "cl": 0,
                                  • "cre": 1692992748,
                                  • "ct": 0,
                                  • "dur": 42,
                                  • "eis": 0,
                                  • "fov": "string",
                                  • "fps": 1001,
                                  • "fps_denom": 30000,
                                  • "gumi": "12345678998765443211234567899875",
                                  • "h": 1080,
                                  • "hc": 99,
                                  • "hi": [
                                    ],
                                  • "lc": 0,
                                  • "ls": -1,
                                  • "mos": [
                                    ],
                                  • "mp": 0,
                                  • "prjn": 0,
                                  • "profile": 255,
                                  • "progr": 0,
                                  • "pta": 0,
                                  • "rot": "string",
                                  • "s": 1234567890,
                                  • "subsample": 0,
                                  • "tr": 0,
                                  • "us": 0,
                                  • "w": 1920
                                  }

                                  Get Media File Screennail

                                  A screennail is a low-res preview image that is higher resolution than a thumbnail.

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +<p>A screennail is a low-res preview image that is higher resolution than a thumbnail.</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  A screennail is a low-res preview image that is higher resolution than a thumbnail.

                                  query Parameters
                                  path
                                  string
                                  Example: path=100GOPRO/GOPR0002.JPG

                                  media file name

                                  Responses

                                  Response Schema: application/octet-stream
                                  string <binary>

                                  Get Media File Telemetry

                                  http://10.5.5.9:8080/gopro/media/screennail

                                  Get Media File Telemetry

                                  Get Media File Telemetry track data

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +<p>Get Media File Telemetry track data</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Get Media File Telemetry track data

                                  query Parameters
                                  path
                                  string
                                  Example: path=100GOPRO/GOPR0002.JPG

                                  media file name

                                  Responses

                                  Response Schema: application/octet-stream
                                  string <binary>

                                  Get Media File Thumbnail

                                  http://10.5.5.9:8080/gopro/media/telemetry

                                  Get Media File Thumbnail


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  query Parameters
                                  path
                                  string
                                  Example: path=100GOPRO/GOPR0002.JPG

                                  media file name

                                  Responses

                                  Response Schema: application/octet-stream
                                  string <binary>

                                  Get Media List

                                  http://10.5.5.9:8080/gopro/media/thumbnail

                                  Get Media List

                                  Limitations <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span> G0010394<span class="token punctuation">.</span>JPG<span class="token punctuation">,</span> G0010395<span class="token punctuation">.</span>JPG<span class="token punctuation">.</span> G0010396<span class="token punctuation">.</span>JPG </code></pre> -<hr> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> -<hr> -<p>Supported Protocols:</p> -<ul> -<li>USB</li> -<li>WIFI</li> -</ul> -" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  To minimize the size of the JSON transmitted by the camera, grouped media items such as Burst Photos, - Time Lapse Photos, Night Lapse Photos, etc are represented with a single item in the media list with additional keys - that allow the user to extrapolate individual filenames for each member of the group.

                                  +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  +

                                  Supported Protocols:

                                  +
                                    +
                                  • USB
                                  • +
                                  • WIFI
                                  • +
                                  +
                                  +

                                  To minimize the size of the JSON transmitted by the camera, grouped media items such as Burst Photos, +Time Lapse Photos, Night Lapse Photos, etc are represented with a single item in the media list with additional keys +that allow the user to extrapolate individual filenames for each member of the group.

                                  Filenames for group media items have the form "GXXXYYYY.ZZZ" where XXX is the group ID, YYY is the group member ID and ZZZ is the file extension.

                                  -

                                  For example, take the media list below, which contains a Time Lapse Photo group media item:

                                  +

                                  For example, take the media list below, which contains a Time Lapse Photo group media item:

                                  {
                                       "id": "2530266050123724003",
                                       "media": [
                                  @@ -2252,21 +2081,6 @@ 

                                  Limitations

                                  ..., G0010394.JPG, G0010395.JPG. G0010396.JPG
                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  -

                                  Supported Protocols:

                                  -
                                    -
                                  • USB
                                  • -
                                  • WIFI
                                  • -

                                  Responses

                                  Response Schema: application/json
                                  id
                                  required
                                  string
                                  Example: "1554375628411872255"
                                  Limitations
                                  id
                                  integer <int32>

                                  Unique preset identifier

                                  -
                                  is_fixed
                                  boolean
                                  isFixed
                                  boolean

                                  Is this preset mutable?

                                  -
                                  is_modified
                                  boolean
                                  isModified
                                  boolean

                                  Has the preset been modified from the factory defaults?

                                  mode
                                  integer (EnumFlatMode)
                                  Enum: -1 4 5 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
                                  Limitations
                                  -
                                  Array of objects (PresetSetting)
                                  Array
                                  id
                                  integer <int32>
                                  Array of objects (PresetSetting)
                                  Array
                                  id
                                  integer <int32>

                                  Setting identifier

                                  -
                                  is_caption
                                  boolean
                                  isCaption
                                  boolean

                                  Does this setting appear on the Preset "pill" in the camera UI?

                                  value
                                  integer <int32>

                                  Setting value

                                  -
                                  title_id
                                  integer (EnumPresetTitle)
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 13 14 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 82 83 93 94
                                  titleId
                                  integer (EnumPresetTitle)
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 13 14 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 82 83 93 94
                                  Limitations
                                  -
                                  title_number
                                  integer <int32>
                                  titleNumber
                                  integer <int32>

                                  Preset title number

                                  -
                                  user_defined
                                  boolean
                                  userDefined
                                  boolean

                                  Is this preset user defined?

                                  -
                                  {
                                  • "icon": 0,
                                  • "id": 0,
                                  • "is_fixed": true,
                                  • "is_modified": true,
                                  • "mode": -1,
                                  • "setting_array": [
                                    ],
                                  • "title_id": 0,
                                  • "title_number": 0,
                                  • "user_defined": true
                                  }

                                  PresetGroup

                                  can_add_preset
                                  boolean
                                  {
                                  • "icon": 0,
                                  • "id": 0,
                                  • "isFixed": true,
                                  • "isModified": true,
                                  • "mode": -1,
                                  • "settingArray": [
                                    ],
                                  • "titleId": 0,
                                  • "titleNumber": 0,
                                  • "userDefined": true
                                  }

                                  PresetGroup

                                  canAddPreset
                                  boolean

                                  Is there room in the group to add additional Presets?

                                  icon
                                  integer (EnumPresetGroupIcon)
                                  Enum: 0 1 2 3 4 5 6 7
                                  Limitations
                                  -
                                  Array of objects (Preset)
                                  Array of objects (Preset)

                                  Array of Presets contained in this Preset Group

                                  Array
                                  icon
                                  integer (EnumPresetIcon)
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 58 59 60 61 62 63 64 65 66 67 70 71 73 74 75 76 77 78 79 1000 1001
                                  Limitations
                                  id
                                  integer <int32>

                                  Unique preset identifier

                                  -
                                  is_fixed
                                  boolean
                                  isFixed
                                  boolean

                                  Is this preset mutable?

                                  -
                                  is_modified
                                  boolean
                                  isModified
                                  boolean

                                  Has the preset been modified from the factory defaults?

                                  mode
                                  integer (EnumFlatMode)
                                  Enum: -1 4 5 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
                                  Limitations
                                  -
                                  Array of objects (PresetSetting)
                                  Array
                                  id
                                  integer <int32>
                                  Array of objects (PresetSetting)
                                  Array
                                  id
                                  integer <int32>

                                  Setting identifier

                                  -
                                  is_caption
                                  boolean
                                  isCaption
                                  boolean

                                  Does this setting appear on the Preset "pill" in the camera UI?

                                  value
                                  integer <int32>

                                  Setting value

                                  -
                                  title_id
                                  integer (EnumPresetTitle)
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 13 14 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 82 83 93 94
                                  titleId
                                  integer (EnumPresetTitle)
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 13 14 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 82 83 93 94
                                  Limitations
                                  -
                                  title_number
                                  integer <int32>
                                  titleNumber
                                  integer <int32>

                                  Preset title number

                                  -
                                  user_defined
                                  boolean
                                  userDefined
                                  boolean

                                  Is this preset user defined?

                                  -
                                  {
                                  • "can_add_preset": true,
                                  • "icon": 0,
                                  • "id": 1000,
                                  • "preset_array": [
                                    ]
                                  }

                                  PresetSetting

                                  id
                                  integer <int32>
                                  {
                                  • "canAddPreset": true,
                                  • "icon": 0,
                                  • "id": 1000,
                                  • "presetArray": [
                                    ]
                                  }

                                  PresetSetting

                                  id
                                  integer <int32>

                                  Setting identifier

                                  -
                                  is_caption
                                  boolean
                                  isCaption
                                  boolean

                                  Does this setting appear on the Preset "pill" in the camera UI?

                                  value
                                  integer <int32>

                                  Setting value

                                  -
                                  {
                                  • "id": 0,
                                  • "is_caption": true,
                                  • "value": 0
                                  }

                                  SingleMediaListItem

                                  cre
                                  required
                                  integer
                                  Example: "1696600109"
                                  {
                                  • "id": 0,
                                  • "isCaption": true,
                                  • "value": 0
                                  }

                                  SingleMediaListItem

                                  cre
                                  required
                                  integer
                                  Example: "1696600109"

                                  Creation time in seconds since epoch

                                  glrv
                                  integer
                                  Example: "817767"

                                  Low resolution video size

                                  @@ -5922,14 +5736,11 @@

                                  Limitations

                                  {
                                  • "cre": 1696600109,
                                  • "glrv": 817767,
                                  • "ls": -1,
                                  • "mod": 1696600109,
                                  • "n": "GOPR0001.JPG",
                                  • "s": 2806303
                                  }

                                  State

                                  object

                                  All currently known setting values indexed by setting ID

                                  2
                                  integer
                                  Enum: 1 4 6 7 9 18 24 25 26 27 28 100 107 108 109 110 111
                                  Limitations <tbody><tr> <td>1</td> <td>4K</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>4</td> <td>2.7K</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>6</td> <td>2.7K 4:3</td> -<td>HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>7</td> <td>1440</td> -<td>HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>9</td> <td>1080</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>18</td> <td>4K 4:3</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>24</td> <td>5K</td> -<td>HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>25</td> <td>5K 4:3</td> -<td>HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> <tr> <td>26</td> <td>5.3K 8:7</td> -<td>HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>27</td> <td>5.3K 4:3</td> -<td>HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>28</td> <td>4K 8:7</td> -<td>HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>100</td> <td>5.3K</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> <tr> <td>107</td> <td>5.3K</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>108</td> <td>4K</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>109</td> <td>4K</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>110</td> <td>1080</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>111</td> <td>2.7K</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Resolution

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -6044,98 +5852,95 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
                                  1 4KHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  4 2.7KHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  6 2.7K 4:3HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  7 1440HERO9 BlackHERO9 Black
                                  9 1080HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  18 4K 4:3HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  24 5KHERO9 BlackHERO9 Black
                                  25 5K 4:3HERO10 BlackHERO10 Black
                                  26 5.3K 8:7HERO11 Black Mini, HERO11 BlackHERO11 Black MiniHERO11 Black
                                  27 5.3K 4:3HERO11 Black Mini, HERO11 BlackHERO11 Black MiniHERO11 Black
                                  28 4K 8:7HERO11 Black Mini, HERO11 BlackHERO11 Black MiniHERO11 Black
                                  100 5.3KHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 Black
                                  107 5.3KHERO12 BlackHERO12 Black
                                  108 4KHERO12 BlackHERO12 Black
                                  109 4KHERO12 BlackHERO12 Black
                                  110 1080HERO12 BlackHERO12 Black
                                  111 2.7KHERO12 BlackHERO12 Black
                                  3
                                  integer
                                  Enum: 0 1 2 5 6 8 9 10 13
                                  Limitations <tbody><tr> <td>0</td> <td>240</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>1</td> <td>120</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>2</td> <td>100</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>5</td> <td>60</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>6</td> <td>50</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>8</td> <td>30</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>9</td> <td>25</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>10</td> <td>24</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>13</td> <td>200</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Frames Per Second

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -6210,58 +6012,55 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - + - +
                                  0 240HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  1 120HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  2 100HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  5 60HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  6 50HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  8 30HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  9 25HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  10 24HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  13 200HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  43
                                  integer
                                  Enum: 0 2 3 4
                                  Limitations <tbody><tr> <td>0</td> <td>Wide</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>2</td> <td>Narrow</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>3</td> <td>Superview</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>4</td> <td>Linear</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Webcam Digital Lenses

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -6311,33 +6107,30 @@

                                  Limitations

                                  - + - + - + - +
                                  0 WideHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  2 NarrowHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  3 SuperviewHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  4 LinearHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  59
                                  integer
                                  Enum: 0 1 4 6 7 11 12
                                  Limitations <tbody><tr> <td>0</td> <td>Never</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>1</td> <td>1 Min</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>4</td> <td>5 Min</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>6</td> <td>15 Min</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>7</td> <td>30 Min</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>11</td> <td>8 Seconds</td> -<td>HERO11 Black Mini</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"></td> </tr> <tr> <td>12</td> <td>30 Seconds</td> -<td>HERO11 Black Mini</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Auto Power Down

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -6402,44 +6192,87 @@

                                  Limitations

                                  - + - + - + - + - + - + - + + +
                                  0 NeverHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  1 1 MinHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  4 5 MinHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  6 15 MinHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  7 30 MinHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  11 8 SecondsHERO11 Black MiniHERO11 Black Mini
                                  12 30 SecondsHERO11 Black MiniHERO11 Black Mini
                                  +
                                  83
                                  integer
                                  Enum: 0 1

                                  GPS

                                  +

                                  HERO11 Black +HERO10 Black + HERO9 Black

                                  + + + + + + + + + + + + + + + + +
                                  ValueMeaningSupported Cameras
                                  0OffHERO11 BlackHERO10 BlackHERO9 Black
                                  1OnHERO11 BlackHERO10 BlackHERO9 Black
                                  108
                                  integer
                                  Enum: 0 1 3 4
                                  Limitations <tbody><tr> <td>0</td> <td>4:3</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>16:9</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>3</td> <td>8:7</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>4</td> <td>9:16</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Aspect Ratio

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -6485,33 +6315,30 @@

                                  Limitations

                                  - + - + - + - +
                                  0 4:3HERO12 BlackHERO12 Black
                                  1 16:9HERO12 BlackHERO12 Black
                                  3 8:7HERO12 BlackHERO12 Black
                                  4 9:16HERO12 BlackHERO12 Black
                                  121
                                  integer
                                  Enum: 0 2 3 4 7 8 9 10 11
                                  Limitations <tbody><tr> <td>0</td> <td>Wide</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>2</td> <td>Narrow</td> -<td>HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>3</td> <td>Superview</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>4</td> <td>Linear</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>7</td> <td>Max SuperView</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>8</td> <td>Linear + Horizon Leveling</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>9</td> <td>HyperView</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>10</td> <td>Linear + Horizon Lock</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>11</td> <td>Max HyperView</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Lens

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -6586,57 +6410,54 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - + - +
                                  0 WideHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  2 NarrowHERO10 Black, HERO9 BlackHERO10 BlackHERO9 Black
                                  3 SuperviewHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  4 LinearHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  7 Max SuperViewHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  8 Linear + Horizon LevelingHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  9 HyperViewHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  10 Linear + Horizon LockHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  11 Max HyperViewHERO12 BlackHERO12 Black
                                  122
                                  integer
                                  Enum: 19 100 101 102
                                  Limitations <tbody><tr> <td>19</td> <td>Narrow</td> -<td>HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>100</td> <td>Max SuperView</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>101</td> <td>Wide</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>102</td> <td>Linear</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Lens

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -6685,32 +6503,29 @@

                                  Limitations

                                  - + - + - + - +
                                  19 NarrowHERO10 Black, HERO9 BlackHERO10 BlackHERO9 Black
                                  100 Max SuperViewHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  101 WideHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  102 LinearHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  123
                                  integer
                                  Enum: 19 100 101 102
                                  Limitations <tbody><tr> <td>19</td> <td>Narrow</td> -<td>HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>100</td> <td>Max SuperView</td> -<td>HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> <tr> <td>101</td> <td>Wide</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>102</td> <td>Linear</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Time Lapse Digital Lenses

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  @@ -6759,32 +6571,29 @@

                                  Limitations

                                  - + - + - + - +
                                  19 NarrowHERO10 Black, HERO9 BlackHERO10 BlackHERO9 Black
                                  100 Max SuperViewHERO10 BlackHERO10 Black
                                  101 WideHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  102 LinearHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  128
                                  integer
                                  Enum: 13 20 21 26
                                  Limitations <tbody><tr> <td>13</td> <td>Time Lapse Video</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>20</td> <td>Time Lapse Photo</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>21</td> <td>Night Lapse Photo</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>26</td> <td>Night Lapse Video</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Media Format

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black +HERO10 Black + HERO9 Black

                                  @@ -6833,33 +6639,30 @@

                                  Limitations

                                  - + - + - + - +
                                  13 Time Lapse VideoHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  20 Time Lapse PhotoHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  21 Night Lapse PhotoHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  26 Night Lapse VideoHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  134
                                  integer
                                  Enum: 2 3
                                  Limitations <tbody><tr> <td>2</td> <td>60Hz</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>3</td> <td>50Hz</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Anti-Flicker

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -6899,23 +6699,20 @@

                                  Limitations

                                  - + - +
                                  2 60HzHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  3 50HzHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  135
                                  integer
                                  Enum: 0 1 2 3 4 100
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>1</td> <td>Low</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>2</td> <td>High</td> -<td>HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>3</td> <td>Boost</td> -<td>HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>4</td> <td>Auto Boost</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>100</td> <td>Standard</td> -<td>HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Hypersmooth

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -6975,39 +6769,36 @@

                                  Limitations

                                  - + - + - + - + - + - +
                                  0 OffHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  1 LowHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO9 Black
                                  2 HighHERO10 Black, HERO9 BlackHERO10 BlackHERO9 Black
                                  3 BoostHERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  4 Auto BoostHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  100 StandardHERO10 BlackHERO10 Black
                                  150
                                  integer
                                  Enum: 0 2
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>2</td> <td>Locked</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Horizon Leveling

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO11 Black

                                  @@ -7043,19 +6831,16 @@

                                  Limitations

                                  - + - +
                                  0 OffHERO11 BlackHERO11 Black
                                  2 LockedHERO11 BlackHERO11 Black
                                  151
                                  integer
                                  Enum: 0 2
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>2</td> <td>Locked</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Horizon Leveling

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO11 Black

                                  @@ -7091,21 +6873,18 @@

                                  Limitations

                                  - + - +
                                  0 OffHERO11 BlackHERO11 Black
                                  2 LockedHERO11 BlackHERO11 Black
                                  162
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>1</td> <td>On</td> -<td>HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Max Lens

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO11 Black +HERO10 Black +HERO9 Black

                                  @@ -7143,22 +6919,19 @@

                                  Limitations

                                  - + - +
                                  0 OffHERO11 Black, HERO10 Black, HERO9 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  1 OnHERO11 Black, HERO10 Black, HERO9 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  167
                                  integer
                                  Enum: 2 3 4
                                  Limitations <tbody><tr> <td>2</td> <td>15 Seconds</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>3</td> <td>30 Seconds</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>4</td> <td>Off</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  HindSight

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black +HERO10 Black + HERO9 Black

                                  @@ -7202,24 +6972,21 @@

                                  Limitations

                                  - + - + - +
                                  2 15 SecondsHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  3 30 SecondsHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  4 OffHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  171
                                  integer
                                  Enum: 0 2 3 4 5 6 7 8 9 10
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>0.5s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>3</td> <td>1s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>4</td> <td>2s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>5</td> <td>5s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>6</td> <td>10s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>7</td> <td>30s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>8</td> <td>60s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>9</td> <td>120s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>10</td> <td>3s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Interval

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -7295,59 +7059,56 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - + - + - +
                                  0 OffHERO12 BlackHERO12 Black
                                  2 0.5sHERO12 BlackHERO12 Black
                                  3 1sHERO12 BlackHERO12 Black
                                  4 2sHERO12 BlackHERO12 Black
                                  5 5sHERO12 BlackHERO12 Black
                                  6 10sHERO12 BlackHERO12 Black
                                  7 30sHERO12 BlackHERO12 Black
                                  8 60sHERO12 BlackHERO12 Black
                                  9 120sHERO12 BlackHERO12 Black
                                  10 3sHERO12 BlackHERO12 Black
                                  172
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7 8 9
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>15 Seconds</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>30 Seconds</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>3</td> <td>1 Minute</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>4</td> <td>5 Minutes</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>5</td> <td>15 Minutes</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>6</td> <td>30 Minutes</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>7</td> <td>1 Hour</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>8</td> <td>2 Hours</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>9</td> <td>3 Hours</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Duration

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -7423,59 +7181,56 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - + - + - +
                                  0 OffHERO12 BlackHERO12 Black
                                  1 15 SecondsHERO12 BlackHERO12 Black
                                  2 30 SecondsHERO12 BlackHERO12 Black
                                  3 1 MinuteHERO12 BlackHERO12 Black
                                  4 5 MinutesHERO12 BlackHERO12 Black
                                  5 15 MinutesHERO12 BlackHERO12 Black
                                  6 30 MinutesHERO12 BlackHERO12 Black
                                  7 1 HourHERO12 BlackHERO12 Black
                                  8 2 HoursHERO12 BlackHERO12 Black
                                  9 3 HoursHERO12 BlackHERO12 Black
                                  173
                                  integer
                                  Enum: 0 1 2
                                  Limitations <tbody><tr> <td>0</td> <td>Maximum Video Performance</td> -<td>HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> <tr> <td>1</td> <td>Extended Battery</td> -<td>HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> <tr> <td>2</td> <td>Tripod / Stationary Video</td> -<td>HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Video Performance Mode

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO10 Black
                                  • -
                                  +

                                  HERO10 Black

                                  @@ -7516,25 +7268,22 @@

                                  Limitations

                                  - + - + - +
                                  0 Maximum Video PerformanceHERO10 BlackHERO10 Black
                                  1 Extended BatteryHERO10 BlackHERO10 Black
                                  2 Tripod / Stationary VideoHERO10 BlackHERO10 Black
                                  175
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>Easy</td> -<td>HERO12 Black, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>1</td> <td>Pro</td> -<td>HERO12 Black, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Controls

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black

                                  @@ -7571,20 +7317,17 @@

                                  Limitations

                                  - + - +
                                  0 EasyHERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black
                                  1 ProHERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black
                                  176
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
                                  Limitations <tbody><tr> <td>0</td> <td>8X Ultra Slo-Mo</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>1</td> <td>4X Super Slo-Mo</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>2</td> <td>2X Slo-Mo</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>3</td> <td>1X Speed (Low Light)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>4</td> <td>4X Super Slo-Mo (Ext. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>5</td> <td>2X Slo-Mo (Ext. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>6</td> <td>1X Speed (Ext. Batt.) (Low Light)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>7</td> <td>8X Ultra Slo-Mo (50Hz)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>8</td> <td>4X Super Slo-Mo (50Hz)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>9</td> <td>2X Slo-Mo (50Hz)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>10</td> <td>1X Speed (50Hz) (Low Light)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>11</td> <td>4X Super Slo-Mo (50Hz) (Ext. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>12</td> <td>2X Slo-Mo (50Hz) (Ext. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>13</td> <td>1X Speed (50Hz) (Ext. Batt.) (Low Light)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>14</td> <td>8X Ultra Slo-Mo (Ext. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>15</td> <td>8X Ultra Slo-Mo (50Hz) (Ext. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>16</td> <td>8X Ultra Slo-Mo (Long. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>17</td> <td>4X Super Slo-Mo (Long. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>18</td> <td>2X Slo-Mo (Long. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>19</td> <td>1X Speed (Long. Batt.) (Low Light)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>20</td> <td>8X Ultra Slo-Mo (50Hz) (Long. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>21</td> <td>4X Super Slo-Mo (50Hz) (Long. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>22</td> <td>2X Slo-Mo (50Hz) (Long. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>23</td> <td>1X Speed (50Hz) (Long. Batt.) (Low Light)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>24</td> <td>2X Slo-Mo (4K)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>25</td> <td>4X Super Slo-Mo (2.7K)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>26</td> <td>2X Slo-Mo (4K) (50Hz)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>27</td> <td>4X Super Slo-Mo (2.7K) (50Hz)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>100</td> <td>8X Ultra Slo-Mo (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>101</td> <td>4X Super Slo-Mo (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>102</td> <td>2X Slo-Mo (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>103</td> <td>1X Speed (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>104</td> <td>8X Ultra Slo-Mo (50Hz) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>105</td> <td>4X Super Slo-Mo (50Hz) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>106</td> <td>2X Slo-Mo (50Hz) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>107</td> <td>1X Speed (50Hz) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>108</td> <td>8X Ultra Slo-Mo (Long. Batt.) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>109</td> <td>4X Super Slo-Mo (Long. Batt.) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>110</td> <td>2X Slo-Mo (Long. Batt.) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>111</td> <td>1X Speed (Long. Batt.) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>112</td> <td>8X Ultra Slo-Mo (50Hz) (Long. Batt.) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>113</td> <td>4X Super Slo-Mo (50Hz) (Long. Batt.) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>114</td> <td>2X Slo-Mo (50Hz) (Long. Batt.) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>115</td> <td>1X Speed (50Hz) (Long. Batt.) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>116</td> <td>2X Slo-Mo (4K) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>117</td> <td>2X Slo-Mo (4K) (50Hz) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>118</td> <td>1X Speed (Low Light) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>119</td> <td>1X Speed (50Hz) (Low Light) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>120</td> <td>2X Slo-Mo (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>121</td> <td>2X Slo-Mo (50Hz) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>122</td> <td>1X Speed (Full Frame) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>123</td> <td>1X Speed (50Hz) (Full Frame) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>124</td> <td>2X Slo-Mo (Full Frame) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>125</td> <td>2X Slo-Mo (50Hz) (Full Frame) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>126</td> <td>1X Speed (4K) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>127</td> <td>1X Speed (4K) (50Hz) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>128</td> <td>1X Speed (2.7K) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>129</td> <td>1X Speed (2.7K) (50Hz) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>130</td> <td>2X Slo-Mo (2.7K) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>131</td> <td>2X Slo-Mo (2.7K) (50Hz) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>132</td> <td>2X Slo-Mo (Long. Batt.) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>133</td> <td>2X Slo-Mo (50Hz) (Long. Batt.) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>134</td> <td>1X Speed (Long. Batt.) (Low Light) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>135</td> <td>1X Speed (50Hz) (Long. Batt.) (Low Light) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>136</td> <td>1X Speed (4K) (Full Frame) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>137</td> <td>1X Speed (4K) (50Hz) (Full Frame) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Easy Mode Speed

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black

                                  @@ -7941,339 +7681,336 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
                                  0 8X Ultra Slo-MoHERO11 BlackHERO11 Black
                                  1 4X Super Slo-MoHERO11 BlackHERO11 Black
                                  2 2X Slo-MoHERO11 BlackHERO11 Black
                                  3 1X Speed (Low Light)HERO11 BlackHERO11 Black
                                  4 4X Super Slo-Mo (Ext. Batt.)HERO11 BlackHERO11 Black
                                  5 2X Slo-Mo (Ext. Batt.)HERO11 BlackHERO11 Black
                                  6 1X Speed (Ext. Batt.) (Low Light)HERO11 BlackHERO11 Black
                                  7 8X Ultra Slo-Mo (50Hz)HERO11 BlackHERO11 Black
                                  8 4X Super Slo-Mo (50Hz)HERO11 BlackHERO11 Black
                                  9 2X Slo-Mo (50Hz)HERO11 BlackHERO11 Black
                                  10 1X Speed (50Hz) (Low Light)HERO11 BlackHERO11 Black
                                  11 4X Super Slo-Mo (50Hz) (Ext. Batt.)HERO11 BlackHERO11 Black
                                  12 2X Slo-Mo (50Hz) (Ext. Batt.)HERO11 BlackHERO11 Black
                                  13 1X Speed (50Hz) (Ext. Batt.) (Low Light)HERO11 BlackHERO11 Black
                                  14 8X Ultra Slo-Mo (Ext. Batt.)HERO11 BlackHERO11 Black
                                  15 8X Ultra Slo-Mo (50Hz) (Ext. Batt.)HERO11 BlackHERO11 Black
                                  16 8X Ultra Slo-Mo (Long. Batt.)HERO11 BlackHERO11 Black
                                  17 4X Super Slo-Mo (Long. Batt.)HERO11 BlackHERO11 Black
                                  18 2X Slo-Mo (Long. Batt.)HERO11 BlackHERO11 Black
                                  19 1X Speed (Long. Batt.) (Low Light)HERO11 BlackHERO11 Black
                                  20 8X Ultra Slo-Mo (50Hz) (Long. Batt.)HERO11 BlackHERO11 Black
                                  21 4X Super Slo-Mo (50Hz) (Long. Batt.)HERO11 BlackHERO11 Black
                                  22 2X Slo-Mo (50Hz) (Long. Batt.)HERO11 BlackHERO11 Black
                                  23 1X Speed (50Hz) (Long. Batt.) (Low Light)HERO11 BlackHERO11 Black
                                  24 2X Slo-Mo (4K)HERO11 BlackHERO11 Black
                                  25 4X Super Slo-Mo (2.7K)HERO11 BlackHERO11 Black
                                  26 2X Slo-Mo (4K) (50Hz)HERO11 BlackHERO11 Black
                                  27 4X Super Slo-Mo (2.7K) (50Hz)HERO11 BlackHERO11 Black
                                  100 8X Ultra Slo-Mo (V2)HERO12 BlackHERO12 Black
                                  101 4X Super Slo-Mo (V2)HERO12 BlackHERO12 Black
                                  102 2X Slo-Mo (V2)HERO12 BlackHERO12 Black
                                  103 1X Speed (Low Light) (V2)HERO12 BlackHERO12 Black
                                  104 8X Ultra Slo-Mo (50Hz) (V2)HERO12 BlackHERO12 Black
                                  105 4X Super Slo-Mo (50Hz) (V2)HERO12 BlackHERO12 Black
                                  106 2X Slo-Mo (50Hz) (V2)HERO12 BlackHERO12 Black
                                  107 1X Speed (50Hz) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  108 8X Ultra Slo-Mo (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  109 4X Super Slo-Mo (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  110 2X Slo-Mo (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  111 1X Speed (Long. Batt.) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  112 8X Ultra Slo-Mo (50Hz) (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  113 4X Super Slo-Mo (50Hz) (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  114 2X Slo-Mo (50Hz) (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  115 1X Speed (50Hz) (Long. Batt.) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  116 2X Slo-Mo (4K) (V2)HERO12 BlackHERO12 Black
                                  117 2X Slo-Mo (4K) (50Hz) (V2)HERO12 BlackHERO12 Black
                                  118 1X Speed (Low Light) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  119 1X Speed (50Hz) (Low Light) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  120 2X Slo-Mo (V2) (Vertical)HERO12 BlackHERO12 Black
                                  121 2X Slo-Mo (50Hz) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  122 1X Speed (Full Frame) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  123 1X Speed (50Hz) (Full Frame) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  124 2X Slo-Mo (Full Frame) (V2)HERO12 BlackHERO12 Black
                                  125 2X Slo-Mo (50Hz) (Full Frame) (V2)HERO12 BlackHERO12 Black
                                  126 1X Speed (4K) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  127 1X Speed (4K) (50Hz) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  128 1X Speed (2.7K) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  129 1X Speed (2.7K) (50Hz) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  130 2X Slo-Mo (2.7K) (V2)HERO12 BlackHERO12 Black
                                  131 2X Slo-Mo (2.7K) (50Hz) (V2)HERO12 BlackHERO12 Black
                                  132 2X Slo-Mo (Long. Batt.) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  133 2X Slo-Mo (50Hz) (Long. Batt.) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  134 1X Speed (Long. Batt.) (Low Light) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  135 1X Speed (50Hz) (Long. Batt.) (Low Light) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  136 1X Speed (4K) (Full Frame) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  137 1X Speed (4K) (50Hz) (Full Frame) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  177
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>1</td> <td>On</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Enable Night Photo

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO11 Black

                                  @@ -8309,21 +8043,18 @@

                                  Limitations

                                  - + - +
                                  0 OffHERO11 BlackHERO11 Black
                                  1 OnHERO11 BlackHERO11 Black
                                  178
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>2.4GHz</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>1</td> <td>5GHz</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Wireless Band

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black

                                  @@ -8361,21 +8089,18 @@

                                  Limitations

                                  - + - +
                                  0 2.4GHzHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  1 5GHzHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  179
                                  integer
                                  Enum: 1 2 3
                                  Limitations <tbody><tr> <td>1</td> <td>Short</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>2</td> <td>Long</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>3</td> <td>Max</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Trail Length

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black

                                  @@ -8418,24 +8140,21 @@

                                  Limitations

                                  - + - + - +
                                  1 ShortHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  2 LongHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  3 MaxHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  180
                                  integer
                                  Enum: 0 101 102
                                  Limitations <tbody><tr> <td>0</td> <td>Highest Quality</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>101</td> <td>Extended Battery (Green Icon)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>102</td> <td>Longest Battery (Green Icon)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Video Mode

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO11 Black

                                  @@ -8476,24 +8192,21 @@

                                  Limitations

                                  - + - + - +
                                  0 Highest QualityHERO11 BlackHERO11 Black
                                  101 Extended Battery (Green Icon)HERO11 BlackHERO11 Black
                                  102 Longest Battery (Green Icon)HERO11 BlackHERO11 Black
                                  182
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>Standard</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>High</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Bit Rate

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -8529,19 +8239,16 @@

                                  Limitations

                                  - + - +
                                  0 StandardHERO12 BlackHERO12 Black
                                  1 HighHERO12 BlackHERO12 Black
                                  183
                                  integer
                                  Enum: 0 2
                                  Limitations <tbody><tr> <td>0</td> <td>8-Bit</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>10-Bit</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Bit Depth

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -8577,19 +8281,16 @@

                                  Limitations

                                  - + - +
                                  0 8-BitHERO12 BlackHERO12 Black
                                  2 10-BitHERO12 BlackHERO12 Black
                                  184
                                  integer
                                  Enum: 0 1 2
                                  Limitations <tbody><tr> <td>0</td> <td>Standard</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>HDR</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>Log</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Profiles

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -8630,24 +8328,21 @@

                                  Limitations

                                  - + - + - +
                                  0 StandardHERO12 BlackHERO12 Black
                                  1 HDRHERO12 BlackHERO12 Black
                                  2 LogHERO12 BlackHERO12 Black
                                  186
                                  integer
                                  Enum: 0 1 2
                                  Limitations <tbody><tr> <td>0</td> <td>Highest Quality</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>Standard Quality</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>Basic Quality</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Video Mode

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -8688,24 +8380,21 @@

                                  Limitations

                                  - + - + - +
                                  0 Highest QualityHERO12 BlackHERO12 Black
                                  1 Standard QualityHERO12 BlackHERO12 Black
                                  2 Basic QualityHERO12 BlackHERO12 Black
                                  187
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7
                                  Limitations <tbody><tr> <td>0</td> <td>TimeWarp</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>Star Trails</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>Light Painting</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>3</td> <td>Vehicle Lights</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>4</td> <td>Max TimeWarp</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>5</td> <td>Max Star Trails</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>6</td> <td>Max Light Painting</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>7</td> <td>Max Vehicle Lights</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Lapse Mode

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -8771,49 +8457,46 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - +
                                  0 TimeWarpHERO12 BlackHERO12 Black
                                  1 Star TrailsHERO12 BlackHERO12 Black
                                  2 Light PaintingHERO12 BlackHERO12 Black
                                  3 Vehicle LightsHERO12 BlackHERO12 Black
                                  4 Max TimeWarpHERO12 BlackHERO12 Black
                                  5 Max Star TrailsHERO12 BlackHERO12 Black
                                  6 Max Light PaintingHERO12 BlackHERO12 Black
                                  7 Max Vehicle LightsHERO12 BlackHERO12 Black
                                  189
                                  integer
                                  Enum: 0 1 2
                                  Limitations <tbody><tr> <td>0</td> <td>None</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>Max Lens 1.0</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>Max Lens 2.0</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Max Lens Mod

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -8854,24 +8534,21 @@

                                  Limitations

                                  - + - + - +
                                  0 NoneHERO12 BlackHERO12 Black
                                  1 Max Lens 1.0HERO12 BlackHERO12 Black
                                  2 Max Lens 2.0HERO12 BlackHERO12 Black
                                  190
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>On</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Max Lens Mod Enable

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -8907,19 +8581,16 @@

                                  Limitations

                                  - + - +
                                  0 OffHERO12 BlackHERO12 Black
                                  1 OnHERO12 BlackHERO12 Black
                                  191
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>Super Photo</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>Night Photo</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Photo Mode

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -8955,19 +8623,16 @@

                                  Limitations

                                  - + - +
                                  0 Super PhotoHERO12 BlackHERO12 Black
                                  1 Night PhotoHERO12 BlackHERO12 Black
                                  192
                                  integer
                                  Enum: 0 1 3
                                  Limitations <tbody><tr> <td>0</td> <td>4:3</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>16:9</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>3</td> <td>8:7</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Aspect Ratio

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -9008,24 +8670,21 @@

                                  Limitations

                                  - + - + - +
                                  0 4:3HERO12 BlackHERO12 Black
                                  1 16:9HERO12 BlackHERO12 Black
                                  3 8:7HERO12 BlackHERO12 Black
                                  193
                                  integer
                                  Enum: 0 1 2
                                  Limitations <tbody><tr> <td>0</td> <td>Widescreen</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>Vertical</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>Full Frame</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Framing

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -9066,40 +8722,39 @@

                                  Limitations

                                  - + - + - +
                                  0 WidescreenHERO12 BlackHERO12 Black
                                  1 VerticalHERO12 BlackHERO12 Black
                                  2 Full FrameHERO12 BlackHERO12 Black
                                  object

                                  All currently known status values indexed by status ID

                                  1
                                  integer
                                  Enum: 0 1

                                  Is the system's internal battery present?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  2
                                  integer
                                  Enum: 0 1 2 3 4
                                  Limitations <td>Charging</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Rough approximation of internal battery level in bars (or charging)

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -9165,141 +8817,138 @@

                                  Limitations

                                  Charging
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  3
                                  integer
                                  Enum: 0 1

                                  Is an external battery connected?

                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  4
                                  integer [ 0 .. 100 ]

                                  External battery power level in percent

                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  5
                                  integer

                                  Unused

                                  6
                                  integer
                                  Enum: 0 1

                                  Is the system currently overheating?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  7
                                  integer

                                  Unused

                                  8
                                  integer
                                  Enum: 0 1

                                  Is the camera busy?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  9
                                  integer
                                  Enum: 0 1

                                  Is Quick Capture feature enabled?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  10
                                  integer
                                  Enum: 0 1

                                  Is the system encoding right now?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  11
                                  integer
                                  Enum: 0 1

                                  Is LCD lock active?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  12
                                  integer

                                  Unused

                                  13
                                  integer

                                  When encoding video, this is the duration (seconds) of the video so far; 0 otherwise

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  14
                                  integer

                                  When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise

                                  +

                                  HERO12 Black +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  15
                                  integer

                                  (DEPRECATED) Number of Broadcast viewers

                                  +
                                  16
                                  integer

                                  (DEPRECATED) Broadcast B-Status

                                  17
                                  integer
                                  Enum: 0 1

                                  Are Wireless Connections enabled?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  18
                                  integer

                                  Unused

                                  19
                                  integer
                                  Enum: 0 1 2 3 4
                                  Limitations <td>Completed</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  The pairing state of the camera

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -9365,15 +9011,12 @@

                                  Limitations

                                  Completed
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  20
                                  integer
                                  Enum: 0 1 2 3
                                  Limitations <td>Pairing Bluetooth Device</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  The last type of pairing in which the camera was engaged

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -9431,31 +9071,22 @@

                                  Limitations

                                  Pairing Bluetooth Device
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  21
                                  integer

                                  Time since boot (milliseconds) of last successful pairing complete action

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  22
                                  integer
                                  Enum: 0 1 2 3 4
                                  Limitations <td>Completed</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  State of current scan for WiFi Access Points

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -9521,33 +9149,24 @@

                                  Limitations

                                  Completed
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  23
                                  integer

                                  Time since boot (milliseconds) that the WiFi Access Point scan completed

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  24
                                  integer
                                  Enum: 0 1 2 3 4
                                  Limitations <td>Completed</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  WiFi AP provisioning state

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -9613,137 +9229,94 @@

                                  Limitations

                                  Completed
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  25
                                  integer

                                  Unused

                                  26
                                  integer

                                  Wireless remote control version

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  27
                                  integer
                                  Enum: 0 1

                                  Is a wireless remote control connected?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  28
                                  integer

                                  Wireless Pairing State. Each bit contains state information (see WirelessPairingStateFlags)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  29
                                  string

                                  SSID of the AP the camera is currently connected to. On BLE connection, value is big-endian byte-encoded int32

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  30
                                  string

                                  The camera's WiFi SSID. On BLE connection, value is big-endian byte-encoded int32

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  31
                                  integer

                                  The number of wireless devices connected to the camera

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  32
                                  integer
                                  Enum: 0 1

                                  Is Preview Stream enabled?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  33
                                  integer
                                  Enum: -1 0 1 2 3 4 8
                                  Limitations <td>SD Card Swapped</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Primary Storage Status

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -9825,85 +9395,78 @@

                                  Limitations

                                  SD Card Swapped
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  34
                                  integer

                                  How many photos can be taken with current settings before sdcard is full

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  35
                                  integer

                                  How many minutes of video can be captured with current settings before sdcard is full

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  36
                                  integer

                                  Total number of group photos on sdcard

                                  +

                                  HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  37
                                  integer

                                  Total number of group videos on sdcard

                                  +

                                  HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  38
                                  integer

                                  Total number of photos on sdcard

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  39
                                  integer

                                  Total number of videos on sdcard

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  40
                                  string

                                  Current date/time (format: %YY%mm%dd%HH%MM%SS, all values in hex)

                                  41
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10
                                  Limitations <td>GoPro App: Ready</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  The current status of Over The Air (OTA) update

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -10017,195 +9577,247 @@

                                  Limitations

                                  GoPro App: Ready
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  42
                                  integer
                                  Enum: 0 1

                                  Is there a pending request to cancel a firmware update download?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  43
                                  integer

                                  Current mode group (deprecated in HERO8)

                                  +
                                  44
                                  integer

                                  Current submode (deprecated in HERO8)

                                  45
                                  integer
                                  Enum: 0 1

                                  Is locate camera feature active?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  46
                                  integer
                                  Enum: 0 1

                                  Are Video Protune settings currently factory default?

                                  +
                                  47
                                  integer
                                  Enum: 0 1

                                  Are Photo Protune settings currently factory default?

                                  +
                                  48
                                  integer
                                  Enum: 0 1

                                  Are Multishot Protune settings currently factory default?

                                  49
                                  integer

                                  The current timelapse interval countdown value (e.g. 5...4...3...2...1...)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  50
                                  integer

                                  Unused

                                  +
                                  51
                                  integer

                                  Unused

                                  +
                                  52
                                  integer

                                  Unused

                                  +
                                  53
                                  integer

                                  Unused

                                  54
                                  integer

                                  Remaining space on the sdcard in Kilobytes

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  55
                                  integer
                                  Enum: 0 1

                                  Is preview stream supported in current recording/mode/secondary-stream?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  56
                                  integer

                                  WiFi signal strength in bars

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  57
                                  integer

                                  Time in milliseconds since system was booted

                                  58
                                  integer

                                  The number of hilights in currently-encoding video (value is set to 0 when encoding stops)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  59
                                  integer

                                  Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  60
                                  integer

                                  The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  61
                                  integer
                                  Enum: 0 1 2

                                  The current state of camera analytics

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  + + + + + + + + + + + + + + + + + + + +
                                  ValueMeaning
                                  0Not ready
                                  1Ready
                                  2On connect
                                  +
                                  62
                                  integer
                                  Value: 0

                                  The size (units??) of the analytics file

                                  +

                                  HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  + + + + + + + + + + + +
                                  ValueMeaning
                                  0Value hard-coded by BOSS in libgpCtrlD/src/camera_status.cpp
                                  +
                                  63
                                  integer
                                  Enum: 0 1

                                  Is the camera currently in a contextual menu (e.g. Preferences)?

                                  +

                                  HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  64
                                  integer

                                  How many minutes of Time Lapse Video can be captured with current settings before sdcard is full

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  65
                                  integer
                                  Enum: 0 1 2 3
                                  Limitations <td>Hemisphere</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Liveview Exposure Select Mode

                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  @@ -10262,100 +9871,74 @@

                                  Limitations

                                  Hemisphere
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  66
                                  integer [ 0 .. 100 ]

                                  Liveview Exposure Select: y-coordinate (percent)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  67
                                  integer [ 0 .. 100 ]

                                  Liveview Exposure Select: y-coordinate (percent)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  68
                                  integer
                                  Enum: 0 1

                                  Does the camera currently have a GPS lock?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  69
                                  integer
                                  Enum: 0 1

                                  Is the camera in AP Mode?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  70
                                  integer [ 0 .. 100 ]

                                  Internal battery level (percent)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  71
                                  integer

                                  The current video group flatmode (id)

                                  +
                                  72
                                  integer

                                  The current photo group flatmode (id)

                                  +
                                  73
                                  integer

                                  The current timelapse group flatmode (id)

                                  74
                                  integer
                                  Enum: 0 1 2
                                  Limitations <td>Accessory connected and a microphone is plugged into the accessory</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Microphone Accessory status

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -10405,33 +9985,24 @@

                                  Limitations

                                  Accessory connected and a microphone is plugged into the accessory
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  75
                                  integer [ 0 .. 100 ]

                                  Digital Zoom level (percent)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  76
                                  integer
                                  Enum: 0 1
                                  Limitations <td>5 GHz</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Wireless Band

                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -10473,135 +10041,166 @@

                                  Limitations

                                  5 GHz
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  77
                                  integer
                                  Enum: 0 1

                                  Is Digital Zoom feature available?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  78
                                  integer
                                  Enum: 0 1

                                  Are current video settings mobile friendly? (related to video compression and frame rate)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  79
                                  integer
                                  Enum: 0 1

                                  Is the camera currently in First Time Use (FTU) UI flow?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO10 Black + HERO9 Black

                                  +
                                  80
                                  integer
                                  Enum: -1 0 1 2 3 4 8

                                  Secondary Storage Status (exclusive to Superbank)

                                  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                  ValueMeaning
                                  -1Unknown
                                  0OK
                                  1SD Card Full
                                  2SD Card Removed
                                  3SD Card Format Error
                                  4SD Card Busy
                                  8SD Card Swapped
                                  81
                                  integer
                                  Enum: 0 1

                                  Is 5GHz wireless band available?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  82
                                  integer
                                  Enum: 0 1

                                  Is the system fully booted and ready to accept commands?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  83
                                  integer
                                  Enum: 0 1

                                  Is the internal battery charged sufficiently to start Over The Air (OTA) update?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  84
                                  integer

                                  Current Capture Delay value (HERO7 only)

                                  85
                                  integer
                                  Enum: 0 1

                                  Is the camera getting too cold to continue recording?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  86
                                  integer
                                  Enum: 0 1 2 3
                                  Limitations <td>270 degrees (laying on left side)</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Rotational orientation of the camera

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -10659,203 +10255,162 @@

                                  Limitations

                                  270 degrees (laying on left side)
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  87
                                  integer
                                  Enum: 0 1

                                  Can camera use high resolution/fps (based on temperature)? (HERO7 Silver/White only)

                                  88
                                  integer
                                  Enum: 0 1

                                  Is this camera model capable of zooming while encoding?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  89
                                  integer

                                  Current Flatmode ID

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  90
                                  integer
                                  Enum: 0 1

                                  Are current flatmode's Protune settings factory default?

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  91
                                  integer
                                  Enum: 0 1

                                  Are system logs ready to be downloaded?

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  92
                                  integer
                                  Enum: 0 1

                                  Is Timewarp 1x active?

                                  93
                                  integer

                                  Current Video Preset (ID)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  94
                                  integer

                                  Current Photo Preset (ID)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  95
                                  integer

                                  Current Time Lapse Preset (ID)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  96
                                  integer

                                  Current Preset Group (ID) (corresponds to ui_mode_groups in settings.json)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  97
                                  integer

                                  Current Preset (ID)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  98
                                  integer

                                  Preset Modified Status, which contains an event ID and a Preset (Group) ID

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  99
                                  integer

                                  The number of Live Bursts can be captured with current settings before sdcard is full

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO11 Black +HERO10 Black + HERO9 Black

                                  100
                                  integer

                                  Total number of Live Bursts on sdcard

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO11 Black + HERO10 Black +HERO9 Black

                                  101
                                  integer
                                  Enum: 0 1

                                  Is Capture Delay currently active (i.e. counting down)?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  102
                                  integer
                                  Enum: 0 2 3
                                  Limitations <td>Media Mod microphone with external microphone</td> </tr> </tbody></table> -<p> Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Media Mod state

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -10905,15 +10457,12 @@

                                  Limitations

                                  Media Mod microphone with external microphone
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  103
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 12
                                  Limitations <td>1/2x (slow-motion)</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Time Warp Speed

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -11043,27 +10589,18 @@

                                  Limitations

                                  1/2x (slow-motion)
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  104
                                  integer
                                  Enum: 0 1

                                  Is the system's Linux core active?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO10 Black + HERO9 Black

                                  105
                                  integer
                                  Enum: 0 1 2
                                  Limitations <td>Max Lens 2.0</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Camera lens type (reflects changes to setting 162 or setting 189)

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -11113,63 +10647,51 @@

                                  Limitations

                                  Max Lens 2.0
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  106
                                  integer
                                  Enum: 0 1

                                  Is Video Hindsight Capture Active?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  107
                                  integer

                                  Scheduled Capture Preset ID

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  108
                                  integer
                                  Enum: 0 1

                                  Is Scheduled Capture set?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  109
                                  integer
                                  Enum: 0 1

                                  Is the camera in the process of creating a custom preset?

                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  110
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7
                                  Limitations <td>111 = Display Mod: 1, HDMI: 1, Display Mod Connected: True</td> </tr> </tbody></table> -<p> Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Display Mod Status (bitmasked)

                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  @@ -11258,64 +10777,43 @@

                                  Limitations

                                  111 = Display Mod: 1, HDMI: 1, Display Mod Connected: True
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  111
                                  integer
                                  Enum: 0 1

                                  Does sdcard meet specified minimum write speed?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black

                                  112
                                  integer

                                  Number of sdcard write speed errors since device booted

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black

                                  113
                                  integer
                                  Enum: 0 1

                                  Is Turbo Transfer active?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  114
                                  integer
                                  Enum: 0 1 2
                                  Limitations <td>Camera External Control: An outside entity (app) has control and is in a menu or modifying settings</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Camera control status ID

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black

                                  @@ -11364,30 +10859,21 @@

                                  Limitations

                                  Camera External Control: An outside entity (app) has control and is in a menu or modifying settings
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  115
                                  integer
                                  Enum: 0 1

                                  Is the camera connected to a PC via USB?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black

                                  116
                                  integer
                                  Enum: 0 1
                                  Limitations <td>Enabled</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Camera control over USB state

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black

                                  @@ -11428,28 +10911,15 @@

                                  Limitations

                                  Enabled
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  117
                                  integer

                                  Total SD card capacity in Kilobytes

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  -
                                  {
                                  • "settings": {
                                    },
                                  • "status": {
                                    }
                                  }

                                  VideoMetadata

                                  ao
                                  required
                                  string
                                  Enum: "auto" "wind" "stereo" "off"
                                  Example: "auto"
                                  + HERO11 Black Mini +HERO11 Black

                                  +
                                  {
                                  • "settings": {
                                    },
                                  • "status": {
                                    }
                                  }

                                  VideoMetadata

                                  ao
                                  required
                                  string
                                  Enum: "auto" "wind" "stereo" "off"
                                  Example: "auto"

                                  Audio option

                                  avc_profile
                                  required
                                  integer [ 0 .. 255 ]
                                  Example: "0"

                                  Advanced Video Code Profile

                                  @@ -11735,40 +11205,32 @@

                                  Limitations

                                  the camera to begin the update process. Chunks are stored until they are explicitly deleted, allowing the client to stop and resume as needed. Details can be found in the diagram below.

                                  simple ota state diagram

                                  -

                                  Resumable OTA Update

                                  Resumable OTA Update

                                  Perform Resumable OTA Update

                                  -

                                  To send a portion of the OTA image as per the requestBody specification, do not use the request parameter.

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +<p>Perform Resumable OTA Update</p> +<p>To send a portion of the OTA image as per the requestBody specification, do not use the <code>request</code> parameter.</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Perform Resumable OTA Update

                                  +

                                  To send a portion of the OTA image as per the requestBody specification, do not use the request parameter.

                                  query Parameters
                                  request
                                  string
                                  Enum: "delete" "showui" "start" "progress" "cancelled"
                                  Limitations

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "bytes_complete": 0,
                                  • "complete": true,
                                  • "message": "string",
                                  • "sha1": "string",
                                  • "status": 0
                                  }

                                  Simple OTA Update

                                  http://10.5.5.9:8080/gp/gpSoftUpdate

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "bytes_complete": 0,
                                  • "complete": true,
                                  • "message": "string",
                                  • "sha1": "string",
                                  • "status": 0
                                  }

                                  Simple OTA Update


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  Request Body schema: multipart/form-data
                                  DirectToSD
                                  integer

                                  Always set to 1

                                  file
                                  string <binary>
                                  Limitations <p>To find the currently available Presets / Preset Groups, use <a href="#operation/OGP_PRESETS_GET">Get Preset Status</a>.</p> ">

                                  Presets are organized into Preset Groups.

                                  To find the currently available Presets / Preset Groups, use Get Preset Status.

                                  -

                                  Get Available Presets

                                  Get Available Presets

                                  Get the currently available Preset Groups and Presets, the set of which -depends on the current camera settings.

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +<p>Get the currently available Preset Groups and Presets, the set of which +<a href="#tag/Presets/Presets">depends</a> on the current camera settings.</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Get the currently available Preset Groups and Presets, the set of which +depends on the current camera settings.

                                  Responses

                                  Response Schema: application/json
                                  Array of objects
                                  Limitations " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  start index of range

                                  Array of objects (PresetGroup)

                                  Array of Preset Groups

                                  -
                                  Array
                                  can_add_preset
                                  boolean
                                  Array
                                  canAddPreset
                                  boolean

                                  Is there room in the group to add additional Presets?

                                  icon
                                  integer (EnumPresetGroupIcon)
                                  Enum: 0 1 2 3 4 5 6 7
                                  Limitations
                                  -
                                  Array of objects (Preset)
                                  Array of objects (Preset)

                                  Array of Presets contained in this Preset Group

                                  Array
                                  icon
                                  integer (EnumPresetIcon)
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 58 59 60 61 62 63 64 65 66 67 70 71 73 74 75 76 77 78 79 1000 1001
                                  Limitations
                                  id
                                  integer <int32>

                                  Unique preset identifier

                                  -
                                  is_fixed
                                  boolean
                                  isFixed
                                  boolean

                                  Is this preset mutable?

                                  -
                                  is_modified
                                  boolean
                                  isModified
                                  boolean

                                  Has the preset been modified from the factory defaults?

                                  mode
                                  integer (EnumFlatMode)
                                  Enum: -1 4 5 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
                                  Limitations
                                  -
                                  Array of objects (PresetSetting)
                                  Array
                                  id
                                  integer <int32>
                                  Array of objects (PresetSetting)
                                  Array
                                  id
                                  integer <int32>

                                  Setting identifier

                                  -
                                  is_caption
                                  boolean
                                  isCaption
                                  boolean

                                  Does this setting appear on the Preset "pill" in the camera UI?

                                  value
                                  integer <int32>

                                  Setting value

                                  -
                                  title_id
                                  integer (EnumPresetTitle)
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 13 14 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 82 83 93 94
                                  titleId
                                  integer (EnumPresetTitle)
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 13 14 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 82 83 93 94
                                  Limitations
                                  -
                                  title_number
                                  integer <int32>
                                  titleNumber
                                  integer <int32>

                                  Preset title number

                                  -
                                  user_defined
                                  boolean
                                  userDefined
                                  boolean

                                  Is this preset user defined?

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "customIconIds": [
                                    ],
                                  • "customTitleIds": [
                                    ],
                                  • "presetGroupArray": [
                                    ]
                                  }

                                  Load Preset by ID

                                  http://10.5.5.9:8080/gopro/camera/presets/get

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "customIconIds": [
                                    ],
                                  • "customTitleIds": [
                                    ],
                                  • "presetGroupArray": [
                                    ]
                                  }

                                  Load Preset by ID

                                  Preset ID's are not constant and must be retrieved via Get Preset Status

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +<p>Preset ID&#39;s are not constant and must be retrieved via <a href="#operation/OGP_PRESETS_GET">Get Preset Status</a></p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Preset ID's are not constant and must be retrieved via Get Preset Status

                                  query Parameters
                                  id
                                  integer

                                  Preset to load

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Load Preset Group by ID

                                  http://10.5.5.9:8080/gopro/camera/presets/load

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Load Preset Group by ID


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  query Parameters
                                  id
                                  integer (EnumPresetGroup)
                                  Enum: 1000 1001 1002
                                  Limitations " class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS sc-ckdEwu LxEPk">

                                  Request was successfully received by the camera

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Update Custom Preset

                                  http://10.5.5.9:8080/gopro/camera/presets/set_group

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Update Custom Preset

                                  Limitations </li> </ol> <p>Note! The range of acceptable custom <code>title_id</code>&#39;s and <code>icon_id</code>&#39;s can be found in the - <a href="#operation/OGP_PRESETS_GET">Get Preset Status</a> response</p> -<hr> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -</ul> -<hr> -<p>Supported Protocols:</p> -<ul> -<li>WIFI</li> -<li>USB</li> -</ul> -" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  This only operates on the currently active Preset and will fail if the current +<a href="#operation/OGP_PRESETS_GET">Get Preset Status</a> response</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black

                                  +

                                  Supported Protocols:

                                  +
                                    +
                                  • USB
                                  • +
                                  • WIFI
                                  • +
                                  +
                                  +

                                  This only operates on the currently active Preset and will fail if the current Preset is not custom.

                                  The use cases are:

                                    @@ -14261,18 +13694,7 @@

                                    Limitations

                                  Note! The range of acceptable custom title_id's and icon_id's can be found in the - Get Preset Status response

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  -
                                  -

                                  Supported Protocols:

                                  -
                                    -
                                  • WIFI
                                  • -
                                  • USB
                                  • -
                                  +Get Preset Status response

                                  Request Body schema: application/json
                                  required
                                  custom_name
                                  string
                                  Limitations ">

                                  When the preview stream is started, the camera starts up a UDP client and begins writing MPEG Transport Stream data to the client on port 8554. In order to stream this data, the client must implement a UDP connection that binds to the same port and decode the data.

                                  -

                                  Start the Preview Stream

                                  Start Preview Stream


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  query Parameters
                                  port
                                  integer
                                  Example: port=8556
                                  Limitations " class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS sc-ckdEwu LxEPk">

                                  Request was successfully received by the camera

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Stop the Preview Stream

                                  http://10.5.5.9:8080/gopro/camera/stream/start

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Stop Preview Stream


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Query

                                  Get information about the camera

                                  -

                                  Get Camera State

                                  Get Camera State

                                  Get all camera settings and statuses.

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +<p>Get all camera settings and statuses.</p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Get all camera settings and statuses.

                                  Responses

                                  Response Schema: application/json
                                  object

                                  All currently known setting values indexed by setting ID

                                  2
                                  integer
                                  Enum: 1 4 6 7 9 18 24 25 26 27 28 100 107 108 109 110 111
                                  Limitations <tbody><tr> <td>1</td> <td>4K</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>4</td> <td>2.7K</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>6</td> <td>2.7K 4:3</td> -<td>HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>7</td> <td>1440</td> -<td>HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>9</td> <td>1080</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>18</td> <td>4K 4:3</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>24</td> <td>5K</td> -<td>HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>25</td> <td>5K 4:3</td> -<td>HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> <tr> <td>26</td> <td>5.3K 8:7</td> -<td>HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>27</td> <td>5.3K 4:3</td> -<td>HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>28</td> <td>4K 8:7</td> -<td>HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>100</td> <td>5.3K</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> <tr> <td>107</td> <td>5.3K</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>108</td> <td>4K</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>109</td> <td>4K</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>110</td> <td>1080</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>111</td> <td>2.7K</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Resolution

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -15868,98 +15260,95 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
                                  1 4KHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  4 2.7KHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  6 2.7K 4:3HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  7 1440HERO9 BlackHERO9 Black
                                  9 1080HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  18 4K 4:3HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  24 5KHERO9 BlackHERO9 Black
                                  25 5K 4:3HERO10 BlackHERO10 Black
                                  26 5.3K 8:7HERO11 Black Mini, HERO11 BlackHERO11 Black MiniHERO11 Black
                                  27 5.3K 4:3HERO11 Black Mini, HERO11 BlackHERO11 Black MiniHERO11 Black
                                  28 4K 8:7HERO11 Black Mini, HERO11 BlackHERO11 Black MiniHERO11 Black
                                  100 5.3KHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 Black
                                  107 5.3KHERO12 BlackHERO12 Black
                                  108 4KHERO12 BlackHERO12 Black
                                  109 4KHERO12 BlackHERO12 Black
                                  110 1080HERO12 BlackHERO12 Black
                                  111 2.7KHERO12 BlackHERO12 Black
                                  3
                                  integer
                                  Enum: 0 1 2 5 6 8 9 10 13
                                  Limitations <tbody><tr> <td>0</td> <td>240</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>1</td> <td>120</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>2</td> <td>100</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>5</td> <td>60</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>6</td> <td>50</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>8</td> <td>30</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>9</td> <td>25</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>10</td> <td>24</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>13</td> <td>200</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Frames Per Second

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -16034,58 +15420,55 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - + - +
                                  0 240HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  1 120HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  2 100HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  5 60HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  6 50HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  8 30HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  9 25HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  10 24HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  13 200HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  43
                                  integer
                                  Enum: 0 2 3 4
                                  Limitations <tbody><tr> <td>0</td> <td>Wide</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>2</td> <td>Narrow</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>3</td> <td>Superview</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>4</td> <td>Linear</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Webcam Digital Lenses

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -16135,33 +15515,30 @@

                                  Limitations

                                  - + - + - + - +
                                  0 WideHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  2 NarrowHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  3 SuperviewHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  4 LinearHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  59
                                  integer
                                  Enum: 0 1 4 6 7 11 12
                                  Limitations <tbody><tr> <td>0</td> <td>Never</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>1</td> <td>1 Min</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>4</td> <td>5 Min</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>6</td> <td>15 Min</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>7</td> <td>30 Min</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>11</td> <td>8 Seconds</td> -<td>HERO11 Black Mini</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"></td> </tr> <tr> <td>12</td> <td>30 Seconds</td> -<td>HERO11 Black Mini</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Auto Power Down

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -16226,44 +15600,87 @@

                                  Limitations

                                  - + - + - + - + - + - + - + + +
                                  0 NeverHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  1 1 MinHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  4 5 MinHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  6 15 MinHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  7 30 MinHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  11 8 SecondsHERO11 Black MiniHERO11 Black Mini
                                  12 30 SecondsHERO11 Black MiniHERO11 Black Mini
                                  +
                                  83
                                  integer
                                  Enum: 0 1

                                  GPS

                                  +

                                  HERO11 Black +HERO10 Black + HERO9 Black

                                  + + + + + + + + + + + + + + + + +
                                  ValueMeaningSupported Cameras
                                  0OffHERO11 BlackHERO10 BlackHERO9 Black
                                  1OnHERO11 BlackHERO10 BlackHERO9 Black
                                  108
                                  integer
                                  Enum: 0 1 3 4
                                  Limitations <tbody><tr> <td>0</td> <td>4:3</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>16:9</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>3</td> <td>8:7</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>4</td> <td>9:16</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Aspect Ratio

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -16309,33 +15723,30 @@

                                  Limitations

                                  - + - + - + - +
                                  0 4:3HERO12 BlackHERO12 Black
                                  1 16:9HERO12 BlackHERO12 Black
                                  3 8:7HERO12 BlackHERO12 Black
                                  4 9:16HERO12 BlackHERO12 Black
                                  121
                                  integer
                                  Enum: 0 2 3 4 7 8 9 10 11
                                  Limitations <tbody><tr> <td>0</td> <td>Wide</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>2</td> <td>Narrow</td> -<td>HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>3</td> <td>Superview</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>4</td> <td>Linear</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>7</td> <td>Max SuperView</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>8</td> <td>Linear + Horizon Leveling</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>9</td> <td>HyperView</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>10</td> <td>Linear + Horizon Lock</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>11</td> <td>Max HyperView</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Lens

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -16410,57 +15818,54 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - + - +
                                  0 WideHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  2 NarrowHERO10 Black, HERO9 BlackHERO10 BlackHERO9 Black
                                  3 SuperviewHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  4 LinearHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  7 Max SuperViewHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  8 Linear + Horizon LevelingHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  9 HyperViewHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  10 Linear + Horizon LockHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  11 Max HyperViewHERO12 BlackHERO12 Black
                                  122
                                  integer
                                  Enum: 19 100 101 102
                                  Limitations <tbody><tr> <td>19</td> <td>Narrow</td> -<td>HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>100</td> <td>Max SuperView</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>101</td> <td>Wide</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>102</td> <td>Linear</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Lens

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -16509,32 +15911,29 @@

                                  Limitations

                                  - + - + - + - +
                                  19 NarrowHERO10 Black, HERO9 BlackHERO10 BlackHERO9 Black
                                  100 Max SuperViewHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  101 WideHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  102 LinearHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  123
                                  integer
                                  Enum: 19 100 101 102
                                  Limitations <tbody><tr> <td>19</td> <td>Narrow</td> -<td>HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>100</td> <td>Max SuperView</td> -<td>HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> <tr> <td>101</td> <td>Wide</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>102</td> <td>Linear</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Time Lapse Digital Lenses

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  @@ -16583,32 +15979,29 @@

                                  Limitations

                                  - + - + - + - +
                                  19 NarrowHERO10 Black, HERO9 BlackHERO10 BlackHERO9 Black
                                  100 Max SuperViewHERO10 BlackHERO10 Black
                                  101 WideHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  102 LinearHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  128
                                  integer
                                  Enum: 13 20 21 26
                                  Limitations <tbody><tr> <td>13</td> <td>Time Lapse Video</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>20</td> <td>Time Lapse Photo</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>21</td> <td>Night Lapse Photo</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>26</td> <td>Night Lapse Video</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Media Format

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black +HERO10 Black + HERO9 Black

                                  @@ -16657,33 +16047,30 @@

                                  Limitations

                                  - + - + - + - +
                                  13 Time Lapse VideoHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  20 Time Lapse PhotoHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  21 Night Lapse PhotoHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  26 Night Lapse VideoHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  134
                                  integer
                                  Enum: 2 3
                                  Limitations <tbody><tr> <td>2</td> <td>60Hz</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>3</td> <td>50Hz</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Anti-Flicker

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -16723,23 +16107,20 @@

                                  Limitations

                                  - + - +
                                  2 60HzHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  3 50HzHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  135
                                  integer
                                  Enum: 0 1 2 3 4 100
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>1</td> <td>Low</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>2</td> <td>High</td> -<td>HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>3</td> <td>Boost</td> -<td>HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>4</td> <td>Auto Boost</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>100</td> <td>Standard</td> -<td>HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Hypersmooth

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -16799,39 +16177,36 @@

                                  Limitations

                                  - + - + - + - + - + - +
                                  0 OffHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  1 LowHERO12 Black, HERO11 Black Mini, HERO11 Black, HERO9 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO9 Black
                                  2 HighHERO10 Black, HERO9 BlackHERO10 BlackHERO9 Black
                                  3 BoostHERO11 Black Mini, HERO11 Black, HERO10 Black, HERO9 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  4 Auto BoostHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  100 StandardHERO10 BlackHERO10 Black
                                  150
                                  integer
                                  Enum: 0 2
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>2</td> <td>Locked</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Horizon Leveling

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO11 Black

                                  @@ -16867,19 +16239,16 @@

                                  Limitations

                                  - + - +
                                  0 OffHERO11 BlackHERO11 Black
                                  2 LockedHERO11 BlackHERO11 Black
                                  151
                                  integer
                                  Enum: 0 2
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>2</td> <td>Locked</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Horizon Leveling

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO11 Black

                                  @@ -16915,21 +16281,18 @@

                                  Limitations

                                  - + - +
                                  0 OffHERO11 BlackHERO11 Black
                                  2 LockedHERO11 BlackHERO11 Black
                                  162
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>1</td> <td>On</td> -<td>HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Max Lens

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO11 Black +HERO10 Black +HERO9 Black

                                  @@ -16967,22 +16327,19 @@

                                  Limitations

                                  - + - +
                                  0 OffHERO11 Black, HERO10 Black, HERO9 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  1 OnHERO11 Black, HERO10 Black, HERO9 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  167
                                  integer
                                  Enum: 2 3 4
                                  Limitations <tbody><tr> <td>2</td> <td>15 Seconds</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>3</td> <td>30 Seconds</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> <tr> <td>4</td> <td>Off</td> -<td>HERO12 Black, HERO11 Black, HERO10 Black, HERO9 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"><img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  HindSight

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black +HERO10 Black + HERO9 Black

                                  @@ -17026,24 +16380,21 @@

                                  Limitations

                                  - + - + - +
                                  2 15 SecondsHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  3 30 SecondsHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  4 OffHERO12 Black, HERO11 Black, HERO10 Black, HERO9 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  171
                                  integer
                                  Enum: 0 2 3 4 5 6 7 8 9 10
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>0.5s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>3</td> <td>1s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>4</td> <td>2s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>5</td> <td>5s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>6</td> <td>10s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>7</td> <td>30s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>8</td> <td>60s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>9</td> <td>120s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>10</td> <td>3s</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Interval

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -17119,59 +16467,56 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - + - + - +
                                  0 OffHERO12 BlackHERO12 Black
                                  2 0.5sHERO12 BlackHERO12 Black
                                  3 1sHERO12 BlackHERO12 Black
                                  4 2sHERO12 BlackHERO12 Black
                                  5 5sHERO12 BlackHERO12 Black
                                  6 10sHERO12 BlackHERO12 Black
                                  7 30sHERO12 BlackHERO12 Black
                                  8 60sHERO12 BlackHERO12 Black
                                  9 120sHERO12 BlackHERO12 Black
                                  10 3sHERO12 BlackHERO12 Black
                                  172
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7 8 9
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>15 Seconds</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>30 Seconds</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>3</td> <td>1 Minute</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>4</td> <td>5 Minutes</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>5</td> <td>15 Minutes</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>6</td> <td>30 Minutes</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>7</td> <td>1 Hour</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>8</td> <td>2 Hours</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>9</td> <td>3 Hours</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Duration

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -17247,59 +16589,56 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - + - + - +
                                  0 OffHERO12 BlackHERO12 Black
                                  1 15 SecondsHERO12 BlackHERO12 Black
                                  2 30 SecondsHERO12 BlackHERO12 Black
                                  3 1 MinuteHERO12 BlackHERO12 Black
                                  4 5 MinutesHERO12 BlackHERO12 Black
                                  5 15 MinutesHERO12 BlackHERO12 Black
                                  6 30 MinutesHERO12 BlackHERO12 Black
                                  7 1 HourHERO12 BlackHERO12 Black
                                  8 2 HoursHERO12 BlackHERO12 Black
                                  9 3 HoursHERO12 BlackHERO12 Black
                                  173
                                  integer
                                  Enum: 0 1 2
                                  Limitations <tbody><tr> <td>0</td> <td>Maximum Video Performance</td> -<td>HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> <tr> <td>1</td> <td>Extended Battery</td> -<td>HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> <tr> <td>2</td> <td>Tripod / Stationary Video</td> -<td>HERO10 Black</td> +<td><img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Video Performance Mode

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO10 Black
                                  • -
                                  +

                                  HERO10 Black

                                  @@ -17340,25 +16676,22 @@

                                  Limitations

                                  - + - + - +
                                  0 Maximum Video PerformanceHERO10 BlackHERO10 Black
                                  1 Extended BatteryHERO10 BlackHERO10 Black
                                  2 Tripod / Stationary VideoHERO10 BlackHERO10 Black
                                  175
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>Easy</td> -<td>HERO12 Black, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>1</td> <td>Pro</td> -<td>HERO12 Black, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Controls

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black

                                  @@ -17395,20 +16725,17 @@

                                  Limitations

                                  - + - +
                                  0 EasyHERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black
                                  1 ProHERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black
                                  176
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
                                  Limitations <tbody><tr> <td>0</td> <td>8X Ultra Slo-Mo</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>1</td> <td>4X Super Slo-Mo</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>2</td> <td>2X Slo-Mo</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>3</td> <td>1X Speed (Low Light)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>4</td> <td>4X Super Slo-Mo (Ext. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>5</td> <td>2X Slo-Mo (Ext. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>6</td> <td>1X Speed (Ext. Batt.) (Low Light)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>7</td> <td>8X Ultra Slo-Mo (50Hz)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>8</td> <td>4X Super Slo-Mo (50Hz)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>9</td> <td>2X Slo-Mo (50Hz)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>10</td> <td>1X Speed (50Hz) (Low Light)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>11</td> <td>4X Super Slo-Mo (50Hz) (Ext. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>12</td> <td>2X Slo-Mo (50Hz) (Ext. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>13</td> <td>1X Speed (50Hz) (Ext. Batt.) (Low Light)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>14</td> <td>8X Ultra Slo-Mo (Ext. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>15</td> <td>8X Ultra Slo-Mo (50Hz) (Ext. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>16</td> <td>8X Ultra Slo-Mo (Long. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>17</td> <td>4X Super Slo-Mo (Long. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>18</td> <td>2X Slo-Mo (Long. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>19</td> <td>1X Speed (Long. Batt.) (Low Light)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>20</td> <td>8X Ultra Slo-Mo (50Hz) (Long. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>21</td> <td>4X Super Slo-Mo (50Hz) (Long. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>22</td> <td>2X Slo-Mo (50Hz) (Long. Batt.)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>23</td> <td>1X Speed (50Hz) (Long. Batt.) (Low Light)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>24</td> <td>2X Slo-Mo (4K)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>25</td> <td>4X Super Slo-Mo (2.7K)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>26</td> <td>2X Slo-Mo (4K) (50Hz)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>27</td> <td>4X Super Slo-Mo (2.7K) (50Hz)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>100</td> <td>8X Ultra Slo-Mo (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>101</td> <td>4X Super Slo-Mo (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>102</td> <td>2X Slo-Mo (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>103</td> <td>1X Speed (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>104</td> <td>8X Ultra Slo-Mo (50Hz) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>105</td> <td>4X Super Slo-Mo (50Hz) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>106</td> <td>2X Slo-Mo (50Hz) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>107</td> <td>1X Speed (50Hz) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>108</td> <td>8X Ultra Slo-Mo (Long. Batt.) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>109</td> <td>4X Super Slo-Mo (Long. Batt.) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>110</td> <td>2X Slo-Mo (Long. Batt.) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>111</td> <td>1X Speed (Long. Batt.) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>112</td> <td>8X Ultra Slo-Mo (50Hz) (Long. Batt.) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>113</td> <td>4X Super Slo-Mo (50Hz) (Long. Batt.) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>114</td> <td>2X Slo-Mo (50Hz) (Long. Batt.) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>115</td> <td>1X Speed (50Hz) (Long. Batt.) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>116</td> <td>2X Slo-Mo (4K) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>117</td> <td>2X Slo-Mo (4K) (50Hz) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>118</td> <td>1X Speed (Low Light) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>119</td> <td>1X Speed (50Hz) (Low Light) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>120</td> <td>2X Slo-Mo (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>121</td> <td>2X Slo-Mo (50Hz) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>122</td> <td>1X Speed (Full Frame) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>123</td> <td>1X Speed (50Hz) (Full Frame) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>124</td> <td>2X Slo-Mo (Full Frame) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>125</td> <td>2X Slo-Mo (50Hz) (Full Frame) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>126</td> <td>1X Speed (4K) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>127</td> <td>1X Speed (4K) (50Hz) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>128</td> <td>1X Speed (2.7K) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>129</td> <td>1X Speed (2.7K) (50Hz) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>130</td> <td>2X Slo-Mo (2.7K) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>131</td> <td>2X Slo-Mo (2.7K) (50Hz) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>132</td> <td>2X Slo-Mo (Long. Batt.) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>133</td> <td>2X Slo-Mo (50Hz) (Long. Batt.) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>134</td> <td>1X Speed (Long. Batt.) (Low Light) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>135</td> <td>1X Speed (50Hz) (Long. Batt.) (Low Light) (V2) (Vertical)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>136</td> <td>1X Speed (4K) (Full Frame) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>137</td> <td>1X Speed (4K) (50Hz) (Full Frame) (Low Light) (V2)</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Easy Mode Speed

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black

                                  @@ -17765,339 +17089,336 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
                                  0 8X Ultra Slo-MoHERO11 BlackHERO11 Black
                                  1 4X Super Slo-MoHERO11 BlackHERO11 Black
                                  2 2X Slo-MoHERO11 BlackHERO11 Black
                                  3 1X Speed (Low Light)HERO11 BlackHERO11 Black
                                  4 4X Super Slo-Mo (Ext. Batt.)HERO11 BlackHERO11 Black
                                  5 2X Slo-Mo (Ext. Batt.)HERO11 BlackHERO11 Black
                                  6 1X Speed (Ext. Batt.) (Low Light)HERO11 BlackHERO11 Black
                                  7 8X Ultra Slo-Mo (50Hz)HERO11 BlackHERO11 Black
                                  8 4X Super Slo-Mo (50Hz)HERO11 BlackHERO11 Black
                                  9 2X Slo-Mo (50Hz)HERO11 BlackHERO11 Black
                                  10 1X Speed (50Hz) (Low Light)HERO11 BlackHERO11 Black
                                  11 4X Super Slo-Mo (50Hz) (Ext. Batt.)HERO11 BlackHERO11 Black
                                  12 2X Slo-Mo (50Hz) (Ext. Batt.)HERO11 BlackHERO11 Black
                                  13 1X Speed (50Hz) (Ext. Batt.) (Low Light)HERO11 BlackHERO11 Black
                                  14 8X Ultra Slo-Mo (Ext. Batt.)HERO11 BlackHERO11 Black
                                  15 8X Ultra Slo-Mo (50Hz) (Ext. Batt.)HERO11 BlackHERO11 Black
                                  16 8X Ultra Slo-Mo (Long. Batt.)HERO11 BlackHERO11 Black
                                  17 4X Super Slo-Mo (Long. Batt.)HERO11 BlackHERO11 Black
                                  18 2X Slo-Mo (Long. Batt.)HERO11 BlackHERO11 Black
                                  19 1X Speed (Long. Batt.) (Low Light)HERO11 BlackHERO11 Black
                                  20 8X Ultra Slo-Mo (50Hz) (Long. Batt.)HERO11 BlackHERO11 Black
                                  21 4X Super Slo-Mo (50Hz) (Long. Batt.)HERO11 BlackHERO11 Black
                                  22 2X Slo-Mo (50Hz) (Long. Batt.)HERO11 BlackHERO11 Black
                                  23 1X Speed (50Hz) (Long. Batt.) (Low Light)HERO11 BlackHERO11 Black
                                  24 2X Slo-Mo (4K)HERO11 BlackHERO11 Black
                                  25 4X Super Slo-Mo (2.7K)HERO11 BlackHERO11 Black
                                  26 2X Slo-Mo (4K) (50Hz)HERO11 BlackHERO11 Black
                                  27 4X Super Slo-Mo (2.7K) (50Hz)HERO11 BlackHERO11 Black
                                  100 8X Ultra Slo-Mo (V2)HERO12 BlackHERO12 Black
                                  101 4X Super Slo-Mo (V2)HERO12 BlackHERO12 Black
                                  102 2X Slo-Mo (V2)HERO12 BlackHERO12 Black
                                  103 1X Speed (Low Light) (V2)HERO12 BlackHERO12 Black
                                  104 8X Ultra Slo-Mo (50Hz) (V2)HERO12 BlackHERO12 Black
                                  105 4X Super Slo-Mo (50Hz) (V2)HERO12 BlackHERO12 Black
                                  106 2X Slo-Mo (50Hz) (V2)HERO12 BlackHERO12 Black
                                  107 1X Speed (50Hz) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  108 8X Ultra Slo-Mo (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  109 4X Super Slo-Mo (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  110 2X Slo-Mo (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  111 1X Speed (Long. Batt.) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  112 8X Ultra Slo-Mo (50Hz) (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  113 4X Super Slo-Mo (50Hz) (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  114 2X Slo-Mo (50Hz) (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  115 1X Speed (50Hz) (Long. Batt.) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  116 2X Slo-Mo (4K) (V2)HERO12 BlackHERO12 Black
                                  117 2X Slo-Mo (4K) (50Hz) (V2)HERO12 BlackHERO12 Black
                                  118 1X Speed (Low Light) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  119 1X Speed (50Hz) (Low Light) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  120 2X Slo-Mo (V2) (Vertical)HERO12 BlackHERO12 Black
                                  121 2X Slo-Mo (50Hz) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  122 1X Speed (Full Frame) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  123 1X Speed (50Hz) (Full Frame) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  124 2X Slo-Mo (Full Frame) (V2)HERO12 BlackHERO12 Black
                                  125 2X Slo-Mo (50Hz) (Full Frame) (V2)HERO12 BlackHERO12 Black
                                  126 1X Speed (4K) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  127 1X Speed (4K) (50Hz) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  128 1X Speed (2.7K) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  129 1X Speed (2.7K) (50Hz) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  130 2X Slo-Mo (2.7K) (V2)HERO12 BlackHERO12 Black
                                  131 2X Slo-Mo (2.7K) (50Hz) (V2)HERO12 BlackHERO12 Black
                                  132 2X Slo-Mo (Long. Batt.) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  133 2X Slo-Mo (50Hz) (Long. Batt.) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  134 1X Speed (Long. Batt.) (Low Light) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  135 1X Speed (50Hz) (Long. Batt.) (Low Light) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  136 1X Speed (4K) (Full Frame) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  137 1X Speed (4K) (50Hz) (Full Frame) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  177
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>1</td> <td>On</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Enable Night Photo

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO11 Black

                                  @@ -18133,21 +17451,18 @@

                                  Limitations

                                  - + - +
                                  0 OffHERO11 BlackHERO11 Black
                                  1 OnHERO11 BlackHERO11 Black
                                  178
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>2.4GHz</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>1</td> <td>5GHz</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Wireless Band

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black

                                  @@ -18185,21 +17497,18 @@

                                  Limitations

                                  - + - +
                                  0 2.4GHzHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  1 5GHzHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  179
                                  integer
                                  Enum: 1 2 3
                                  Limitations <tbody><tr> <td>1</td> <td>Short</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>2</td> <td>Long</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>3</td> <td>Max</td> -<td>HERO12 Black, HERO11 Black Mini, HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"><img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Trail Length

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black

                                  @@ -18242,24 +17548,21 @@

                                  Limitations

                                  - + - + - +
                                  1 ShortHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  2 LongHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  3 MaxHERO12 Black, HERO11 Black Mini, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  180
                                  integer
                                  Enum: 0 101 102
                                  Limitations <tbody><tr> <td>0</td> <td>Highest Quality</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>101</td> <td>Extended Battery (Green Icon)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> <tr> <td>102</td> <td>Longest Battery (Green Icon)</td> -<td>HERO11 Black</td> +<td><img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Video Mode

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO11 Black

                                  @@ -18300,24 +17600,21 @@

                                  Limitations

                                  - + - + - +
                                  0 Highest QualityHERO11 BlackHERO11 Black
                                  101 Extended Battery (Green Icon)HERO11 BlackHERO11 Black
                                  102 Longest Battery (Green Icon)HERO11 BlackHERO11 Black
                                  182
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>Standard</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>High</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Bit Rate

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -18353,19 +17647,16 @@

                                  Limitations

                                  - + - +
                                  0 StandardHERO12 BlackHERO12 Black
                                  1 HighHERO12 BlackHERO12 Black
                                  183
                                  integer
                                  Enum: 0 2
                                  Limitations <tbody><tr> <td>0</td> <td>8-Bit</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>10-Bit</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Bit Depth

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -18401,19 +17689,16 @@

                                  Limitations

                                  - + - +
                                  0 8-BitHERO12 BlackHERO12 Black
                                  2 10-BitHERO12 BlackHERO12 Black
                                  184
                                  integer
                                  Enum: 0 1 2
                                  Limitations <tbody><tr> <td>0</td> <td>Standard</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>HDR</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>Log</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Profiles

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -18454,24 +17736,21 @@

                                  Limitations

                                  - + - + - +
                                  0 StandardHERO12 BlackHERO12 Black
                                  1 HDRHERO12 BlackHERO12 Black
                                  2 LogHERO12 BlackHERO12 Black
                                  186
                                  integer
                                  Enum: 0 1 2
                                  Limitations <tbody><tr> <td>0</td> <td>Highest Quality</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>Standard Quality</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>Basic Quality</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Video Mode

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -18512,24 +17788,21 @@

                                  Limitations

                                  - + - + - +
                                  0 Highest QualityHERO12 BlackHERO12 Black
                                  1 Standard QualityHERO12 BlackHERO12 Black
                                  2 Basic QualityHERO12 BlackHERO12 Black
                                  187
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7
                                  Limitations <tbody><tr> <td>0</td> <td>TimeWarp</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>Star Trails</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>Light Painting</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>3</td> <td>Vehicle Lights</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>4</td> <td>Max TimeWarp</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>5</td> <td>Max Star Trails</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>6</td> <td>Max Light Painting</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>7</td> <td>Max Vehicle Lights</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Lapse Mode

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -18595,49 +17865,46 @@

                                  Limitations

                                  - + - + - + - + - + - + - + - +
                                  0 TimeWarpHERO12 BlackHERO12 Black
                                  1 Star TrailsHERO12 BlackHERO12 Black
                                  2 Light PaintingHERO12 BlackHERO12 Black
                                  3 Vehicle LightsHERO12 BlackHERO12 Black
                                  4 Max TimeWarpHERO12 BlackHERO12 Black
                                  5 Max Star TrailsHERO12 BlackHERO12 Black
                                  6 Max Light PaintingHERO12 BlackHERO12 Black
                                  7 Max Vehicle LightsHERO12 BlackHERO12 Black
                                  189
                                  integer
                                  Enum: 0 1 2
                                  Limitations <tbody><tr> <td>0</td> <td>None</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>Max Lens 1.0</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>Max Lens 2.0</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Max Lens Mod

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -18678,24 +17942,21 @@

                                  Limitations

                                  - + - + - +
                                  0 NoneHERO12 BlackHERO12 Black
                                  1 Max Lens 1.0HERO12 BlackHERO12 Black
                                  2 Max Lens 2.0HERO12 BlackHERO12 Black
                                  190
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>Off</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>On</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Max Lens Mod Enable

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -18731,19 +17989,16 @@

                                  Limitations

                                  - + - +
                                  0 OffHERO12 BlackHERO12 Black
                                  1 OnHERO12 BlackHERO12 Black
                                  191
                                  integer
                                  Enum: 0 1
                                  Limitations <tbody><tr> <td>0</td> <td>Super Photo</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>Night Photo</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Photo Mode

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -18779,19 +18031,16 @@

                                  Limitations

                                  - + - +
                                  0 Super PhotoHERO12 BlackHERO12 Black
                                  1 Night PhotoHERO12 BlackHERO12 Black
                                  192
                                  integer
                                  Enum: 0 1 3
                                  Limitations <tbody><tr> <td>0</td> <td>4:3</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>16:9</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>3</td> <td>8:7</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Aspect Ratio

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -18832,24 +18078,21 @@

                                  Limitations

                                  - + - + - +
                                  0 4:3HERO12 BlackHERO12 Black
                                  1 16:9HERO12 BlackHERO12 Black
                                  3 8:7HERO12 BlackHERO12 Black
                                  193
                                  integer
                                  Enum: 0 1 2
                                  Limitations <tbody><tr> <td>0</td> <td>Widescreen</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>1</td> <td>Vertical</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> <tr> <td>2</td> <td>Full Frame</td> -<td>HERO12 Black</td> +<td><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"></td> </tr> </tbody></table> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Framing

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +

                                  HERO12 Black

                                  @@ -18890,40 +18130,39 @@

                                  Limitations

                                  - + - + - +
                                  0 WidescreenHERO12 BlackHERO12 Black
                                  1 VerticalHERO12 BlackHERO12 Black
                                  2 Full FrameHERO12 BlackHERO12 Black
                                  object

                                  All currently known status values indexed by status ID

                                  1
                                  integer
                                  Enum: 0 1

                                  Is the system's internal battery present?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  2
                                  integer
                                  Enum: 0 1 2 3 4
                                  Limitations <td>Charging</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Rough approximation of internal battery level in bars (or charging)

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -18989,141 +18225,138 @@

                                  Limitations

                                  Charging
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  3
                                  integer
                                  Enum: 0 1

                                  Is an external battery connected?

                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  4
                                  integer [ 0 .. 100 ]

                                  External battery power level in percent

                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  5
                                  integer

                                  Unused

                                  6
                                  integer
                                  Enum: 0 1

                                  Is the system currently overheating?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  7
                                  integer

                                  Unused

                                  8
                                  integer
                                  Enum: 0 1

                                  Is the camera busy?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  9
                                  integer
                                  Enum: 0 1

                                  Is Quick Capture feature enabled?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  10
                                  integer
                                  Enum: 0 1

                                  Is the system encoding right now?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  11
                                  integer
                                  Enum: 0 1

                                  Is LCD lock active?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  12
                                  integer

                                  Unused

                                  13
                                  integer

                                  When encoding video, this is the duration (seconds) of the video so far; 0 otherwise

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  14
                                  integer

                                  When broadcasting (Live Stream), this is the broadcast duration (seconds) so far; 0 otherwise

                                  +

                                  HERO12 Black +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  15
                                  integer

                                  (DEPRECATED) Number of Broadcast viewers

                                  +
                                  16
                                  integer

                                  (DEPRECATED) Broadcast B-Status

                                  17
                                  integer
                                  Enum: 0 1

                                  Are Wireless Connections enabled?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  18
                                  integer

                                  Unused

                                  19
                                  integer
                                  Enum: 0 1 2 3 4
                                  Limitations <td>Completed</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  The pairing state of the camera

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -19189,15 +18419,12 @@

                                  Limitations

                                  Completed
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  20
                                  integer
                                  Enum: 0 1 2 3
                                  Limitations <td>Pairing Bluetooth Device</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  The last type of pairing in which the camera was engaged

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -19255,31 +18479,22 @@

                                  Limitations

                                  Pairing Bluetooth Device
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  21
                                  integer

                                  Time since boot (milliseconds) of last successful pairing complete action

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  22
                                  integer
                                  Enum: 0 1 2 3 4
                                  Limitations <td>Completed</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  State of current scan for WiFi Access Points

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -19345,33 +18557,24 @@

                                  Limitations

                                  Completed
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  23
                                  integer

                                  Time since boot (milliseconds) that the WiFi Access Point scan completed

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  24
                                  integer
                                  Enum: 0 1 2 3 4
                                  Limitations <td>Completed</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  WiFi AP provisioning state

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -19437,137 +18637,94 @@

                                  Limitations

                                  Completed
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  25
                                  integer

                                  Unused

                                  26
                                  integer

                                  Wireless remote control version

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  27
                                  integer
                                  Enum: 0 1

                                  Is a wireless remote control connected?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  28
                                  integer

                                  Wireless Pairing State. Each bit contains state information (see WirelessPairingStateFlags)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  29
                                  string

                                  SSID of the AP the camera is currently connected to. On BLE connection, value is big-endian byte-encoded int32

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  30
                                  string

                                  The camera's WiFi SSID. On BLE connection, value is big-endian byte-encoded int32

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  31
                                  integer

                                  The number of wireless devices connected to the camera

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  32
                                  integer
                                  Enum: 0 1

                                  Is Preview Stream enabled?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  33
                                  integer
                                  Enum: -1 0 1 2 3 4 8
                                  Limitations <td>SD Card Swapped</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Primary Storage Status

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -19649,85 +18803,78 @@

                                  Limitations

                                  SD Card Swapped
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  34
                                  integer

                                  How many photos can be taken with current settings before sdcard is full

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  35
                                  integer

                                  How many minutes of video can be captured with current settings before sdcard is full

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  36
                                  integer

                                  Total number of group photos on sdcard

                                  +

                                  HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  37
                                  integer

                                  Total number of group videos on sdcard

                                  +

                                  HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  38
                                  integer

                                  Total number of photos on sdcard

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  39
                                  integer

                                  Total number of videos on sdcard

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  40
                                  string

                                  Current date/time (format: %YY%mm%dd%HH%MM%SS, all values in hex)

                                  41
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10
                                  Limitations <td>GoPro App: Ready</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  The current status of Over The Air (OTA) update

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -19841,195 +18985,247 @@

                                  Limitations

                                  GoPro App: Ready
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  42
                                  integer
                                  Enum: 0 1

                                  Is there a pending request to cancel a firmware update download?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  43
                                  integer

                                  Current mode group (deprecated in HERO8)

                                  +
                                  44
                                  integer

                                  Current submode (deprecated in HERO8)

                                  45
                                  integer
                                  Enum: 0 1

                                  Is locate camera feature active?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  46
                                  integer
                                  Enum: 0 1

                                  Are Video Protune settings currently factory default?

                                  +
                                  47
                                  integer
                                  Enum: 0 1

                                  Are Photo Protune settings currently factory default?

                                  +
                                  48
                                  integer
                                  Enum: 0 1

                                  Are Multishot Protune settings currently factory default?

                                  49
                                  integer

                                  The current timelapse interval countdown value (e.g. 5...4...3...2...1...)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  50
                                  integer

                                  Unused

                                  +
                                  51
                                  integer

                                  Unused

                                  +
                                  52
                                  integer

                                  Unused

                                  +
                                  53
                                  integer

                                  Unused

                                  54
                                  integer

                                  Remaining space on the sdcard in Kilobytes

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  55
                                  integer
                                  Enum: 0 1

                                  Is preview stream supported in current recording/mode/secondary-stream?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  56
                                  integer

                                  WiFi signal strength in bars

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  57
                                  integer

                                  Time in milliseconds since system was booted

                                  58
                                  integer

                                  The number of hilights in currently-encoding video (value is set to 0 when encoding stops)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  59
                                  integer

                                  Time since boot (milliseconds) of most recent hilight in encoding video (set to 0 when encoding stops)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  60
                                  integer

                                  The minimum time between camera status updates (milliseconds). Best practice is to not poll for status more often than this

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  61
                                  integer
                                  Enum: 0 1 2

                                  The current state of camera analytics

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  + + + + + + + + + + + + + + + + + + + +
                                  ValueMeaning
                                  0Not ready
                                  1Ready
                                  2On connect
                                  +
                                  62
                                  integer
                                  Value: 0

                                  The size (units??) of the analytics file

                                  +

                                  HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  + + + + + + + + + + + +
                                  ValueMeaning
                                  0Value hard-coded by BOSS in libgpCtrlD/src/camera_status.cpp
                                  +
                                  63
                                  integer
                                  Enum: 0 1

                                  Is the camera currently in a contextual menu (e.g. Preferences)?

                                  +

                                  HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  64
                                  integer

                                  How many minutes of Time Lapse Video can be captured with current settings before sdcard is full

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  65
                                  integer
                                  Enum: 0 1 2 3
                                  Limitations <td>Hemisphere</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Liveview Exposure Select Mode

                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  @@ -20086,100 +19279,74 @@

                                  Limitations

                                  Hemisphere
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  66
                                  integer [ 0 .. 100 ]

                                  Liveview Exposure Select: y-coordinate (percent)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  67
                                  integer [ 0 .. 100 ]

                                  Liveview Exposure Select: y-coordinate (percent)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  68
                                  integer
                                  Enum: 0 1

                                  Does the camera currently have a GPS lock?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  69
                                  integer
                                  Enum: 0 1

                                  Is the camera in AP Mode?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  70
                                  integer [ 0 .. 100 ]

                                  Internal battery level (percent)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  71
                                  integer

                                  The current video group flatmode (id)

                                  +
                                  72
                                  integer

                                  The current photo group flatmode (id)

                                  +
                                  73
                                  integer

                                  The current timelapse group flatmode (id)

                                  74
                                  integer
                                  Enum: 0 1 2
                                  Limitations <td>Accessory connected and a microphone is plugged into the accessory</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Microphone Accessory status

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -20229,33 +19393,24 @@

                                  Limitations

                                  Accessory connected and a microphone is plugged into the accessory
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  75
                                  integer [ 0 .. 100 ]

                                  Digital Zoom level (percent)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  76
                                  integer
                                  Enum: 0 1
                                  Limitations <td>5 GHz</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Wireless Band

                                  +

                                  HERO12 Black +HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -20297,135 +19449,166 @@

                                  Limitations

                                  5 GHz
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  77
                                  integer
                                  Enum: 0 1

                                  Is Digital Zoom feature available?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  78
                                  integer
                                  Enum: 0 1

                                  Are current video settings mobile friendly? (related to video compression and frame rate)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  79
                                  integer
                                  Enum: 0 1

                                  Is the camera currently in First Time Use (FTU) UI flow?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO10 Black + HERO9 Black

                                  +
                                  80
                                  integer
                                  Enum: -1 0 1 2 3 4 8

                                  Secondary Storage Status (exclusive to Superbank)

                                  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                  ValueMeaning
                                  -1Unknown
                                  0OK
                                  1SD Card Full
                                  2SD Card Removed
                                  3SD Card Format Error
                                  4SD Card Busy
                                  8SD Card Swapped
                                  81
                                  integer
                                  Enum: 0 1

                                  Is 5GHz wireless band available?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  82
                                  integer
                                  Enum: 0 1

                                  Is the system fully booted and ready to accept commands?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  83
                                  integer
                                  Enum: 0 1

                                  Is the internal battery charged sufficiently to start Over The Air (OTA) update?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  84
                                  integer

                                  Current Capture Delay value (HERO7 only)

                                  85
                                  integer
                                  Enum: 0 1

                                  Is the camera getting too cold to continue recording?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  86
                                  integer
                                  Enum: 0 1 2 3
                                  Limitations <td>270 degrees (laying on left side)</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Rotational orientation of the camera

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -20483,203 +19663,162 @@

                                  Limitations

                                  270 degrees (laying on left side)
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  87
                                  integer
                                  Enum: 0 1

                                  Can camera use high resolution/fps (based on temperature)? (HERO7 Silver/White only)

                                  88
                                  integer
                                  Enum: 0 1

                                  Is this camera model capable of zooming while encoding?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  89
                                  integer

                                  Current Flatmode ID

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +<p><img src="https://img.shields.io/badge/HERO12%20Black-911eb4" alt="HERO12 Black"> + <img src="https://img.shields.io/badge/HERO11%20Black%20Mini-f58231" alt="HERO11 Black Mini"> +<img src="https://img.shields.io/badge/HERO11%20Black-ffe119" alt="HERO11 Black"> + <img src="https://img.shields.io/badge/HERO10%20Black-3cb44b" alt="HERO10 Black"> +<img src="https://img.shields.io/badge/HERO9%20Black-e6194b" alt="HERO9 Black"></p> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Current Flatmode ID

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  90
                                  integer
                                  Enum: 0 1

                                  Are current flatmode's Protune settings factory default?

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  91
                                  integer
                                  Enum: 0 1

                                  Are system logs ready to be downloaded?

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  +
                                  92
                                  integer
                                  Enum: 0 1

                                  Is Timewarp 1x active?

                                  93
                                  integer

                                  Current Video Preset (ID)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  94
                                  integer

                                  Current Photo Preset (ID)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  95
                                  integer

                                  Current Time Lapse Preset (ID)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  96
                                  integer

                                  Current Preset Group (ID) (corresponds to ui_mode_groups in settings.json)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  97
                                  integer

                                  Current Preset (ID)

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  98
                                  integer

                                  Preset Modified Status, which contains an event ID and a Preset (Group) ID

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  99
                                  integer

                                  The number of Live Bursts can be captured with current settings before sdcard is full

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO11 Black +HERO10 Black + HERO9 Black

                                  100
                                  integer

                                  Total number of Live Bursts on sdcard

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO11 Black + HERO10 Black +HERO9 Black

                                  101
                                  integer
                                  Enum: 0 1

                                  Is Capture Delay currently active (i.e. counting down)?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  102
                                  integer
                                  Enum: 0 2 3
                                  Limitations <td>Media Mod microphone with external microphone</td> </tr> </tbody></table> -<p> Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Media Mod state

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -20729,15 +19865,12 @@

                                  Limitations

                                  Media Mod microphone with external microphone
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  103
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 12
                                  Limitations <td>1/2x (slow-motion)</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Time Warp Speed

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -20867,27 +19997,18 @@

                                  Limitations

                                  1/2x (slow-motion)
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  104
                                  integer
                                  Enum: 0 1

                                  Is the system's Linux core active?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO10 Black + HERO9 Black

                                  105
                                  integer
                                  Enum: 0 1 2
                                  Limitations <td>Max Lens 2.0</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Camera lens type (reflects changes to setting 162 or setting 189)

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  @@ -20937,63 +20055,51 @@

                                  Limitations

                                  Max Lens 2.0
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  106
                                  integer
                                  Enum: 0 1

                                  Is Video Hindsight Capture Active?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  107
                                  integer

                                  Scheduled Capture Preset ID

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  108
                                  integer
                                  Enum: 0 1

                                  Is Scheduled Capture set?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  109
                                  integer
                                  Enum: 0 1

                                  Is the camera in the process of creating a custom preset?

                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  110
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7
                                  Limitations <td>111 = Display Mod: 1, HDMI: 1, Display Mod Connected: True</td> </tr> </tbody></table> -<p> Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -<li>HERO9 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Display Mod Status (bitmasked)

                                  +

                                  HERO12 Black + HERO11 Black +HERO10 Black + HERO9 Black

                                  @@ -21082,64 +20185,43 @@

                                  Limitations

                                  111 = Display Mod: 1, HDMI: 1, Display Mod Connected: True
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  111
                                  integer
                                  Enum: 0 1

                                  Does sdcard meet specified minimum write speed?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black

                                  112
                                  integer

                                  Number of sdcard write speed errors since device booted

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black

                                  113
                                  integer
                                  Enum: 0 1

                                  Is Turbo Transfer active?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black +HERO9 Black

                                  114
                                  integer
                                  Enum: 0 1 2
                                  Limitations <td>Camera External Control: An outside entity (app) has control and is in a menu or modifying settings</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Camera control status ID

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black

                                  @@ -21188,30 +20267,21 @@

                                  Limitations

                                  Camera External Control: An outside entity (app) has control and is in a menu or modifying settings
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  115
                                  integer
                                  Enum: 0 1

                                  Is the camera connected to a PC via USB?

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black

                                  116
                                  integer
                                  Enum: 0 1
                                  Limitations <td>Enabled</td> </tr> </tbody></table> -<p>Supported Cameras:</p> -<ul> -<li>HERO12 Black</li> -<li>HERO11 Black Mini</li> -<li>HERO11 Black</li> -<li>HERO10 Black</li> -</ul> " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Camera control over USB state

                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black + HERO10 Black

                                  @@ -21252,59 +20319,34 @@

                                  Limitations

                                  Enabled
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  117
                                  integer

                                  Total SD card capacity in Kilobytes

                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  +

                                  HERO12 Black + HERO11 Black Mini +HERO11 Black

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "settings": {
                                    },
                                  • "status": {
                                    }
                                  }

                                  Get Date / Time

                                  http://10.5.5.9:8080/gopro/camera/state

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "settings": {
                                    },
                                  • "status": {
                                    }
                                  }

                                  Get Date / Time


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +

                                  Responses

                                  Response Schema: application/json
                                  date
                                  required
                                  string
                                  Example: "2023_12_31"
                                  Limitations " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Timezone offset in minutes

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "date": "2023_12_31",
                                  • "dst": 0,
                                  • "time": "11_05_45",
                                  • "tzone": -480
                                  }

                                  Get Hardware Info

                                  http://10.5.5.9:8080/gopro/camera/get_date_time

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "date": "2023_12_31",
                                  • "dst": 0,
                                  • "time": "11_05_45",
                                  • "tzone": -480
                                  }

                                  Get Hardware Info


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +

                                  Responses

                                  Response Schema: application/json
                                  object
                                  ap_mac_addr
                                  string
                                  Example: "065747046ceb"
                                  Limitations " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Camera serial number

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "info": {
                                    }
                                  }

                                  Get Last Captured Media

                                  http://10.5.5.9:8080/gopro/camera/info

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "info": {
                                    }
                                  }

                                  Get Last Captured Media

                                  This will return the complete path of the last captured media. Depending on the type of media captured, it will return:

                                  -
                                    -
                                  • single photo / video: The single media path
                                  • -
                                  • any grouped media: The path to the first captured media in the group
                                  • -
                                  -
                                  -

                                  Supported Cameras:

                                  +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black

                                  +

                                  Supported Protocols:

                                    -
                                  • HERO12 Black
                                  • +
                                  • USB
                                  • +
                                  • WIFI

                                  -

                                  Supported Protocols:

                                  +

                                  This will return the complete path of the last captured media. Depending on the type of media captured, it will return:

                                    -
                                  • WIFI
                                  • -
                                  • USB
                                  • +
                                  • single photo / video: The single media path
                                  • +
                                  • any grouped media: The path to the first captured media in the group

                                  Responses

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "file": "GOPR0002.JPG",
                                  • "folder": "100GOPRO"
                                  }

                                  Get Open GoPro Version

                                  http://10.5.5.9:8080/gopro/media/last_captured

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "file": "GOPR0002.JPG",
                                  • "folder": "100GOPRO"
                                  }

                                  Get Open GoPro Version


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +

                                  Responses

                                  Response Schema: application/json
                                  version
                                  string <version>
                                  Example: "2.0"
                                  JSON list of objects that contain setting and option IDs necessary to construct set-setting commands and are given in dependency order as outlined above. For more information on the object format, see the JSON schema

                                  -

                                  Anti-Flicker (134)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +

                                  Anti-Flicker (134)

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 2 3
                                  Example: 2
                                  @@ -21579,61 +20589,53 @@

                                  JSON

                                  - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  2 60HzHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  3 50HzHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Aspect Ratio (108)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=134&option=3

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Aspect Ratio (108)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 3 4
                                  @@ -21641,66 +20643,58 @@

                                  JSON

                                  - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 4:3HERO12 BlackHERO12 Black
                                  1 16:9HERO12 BlackHERO12 Black
                                  3 8:7HERO12 BlackHERO12 Black
                                  4 9:16HERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Aspect Ratio (192)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=108&option=4

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Aspect Ratio (192)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 3
                                  @@ -21708,89 +20702,81 @@

                                  JSON

                                  - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 4:3HERO12 BlackHERO12 Black
                                  1 16:9HERO12 BlackHERO12 Black
                                  3 8:7HERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Auto Power Down (59)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=192&option=3

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Auto Power Down (59)

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 4 6 7 11 12
                                  Example: 4
                                  @@ -21798,76 +20784,68 @@

                                  JSON

                                  - + - + - + - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 NeverHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  1 1 MinHERO11 Black Mini, HERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  4 5 MinHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  6 15 MinHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  7 30 MinHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  11 8 SecondsHERO11 Black MiniHERO11 Black Mini
                                  12 30 SecondsHERO11 Black MiniHERO11 Black Mini

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Bit Depth (183)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=59&option=12

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Bit Depth (183)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 2
                                  @@ -21875,51 +20853,43 @@

                                  JSON

                                  - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 8-BitHERO12 BlackHERO12 Black
                                  2 10-BitHERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Bit Rate (182)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=183&option=2

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Bit Rate (182)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1
                                  Example: 1
                                  @@ -21927,53 +20897,45 @@

                                  JSON

                                  - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 StandardHERO12 BlackHERO12 Black
                                  1 HighHERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Controls (175)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=182&option=1

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Controls (175)

                                  HERO12 Black +HERO11 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1
                                  @@ -21981,91 +20943,83 @@

                                  JSON

                                  - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 EasyHERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black
                                  1 ProHERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Duration (172)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=175&option=1

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Duration (172)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7 8 9
                                  @@ -22073,413 +21027,405 @@

                                  JSON

                                  - + - + - + - + - + - + - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 OffHERO12 BlackHERO12 Black
                                  1 15 SecondsHERO12 BlackHERO12 Black
                                  2 30 SecondsHERO12 BlackHERO12 Black
                                  3 1 MinuteHERO12 BlackHERO12 Black
                                  4 5 MinutesHERO12 BlackHERO12 Black
                                  5 15 MinutesHERO12 BlackHERO12 Black
                                  6 30 MinutesHERO12 BlackHERO12 Black
                                  7 1 HourHERO12 BlackHERO12 Black
                                  8 2 HoursHERO12 BlackHERO12 Black
                                  9 3 HoursHERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Easy Mode Speed (176)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=172&option=9

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Easy Mode Speed (176)

                                  HERO12 Black +HERO11 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
                                  Example: 103
                                  @@ -22487,371 +21433,363 @@

                                  JSON

                                  - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 8X Ultra Slo-MoHERO11 BlackHERO11 Black
                                  1 4X Super Slo-MoHERO11 BlackHERO11 Black
                                  2 2X Slo-MoHERO11 BlackHERO11 Black
                                  3 1X Speed (Low Light)HERO11 BlackHERO11 Black
                                  4 4X Super Slo-Mo (Ext. Batt.)HERO11 BlackHERO11 Black
                                  5 2X Slo-Mo (Ext. Batt.)HERO11 BlackHERO11 Black
                                  6 1X Speed (Ext. Batt.) (Low Light)HERO11 BlackHERO11 Black
                                  7 8X Ultra Slo-Mo (50Hz)HERO11 BlackHERO11 Black
                                  8 4X Super Slo-Mo (50Hz)HERO11 BlackHERO11 Black
                                  9 2X Slo-Mo (50Hz)HERO11 BlackHERO11 Black
                                  10 1X Speed (50Hz) (Low Light)HERO11 BlackHERO11 Black
                                  11 4X Super Slo-Mo (50Hz) (Ext. Batt.)HERO11 BlackHERO11 Black
                                  12 2X Slo-Mo (50Hz) (Ext. Batt.)HERO11 BlackHERO11 Black
                                  13 1X Speed (50Hz) (Ext. Batt.) (Low Light)HERO11 BlackHERO11 Black
                                  14 8X Ultra Slo-Mo (Ext. Batt.)HERO11 BlackHERO11 Black
                                  15 8X Ultra Slo-Mo (50Hz) (Ext. Batt.)HERO11 BlackHERO11 Black
                                  16 8X Ultra Slo-Mo (Long. Batt.)HERO11 BlackHERO11 Black
                                  17 4X Super Slo-Mo (Long. Batt.)HERO11 BlackHERO11 Black
                                  18 2X Slo-Mo (Long. Batt.)HERO11 BlackHERO11 Black
                                  19 1X Speed (Long. Batt.) (Low Light)HERO11 BlackHERO11 Black
                                  20 8X Ultra Slo-Mo (50Hz) (Long. Batt.)HERO11 BlackHERO11 Black
                                  21 4X Super Slo-Mo (50Hz) (Long. Batt.)HERO11 BlackHERO11 Black
                                  22 2X Slo-Mo (50Hz) (Long. Batt.)HERO11 BlackHERO11 Black
                                  23 1X Speed (50Hz) (Long. Batt.) (Low Light)HERO11 BlackHERO11 Black
                                  24 2X Slo-Mo (4K)HERO11 BlackHERO11 Black
                                  25 4X Super Slo-Mo (2.7K)HERO11 BlackHERO11 Black
                                  26 2X Slo-Mo (4K) (50Hz)HERO11 BlackHERO11 Black
                                  27 4X Super Slo-Mo (2.7K) (50Hz)HERO11 BlackHERO11 Black
                                  100 8X Ultra Slo-Mo (V2)HERO12 BlackHERO12 Black
                                  101 4X Super Slo-Mo (V2)HERO12 BlackHERO12 Black
                                  102 2X Slo-Mo (V2)HERO12 BlackHERO12 Black
                                  103 1X Speed (Low Light) (V2)HERO12 BlackHERO12 Black
                                  104 8X Ultra Slo-Mo (50Hz) (V2)HERO12 BlackHERO12 Black
                                  105 4X Super Slo-Mo (50Hz) (V2)HERO12 BlackHERO12 Black
                                  106 2X Slo-Mo (50Hz) (V2)HERO12 BlackHERO12 Black
                                  107 1X Speed (50Hz) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  108 8X Ultra Slo-Mo (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  109 4X Super Slo-Mo (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  110 2X Slo-Mo (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  111 1X Speed (Long. Batt.) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  112 8X Ultra Slo-Mo (50Hz) (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  113 4X Super Slo-Mo (50Hz) (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  114 2X Slo-Mo (50Hz) (Long. Batt.) (V2)HERO12 BlackHERO12 Black
                                  115 1X Speed (50Hz) (Long. Batt.) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  116 2X Slo-Mo (4K) (V2)HERO12 BlackHERO12 Black
                                  117 2X Slo-Mo (4K) (50Hz) (V2)HERO12 BlackHERO12 Black
                                  118 1X Speed (Low Light) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  119 1X Speed (50Hz) (Low Light) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  120 2X Slo-Mo (V2) (Vertical)HERO12 BlackHERO12 Black
                                  121 2X Slo-Mo (50Hz) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  122 1X Speed (Full Frame) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  123 1X Speed (50Hz) (Full Frame) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  124 2X Slo-Mo (Full Frame) (V2)HERO12 BlackHERO12 Black
                                  125 2X Slo-Mo (50Hz) (Full Frame) (V2)HERO12 BlackHERO12 Black
                                  126 1X Speed (4K) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  127 1X Speed (4K) (50Hz) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  128 1X Speed (2.7K) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  129 1X Speed (2.7K) (50Hz) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  130 2X Slo-Mo (2.7K) (V2)HERO12 BlackHERO12 Black
                                  131 2X Slo-Mo (2.7K) (50Hz) (V2)HERO12 BlackHERO12 Black
                                  132 2X Slo-Mo (Long. Batt.) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  133 2X Slo-Mo (50Hz) (Long. Batt.) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  134 1X Speed (Long. Batt.) (Low Light) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  135 1X Speed (50Hz) (Long. Batt.) (Low Light) (V2) (Vertical)HERO12 BlackHERO12 Black
                                  136 1X Speed (4K) (Full Frame) (Low Light) (V2)HERO12 BlackHERO12 Black
                                  137 1X Speed (4K) (50Hz) (Full Frame) (Low Light) (V2)HERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Enable Night Photo (177)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=176&option=137

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Enable Night Photo (177)

                                  HERO11 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1
                                  @@ -22859,94 +21797,86 @@

                                  JSON

                                  - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 OffHERO11 BlackHERO11 Black
                                  1 OnHERO11 BlackHERO11 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Frames Per Second (3)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=177&option=1

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Frames Per Second (3)

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 2 5 6 8 9 10 13
                                  @@ -22954,91 +21884,83 @@

                                  JSON

                                  - + - + - + - + - + - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 240HERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  1 120HERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  2 100HERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  5 60HERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  6 50HERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  8 30HERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  9 25HERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  10 24HERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  13 200HERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Framing (193)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=3&option=13

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Framing (193)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 2
                                  @@ -23046,67 +21968,107 @@

                                  JSON

                                  - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 WidescreenHERO12 BlackHERO12 Black
                                  1 VerticalHERO12 BlackHERO12 Black
                                  2 Full FrameHERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  HindSight (167)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=193&option=2

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  GPS (83)

                                  HERO11 Black +HERO10 Black + HERO9 Black

                                  +
                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1
                                  Example: 1
                                  + + + + + + + + + + + + + + + + + +
                                  IDMeaningSupported Cameras
                                  0OffHERO11 BlackHERO10 BlackHERO9 Black
                                  1OnHERO11 BlackHERO10 BlackHERO9 Black
                                  +

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  HindSight (167)

                                  HERO12 Black +HERO11 Black + HERO10 Black +HERO9 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 2 3 4
                                  Example: 2
                                  @@ -23114,56 +22076,48 @@

                                  JSON

                                  - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  2 15 SecondsHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  3 30 SecondsHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  4 OffHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Horizon Leveling (150)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=167&option=4

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Horizon Leveling (150)

                                  HERO11 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 2
                                  @@ -23171,51 +22125,43 @@

                                  JSON

                                  - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 OffHERO11 BlackHERO11 Black
                                  2 LockedHERO11 BlackHERO11 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Horizon Leveling (151)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=150&option=2

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Horizon Leveling (151)

                                  HERO11 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 2
                                  @@ -23223,79 +22169,71 @@

                                  JSON

                                  - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 OffHERO11 BlackHERO11 Black
                                  2 LockedHERO11 BlackHERO11 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Hypersmooth (135)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=151&option=2

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Hypersmooth (135)

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 2 3 4 100
                                  Example: 3
                                  @@ -23303,111 +22241,103 @@

                                  JSON

                                  - + - + - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 OffHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  1 LowHERO11 Black Mini, HERO9 Black, HERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO9 Black
                                  2 HighHERO9 Black, HERO10 BlackHERO10 BlackHERO9 Black
                                  3 BoostHERO11 Black Mini, HERO9 Black, HERO10 Black, HERO11 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  4 Auto BoostHERO11 Black Mini, HERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  100 StandardHERO10 BlackHERO10 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Interval (171)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=135&option=100

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Interval (171)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 2 3 4 5 6 7 8 9 10
                                  @@ -23415,121 +22345,113 @@

                                  JSON

                                  - + - + - + - + - + - + - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 OffHERO12 BlackHERO12 Black
                                  2 0.5sHERO12 BlackHERO12 Black
                                  3 1sHERO12 BlackHERO12 Black
                                  4 2sHERO12 BlackHERO12 Black
                                  5 5sHERO12 BlackHERO12 Black
                                  6 10sHERO12 BlackHERO12 Black
                                  7 30sHERO12 BlackHERO12 Black
                                  8 60sHERO12 BlackHERO12 Black
                                  9 120sHERO12 BlackHERO12 Black
                                  10 3sHERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Lapse Mode (187)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=171&option=10

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Lapse Mode (187)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7
                                  @@ -23537,124 +22459,116 @@

                                  JSON

                                  - + - + - + - + - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 TimeWarpHERO12 BlackHERO12 Black
                                  1 Star TrailsHERO12 BlackHERO12 Black
                                  2 Light PaintingHERO12 BlackHERO12 Black
                                  3 Vehicle LightsHERO12 BlackHERO12 Black
                                  4 Max TimeWarpHERO12 BlackHERO12 Black
                                  5 Max Star TrailsHERO12 BlackHERO12 Black
                                  6 Max Light PaintingHERO12 BlackHERO12 Black
                                  7 Max Vehicle LightsHERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Lens (121)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=187&option=7

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Lens (121)

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 2 3 4 7 8 9 10 11
                                  Example: 7
                                  @@ -23662,102 +22576,94 @@

                                  JSON

                                  - + - + - + - + - + - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 WideHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  2 NarrowHERO9 Black, HERO10 BlackHERO10 BlackHERO9 Black
                                  3 SuperviewHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  4 LinearHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  7 Max SuperViewHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  8 Linear + Horizon LevelingHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  9 HyperViewHERO11 Black Mini, HERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  10 Linear + Horizon LockHERO11 Black Mini, HERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  11 Max HyperViewHERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Lens (122)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=121&option=11

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Lens (122)

                                  HERO12 Black +HERO11 Black + HERO10 Black +HERO9 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 19 100 101 102
                                  Example: 100
                                  @@ -23765,65 +22671,57 @@

                                  JSON

                                  - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  19 NarrowHERO9 Black, HERO10 BlackHERO10 BlackHERO9 Black
                                  100 Max SuperViewHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  101 WideHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  102 LinearHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Max Lens (162)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=122&option=102

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Max Lens (162)

                                  HERO11 Black +HERO10 Black + HERO9 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1
                                  @@ -23831,56 +22729,48 @@

                                  JSON

                                  - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 OffHERO9 Black, HERO10 Black, HERO11 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  1 OnHERO9 Black, HERO10 Black, HERO11 BlackHERO11 BlackHERO10 BlackHERO9 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Max Lens Mod (189)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=162&option=1

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Max Lens Mod (189)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 2
                                  @@ -23888,56 +22778,48 @@

                                  JSON

                                  - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 NoneHERO12 BlackHERO12 Black
                                  1 Max Lens 1.0HERO12 BlackHERO12 Black
                                  2 Max Lens 2.0HERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Max Lens Mod Enable (190)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=189&option=2

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Max Lens Mod Enable (190)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1
                                  @@ -23945,67 +22827,59 @@

                                  JSON

                                  - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 OffHERO12 BlackHERO12 Black
                                  1 OnHERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Media Format (128)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=190&option=1

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Media Format (128)

                                  HERO12 Black +HERO11 Black + HERO10 Black +HERO9 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 13 20 21 26
                                  Example: 13
                                  @@ -24013,61 +22887,53 @@

                                  JSON

                                  - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  13 Time Lapse VideoHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  20 Time Lapse PhotoHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  21 Night Lapse PhotoHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  26 Night Lapse VideoHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Photo Mode (191)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=128&option=26

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Photo Mode (191)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1
                                  @@ -24075,56 +22941,48 @@

                                  JSON

                                  - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 Super PhotoHERO12 BlackHERO12 Black
                                  1 Night PhotoHERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Profiles (184)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=191&option=1

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Profiles (184)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 2
                                  @@ -24132,139 +22990,131 @@

                                  JSON

                                  - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 StandardHERO12 BlackHERO12 Black
                                  1 HDRHERO12 BlackHERO12 Black
                                  2 LogHERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Resolution (2)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=184&option=2

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Resolution (2)

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 1 4 6 7 9 18 24 25 26 27 28 100 107 108 109 110 111
                                  Example: 24
                                  @@ -24272,142 +23122,134 @@

                                  JSON

                                  - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  1 4KHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  4 2.7KHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  6 2.7K 4:3HERO11 Black Mini, HERO9 Black, HERO10 Black, HERO11 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  7 1440HERO9 BlackHERO9 Black
                                  9 1080HERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  18 4K 4:3HERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  24 5KHERO9 BlackHERO9 Black
                                  25 5K 4:3HERO10 BlackHERO10 Black
                                  26 5.3K 8:7HERO11 Black Mini, HERO11 BlackHERO11 Black MiniHERO11 Black
                                  27 5.3K 4:3HERO11 Black Mini, HERO11 BlackHERO11 Black MiniHERO11 Black
                                  28 4K 8:7HERO11 Black Mini, HERO11 BlackHERO11 Black MiniHERO11 Black
                                  100 5.3KHERO11 Black Mini, HERO12 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 Black
                                  107 5.3KHERO12 BlackHERO12 Black
                                  108 4KHERO12 BlackHERO12 Black
                                  109 4KHERO12 BlackHERO12 Black
                                  110 1080HERO12 BlackHERO12 Black
                                  111 2.7KHERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Time Lapse Digital Lenses (123)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=2&option=111

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Time Lapse Digital Lenses (123)

                                  HERO12 Black +HERO11 Black + HERO10 Black +HERO9 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 19 100 101 102
                                  Example: 101
                                  @@ -24415,70 +23257,62 @@

                                  JSON

                                  - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  19 NarrowHERO9 Black, HERO10 BlackHERO10 BlackHERO9 Black
                                  100 Max SuperViewHERO10 BlackHERO10 Black
                                  101 WideHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black
                                  102 LinearHERO12 Black, HERO9 Black, HERO10 Black, HERO11 BlackHERO12 BlackHERO11 BlackHERO10 BlackHERO9 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Trail Length (179)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=123&option=102

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Trail Length (179)

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 1 2 3
                                  Example: 3
                                  @@ -24486,61 +23320,53 @@

                                  JSON

                                  - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  1 ShortHERO11 Black Mini, HERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  2 LongHERO11 Black Mini, HERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  3 MaxHERO11 Black Mini, HERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Video Mode (180)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO11 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=179&option=3

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Video Mode (180)

                                  HERO11 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 101 102
                                  @@ -24548,61 +23374,53 @@

                                  JSON

                                  - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 Highest QualityHERO11 BlackHERO11 Black
                                  101 Extended Battery (Green Icon)HERO11 BlackHERO11 Black
                                  102 Longest Battery (Green Icon)HERO11 BlackHERO11 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Video Mode (186)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=180&option=102

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Video Mode (186)

                                  HERO12 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 2
                                  @@ -24610,61 +23428,53 @@

                                  JSON

                                  - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 Highest QualityHERO12 BlackHERO12 Black
                                  1 Standard QualityHERO12 BlackHERO12 Black
                                  2 Basic QualityHERO12 BlackHERO12 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Video Performance Mode (173)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO10 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=186&option=2

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Video Performance Mode (173)

                                  HERO10 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1 2
                                  @@ -24672,74 +23482,66 @@

                                  JSON

                                  - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 Maximum Video PerformanceHERO10 BlackHERO10 Black
                                  1 Extended BatteryHERO10 BlackHERO10 Black
                                  2 Tripod / Stationary VideoHERO10 BlackHERO10 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Webcam Digital Lenses (43)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  • HERO9 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=173&option=2

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Webcam Digital Lenses (43)

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black +HERO10 Black + HERO9 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 2 3 4
                                  Example: 3
                                  @@ -24747,65 +23549,57 @@

                                  JSON

                                  - + - + - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 WideHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  2 NarrowHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  3 SuperviewHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black
                                  4 LinearHERO10 Black, HERO11 Black, HERO11 Black Mini, HERO9 Black, HERO12 BlackHERO12 BlackHERO11 Black MiniHERO11 BlackHERO10 BlackHERO9 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Wireless Band (178)


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black Mini
                                  • -
                                  • HERO11 Black
                                  • -
                                  +
                                  http://10.5.5.9:8080/gopro/camera/setting?setting=43&option=4

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Wireless Band (178)

                                  HERO12 Black +HERO11 Black Mini + HERO11 Black

                                  path Parameters
                                  option
                                  required
                                  integer
                                  Enum: 0 1
                                  @@ -24813,25 +23607,25 @@

                                  JSON

                                  - + - + - +
                                  ID MeaningCamerasSupported Cameras
                                  0 2.4GHzHERO11 Black Mini, HERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black
                                  1 5GHzHERO11 Black Mini, HERO12 Black, HERO11 BlackHERO12 BlackHERO11 Black MiniHERO11 Black

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Webcam

                                  http://10.5.5.9:8080/gopro/camera/setting?setting=178&option=1

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Webcam

                                  Webcam Stabilization

                                  Note! The Low Hypersmooth option provides lower/lighter stabilization when used in Webcam mode vs other camera modes.

                                  -

                                  Enter Webcam Preview

                                  Enter Webcam Preview

                                  Not supported on WiFi for: - - Hero 11 Black Mini - - Hero 11 Black - - Hero 10 Black - - Hero 9 Black

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  -
                                  -

                                  Supported Protocols:

                                  +<hr> +<p>Not supported on <strong>WiFi</strong> for:</p> +<pre><code><span class="token operator">-</span> Hero <span class="token number">11</span> Black Mini +<span class="token operator">-</span> Hero <span class="token number">11</span> Black +<span class="token operator">-</span> Hero <span class="token number">10</span> Black +<span class="token operator">-</span> Hero <span class="token number">9</span> Black +</code></pre> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black + HERO10 Black

                                  +

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Not supported on WiFi for:

                                  +
                                  - Hero 11 Black Mini
                                  +- Hero 11 Black
                                  +- Hero 10 Black
                                  +- Hero 9 Black
                                  +

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Exit Webcam Mode

                                  http://10.5.5.9:8080/gopro/webcam/preview

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Exit Webcam Mode

                                  Not supported on WiFi for: - - Hero 11 Black Mini - - Hero 11 Black - - Hero 10 Black - - Hero 9 Black

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  -
                                  -

                                  Supported Protocols:

                                  +<hr> +<p>Not supported on <strong>WiFi</strong> for:</p> +<pre><code><span class="token operator">-</span> Hero <span class="token number">11</span> Black Mini +<span class="token operator">-</span> Hero <span class="token number">11</span> Black +<span class="token operator">-</span> Hero <span class="token number">10</span> Black +<span class="token operator">-</span> Hero <span class="token number">9</span> Black +</code></pre> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black + HERO10 Black

                                  +

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Not supported on WiFi for:

                                  +
                                  - Hero 11 Black Mini
                                  +- Hero 11 Black
                                  +- Hero 10 Black
                                  +- Hero 9 Black
                                  +

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Get Webcam Status

                                  http://10.5.5.9:8080/gopro/webcam/exit

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Get Webcam Status


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black + HERO10 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +

                                  Responses

                                  Response Schema: application/json
                                  error
                                  integer
                                  Enum: 0 1 2 3 4 5 6 7 8
                                  Webcam Stabilization

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "error": 0,
                                  • "status": 0
                                  }

                                  Get Webcam Version

                                  http://10.5.5.9:8080/gopro/webcam/status

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "error": 0,
                                  • "status": 0
                                  }

                                  Get Webcam Version


                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  -
                                  +<hr> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black + HERO10 Black

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +

                                  Responses

                                  Response Schema: application/json
                                  max_lens_support
                                  boolean
                                  Webcam Stabilization " class="sc-iKOmoZ sc-cCzLxZ WVNwY jaVotg">

                                  Current webcam version

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "max_lens_support": true,
                                  • "usb_3_1_compatible": true,
                                  • "version": 0
                                  }

                                  Start Webcam

                                  http://10.5.5.9:8080/gopro/webcam/version

                                  Response samples

                                  Content type
                                  application/json
                                  {
                                  • "max_lens_support": true,
                                  • "usb_3_1_compatible": true,
                                  • "version": 0
                                  }

                                  Start Webcam

                                  Not supported on WiFi for:

                                  +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black + HERO10 Black

                                  +

                                  Supported Protocols:

                                  +
                                    +
                                  • USB
                                  • +
                                  • WIFI
                                  • +
                                  +
                                  +

                                  Not supported on WiFi for:

                                  • Hero 11 Black Mini
                                  • Hero 11 Black
                                  • Hero 10 Black
                                  • Hero 9 Black
                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  -
                                  -

                                  Supported Protocols:

                                  -
                                    -
                                  • USB
                                  • -
                                  • WIFI
                                  • -
                                  query Parameters
                                  res
                                  integer
                                  Webcam Stabilization " class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS sc-ckdEwu LxEPk">

                                  Request was successfully received by the camera

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Stop Webcam

                                  http://10.5.5.9:8080/gopro/webcam/start

                                  Response samples

                                  Content type
                                  application/json
                                  { }

                                  Stop Webcam

                                  Not supported on WiFi for: - - Hero 11 Black Mini - - Hero 11 Black - - Hero 10 Black - - Hero 9 Black

                                  -
                                  -

                                  Supported Cameras:

                                  -
                                    -
                                  • HERO12 Black
                                  • -
                                  • HERO11 Black
                                  • -
                                  • HERO10 Black
                                  • -
                                  -
                                  -

                                  Supported Protocols:

                                  +<hr> +<p>Not supported on <strong>WiFi</strong> for:</p> +<pre><code><span class="token operator">-</span> Hero <span class="token number">11</span> Black Mini +<span class="token operator">-</span> Hero <span class="token number">11</span> Black +<span class="token operator">-</span> Hero <span class="token number">10</span> Black +<span class="token operator">-</span> Hero <span class="token number">9</span> Black +</code></pre> +" class="sc-iKOmoZ sc-cCzLxZ WVNwY VEBGS">

                                  HERO12 Black +HERO11 Black + HERO10 Black

                                  +

                                  Supported Protocols:

                                  • USB
                                  • WIFI
                                  +
                                  +

                                  Not supported on WiFi for:

                                  +
                                  - Hero 11 Black Mini
                                  +- Hero 11 Black
                                  +- Hero 10 Black
                                  +- Hero 9 Black
                                  +

                                  Responses

                                  Response Schema: application/json
                                  object

                                  Response samples

                                  Content type
                                  application/json
                                  { }
                                  +
                                  http://10.5.5.9:8080/gopro/webcam/stop

                                  Response samples

                                  Content type
                                  application/json
                                  { }