Skip to content

Commit 61d8e84

Browse files
authored
Add ConBee zigpy device. (#55)
* ConBee zigpy Device. * Update tests.
1 parent fe78fd5 commit 61d8e84

File tree

2 files changed

+107
-6
lines changed

2 files changed

+107
-6
lines changed

tests/test_application.py

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,16 @@ async def _version():
152152
app._api.version = mock.MagicMock(
153153
side_effect=_version)
154154

155-
await app.startup(auto_form=False)
156-
assert app.form_network.call_count == 0
157-
await app.startup(auto_form=True)
158-
assert app.form_network.call_count == 1
155+
with mock.patch('zigpy_deconz.zigbee.application.ConBeeDevice') as con:
156+
con.new.side_effect = asyncio.coroutine(mock.MagicMock())
157+
await app.startup(auto_form=False)
158+
assert app.form_network.call_count == 0
159+
await app.startup(auto_form=True)
160+
assert app.form_network.call_count == 1
159161

160162

161163
@pytest.mark.asyncio
162-
async def test_permit(app):
164+
async def test_permit(app, nwk):
163165
app._api.write_parameter = mock.MagicMock(
164166
side_effect=asyncio.coroutine(mock.MagicMock()))
165167
time_s = 30
@@ -187,7 +189,7 @@ def aps_data_request(req_id, dst_addr_ep, profile, cluster, src_ep, data):
187189
app.get_device = mock.MagicMock(
188190
return_value=zigpy.device.Device(app,
189191
mock.sentinel.ieee,
190-
mock.sentinel.nwk))
192+
nwk))
191193

192194
return await app.request(nwk, 0x0260, 1, 2, 3, seq, b'\x01\x02\x03', expect_reply=expect_reply, **kwargs)
193195

@@ -306,3 +308,54 @@ def test_rx_device_annce(app, addr_ieee, addr_nwk):
306308
assert app.handle_join.call_args[0][0] == addr_nwk.address
307309
assert app.handle_join.call_args[0][1] == addr_ieee.address
308310
assert app.handle_join.call_args[0][2] == 0
311+
312+
313+
@pytest.mark.asyncio
314+
async def test_conbee_dev_add_to_group(app, nwk):
315+
group = mock.MagicMock()
316+
app._groups = mock.MagicMock()
317+
app._groups.add_group.return_value = group
318+
319+
conbee = application.ConBeeDevice(app, mock.sentinel.ieee, nwk)
320+
321+
await conbee.add_to_group(mock.sentinel.grp_id, mock.sentinel.grp_name)
322+
assert group.add_member.call_count == 1
323+
324+
assert app.groups.add_group.call_count == 1
325+
assert app.groups.add_group.call_args[0][0] is mock.sentinel.grp_id
326+
assert app.groups.add_group.call_args[0][1] is mock.sentinel.grp_name
327+
328+
329+
@pytest.mark.asyncio
330+
async def test_conbee_dev_remove_from_group(app, nwk):
331+
group = mock.MagicMock()
332+
app.groups[mock.sentinel.grp_id] = group
333+
conbee = application.ConBeeDevice(app,
334+
mock.sentinel.ieee, nwk)
335+
336+
await conbee.remove_from_group(mock.sentinel.grp_id)
337+
assert group.remove_member.call_count == 1
338+
339+
340+
def test_conbee_props(nwk):
341+
conbee = application.ConBeeDevice(app, mock.sentinel.ieee, nwk)
342+
assert conbee.manufacturer is not None
343+
assert conbee.model is not None
344+
345+
346+
@pytest.mark.asyncio
347+
async def test_conbee_new(app, nwk, monkeypatch):
348+
mock_init = mock.MagicMock(
349+
side_effect=asyncio.coroutine(mock.MagicMock())
350+
)
351+
monkeypatch.setattr(zigpy.device.Device, '_initialize', mock_init)
352+
353+
conbee = await application.ConBeeDevice.new(app, mock.sentinel.ieee, nwk)
354+
assert isinstance(conbee, zigpy_deconz.zigbee.application.ConBeeDevice)
355+
assert mock_init.call_count == 1
356+
mock_init.reset_mock()
357+
358+
app.devices[mock.sentinel.ieee] = mock.MagicMock()
359+
conbee = await application.ConBeeDevice.new(app, mock.sentinel.ieee, nwk)
360+
assert isinstance(conbee, zigpy_deconz.zigbee.application.ConBeeDevice)
361+
assert mock_init.call_count == 0

zigpy_deconz/zigbee/application.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import zigpy.application
99
import zigpy.exceptions
10+
import zigpy.endpoint
1011
import zigpy.types
1112
import zigpy.util
1213
import zigpy.device
@@ -65,6 +66,8 @@ async def startup(self, auto_form=False):
6566

6667
if auto_form:
6768
await self.form_network()
69+
self.devices[self.ieee] = await ConBeeDevice.new(self,
70+
self.ieee, self.nwk)
6871

6972
async def force_remove(self, dev):
7073
"""Forcibly remove device from NCP."""
@@ -283,3 +286,48 @@ def __exit__(self, exc_type, exc_value, exc_traceback):
283286
self.sequence, exc_type.__name__)
284287

285288
return False
289+
290+
291+
class ConBeeDevice(zigpy.device.Device):
292+
"""Zigpy Device representing Coordinator."""
293+
294+
async def add_to_group(self, grp_id: int,
295+
name: str = None) -> None:
296+
group = self.application.groups.add_group(grp_id, name)
297+
group.add_member(self)
298+
return
299+
300+
async def remove_from_group(self, grp_id: int) -> None:
301+
self.application.groups[grp_id].remove_member(self)
302+
return
303+
304+
@property
305+
def manufacturer(self):
306+
return "dresden elektronik"
307+
308+
@property
309+
def model(self):
310+
return 'ConBee'
311+
312+
@classmethod
313+
async def new(cls, application, ieee, nwk):
314+
"""Create or replace zigpy device."""
315+
dev = cls(application, ieee, nwk)
316+
317+
if ieee in application.devices:
318+
from_dev = application.get_device(ieee=ieee)
319+
dev.status = from_dev.status
320+
dev.node_desc = from_dev.node_desc
321+
for ep_id, from_ep in from_dev.endpoints.items():
322+
if not ep_id:
323+
continue # Skip ZDO
324+
ep = dev.add_endpoint(ep_id)
325+
ep.profile_id = from_ep.profile_id
326+
ep.device_type = from_ep.device_type
327+
ep.status = from_ep.status
328+
ep.in_clusters = from_ep.in_clusters
329+
ep.out_clusters = from_ep.out_clusters
330+
else:
331+
await dev._initialize()
332+
333+
return dev

0 commit comments

Comments
 (0)