Skip to content

Commit 99267fc

Browse files
authored
Send multicast support. (#57)
* Send multicast request method.
1 parent 921a1b9 commit 99267fc

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

tests/test_application.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,3 +547,40 @@ def test_rx_device_annce(app, ieee, nwk):
547547
assert app.handle_join.call_args[0][0] == nwk
548548
assert app.handle_join.call_args[0][1] == ieee
549549
assert app.handle_join.call_args[0][2] == 0
550+
551+
552+
async def _test_mrequest(app, send_success=True, send_timeout=False, **kwargs):
553+
seq = 123
554+
group_id = 0x2345
555+
556+
def _mock_command(
557+
cmdname, ieee, nwk, src_ep, dst_ep, cluster, profile, radius, options, data
558+
):
559+
send_fut = asyncio.Future()
560+
if not send_timeout:
561+
if send_success:
562+
send_fut.set_result(xbee_t.TXStatus.SUCCESS)
563+
else:
564+
send_fut.set_result(xbee_t.TXStatus.ADDRESS_NOT_FOUND)
565+
return send_fut
566+
567+
app._api._command = mock.MagicMock(side_effect=_mock_command)
568+
return await app.mrequest(group_id, 0x0260, 1, 2, seq, b"\xaa\x55\xbe\xef")
569+
570+
571+
@pytest.mark.asyncio
572+
async def test_mrequest_with_reply(app):
573+
r = await _test_mrequest(app, send_success=True)
574+
assert r[0] == 0
575+
576+
577+
@pytest.mark.asyncio
578+
async def test_mrequest_send_timeout(app):
579+
r = await _test_mrequest(app, send_timeout=True)
580+
assert r[0] != 0
581+
582+
583+
@pytest.mark.asyncio
584+
async def test_mrequest_send_fail(app):
585+
r = await _test_mrequest(app, send_success=False)
586+
assert r[0] != 0

zigpy_xbee/zigbee/application.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,48 @@ async def _get_association_state(self):
134134
state = await self._api._at_command("AI")
135135
return state
136136

137+
async def mrequest(
138+
self,
139+
group_id,
140+
profile,
141+
cluster,
142+
src_ep,
143+
sequence,
144+
data,
145+
*,
146+
hops=0,
147+
non_member_radius=3
148+
):
149+
"""Submit and send data out as a multicast transmission.
150+
:param group_id: destination multicast address
151+
:param profile: Zigbee Profile ID to use for outgoing message
152+
:param cluster: cluster id where the message is being sent
153+
:param src_ep: source endpoint id
154+
:param sequence: transaction sequence number of the message
155+
:param data: Zigbee message payload
156+
:param hops: the message will be delivered to all nodes within this number of
157+
hops of the sender. A value of zero is converted to MAX_HOPS
158+
:param non_member_radius: the number of hops that the message will be forwarded
159+
by devices that are not members of the group. A value
160+
of 7 or greater is treated as infinite
161+
:returns: return a tuple of a status and an error_message. Original requestor
162+
has more context to provide a more meaningful error message
163+
"""
164+
LOGGER.debug("Zigbee request tsn #%s: %s", sequence, binascii.hexlify(data))
165+
166+
send_req = self._api.tx_explicit(
167+
UNKNOWN_IEEE, group_id, src_ep, src_ep, cluster, profile, hops, 0x08, data
168+
)
169+
170+
try:
171+
v = await asyncio.wait_for(send_req, timeout=TIMEOUT_TX_STATUS)
172+
except asyncio.TimeoutError:
173+
return TXStatus.NETWORK_ACK_FAILURE, "Timeout waiting for ACK"
174+
175+
if v != TXStatus.SUCCESS:
176+
return v, "Error sending tsn #%s: %s".format(sequence, v.name)
177+
return v, "Successfully sent tsn #%s: %s".format(sequence, v.name)
178+
137179
async def request(
138180
self,
139181
device,

0 commit comments

Comments
 (0)