core/tests/components/shelly/conftest.py

338 lines
8.7 KiB
Python

"""Test configuration for Shelly."""
from __future__ import annotations
from unittest.mock import AsyncMock, Mock, PropertyMock, patch
from aioshelly.block_device import BlockDevice
from aioshelly.rpc_device import RpcDevice, UpdateType
import pytest
from homeassistant.components.shelly.const import (
EVENT_SHELLY_CLICK,
REST_SENSORS_UPDATE_INTERVAL,
)
from . import MOCK_MAC
from tests.common import async_capture_events, async_mock_service, mock_device_registry
MOCK_SETTINGS = {
"name": "Test name",
"mode": "relay",
"device": {
"mac": MOCK_MAC,
"hostname": "test-host",
"type": "SHSW-25",
"num_outputs": 2,
},
"coiot": {"update_period": 15},
"fw": "20201124-092159/v1.9.0@57ac4ad8",
"relays": [{"btn_type": "momentary"}, {"btn_type": "toggle"}],
"rollers": [{"positioning": True}],
"external_power": 0,
"thermostats": [{"schedule_profile_names": ["Profile1", "Profile2"]}],
}
def mock_light_set_state(
turn="on",
mode="color",
red=45,
green=55,
blue=65,
white=70,
gain=19,
temp=4050,
brightness=50,
effect=0,
transition=0,
):
"""Mock light block set_state."""
return {
"ison": turn == "on",
"mode": mode,
"red": red,
"green": green,
"blue": blue,
"white": white,
"gain": gain,
"temp": temp,
"brightness": brightness,
"effect": effect,
"transition": transition,
}
MOCK_BLOCKS = [
Mock(
sensor_ids={
"inputEvent": "S",
"inputEventCnt": 2,
"overpower": 0,
"power": 53.4,
"energy": 1234567.89,
},
channel="0",
type="relay",
overpower=0,
power=53.4,
energy=1234567.89,
description="relay_0",
set_state=AsyncMock(side_effect=lambda turn: {"ison": turn == "on"}),
),
Mock(
sensor_ids={"roller": "stop", "rollerPos": 0},
channel="1",
type="roller",
set_state=AsyncMock(
side_effect=lambda go, roller_pos=0: {
"current_pos": roller_pos,
"state": go,
}
),
),
Mock(
sensor_ids={"mode": "color", "effect": 0},
channel="0",
output=mock_light_set_state()["ison"],
colorTemp=mock_light_set_state()["temp"],
**mock_light_set_state(),
type="light",
set_state=AsyncMock(side_effect=mock_light_set_state),
),
Mock(
sensor_ids={"motion": 0, "temp": 22.1, "gas": "mild"},
channel="0",
motion=0,
temp=22.1,
gas="mild",
targetTemp=4,
description="sensor_0",
type="sensor",
),
Mock(
sensor_ids={"battery": 98, "valvePos": 50},
channel="0",
battery=98,
cfgChanged=0,
mode=0,
valvePos=50,
inputEvent="S",
wakeupEvent=["button"],
description="device_0",
type="device",
),
Mock(
sensor_ids={"powerFactor": 0.98},
channel="0",
powerFactor=0.98,
targetTemp=4,
temp=22.1,
description="emeter_0",
type="emeter",
),
]
MOCK_CONFIG = {
"input:0": {"id": 0, "type": "button"},
"light:0": {"name": "test light_0"},
"switch:0": {"name": "test switch_0"},
"cover:0": {"name": "test cover_0"},
"sys": {
"ui_data": {},
"device": {"name": "Test name"},
"wakeup_period": 0,
},
}
MOCK_SHELLY_COAP = {
"mac": MOCK_MAC,
"auth": False,
"fw": "20201124-092854/v1.9.0@57ac4ad8",
"num_outputs": 2,
}
MOCK_SHELLY_RPC = {
"name": "Test Gen2",
"id": "shellyplus2pm-123456789abc",
"mac": MOCK_MAC,
"model": "SNSW-002P16EU",
"gen": 2,
"fw_id": "20220830-130540/0.11.0-gfa1bc37",
"ver": "0.11.0",
"app": "Plus2PM",
"auth_en": False,
"auth_domain": None,
"profile": "cover",
}
MOCK_STATUS_COAP = {
"update": {
"status": "pending",
"has_update": True,
"beta_version": "some_beta_version",
"new_version": "some_new_version",
"old_version": "some_old_version",
},
"uptime": 5 * REST_SENSORS_UPDATE_INTERVAL,
"wifi_sta": {"rssi": -64},
}
MOCK_STATUS_RPC = {
"switch:0": {"output": True},
"light:0": {"output": True, "brightness": 53.0},
"cloud": {"connected": False},
"cover:0": {
"state": "stopped",
"pos_control": True,
"current_pos": 50,
"apower": 85.3,
},
"devicepower:0": {"external": {"present": True}},
"temperature:0": {"tC": 22.9},
"illuminance:0": {"lux": 345},
"sys": {
"available_updates": {
"beta": {"version": "some_beta_version"},
"stable": {"version": "some_beta_version"},
}
},
"voltmeter": {"voltage": 4.321},
"wifi": {"rssi": -63},
}
@pytest.fixture(autouse=True)
def mock_coap():
"""Mock out coap."""
with patch(
"homeassistant.components.shelly.utils.COAP",
return_value=Mock(
initialize=AsyncMock(),
close=Mock(),
),
):
yield
@pytest.fixture(autouse=True)
def mock_ws_server():
"""Mock out ws_server."""
with patch("homeassistant.components.shelly.utils.get_ws_context"):
yield
@pytest.fixture
def device_reg(hass):
"""Return an empty, loaded, registry."""
return mock_device_registry(hass)
@pytest.fixture
def calls(hass):
"""Track calls to a mock service."""
return async_mock_service(hass, "test", "automation")
@pytest.fixture
def events(hass):
"""Yield caught shelly_click events."""
return async_capture_events(hass, EVENT_SHELLY_CLICK)
@pytest.fixture
async def mock_block_device():
"""Mock block (Gen1, CoAP) device."""
with patch("aioshelly.block_device.BlockDevice.create") as block_device_mock:
def update():
block_device_mock.return_value.subscribe_updates.call_args[0][0]({})
device = Mock(
spec=BlockDevice,
blocks=MOCK_BLOCKS,
settings=MOCK_SETTINGS,
shelly=MOCK_SHELLY_COAP,
version="0.10.0",
status=MOCK_STATUS_COAP,
firmware_version="some fw string",
initialized=True,
model="SHSW-1",
)
type(device).name = PropertyMock(return_value="Test name")
block_device_mock.return_value = device
block_device_mock.return_value.mock_update = Mock(side_effect=update)
yield block_device_mock.return_value
def _mock_rpc_device(version: str | None = None):
"""Mock rpc (Gen2, Websocket) device."""
device = Mock(
spec=RpcDevice,
config=MOCK_CONFIG,
event={},
shelly=MOCK_SHELLY_RPC,
version=version or "0.12.0",
hostname="test-host",
status=MOCK_STATUS_RPC,
firmware_version="some fw string",
initialized=True,
)
type(device).name = PropertyMock(return_value="Test name")
return device
@pytest.fixture
async def mock_pre_ble_rpc_device():
"""Mock rpc (Gen2, Websocket) device pre BLE."""
with patch("aioshelly.rpc_device.RpcDevice.create") as rpc_device_mock:
def update():
rpc_device_mock.return_value.subscribe_updates.call_args[0][0](
{}, UpdateType.STATUS
)
device = _mock_rpc_device("0.11.0")
rpc_device_mock.return_value = device
rpc_device_mock.return_value.mock_update = Mock(side_effect=update)
yield rpc_device_mock.return_value
@pytest.fixture
async def mock_rpc_device():
"""Mock rpc (Gen2, Websocket) device with BLE support."""
with patch("aioshelly.rpc_device.RpcDevice.create") as rpc_device_mock, patch(
"homeassistant.components.shelly.bluetooth.async_start_scanner"
):
def update():
rpc_device_mock.return_value.subscribe_updates.call_args[0][0](
{}, UpdateType.STATUS
)
def event():
rpc_device_mock.return_value.subscribe_updates.call_args[0][0](
{}, UpdateType.EVENT
)
def disconnected():
rpc_device_mock.return_value.subscribe_updates.call_args[0][0](
{}, UpdateType.DISCONNECTED
)
device = _mock_rpc_device("0.12.0")
rpc_device_mock.return_value = device
rpc_device_mock.return_value.mock_disconnected = Mock(side_effect=disconnected)
rpc_device_mock.return_value.mock_update = Mock(side_effect=update)
rpc_device_mock.return_value.mock_event = Mock(side_effect=event)
yield rpc_device_mock.return_value
@pytest.fixture(autouse=True)
def mock_bluetooth(enable_bluetooth):
"""Auto mock bluetooth."""