Skip to content

Commit 967fcc4

Browse files
committed
Support zigpy 0.9
1 parent 6136fc1 commit 967fcc4

File tree

4 files changed

+37
-64
lines changed

4 files changed

+37
-64
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def is_raspberry_pi(raise_on_errors=False):
4848

4949

5050
requires = ['pyserial-asyncio',
51-
'zigpy-homeassistant', # https://github.com/zigpy/zigpy/issues/190
51+
'zigpy-homeassistant>=0.9.0', # https://github.com/zigpy/zigpy/issues/190
5252
]
5353
if is_raspberry_pi():
5454
requires.append('RPi.GPIO')

zigpy_zigate/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
MAJOR_VERSION = 0
2-
MINOR_VERSION = 3
3-
PATCH_VERSION = '1'
2+
MINOR_VERSION = 4
3+
PATCH_VERSION = '0'
44
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
55
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)

zigpy_zigate/api.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
}
3535

3636

37+
class NoResponseError(Exception):
38+
pass
39+
40+
3741
class ZiGate:
3842
def __init__(self):
3943
self._uart = None
@@ -77,7 +81,7 @@ async def command(self, cmd, data=b'', wait_response=None, wait_status=True):
7781
)
7882
except asyncio.TimeoutError:
7983
LOGGER.warning("No response to command 0x{:04x}".format(cmd))
80-
raise
84+
raise NoResponseError
8185

8286
def _command(self, cmd, data=b'', wait_response=None, wait_status=True):
8387
self._uart.send(cmd, data)

zigpy_zigate/zigbee/application.py

Lines changed: 29 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import asyncio
22
import logging
33

4-
from zigpy.exceptions import DeliveryError
54
import zigpy.device
65
import zigpy.application
76
import zigpy.util
87
from zigpy_zigate import types as t
8+
from zigpy_zigate.api import NoResponseError
99

1010
LOGGER = logging.getLogger(__name__)
1111

@@ -18,7 +18,6 @@ def __init__(self, api, database_file=None):
1818
api.set_application(self)
1919

2020
self._pending = {}
21-
self._zigate_seq = {}
2221

2322
self._nwk = 0
2423
self._ieee = 0
@@ -106,78 +105,48 @@ def zigate_callback_handler(self, msg, response, lqi):
106105
return
107106
rssi = 0
108107
device.radio_details(lqi, rssi)
109-
tsn, command_id, is_reply, args = self.deserialize(device, response[3],
110-
response[2], response[-1])
111-
if is_reply:
112-
self._handle_reply(device, response, tsn, command_id, args)
113-
else:
114-
self.handle_message(device, False, response[1],
115-
response[2],
116-
response[3], response[4],
117-
tsn, command_id, args)
108+
self.handle_message(device, response[1],
109+
response[2],
110+
response[3], response[4], response[-1])
118111
elif msg == 0x8702: # APS Data confirm Fail
119112
self._handle_frame_failure(response[4], response[0])
120113

121-
def _handle_reply(self, sender, response, tsn, command_id, args):
122-
try:
123-
send_fut, reply_fut = self._pending[tsn]
124-
if send_fut.done():
125-
self._pending.pop(tsn)
126-
if reply_fut:
127-
reply_fut.set_result(args)
128-
return
129-
except KeyError:
130-
LOGGER.warning("Unexpected response TSN=%s command=%s args=%s", tsn, command_id, args)
131-
except asyncio.futures.InvalidStateError as exc:
132-
LOGGER.debug("Invalid state on future - probably duplicate response: %s", exc)
133-
# We've already handled, don't drop through to device handler
134-
# EDIT : Temporary remove return since we can receive more that one reply with the same tsn
135-
# return
136-
137-
self.handle_message(sender, True, response[1],
138-
response[2], response[3], response[4],
139-
tsn, command_id, args)
140-
141114
def _handle_frame_failure(self, message_tag, status):
142115
try:
143-
send_fut, reply_fut = self._pending.pop(message_tag)
144-
send_fut.set_exception(DeliveryError("Message send failure: %s" % (status, )))
145-
if reply_fut:
146-
reply_fut.cancel()
116+
send_fut = self._pending.pop(message_tag)
117+
send_fut.set_result(status)
147118
except KeyError:
148119
LOGGER.warning("Unexpected message send failure")
149120
except asyncio.futures.InvalidStateError as exc:
150121
LOGGER.debug("Invalid state on future - probably duplicate response: %s", exc)
151122

152123
@zigpy.util.retryable_request
153-
async def request(self, nwk, profile, cluster, src_ep, dst_ep, sequence, data, expect_reply=True, timeout=10):
154-
LOGGER.debug('request %s', (nwk, profile, cluster, src_ep, dst_ep, sequence, data, expect_reply, timeout))
155-
assert sequence not in self._pending
124+
async def request(self, device, profile, cluster, src_ep, dst_ep, sequence, data,
125+
expect_reply=True, use_ieee=False):
126+
LOGGER.debug('request %s',
127+
(device.nwk, profile, cluster, src_ep, dst_ep, sequence, data, expect_reply, use_ieee))
128+
req_id = self.get_sequence()
156129
send_fut = asyncio.Future()
157-
reply_fut = None
158-
if expect_reply:
159-
reply_fut = asyncio.Future()
160-
self._pending[sequence] = (send_fut, reply_fut)
161-
v, lqi = await self._api.raw_aps_data_request(nwk, src_ep, dst_ep, profile, cluster, data)
162-
self._zigate_seq[sequence] = v[1]
130+
self._pending[req_id] = send_fut
131+
try:
132+
v, lqi = await self._api.raw_aps_data_request(device.nwk, src_ep, dst_ep, profile, cluster, data)
133+
except NoResponseError:
134+
return 1, "ZiGate doesn't answer to command"
163135

164136
if v[0] != 0:
165-
self._pending.pop(sequence)
166-
self._zigate_seq.pop(sequence)
167-
if expect_reply:
168-
reply_fut.cancel()
169-
raise DeliveryError("Message send failure %s" % (v[0], ))
170-
171-
if expect_reply:
172-
# Wait for reply
173-
try:
174-
v = await asyncio.wait_for(reply_fut, timeout)
175-
except: # noqa: E722
176-
# If we timeout (or fail for any reason), clear the future
177-
self._pending.pop(sequence)
178-
self._zigate_seq.pop(sequence)
179-
raise
180-
return v
137+
self._pending.pop(req_id)
138+
return v[0], "Message send failure %s"
139+
140+
# Commented out for now
141+
# Currently (Firmware 3.1a) only send APS Data confirm in case of failure
142+
# try:
143+
# v = await asyncio.wait_for(send_fut, 120)
144+
# except asyncio.TimeoutError:
145+
# return 1, "timeout waiting for message %s send ACK" % (sequence, )
146+
# finally:
147+
# self._pending.pop(req_id)
148+
# return v, "Message sent"
149+
return 0, "Message sent"
181150

182151
async def permit_ncp(self, time_s=60):
183152
assert 0 <= time_s <= 254

0 commit comments

Comments
 (0)