Skip to content
Merged
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
65 changes: 59 additions & 6 deletions tests/test_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,16 @@ async def _version():
app._api.version = mock.MagicMock(
side_effect=_version)

await app.startup(auto_form=False)
assert app.form_network.call_count == 0
await app.startup(auto_form=True)
assert app.form_network.call_count == 1
with mock.patch('zigpy_deconz.zigbee.application.ConBeeDevice') as con:
con.new.side_effect = asyncio.coroutine(mock.MagicMock())
await app.startup(auto_form=False)
assert app.form_network.call_count == 0
await app.startup(auto_form=True)
assert app.form_network.call_count == 1


@pytest.mark.asyncio
async def test_permit(app):
async def test_permit(app, nwk):
app._api.write_parameter = mock.MagicMock(
side_effect=asyncio.coroutine(mock.MagicMock()))
time_s = 30
Expand Down Expand Up @@ -187,7 +189,7 @@ def aps_data_request(req_id, dst_addr_ep, profile, cluster, src_ep, data):
app.get_device = mock.MagicMock(
return_value=zigpy.device.Device(app,
mock.sentinel.ieee,
mock.sentinel.nwk))
nwk))

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

Expand Down Expand Up @@ -306,3 +308,54 @@ def test_rx_device_annce(app, addr_ieee, addr_nwk):
assert app.handle_join.call_args[0][0] == addr_nwk.address
assert app.handle_join.call_args[0][1] == addr_ieee.address
assert app.handle_join.call_args[0][2] == 0


@pytest.mark.asyncio
async def test_conbee_dev_add_to_group(app, nwk):
group = mock.MagicMock()
app._groups = mock.MagicMock()
app._groups.add_group.return_value = group

conbee = application.ConBeeDevice(app, mock.sentinel.ieee, nwk)

await conbee.add_to_group(mock.sentinel.grp_id, mock.sentinel.grp_name)
assert group.add_member.call_count == 1

assert app.groups.add_group.call_count == 1
assert app.groups.add_group.call_args[0][0] is mock.sentinel.grp_id
assert app.groups.add_group.call_args[0][1] is mock.sentinel.grp_name


@pytest.mark.asyncio
async def test_conbee_dev_remove_from_group(app, nwk):
group = mock.MagicMock()
app.groups[mock.sentinel.grp_id] = group
conbee = application.ConBeeDevice(app,
mock.sentinel.ieee, nwk)

await conbee.remove_from_group(mock.sentinel.grp_id)
assert group.remove_member.call_count == 1


def test_conbee_props(nwk):
conbee = application.ConBeeDevice(app, mock.sentinel.ieee, nwk)
assert conbee.manufacturer is not None
assert conbee.model is not None


@pytest.mark.asyncio
async def test_conbee_new(app, nwk, monkeypatch):
mock_init = mock.MagicMock(
side_effect=asyncio.coroutine(mock.MagicMock())
)
monkeypatch.setattr(zigpy.device.Device, '_initialize', mock_init)

conbee = await application.ConBeeDevice.new(app, mock.sentinel.ieee, nwk)
assert isinstance(conbee, zigpy_deconz.zigbee.application.ConBeeDevice)
assert mock_init.call_count == 1
mock_init.reset_mock()

app.devices[mock.sentinel.ieee] = mock.MagicMock()
conbee = await application.ConBeeDevice.new(app, mock.sentinel.ieee, nwk)
assert isinstance(conbee, zigpy_deconz.zigbee.application.ConBeeDevice)
assert mock_init.call_count == 0
48 changes: 48 additions & 0 deletions zigpy_deconz/zigbee/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import zigpy.application
import zigpy.exceptions
import zigpy.endpoint
import zigpy.types
import zigpy.util
import zigpy.device
Expand Down Expand Up @@ -65,6 +66,8 @@ async def startup(self, auto_form=False):

if auto_form:
await self.form_network()
self.devices[self.ieee] = await ConBeeDevice.new(self,
self.ieee, self.nwk)

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

return False


class ConBeeDevice(zigpy.device.Device):
"""Zigpy Device representing Coordinator."""

async def add_to_group(self, grp_id: int,
name: str = None) -> None:
group = self.application.groups.add_group(grp_id, name)
group.add_member(self)
return

async def remove_from_group(self, grp_id: int) -> None:
self.application.groups[grp_id].remove_member(self)
return

@property
def manufacturer(self):
return "dresden elektronik"

@property
def model(self):
return 'ConBee'

@classmethod
async def new(cls, application, ieee, nwk):
"""Create or replace zigpy device."""
dev = cls(application, ieee, nwk)

if ieee in application.devices:
from_dev = application.get_device(ieee=ieee)
dev.status = from_dev.status
dev.node_desc = from_dev.node_desc
for ep_id, from_ep in from_dev.endpoints.items():
if not ep_id:
continue # Skip ZDO
ep = dev.add_endpoint(ep_id)
ep.profile_id = from_ep.profile_id
ep.device_type = from_ep.device_type
ep.status = from_ep.status
ep.in_clusters = from_ep.in_clusters
ep.out_clusters = from_ep.out_clusters
else:
await dev._initialize()

return dev