Skip to content

Commit

Permalink
Tutorials maintenance (#450)
Browse files Browse the repository at this point in the history
* Update dependencies
* Port to latest bleak and test each tutorial
* Update tutorial markdown files
  • Loading branch information
tcamise-gpsw authored Dec 7, 2023
1 parent 9b895dc commit 807d178
Show file tree
Hide file tree
Showing 17 changed files with 495 additions and 464 deletions.
804 changes: 414 additions & 390 deletions demos/python/tutorial/poetry.lock

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions demos/python/tutorial/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "open-gopro-tutorials"
version = "0.1.0"
version = "0.2.0"
description = "Open GoPro Python Tutorials"
authors = ["Tim Camise <tcamise@gopro.com>"]
license = "MIT"
Expand All @@ -25,21 +25,21 @@ classifiers = [

[tool.poetry.dependencies]
python = ">=3.8,<3.11"
bleak = "0.15.1"
bleak = "0.21.1"
requests = "^2"
rich = "^13.3.2"
rich = "^13"

[tool.poetry.group.dev.dependencies]
poethepoet = "^0.18.1"
poethepoet = "^0"
black = "*"
mypy = "^1"
pytest = "^7.2.2"
pytest-asyncio = "^0.20.3"
pytest-html = "^3.2.0"
pytest-cov = "^4.0.0"
mypy = "*"
pytest = "^7"
pytest-asyncio = "^0"
pytest-html = "^3"
pytest-cov = "^4"
coverage = { extras = ["toml"], version = "^6" }
pylint = "^2.16.4"
types-requests = "^2.28.11.15"
pylint = "^2"
types-requests = "*"

[build-system]
requires = ["poetry-core"]
Expand Down
5 changes: 5 additions & 0 deletions demos/python/tutorial/tutorial_modules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@

# pylint: disable=wrong-import-position

from typing import Callable
import logging

from bleak.backends.characteristic import BleakGATTCharacteristic

from rich.logging import RichHandler
from rich import traceback

Expand All @@ -25,6 +28,8 @@
GOPRO_BASE_UUID = "b5f9{}-aa8d-11e3-9046-0002a5d5c51b"
GOPRO_BASE_URL = "http://10.5.5.9:8080"

noti_handler_T = Callable[[BleakGATTCharacteristic, bytearray], 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
import sys
import asyncio
import argparse
from typing import Dict, Any, List, Callable, Optional
from typing import Dict, Any, List, Optional

from bleak import BleakScanner, BleakClient
from bleak.backends.device import BLEDevice as BleakDevice

from tutorial_modules import logger
from tutorial_modules import logger, noti_handler_T


def exception_handler(loop: asyncio.AbstractEventLoop, context: Dict[str, Any]) -> None:
Expand All @@ -25,18 +25,15 @@ def exception_handler(loop: asyncio.AbstractEventLoop, context: Dict[str, Any])
logger.critical("This is unexpected and unrecoverable.")


async def connect_ble(
notification_handler: Callable[[int, bytes], None],
identifier: Optional[str] = None,
) -> BleakClient:
async def connect_ble(notification_handler: noti_handler_T, identifier: Optional[str] = None) -> BleakClient:
"""Connect to a GoPro, then pair, and enable notifications
If identifier is None, the first discovered GoPro will be connected to.
Retry 10 times
Args:
notification_handler (Callable[[int, bytes], None]): callback when notification is received
notification_handler (noti_handler_T): callback when notification is received
identifier (str, optional): Last 4 digits of GoPro serial number. Defaults to None.
Raises:
Expand Down Expand Up @@ -102,7 +99,7 @@ def _scan_callback(device: BleakDevice, _: Any) -> None:
for char in service.characteristics:
if "notify" in char.properties:
logger.info(f"Enabling notification on char {char.uuid}")
await client.start_notify(char, notification_handler) # type: ignore
await client.start_notify(char, notification_handler)
logger.info("Done enabling notifications")

return client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
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 GOPRO_BASE_UUID, connect_ble, logger, noti_handler_T


async def main(identifier: Optional[str]) -> None:
Expand All @@ -23,11 +23,11 @@ async def main(identifier: Optional[str]) -> None:

client: BleakClient

def notification_handler(handle: int, data: bytes) -> None:
logger.info(f'Received response at {handle=}: {hexlify(data, ":")!r}')
def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> 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
if client.services.characteristics[handle].uuid == response_uuid and data[2] == 0x00:
if client.services.characteristics[characteristic.handle].uuid == response_uuid and data[2] == 0x00:
logger.info("Command sent successfully")
# Anything else is unexpected. This shouldn't happen
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from binascii import hexlify

from bleak import BleakClient
from bleak.backends.characteristic import BleakGATTCharacteristic

from tutorial_modules import GOPRO_BASE_UUID, connect_ble, logger

Expand All @@ -23,11 +24,11 @@ async def main(identifier: Optional[str]) -> None:

client: BleakClient

def notification_handler(handle: int, data: bytes) -> None:
logger.info(f'Received response at {handle=}: {hexlify(data, ":")!r}')
def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> 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
if client.services.characteristics[handle].uuid == response_uuid and data[2] == 0x00:
if client.services.characteristics[characteristic.handle].uuid == response_uuid and data[2] == 0x00:
logger.info("Command sent successfully")
# Anything else is unexpected. This shouldn't happen
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from binascii import hexlify

from bleak import BleakClient
from bleak.backends.characteristic import BleakGATTCharacteristic

from tutorial_modules import GOPRO_BASE_UUID, connect_ble, logger

Expand All @@ -23,11 +24,11 @@ async def main(identifier: Optional[str]) -> None:

client: BleakClient

def notification_handler(handle: int, data: bytes) -> None:
logger.info(f'Received response at {handle=}: {hexlify(data, ":")!r}')
def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> 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
if client.services.characteristics[handle].uuid == response_uuid and data[2] == 0x00:
if client.services.characteristics[characteristic.handle].uuid == response_uuid and data[2] == 0x00:
logger.info("Command sent successfully")
# Anything else is unexpected. This shouldn't happen
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
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

Expand All @@ -24,11 +24,11 @@ async def main(identifier: Optional[str]) -> None:

client: BleakClient

def notification_handler(handle: int, data: bytes) -> None:
logger.info(f'Received response at {handle}: {data.hex(":")}')
def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> 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
if client.services.characteristics[handle].uuid == response_uuid and data[2] == 0x00:
if client.services.characteristics[characteristic.handle].uuid == response_uuid and data[2] == 0x00:
logger.info("Command sent successfully")
# Anything else is unexpected. This shouldn't happen
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
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

Expand Down Expand Up @@ -94,16 +95,19 @@ async def main(identifier: Optional[str]) -> None:
client: BleakClient
response = Response()

def notification_handler(handle: int, data: bytes) -> None:
logger.info(f'Received response at {handle=}: {hexlify(data, ":")!r}')
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[handle].uuid == response_uuid and response.status == 0:
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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
import sys
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

Expand All @@ -23,11 +23,11 @@ async def main(identifier: Optional[str]) -> None:

client: BleakClient

def notification_handler(handle: int, data: bytes) -> None:
logger.info(f'Received response at {handle=}: {hexlify(data, ":")!r}')
def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> 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
if client.services.characteristics[handle].uuid == response_uuid:
if client.services.characteristics[characteristic.handle].uuid == response_uuid:
# First byte is the length for this command.
length = data[0]
# Second byte is the ID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
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, Response

Expand Down Expand Up @@ -70,8 +70,8 @@ async def main(identifier: Optional[str]) -> None:
client: BleakClient
response = Response()

def notification_handler(handle: int, data: bytes) -> None:
logger.info(f'Received response at {handle=}: {hexlify(data, ":")!r}')
def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None:
logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}')

response.accumulate(data)

Expand All @@ -80,15 +80,15 @@ def notification_handler(handle: int, data: bytes) -> None:
response.parse()

# If this is query response, it must contain a resolution value
if client.services.characteristics[handle].uuid == QUERY_RSP_UUID:
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[handle].uuid == SETTINGS_RSP_UUID:
elif client.services.characteristics[characteristic.handle].uuid == SETTINGS_RSP_UUID:
logger.info("Command sent successfully")
# Anything else is unexpected. This shouldn't happen
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
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, Response

Expand Down Expand Up @@ -42,8 +42,8 @@ async def main(identifier: Optional[str]) -> None:
client: BleakClient
response = Response()

def notification_handler(handle: int, data: bytes) -> None:
logger.info(f'Received response at {handle=}: {hexlify(data, ":")!r}')
def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None:
logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}')

response.accumulate(data)

Expand All @@ -52,11 +52,11 @@ def notification_handler(handle: int, data: bytes) -> None:
response.parse()

# If this is query response, it must contain a resolution value
if client.services.characteristics[handle].uuid == QUERY_RSP_UUID:
if client.services.characteristics[characteristic.handle].uuid == QUERY_RSP_UUID:
global resolution
resolution = Resolution(response.data[RESOLUTION_ID][0])
# If this is a setting response, it will just show the status
elif client.services.characteristics[handle].uuid == SETTINGS_RSP_UUID:
elif client.services.characteristics[characteristic.handle].uuid == SETTINGS_RSP_UUID:
logger.info("Command sent successfully")
# Anything else is unexpected. This shouldn't happen
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
# This copyright was auto-generated on Wed, Sep 1, 2021 5:06:00 PM

import sys
import time
import enum
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, Response

Expand Down Expand Up @@ -44,8 +43,8 @@ async def main(identifier: Optional[str]) -> None:
client: BleakClient
response = Response()

def notification_handler(handle: int, data: bytes) -> None:
logger.info(f'Received response at {handle=}: {hexlify(data, ":")!r}')
def notification_handler(characteristic: BleakGATTCharacteristic, data: bytes) -> None:
logger.info(f'Received response at handle {characteristic.handle}: {data.hex(":")}')

response.accumulate(data)

Expand All @@ -54,11 +53,11 @@ def notification_handler(handle: int, data: bytes) -> None:
response.parse()

# If this is query response, it must contain a resolution value
if client.services.characteristics[handle].uuid == QUERY_RSP_UUID:
if client.services.characteristics[characteristic.handle].uuid == QUERY_RSP_UUID:
global resolution
resolution = Resolution(response.data[RESOLUTION_ID][0])
# If this is a setting response, it will just show the status
elif client.services.characteristics[handle].uuid == SETTINGS_RSP_UUID:
elif client.services.characteristics[characteristic.handle].uuid == SETTINGS_RSP_UUID:
logger.info("Command sent successfully")
# Anything else is unexpected. This shouldn't happen
else:
Expand Down
Loading

0 comments on commit 807d178

Please sign in to comment.