Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def __init__(self) -> None:
p.RequestCommand.SEND_UNICAST: self.on_send_unicast,
p.RequestCommand.SEND_BROADCAST: self.on_send_broadcast,
p.RequestCommand.SEND_GROUPCAST: self.on_send_groupcast,
p.RequestCommand.SEND_GPDF: self.on_send_gpdf,
p.RequestCommand.CANCEL_REQUEST: self.on_cancel_request,
p.RequestCommand.PERMIT_JOINS: self.on_empty_ok,
p.RequestCommand.SET_CHANNEL: self.on_empty_ok,
Expand Down Expand Up @@ -316,6 +317,13 @@ async def on_send_groupcast(
)
return None

async def on_send_gpdf(self, request: p.SendGpdf, request_id: int) -> None:
# Sent once its GPD listened
await self.send_notification(
p.SendConfirm(status=p.SendStatus.SUCCESS), request_id
)
return None

async def on_cancel_request(
self, request: p.CancelRequest, request_id: int
) -> p.CancelResult:
Expand Down
68 changes: 68 additions & 0 deletions tests/test_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,74 @@
)


@pytest.mark.parametrize(
("target", "kind", "src_id", "gpd_ieee", "endpoint"),
[
(
zgp.types.SrcID(0x12345678),
p.wire.GpdfTargetKind.SRC_ID,
0x12345678,
None,
None,
),
(
(DEVICE_IEEE, 0x01),
p.wire.GpdfTargetKind.IEEE,
None,
DEVICE_IEEE,
0x01,
),
(None, p.wire.GpdfTargetKind.MAINTENANCE, None, None, None),
],
)
async def test_send_gpdf(
app: ControllerApplication,
server: SyntheticZiggurat,
target: zgp.types.SrcID | tuple[t.EUI64, int] | None,
kind: p.wire.GpdfTargetKind,
src_id: int | None,
gpd_ieee: t.EUI64 | None,
endpoint: int | None,
) -> None:
await app.send_gpdf(

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf[None-GpdfTargetKind.MAINTENANCE-None-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf[None-GpdfTargetKind.MAINTENANCE-None-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf[0x12345678-GpdfTargetKind.SRC_ID-305419896-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf[0x12345678-GpdfTargetKind.SRC_ID-305419896-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf[target1-GpdfTargetKind.IEEE-None-gpd_ieee1-1] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf[target1-GpdfTargetKind.IEEE-None-gpd_ieee1-1] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf[None-GpdfTargetKind.MAINTENANCE-None-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf[None-GpdfTargetKind.MAINTENANCE-None-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf[0x12345678-GpdfTargetKind.SRC_ID-305419896-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf[0x12345678-GpdfTargetKind.SRC_ID-305419896-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf[target1-GpdfTargetKind.IEEE-None-gpd_ieee1-1] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf[target1-GpdfTargetKind.IEEE-None-gpd_ieee1-1] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf[target1-GpdfTargetKind.IEEE-None-gpd_ieee1-1] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf[target1-GpdfTargetKind.IEEE-None-gpd_ieee1-1] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf[0x12345678-GpdfTargetKind.SRC_ID-305419896-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf[0x12345678-GpdfTargetKind.SRC_ID-305419896-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf[None-GpdfTargetKind.MAINTENANCE-None-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf[None-GpdfTargetKind.MAINTENANCE-None-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf[None-GpdfTargetKind.MAINTENANCE-None-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf[0x12345678-GpdfTargetKind.SRC_ID-305419896-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf[None-GpdfTargetKind.MAINTENANCE-None-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf[0x12345678-GpdfTargetKind.SRC_ID-305419896-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf[target1-GpdfTargetKind.IEEE-None-gpd_ieee1-1] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf[target1-GpdfTargetKind.IEEE-None-gpd_ieee1-1] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf[None-GpdfTargetKind.MAINTENANCE-None-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf[None-GpdfTargetKind.MAINTENANCE-None-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf[0x12345678-GpdfTargetKind.SRC_ID-305419896-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf[0x12345678-GpdfTargetKind.SRC_ID-305419896-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf[target1-GpdfTargetKind.IEEE-None-gpd_ieee1-1] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf[target1-GpdfTargetKind.IEEE-None-gpd_ieee1-1] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf[None-GpdfTargetKind.MAINTENANCE-None-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf[None-GpdfTargetKind.MAINTENANCE-None-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf[0x12345678-GpdfTargetKind.SRC_ID-305419896-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf[0x12345678-GpdfTargetKind.SRC_ID-305419896-None-None] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf[target1-GpdfTargetKind.IEEE-None-gpd_ieee1-1] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 951 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf[target1-GpdfTargetKind.IEEE-None-gpd_ieee1-1] AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'
target=target,
command_id=zgp.types.GPDCommandID(0xFE),
payload=b"\x00",
channel=15,
lifetime=timedelta(seconds=20),
)

send = server.sent(p.SendGpdf)[-1]
assert send.target == kind
assert send.src_id == src_id
assert send.gpd_ieee == gpd_ieee
assert send.endpoint == endpoint
assert send.channel == 15
assert send.lifetime_ms == 20_000
assert send.command_id == 0xFE
assert bytes(send.payload) == b"\x00"


async def test_send_gpdf_not_sent(
app: ControllerApplication, server: SyntheticZiggurat
) -> None:
async def expired(request: p.SendGpdf, request_id: int) -> None:
await server.send_notification(
p.SendConfirm(status=p.SendStatus.GPDF_EXPIRED), request_id
)

server.handlers[p.RequestCommand.SEND_GPDF] = expired

with pytest.raises(DeliveryError, match="GPDF_EXPIRED"):
await app.send_gpdf(

Check failure on line 981 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf_not_sent AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 981 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf_not_sent AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 981 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf_not_sent AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 981 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf_not_sent AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 981 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf_not_sent AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 981 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf_not_sent AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 981 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf_not_sent AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 981 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

test_send_gpdf_not_sent AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'. Did you mean: '_send_gpdf'?

Check failure on line 981 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf_not_sent AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 981 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

test_send_gpdf_not_sent AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 981 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf_not_sent AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'

Check failure on line 981 in tests/test_application.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

test_send_gpdf_not_sent AttributeError: 'ControllerApplication' object has no attribute 'send_gpdf'
target=zgp.types.SrcID(0x12345678),
command_id=zgp.types.GPDCommandID(0xFE),
payload=b"\x00",
channel=15,
lifetime=timedelta(seconds=20),
)


async def test_add_endpoint(
app: ControllerApplication, server: SyntheticZiggurat
) -> None:
Expand Down
25 changes: 25 additions & 0 deletions tests/test_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import pytest
import zigpy.types as t
from zigpy.zgp.types import SrcID

from zigpy_ziggurat.zigbee import protocol as p

Expand Down Expand Up @@ -119,3 +120,27 @@ def test_load_request_round_trip(request_obj: p.Request) -> None:
parsed, rest = type(request_obj).deserialize(request_obj.serialize())
assert rest == b""
assert parsed == request_obj


@pytest.mark.parametrize(
("target", "expected"),
[
# Target kind in bits 0-1 of the first byte
(SrcID(0x12345678), bytes.fromhex("00 78563412 0F 204E0000 FE 01 00")),
((_IEEE, 0x01), bytes.fromhex("01 7766554433221100 01 0F 204E0000 FE 01 00")),
(None, bytes.fromhex("02 0F 204E0000 FE 01 00")),
],
)
def test_send_gpdf_build(
target: SrcID | tuple[t.EUI64, int] | None, expected: bytes
) -> None:
send = p.SendGpdf.build(
target=target,
command_id=0xFE,
payload=b"\x00",
channel=15,
lifetime=timedelta(seconds=20),
)

assert send.serialize() == expected
assert p.SendGpdf.deserialize(expected) == (send, b"")
2 changes: 1 addition & 1 deletion zigpy_ziggurat/zigbee/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ async def request(self, request: p.Request) -> p.Response | None:
self._pending.pop(request_id, None)

async def request_confirmed(
self, send: p.SendUnicast | p.SendBroadcast | p.SendGroupcast
self, send: p.SendUnicast | p.SendBroadcast | p.SendGroupcast | p.SendGpdf
) -> None:
"""Send and await the terminal confirmation."""

Expand Down
26 changes: 26 additions & 0 deletions zigpy_ziggurat/zigbee/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import zigpy.state
import zigpy.types as t
import zigpy.zdo.types as zdo_t
from zigpy.zgp.types import GPDCommandID, SrcID
from zigpy.zgp.util import parse_gpdf

from zigpy_ziggurat.config import CONF_TUNABLES, CONF_ZIGGURAT_CONFIG, CONFIG_SCHEMA
Expand Down Expand Up @@ -836,6 +837,31 @@ def _handle_received_gpdf(self, command: p.ReceivedGpdf) -> None:

self.gp_packet_received(packet)

async def _send_gpdf(
self,
*,
target: SrcID | tuple[t.EUI64, int] | None,
command_id: GPDCommandID,
payload: bytes,
channel: int,
lifetime: timedelta,
) -> None:
# Ziggurat holds the GPDF until its GPD sends a GPDF with RxAfterTx, then sends
# it in the GPD's receive window
assert self._api is not None
_, status = await self._api.request_confirmed(
p.SendGpdf.build(
target=target,
command_id=command_id,
payload=payload,
channel=channel,
lifetime=lifetime,
)
)

if status != p.SendStatus.SUCCESS:
raise DeliveryError(f"GPDF not sent: {status.name}")

async def send_packet(self, packet: t.ZigbeePacket) -> None:
dst = packet.dst
assert dst is not None and dst.address is not None
Expand Down
42 changes: 42 additions & 0 deletions zigpy_ziggurat/zigbee/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from zigpy.exceptions import DeliveryError
import zigpy.types as t
from zigpy.zgp.types import SrcID

from zigpy_ziggurat.zigbee import wire

Expand Down Expand Up @@ -296,6 +297,47 @@ def build(
)


class SendGpdf(Request, wire.SendGpdfPayload):
command = RequestCommand.SEND_GPDF

@classmethod
def build(
cls,
*,
target: SrcID | tuple[t.EUI64, int] | None,
command_id: int,
payload: bytes,
channel: int,
lifetime: timedelta,
) -> SendGpdf:
src_id: t.uint32_t | None = None
gpd_ieee: t.EUI64 | None = None
endpoint: t.uint8_t | None = None

match target:
case None:
kind = wire.GpdfTargetKind.MAINTENANCE
case (ieee, ep):
kind = wire.GpdfTargetKind.IEEE
gpd_ieee = ieee
endpoint = t.uint8_t(ep)
case _:
kind = wire.GpdfTargetKind.SRC_ID
src_id = t.uint32_t(target)

return cls(
target=kind,
reserved=t.uint6_t(0),
src_id=src_id,
gpd_ieee=gpd_ieee,
endpoint=endpoint,
channel=t.uint8_t(channel),
lifetime_ms=t.uint32_t(lifetime // timedelta(milliseconds=1)),
command_id=t.uint8_t(command_id),
payload=t.LVBytes(payload),
)


class PermitJoins(Request, wire.PermitJoinsPayload):
command = RequestCommand.PERMIT_JOINS

Expand Down
27 changes: 27 additions & 0 deletions zigpy_ziggurat/zigbee/wire.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class RequestCommand(t.enum8):
SET_NWK_UPDATE_ID = 0x36
SET_PROVISIONAL_KEY = 0x37
SET_TUNABLE = 0x38
SEND_GPDF = 0x39
ENERGY_SCAN = 0x40
NETWORK_SCAN = 0x41
PACKET_CAPTURE = 0x42
Expand Down Expand Up @@ -312,6 +313,30 @@ class SendGroupcastPayload(t.Struct):
asdu: t.LongOctetString


class GpdfTargetKind(t.enum2):
SRC_ID = 0
IEEE = 1
MAINTENANCE = 2


class SendGpdfPayload(t.Struct):
target: GpdfTargetKind
reserved: t.uint6_t
src_id: t.uint32_t = t.StructField( # type: ignore[assignment]
requires=lambda s: cast(SendGpdfPayload, s).target in (GpdfTargetKind.SRC_ID,)
)
gpd_ieee: t.EUI64 = t.StructField( # type: ignore[assignment]
requires=lambda s: cast(SendGpdfPayload, s).target in (GpdfTargetKind.IEEE,)
)
endpoint: t.uint8_t = t.StructField( # type: ignore[assignment]
requires=lambda s: cast(SendGpdfPayload, s).target in (GpdfTargetKind.IEEE,)
)
channel: t.uint8_t
lifetime_ms: t.uint32_t
command_id: t.uint8_t
payload: t.LVBytes


class CancelRequestPayload(t.Struct):
request_id: t.uint16_t

Expand Down Expand Up @@ -430,6 +455,8 @@ class SendStatus(t.enum8):
FRAME_BUDGET_EXHAUSTED = 10
CANCELLED = 11
RADIO_ERROR = 12
GPDF_EXPIRED = 14
GPDF_REPLACED = 15


class SendConfirmPayload(t.Struct):
Expand Down
Loading