Leverage zigpy for IEEE address conversions (#27972)

* Refactor EUI64 conversions.

* Update ZHA dependencies.

* Update tests.
This commit is contained in:
Alexei Chetroi 2019-10-21 13:14:17 -04:00 committed by David F. Mulcahey
parent 643257d911
commit a0c50f4794
13 changed files with 135 additions and 81 deletions

View File

@ -4,6 +4,7 @@ import asyncio
import logging import logging
import voluptuous as vol import voluptuous as vol
from zigpy.types.named import EUI64
from homeassistant.components import websocket_api from homeassistant.components import websocket_api
from homeassistant.core import callback from homeassistant.core import callback
@ -44,7 +45,7 @@ from .core.const import (
WARNING_DEVICE_STROBE_HIGH, WARNING_DEVICE_STROBE_HIGH,
WARNING_DEVICE_STROBE_YES, WARNING_DEVICE_STROBE_YES,
) )
from .core.helpers import async_is_bindable_target, convert_ieee, get_matched_clusters from .core.helpers import async_is_bindable_target, get_matched_clusters
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -76,16 +77,16 @@ IEEE_SERVICE = "ieee_based_service"
SERVICE_SCHEMAS = { SERVICE_SCHEMAS = {
SERVICE_PERMIT: vol.Schema( SERVICE_PERMIT: vol.Schema(
{ {
vol.Optional(ATTR_IEEE_ADDRESS, default=None): convert_ieee, vol.Optional(ATTR_IEEE_ADDRESS, default=None): EUI64.convert,
vol.Optional(ATTR_DURATION, default=60): vol.All( vol.Optional(ATTR_DURATION, default=60): vol.All(
vol.Coerce(int), vol.Range(0, 254) vol.Coerce(int), vol.Range(0, 254)
), ),
} }
), ),
IEEE_SERVICE: vol.Schema({vol.Required(ATTR_IEEE_ADDRESS): convert_ieee}), IEEE_SERVICE: vol.Schema({vol.Required(ATTR_IEEE_ADDRESS): EUI64.convert}),
SERVICE_SET_ZIGBEE_CLUSTER_ATTRIBUTE: vol.Schema( SERVICE_SET_ZIGBEE_CLUSTER_ATTRIBUTE: vol.Schema(
{ {
vol.Required(ATTR_IEEE): convert_ieee, vol.Required(ATTR_IEEE): EUI64.convert,
vol.Required(ATTR_ENDPOINT_ID): cv.positive_int, vol.Required(ATTR_ENDPOINT_ID): cv.positive_int,
vol.Required(ATTR_CLUSTER_ID): cv.positive_int, vol.Required(ATTR_CLUSTER_ID): cv.positive_int,
vol.Optional(ATTR_CLUSTER_TYPE, default=CLUSTER_TYPE_IN): cv.string, vol.Optional(ATTR_CLUSTER_TYPE, default=CLUSTER_TYPE_IN): cv.string,
@ -96,7 +97,7 @@ SERVICE_SCHEMAS = {
), ),
SERVICE_WARNING_DEVICE_SQUAWK: vol.Schema( SERVICE_WARNING_DEVICE_SQUAWK: vol.Schema(
{ {
vol.Required(ATTR_IEEE): convert_ieee, vol.Required(ATTR_IEEE): EUI64.convert,
vol.Optional( vol.Optional(
ATTR_WARNING_DEVICE_MODE, default=WARNING_DEVICE_SQUAWK_MODE_ARMED ATTR_WARNING_DEVICE_MODE, default=WARNING_DEVICE_SQUAWK_MODE_ARMED
): cv.positive_int, ): cv.positive_int,
@ -110,7 +111,7 @@ SERVICE_SCHEMAS = {
), ),
SERVICE_WARNING_DEVICE_WARN: vol.Schema( SERVICE_WARNING_DEVICE_WARN: vol.Schema(
{ {
vol.Required(ATTR_IEEE): convert_ieee, vol.Required(ATTR_IEEE): EUI64.convert,
vol.Optional( vol.Optional(
ATTR_WARNING_DEVICE_MODE, default=WARNING_DEVICE_MODE_EMERGENCY ATTR_WARNING_DEVICE_MODE, default=WARNING_DEVICE_MODE_EMERGENCY
): cv.positive_int, ): cv.positive_int,
@ -131,7 +132,7 @@ SERVICE_SCHEMAS = {
), ),
SERVICE_ISSUE_ZIGBEE_CLUSTER_COMMAND: vol.Schema( SERVICE_ISSUE_ZIGBEE_CLUSTER_COMMAND: vol.Schema(
{ {
vol.Required(ATTR_IEEE): convert_ieee, vol.Required(ATTR_IEEE): EUI64.convert,
vol.Required(ATTR_ENDPOINT_ID): cv.positive_int, vol.Required(ATTR_ENDPOINT_ID): cv.positive_int,
vol.Required(ATTR_CLUSTER_ID): cv.positive_int, vol.Required(ATTR_CLUSTER_ID): cv.positive_int,
vol.Optional(ATTR_CLUSTER_TYPE, default=CLUSTER_TYPE_IN): cv.string, vol.Optional(ATTR_CLUSTER_TYPE, default=CLUSTER_TYPE_IN): cv.string,
@ -149,7 +150,7 @@ SERVICE_SCHEMAS = {
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
vol.Required("type"): "zha/devices/permit", vol.Required("type"): "zha/devices/permit",
vol.Optional(ATTR_IEEE, default=None): convert_ieee, vol.Optional(ATTR_IEEE, default=None): EUI64.convert,
vol.Optional(ATTR_DURATION, default=60): vol.All( vol.Optional(ATTR_DURATION, default=60): vol.All(
vol.Coerce(int), vol.Range(0, 254) vol.Coerce(int), vol.Range(0, 254)
), ),
@ -200,7 +201,7 @@ async def websocket_get_devices(hass, connection, msg):
@websocket_api.require_admin @websocket_api.require_admin
@websocket_api.async_response @websocket_api.async_response
@websocket_api.websocket_command( @websocket_api.websocket_command(
{vol.Required(TYPE): "zha/device", vol.Required(ATTR_IEEE): convert_ieee} {vol.Required(TYPE): "zha/device", vol.Required(ATTR_IEEE): EUI64.convert}
) )
async def websocket_get_device(hass, connection, msg): async def websocket_get_device(hass, connection, msg):
"""Get ZHA devices.""" """Get ZHA devices."""
@ -252,7 +253,7 @@ def async_get_device_info(hass, device, ha_device_registry=None):
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
vol.Required(TYPE): "zha/devices/reconfigure", vol.Required(TYPE): "zha/devices/reconfigure",
vol.Required(ATTR_IEEE): convert_ieee, vol.Required(ATTR_IEEE): EUI64.convert,
} }
) )
async def websocket_reconfigure_node(hass, connection, msg): async def websocket_reconfigure_node(hass, connection, msg):
@ -267,7 +268,7 @@ async def websocket_reconfigure_node(hass, connection, msg):
@websocket_api.require_admin @websocket_api.require_admin
@websocket_api.async_response @websocket_api.async_response
@websocket_api.websocket_command( @websocket_api.websocket_command(
{vol.Required(TYPE): "zha/devices/clusters", vol.Required(ATTR_IEEE): convert_ieee} {vol.Required(TYPE): "zha/devices/clusters", vol.Required(ATTR_IEEE): EUI64.convert}
) )
async def websocket_device_clusters(hass, connection, msg): async def websocket_device_clusters(hass, connection, msg):
"""Return a list of device clusters.""" """Return a list of device clusters."""
@ -305,7 +306,7 @@ async def websocket_device_clusters(hass, connection, msg):
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
vol.Required(TYPE): "zha/devices/clusters/attributes", vol.Required(TYPE): "zha/devices/clusters/attributes",
vol.Required(ATTR_IEEE): convert_ieee, vol.Required(ATTR_IEEE): EUI64.convert,
vol.Required(ATTR_ENDPOINT_ID): int, vol.Required(ATTR_ENDPOINT_ID): int,
vol.Required(ATTR_CLUSTER_ID): int, vol.Required(ATTR_CLUSTER_ID): int,
vol.Required(ATTR_CLUSTER_TYPE): str, vol.Required(ATTR_CLUSTER_TYPE): str,
@ -346,7 +347,7 @@ async def websocket_device_cluster_attributes(hass, connection, msg):
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
vol.Required(TYPE): "zha/devices/clusters/commands", vol.Required(TYPE): "zha/devices/clusters/commands",
vol.Required(ATTR_IEEE): convert_ieee, vol.Required(ATTR_IEEE): EUI64.convert,
vol.Required(ATTR_ENDPOINT_ID): int, vol.Required(ATTR_ENDPOINT_ID): int,
vol.Required(ATTR_CLUSTER_ID): int, vol.Required(ATTR_CLUSTER_ID): int,
vol.Required(ATTR_CLUSTER_TYPE): str, vol.Required(ATTR_CLUSTER_TYPE): str,
@ -400,7 +401,7 @@ async def websocket_device_cluster_commands(hass, connection, msg):
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
vol.Required(TYPE): "zha/devices/clusters/attributes/value", vol.Required(TYPE): "zha/devices/clusters/attributes/value",
vol.Required(ATTR_IEEE): convert_ieee, vol.Required(ATTR_IEEE): EUI64.convert,
vol.Required(ATTR_ENDPOINT_ID): int, vol.Required(ATTR_ENDPOINT_ID): int,
vol.Required(ATTR_CLUSTER_ID): int, vol.Required(ATTR_CLUSTER_ID): int,
vol.Required(ATTR_CLUSTER_TYPE): str, vol.Required(ATTR_CLUSTER_TYPE): str,
@ -444,7 +445,7 @@ async def websocket_read_zigbee_cluster_attributes(hass, connection, msg):
@websocket_api.require_admin @websocket_api.require_admin
@websocket_api.async_response @websocket_api.async_response
@websocket_api.websocket_command( @websocket_api.websocket_command(
{vol.Required(TYPE): "zha/devices/bindable", vol.Required(ATTR_IEEE): convert_ieee} {vol.Required(TYPE): "zha/devices/bindable", vol.Required(ATTR_IEEE): EUI64.convert}
) )
async def websocket_get_bindable_devices(hass, connection, msg): async def websocket_get_bindable_devices(hass, connection, msg):
"""Directly bind devices.""" """Directly bind devices."""
@ -472,8 +473,8 @@ async def websocket_get_bindable_devices(hass, connection, msg):
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
vol.Required(TYPE): "zha/devices/bind", vol.Required(TYPE): "zha/devices/bind",
vol.Required(ATTR_SOURCE_IEEE): convert_ieee, vol.Required(ATTR_SOURCE_IEEE): EUI64.convert,
vol.Required(ATTR_TARGET_IEEE): convert_ieee, vol.Required(ATTR_TARGET_IEEE): EUI64.convert,
} }
) )
async def websocket_bind_devices(hass, connection, msg): async def websocket_bind_devices(hass, connection, msg):
@ -494,8 +495,8 @@ async def websocket_bind_devices(hass, connection, msg):
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
vol.Required(TYPE): "zha/devices/unbind", vol.Required(TYPE): "zha/devices/unbind",
vol.Required(ATTR_SOURCE_IEEE): convert_ieee, vol.Required(ATTR_SOURCE_IEEE): EUI64.convert,
vol.Required(ATTR_TARGET_IEEE): convert_ieee, vol.Required(ATTR_TARGET_IEEE): EUI64.convert,
} }
) )
async def websocket_unbind_devices(hass, connection, msg): async def websocket_unbind_devices(hass, connection, msg):

View File

@ -8,6 +8,8 @@ import asyncio
import collections import collections
import logging import logging
from zigpy.types.named import EUI64
from homeassistant.core import callback from homeassistant.core import callback
from .const import ( from .const import (
@ -78,15 +80,6 @@ async def check_zigpy_connection(usb_path, radio_type, database_path):
return True return True
def convert_ieee(ieee_str):
"""Convert given ieee string to EUI64."""
from zigpy.types import EUI64, uint8_t
if ieee_str is None:
return None
return EUI64([uint8_t(p, base=16) for p in ieee_str.split(":")])
def get_attr_id_by_name(cluster, attr_name): def get_attr_id_by_name(cluster, attr_name):
"""Get the attribute id for a cluster attribute by its name.""" """Get the attribute id for a cluster attribute by its name."""
return next( return next(
@ -145,7 +138,7 @@ async def async_get_zha_device(hass, device_id):
registry_device = device_registry.async_get(device_id) registry_device = device_registry.async_get(device_id)
zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY]
ieee_address = list(list(registry_device.identifiers)[0])[1] ieee_address = list(list(registry_device.identifiers)[0])[1]
ieee = convert_ieee(ieee_address) ieee = EUI64.convert(ieee_address)
return zha_gateway.devices[ieee] return zha_gateway.devices[ieee]

View File

@ -6,10 +6,10 @@
"requirements": [ "requirements": [
"bellows-homeassistant==0.10.0", "bellows-homeassistant==0.10.0",
"zha-quirks==0.0.26", "zha-quirks==0.0.26",
"zigpy-deconz==0.5.0", "zigpy-deconz==0.6.0",
"zigpy-homeassistant==0.9.0", "zigpy-homeassistant==0.10.0",
"zigpy-xbee-homeassistant==0.5.0", "zigpy-xbee-homeassistant==0.6.0",
"zigpy-zigate==0.4.1" "zigpy-zigate==0.5.0"
], ],
"dependencies": [], "dependencies": [],
"codeowners": ["@dmulcahey", "@adminiuga"] "codeowners": ["@dmulcahey", "@adminiuga"]

View File

@ -2032,16 +2032,16 @@ zhong_hong_hvac==1.0.9
ziggo-mediabox-xl==1.1.0 ziggo-mediabox-xl==1.1.0
# homeassistant.components.zha # homeassistant.components.zha
zigpy-deconz==0.5.0 zigpy-deconz==0.6.0
# homeassistant.components.zha # homeassistant.components.zha
zigpy-homeassistant==0.9.0 zigpy-homeassistant==0.10.0
# homeassistant.components.zha # homeassistant.components.zha
zigpy-xbee-homeassistant==0.5.0 zigpy-xbee-homeassistant==0.6.0
# homeassistant.components.zha # homeassistant.components.zha
zigpy-zigate==0.4.1 zigpy-zigate==0.5.0
# homeassistant.components.zoneminder # homeassistant.components.zoneminder
zm-py==0.3.3 zm-py==0.3.3

View File

@ -641,13 +641,13 @@ zeroconf==0.23.0
zha-quirks==0.0.26 zha-quirks==0.0.26
# homeassistant.components.zha # homeassistant.components.zha
zigpy-deconz==0.5.0 zigpy-deconz==0.6.0
# homeassistant.components.zha # homeassistant.components.zha
zigpy-homeassistant==0.9.0 zigpy-homeassistant==0.10.0
# homeassistant.components.zha # homeassistant.components.zha
zigpy-xbee-homeassistant==0.5.0 zigpy-xbee-homeassistant==0.6.0
# homeassistant.components.zha # homeassistant.components.zha
zigpy-zigate==0.4.1 zigpy-zigate==0.5.0

View File

@ -3,6 +3,8 @@ import time
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
from asynctest import CoroutineMock from asynctest import CoroutineMock
from zigpy.types.named import EUI64
import zigpy.zcl.foundation as zcl_f
from homeassistant.components.zha.core.const import ( from homeassistant.components.zha.core.const import (
DATA_ZHA, DATA_ZHA,
@ -10,7 +12,6 @@ from homeassistant.components.zha.core.const import (
DATA_ZHA_CONFIG, DATA_ZHA_CONFIG,
DATA_ZHA_DISPATCHERS, DATA_ZHA_DISPATCHERS,
) )
from homeassistant.components.zha.core.helpers import convert_ieee
from homeassistant.util import slugify from homeassistant.util import slugify
from tests.common import mock_coro from tests.common import mock_coro
@ -21,7 +22,7 @@ class FakeApplication:
def __init__(self): def __init__(self):
"""Init fake application.""" """Init fake application."""
self.ieee = convert_ieee("00:15:8d:00:02:32:4f:32") self.ieee = EUI64.convert("00:15:8d:00:02:32:4f:32")
self.nwk = 0x087D self.nwk = 0x087D
@ -71,7 +72,6 @@ def patch_cluster(cluster):
cluster.configure_reporting = CoroutineMock(return_value=[0]) cluster.configure_reporting = CoroutineMock(return_value=[0])
cluster.deserialize = Mock() cluster.deserialize = Mock()
cluster.handle_cluster_request = Mock() cluster.handle_cluster_request = Mock()
cluster.handle_cluster_general_request = Mock()
cluster.read_attributes = CoroutineMock() cluster.read_attributes = CoroutineMock()
cluster.read_attributes_raw = Mock() cluster.read_attributes_raw = Mock()
cluster.unbind = CoroutineMock(return_value=[0]) cluster.unbind = CoroutineMock(return_value=[0])
@ -83,7 +83,7 @@ class FakeDevice:
def __init__(self, ieee, manufacturer, model): def __init__(self, ieee, manufacturer, model):
"""Init fake device.""" """Init fake device."""
self._application = APPLICATION self._application = APPLICATION
self.ieee = convert_ieee(ieee) self.ieee = EUI64.convert(ieee)
self.nwk = 0xB79C self.nwk = 0xB79C
self.zdo = Mock() self.zdo = Mock()
self.endpoints = {0: self.zdo} self.endpoints = {0: self.zdo}
@ -230,3 +230,12 @@ async def async_test_device_join(
domain, zigpy_device, cluster, use_suffix=device_type is None domain, zigpy_device, cluster, use_suffix=device_type is None
) )
assert hass.states.get(entity_id) is not None assert hass.states.get(entity_id) is not None
def make_zcl_header(command_id: int, global_command: bool = True) -> zcl_f.ZCLHeader:
"""Cluster.handle_message() ZCL Header helper."""
if global_command:
frc = zcl_f.FrameControl(zcl_f.FrameType.GLOBAL_COMMAND)
else:
frc = zcl_f.FrameControl(zcl_f.FrameType.CLUSTER_COMMAND)
return zcl_f.ZCLHeader(frc, tsn=1, command_id=command_id)

View File

@ -1,12 +1,16 @@
"""Test zha binary sensor.""" """Test zha binary sensor."""
from zigpy.zcl.foundation import Command
from homeassistant.components.binary_sensor import DOMAIN from homeassistant.components.binary_sensor import DOMAIN
from homeassistant.const import STATE_ON, STATE_OFF, STATE_UNAVAILABLE from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE
from .common import ( from .common import (
async_enable_traffic,
async_init_zigpy_device, async_init_zigpy_device,
async_test_device_join,
make_attribute, make_attribute,
make_entity_id, make_entity_id,
async_test_device_join, make_zcl_header,
async_enable_traffic,
) )
@ -74,13 +78,15 @@ async def async_test_binary_sensor_on_off(hass, cluster, entity_id):
"""Test getting on and off messages for binary sensors.""" """Test getting on and off messages for binary sensors."""
# binary sensor on # binary sensor on
attr = make_attribute(0, 1) attr = make_attribute(0, 1)
cluster.handle_message(1, 0x0A, [[attr]]) hdr = make_zcl_header(Command.Report_Attributes)
cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ON assert hass.states.get(entity_id).state == STATE_ON
# binary sensor off # binary sensor off
attr.value.value = 0 attr.value.value = 0
cluster.handle_message(0, 0x0A, [[attr]]) cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_OFF assert hass.states.get(entity_id).state == STATE_OFF

View File

@ -1,19 +1,25 @@
"""Test ZHA Device Tracker.""" """Test ZHA Device Tracker."""
from datetime import timedelta from datetime import timedelta
import time import time
from zigpy.zcl.foundation import Command
from homeassistant.components.device_tracker import DOMAIN, SOURCE_TYPE_ROUTER from homeassistant.components.device_tracker import DOMAIN, SOURCE_TYPE_ROUTER
from homeassistant.const import STATE_HOME, STATE_NOT_HOME, STATE_UNAVAILABLE
from homeassistant.components.zha.core.registries import ( from homeassistant.components.zha.core.registries import (
SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE, SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE,
) )
from homeassistant.const import STATE_HOME, STATE_NOT_HOME, STATE_UNAVAILABLE
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from .common import ( from .common import (
async_enable_traffic,
async_init_zigpy_device, async_init_zigpy_device,
async_test_device_join,
make_attribute, make_attribute,
make_entity_id, make_entity_id,
async_test_device_join, make_zcl_header,
async_enable_traffic,
) )
from tests.common import async_fire_time_changed from tests.common import async_fire_time_changed
@ -67,10 +73,11 @@ async def test_device_tracker(hass, config_entry, zha_gateway):
# turn state flip # turn state flip
attr = make_attribute(0x0020, 23) attr = make_attribute(0x0020, 23)
cluster.handle_message(1, 0x0A, [[attr]]) hdr = make_zcl_header(Command.Report_Attributes)
cluster.handle_message(hdr, [[attr]])
attr = make_attribute(0x0021, 200) attr = make_attribute(0x0021, 200)
cluster.handle_message(1, 0x0A, [[attr]]) cluster.handle_message(hdr, [[attr]])
zigpy_device.last_seen = time.time() + 10 zigpy_device.last_seen = time.time() + 10
next_update = dt_util.utcnow() + timedelta(seconds=30) next_update = dt_util.utcnow() + timedelta(seconds=30)

View File

@ -1,18 +1,30 @@
"""Test zha fan.""" """Test zha fan."""
from unittest.mock import call, patch from unittest.mock import call, patch
from zigpy.zcl.foundation import Command
from homeassistant.components import fan from homeassistant.components import fan
from homeassistant.const import STATE_ON, STATE_OFF, STATE_UNAVAILABLE
from homeassistant.components.fan import ATTR_SPEED, DOMAIN, SERVICE_SET_SPEED from homeassistant.components.fan import ATTR_SPEED, DOMAIN, SERVICE_SET_SPEED
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF from homeassistant.const import (
from tests.common import mock_coro ATTR_ENTITY_ID,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
)
from .common import ( from .common import (
async_enable_traffic,
async_init_zigpy_device, async_init_zigpy_device,
async_test_device_join,
make_attribute, make_attribute,
make_entity_id, make_entity_id,
async_test_device_join, make_zcl_header,
async_enable_traffic,
) )
from tests.common import mock_coro
async def test_fan(hass, config_entry, zha_gateway): async def test_fan(hass, config_entry, zha_gateway):
"""Test zha fan platform.""" """Test zha fan platform."""
@ -44,13 +56,14 @@ async def test_fan(hass, config_entry, zha_gateway):
# turn on at fan # turn on at fan
attr = make_attribute(0, 1) attr = make_attribute(0, 1)
cluster.handle_message(1, 0x0A, [[attr]]) hdr = make_zcl_header(Command.Report_Attributes)
cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ON assert hass.states.get(entity_id).state == STATE_ON
# turn off at fan # turn off at fan
attr.value.value = 0 attr.value.value = 0
cluster.handle_message(0, 0x0A, [[attr]]) cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_OFF assert hass.states.get(entity_id).state == STATE_OFF

View File

@ -2,6 +2,8 @@
import asyncio import asyncio
from unittest.mock import MagicMock, call, patch, sentinel from unittest.mock import MagicMock, call, patch, sentinel
from zigpy.zcl.foundation import Command
from homeassistant.components.light import DOMAIN from homeassistant.components.light import DOMAIN
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE
@ -11,6 +13,7 @@ from .common import (
async_test_device_join, async_test_device_join,
make_attribute, make_attribute,
make_entity_id, make_entity_id,
make_zcl_header,
) )
from tests.common import mock_coro from tests.common import mock_coro
@ -123,13 +126,14 @@ async def async_test_on_off_from_light(hass, cluster, entity_id):
"""Test on off functionality from the light.""" """Test on off functionality from the light."""
# turn on at light # turn on at light
attr = make_attribute(0, 1) attr = make_attribute(0, 1)
cluster.handle_message(1, 0x0A, [[attr]]) hdr = make_zcl_header(Command.Report_Attributes)
cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ON assert hass.states.get(entity_id).state == STATE_ON
# turn off at light # turn off at light
attr.value.value = 0 attr.value.value = 0
cluster.handle_message(0, 0x0A, [[attr]]) cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_OFF assert hass.states.get(entity_id).state == STATE_OFF
@ -138,7 +142,8 @@ async def async_test_on_from_light(hass, cluster, entity_id):
"""Test on off functionality from the light.""" """Test on off functionality from the light."""
# turn on at light # turn on at light
attr = make_attribute(0, 1) attr = make_attribute(0, 1)
cluster.handle_message(1, 0x0A, [[attr]]) hdr = make_zcl_header(Command.Report_Attributes)
cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ON assert hass.states.get(entity_id).state == STATE_ON
@ -243,7 +248,8 @@ async def async_test_level_on_off_from_hass(
async def async_test_dimmer_from_light(hass, cluster, entity_id, level, expected_state): async def async_test_dimmer_from_light(hass, cluster, entity_id, level, expected_state):
"""Test dimmer functionality from the light.""" """Test dimmer functionality from the light."""
attr = make_attribute(0, level) attr = make_attribute(0, level)
cluster.handle_message(1, 0x0A, [[attr]]) hdr = make_zcl_header(Command.Report_Attributes)
cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == expected_state assert hass.states.get(entity_id).state == expected_state
# hass uses None for brightness of 0 in state attributes # hass uses None for brightness of 0 in state attributes

View File

@ -1,15 +1,21 @@
"""Test zha lock.""" """Test zha lock."""
from unittest.mock import patch from unittest.mock import patch
from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED, STATE_UNAVAILABLE
from zigpy.zcl.foundation import Command
from homeassistant.components.lock import DOMAIN from homeassistant.components.lock import DOMAIN
from tests.common import mock_coro from homeassistant.const import STATE_LOCKED, STATE_UNAVAILABLE, STATE_UNLOCKED
from .common import ( from .common import (
async_enable_traffic,
async_init_zigpy_device, async_init_zigpy_device,
make_attribute, make_attribute,
make_entity_id, make_entity_id,
async_enable_traffic, make_zcl_header,
) )
from tests.common import mock_coro
LOCK_DOOR = 0 LOCK_DOOR = 0
UNLOCK_DOOR = 1 UNLOCK_DOOR = 1
@ -43,13 +49,14 @@ async def test_lock(hass, config_entry, zha_gateway):
# set state to locked # set state to locked
attr = make_attribute(0, 1) attr = make_attribute(0, 1)
cluster.handle_message(1, 0x0A, [[attr]]) hdr = make_zcl_header(Command.Report_Attributes)
cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_LOCKED assert hass.states.get(entity_id).state == STATE_LOCKED
# set state to unlocked # set state to unlocked
attr.value.value = 2 attr.value.value = 2
cluster.handle_message(0, 0x0A, [[attr]]) cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_UNLOCKED assert hass.states.get(entity_id).state == STATE_UNLOCKED

View File

@ -1,12 +1,16 @@
"""Test zha sensor.""" """Test zha sensor."""
from zigpy.zcl.foundation import Command
from homeassistant.components.sensor import DOMAIN from homeassistant.components.sensor import DOMAIN
from homeassistant.const import STATE_UNKNOWN, STATE_UNAVAILABLE from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN
from .common import ( from .common import (
async_enable_traffic,
async_init_zigpy_device, async_init_zigpy_device,
async_test_device_join,
make_attribute, make_attribute,
make_entity_id, make_entity_id,
async_test_device_join, make_zcl_header,
async_enable_traffic,
) )
@ -177,7 +181,8 @@ async def send_attribute_report(hass, cluster, attrid, value):
device is paired to the zigbee network. device is paired to the zigbee network.
""" """
attr = make_attribute(attrid, value) attr = make_attribute(attrid, value)
cluster.handle_message(1, 0x0A, [[attr]]) hdr = make_zcl_header(Command.Report_Attributes)
cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()

View File

@ -1,16 +1,22 @@
"""Test zha switch.""" """Test zha switch."""
from unittest.mock import call, patch from unittest.mock import call, patch
from zigpy.zcl.foundation import Command
from homeassistant.components.switch import DOMAIN from homeassistant.components.switch import DOMAIN
from homeassistant.const import STATE_ON, STATE_OFF, STATE_UNAVAILABLE from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE
from tests.common import mock_coro
from .common import ( from .common import (
async_enable_traffic,
async_init_zigpy_device, async_init_zigpy_device,
async_test_device_join,
make_attribute, make_attribute,
make_entity_id, make_entity_id,
async_test_device_join, make_zcl_header,
async_enable_traffic,
) )
from tests.common import mock_coro
ON = 1 ON = 1
OFF = 0 OFF = 0
@ -44,13 +50,14 @@ async def test_switch(hass, config_entry, zha_gateway):
# turn on at switch # turn on at switch
attr = make_attribute(0, 1) attr = make_attribute(0, 1)
cluster.handle_message(1, 0x0A, [[attr]]) hdr = make_zcl_header(Command.Report_Attributes)
cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ON assert hass.states.get(entity_id).state == STATE_ON
# turn off at switch # turn off at switch
attr.value.value = 0 attr.value.value = 0
cluster.handle_message(0, 0x0A, [[attr]]) cluster.handle_message(hdr, [[attr]])
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_OFF assert hass.states.get(entity_id).state == STATE_OFF