mirror of
https://github.com/home-assistant/core.git
synced 2026-09-25 17:04:04 -04:00
Use pybalboa 1.0.0 (#87214)
* Use pybalboa 1.0.0 * Code changes per PR review
This commit is contained in:
@@ -1,25 +1,21 @@
|
||||
"""Test the Balboa Spa Client integration."""
|
||||
from homeassistant.components.balboa.const import DOMAIN as BALBOA_DOMAIN
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.components.balboa import CONF_SYNC_TIME, DOMAIN
|
||||
from homeassistant.const import CONF_HOST
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
BALBOA_DEFAULT_PORT = 4257
|
||||
TEST_HOST = "balboatest.localdomain"
|
||||
|
||||
|
||||
async def init_integration(hass: HomeAssistant) -> MockConfigEntry:
|
||||
"""Mock integration setup."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=BALBOA_DOMAIN,
|
||||
data={
|
||||
CONF_HOST: TEST_HOST,
|
||||
},
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN, data={CONF_HOST: TEST_HOST}, options={CONF_SYNC_TIME: True}
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
return config_entry
|
||||
return entry
|
||||
|
||||
@@ -1,94 +1,61 @@
|
||||
"""Provide common fixtures."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Generator
|
||||
import time
|
||||
from unittest.mock import MagicMock, patch
|
||||
from collections.abc import Callable, Generator
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from pybalboa.balboa import text_heatmode
|
||||
from pybalboa.enums import HeatMode
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import init_integration
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@pytest.fixture(name="integration")
|
||||
async def integration_fixture(hass: HomeAssistant) -> MockConfigEntry:
|
||||
"""Set up the balboa integration."""
|
||||
return await init_integration(hass)
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def client_fixture() -> Generator[None, MagicMock, None]:
|
||||
"""Mock balboa."""
|
||||
def client_fixture() -> Generator[MagicMock, None, None]:
|
||||
"""Mock balboa spa client."""
|
||||
with patch(
|
||||
"homeassistant.components.balboa.BalboaSpaWifi", autospec=True
|
||||
"homeassistant.components.balboa.SpaClient", autospec=True
|
||||
) as mock_balboa:
|
||||
# common attributes
|
||||
client = mock_balboa.return_value
|
||||
client.connected = True
|
||||
client.lastupd = time.time()
|
||||
client.new_data_cb = None
|
||||
client.connect.return_value = True
|
||||
client.get_macaddr.return_value = "ef:ef:ef:c0:ff:ee"
|
||||
client.get_model_name.return_value = "FakeSpa"
|
||||
client.get_ssid.return_value = "V0.0"
|
||||
callback: list[Callable] = []
|
||||
|
||||
# constants should preferably be moved in the library
|
||||
# to be class attributes or further refactored
|
||||
client.TSCALE_C = 1
|
||||
client.TSCALE_F = 0
|
||||
client.HEATMODE_READY = 0
|
||||
client.HEATMODE_REST = 1
|
||||
client.HEATMODE_RNR = 2
|
||||
client.TIMESCALE_12H = 0
|
||||
client.TIMESCALE_24H = 1
|
||||
client.PUMP_OFF = 0
|
||||
client.PUMP_LOW = 1
|
||||
client.PUMP_HIGH = 2
|
||||
client.TEMPRANGE_LOW = 0
|
||||
client.TEMPRANGE_HIGH = 1
|
||||
client.tmin = [
|
||||
[50.0, 10.0],
|
||||
[80.0, 26.0],
|
||||
]
|
||||
client.tmax = [
|
||||
[80.0, 26.0],
|
||||
[104.0, 40.0],
|
||||
]
|
||||
client.BLOWER_OFF = 0
|
||||
client.BLOWER_LOW = 1
|
||||
client.BLOWER_MEDIUM = 2
|
||||
client.BLOWER_HIGH = 3
|
||||
client.FILTER_OFF = 0
|
||||
client.FILTER_1 = 1
|
||||
client.FILTER_2 = 2
|
||||
client.FILTER_1_2 = 3
|
||||
client.OFF = 0
|
||||
client.ON = 1
|
||||
client.HEATSTATE_IDLE = 0
|
||||
client.HEATSTATE_HEATING = 1
|
||||
client.HEATSTATE_HEAT_WAITING = 2
|
||||
client.VOLTAGE_240 = 240
|
||||
client.VOLTAGE_UNKNOWN = 0
|
||||
client.HEATERTYPE_STANDARD = "Standard"
|
||||
client.HEATERTYPE_UNKNOWN = "Unknown"
|
||||
def on(_, _callback: Callable): # pylint: disable=invalid-name
|
||||
callback.append(_callback)
|
||||
return lambda: None
|
||||
|
||||
# Climate attributes
|
||||
client.heatmode = 0
|
||||
client.get_heatmode_stringlist.return_value = text_heatmode
|
||||
client.get_tempscale.return_value = client.TSCALE_F
|
||||
client.have_blower.return_value = False
|
||||
def emit(_):
|
||||
for _cb in callback:
|
||||
_cb()
|
||||
|
||||
# Climate methods
|
||||
client.get_heatstate.return_value = 0
|
||||
client.get_blower.return_value = 0
|
||||
client.get_curtemp.return_value = 20.0
|
||||
client.get_settemp.return_value = 20.0
|
||||
client.on.side_effect = on
|
||||
client.emit.side_effect = emit
|
||||
|
||||
def get_heatmode(text=False):
|
||||
"""Ask for the current heatmode."""
|
||||
if text:
|
||||
return text_heatmode[client.heatmode]
|
||||
return client.heatmode
|
||||
client.model = "FakeSpa"
|
||||
client.mac_address = "ef:ef:ef:c0:ff:ee"
|
||||
client.software_version = "M0 V0.0"
|
||||
|
||||
client.blowers = []
|
||||
client.circulation_pump.state = 0
|
||||
client.filter_cycle_1_running = False
|
||||
client.filter_cycle_2_running = False
|
||||
client.temperature_unit = 1
|
||||
client.temperature = 10
|
||||
client.temperature_minimum = 10
|
||||
client.temperature_maximum = 40
|
||||
client.target_temperature = 40
|
||||
client.heat_mode.state = HeatMode.READY
|
||||
client.heat_mode.set_state = AsyncMock()
|
||||
client.heat_mode.options = list(HeatMode)[:2]
|
||||
client.heat_state = 2
|
||||
|
||||
client.get_heatmode.side_effect = get_heatmode
|
||||
yield client
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def set_temperature_wait():
|
||||
"""Mock set temperature wait time."""
|
||||
with patch("homeassistant.components.balboa.climate.SET_TEMPERATURE_WAIT", new=0):
|
||||
yield
|
||||
|
||||
@@ -1,56 +1,46 @@
|
||||
"""Tests of the climate entity of the balboa integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from homeassistant.const import STATE_OFF, STATE_ON
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import init_integration
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
ENTITY_BINARY_SENSOR = "binary_sensor.fakespa_"
|
||||
|
||||
FILTER_MAP = [
|
||||
[STATE_OFF, STATE_OFF],
|
||||
[STATE_ON, STATE_OFF],
|
||||
[STATE_OFF, STATE_ON],
|
||||
[STATE_ON, STATE_ON],
|
||||
]
|
||||
|
||||
|
||||
async def test_filters(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
async def test_filters(
|
||||
hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test spa filters."""
|
||||
for num in (1, 2):
|
||||
sensor = f"{ENTITY_BINARY_SENSOR}filter{num}"
|
||||
|
||||
config_entry = await init_integration(hass)
|
||||
state = hass.states.get(sensor)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
for filter_mode in range(4):
|
||||
for spa_filter in range(1, 3):
|
||||
state = await _patch_filter(
|
||||
hass, config_entry, filter_mode, spa_filter, client
|
||||
)
|
||||
assert state.state == FILTER_MAP[filter_mode][spa_filter - 1]
|
||||
setattr(client, f"filter_cycle_{num}_running", True)
|
||||
client.emit("")
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(sensor)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
|
||||
async def test_circ_pump(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
async def test_circ_pump(
|
||||
hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test spa circ pump."""
|
||||
client.have_circ_pump.return_value = (True,)
|
||||
config_entry = await init_integration(hass)
|
||||
sensor = f"{ENTITY_BINARY_SENSOR}circ_pump"
|
||||
|
||||
state = await _patch_circ_pump(hass, config_entry, True, client)
|
||||
assert state.state == STATE_ON
|
||||
state = await _patch_circ_pump(hass, config_entry, False, client)
|
||||
state = hass.states.get(sensor)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
|
||||
async def _patch_circ_pump(hass, config_entry, pump_state, client):
|
||||
"""Patch the circ pump state."""
|
||||
client.get_circ_pump.return_value = pump_state
|
||||
await client.new_data_cb()
|
||||
client.circulation_pump.state = 1
|
||||
client.emit("")
|
||||
await hass.async_block_till_done()
|
||||
return hass.states.get(f"{ENTITY_BINARY_SENSOR}circ_pump")
|
||||
|
||||
|
||||
async def _patch_filter(hass, config_entry, filter_mode, num, client):
|
||||
"""Patch the filter state."""
|
||||
client.get_filtermode.return_value = filter_mode
|
||||
await client.new_data_cb()
|
||||
await hass.async_block_till_done()
|
||||
return hass.states.get(f"{ENTITY_BINARY_SENSOR}filter{num}")
|
||||
state = hass.states.get(sensor)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
@@ -3,10 +3,13 @@ from __future__ import annotations
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from pybalboa import SpaControl
|
||||
from pybalboa.enums import HeatMode, OffLowMediumHighState
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
ATTR_FAN_MODE,
|
||||
ATTR_FAN_MODES,
|
||||
ATTR_HVAC_ACTION,
|
||||
ATTR_HVAC_MODES,
|
||||
ATTR_MAX_TEMP,
|
||||
@@ -22,19 +25,13 @@ from homeassistant.components.climate import (
|
||||
HVACMode,
|
||||
)
|
||||
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.core import HomeAssistant, State
|
||||
|
||||
from . import init_integration
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.climate import common
|
||||
|
||||
FAN_SETTINGS = [
|
||||
FAN_OFF,
|
||||
FAN_LOW,
|
||||
FAN_MEDIUM,
|
||||
FAN_HIGH,
|
||||
]
|
||||
|
||||
HVAC_SETTINGS = [
|
||||
HVACMode.HEAT,
|
||||
HVACMode.OFF,
|
||||
@@ -44,9 +41,29 @@ HVAC_SETTINGS = [
|
||||
ENTITY_CLIMATE = "climate.fakespa_climate"
|
||||
|
||||
|
||||
async def test_spa_defaults(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
async def test_spa_defaults(
|
||||
hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test supported features flags."""
|
||||
await init_integration(hass)
|
||||
state = hass.states.get(ENTITY_CLIMATE)
|
||||
|
||||
assert state
|
||||
assert (
|
||||
state.attributes["supported_features"]
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE
|
||||
)
|
||||
assert state.state == HVACMode.HEAT
|
||||
assert state.attributes[ATTR_MIN_TEMP] == 10.0
|
||||
assert state.attributes[ATTR_MAX_TEMP] == 40.0
|
||||
assert state.attributes[ATTR_PRESET_MODE] == "ready"
|
||||
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE
|
||||
|
||||
|
||||
async def test_spa_defaults_fake_tscale(
|
||||
hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test supported features flags."""
|
||||
client.temperature_unit = 1
|
||||
|
||||
state = hass.states.get(ENTITY_CLIMATE)
|
||||
|
||||
@@ -58,39 +75,95 @@ async def test_spa_defaults(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
assert state.state == HVACMode.HEAT
|
||||
assert state.attributes[ATTR_MIN_TEMP] == 10.0
|
||||
assert state.attributes[ATTR_MAX_TEMP] == 40.0
|
||||
assert state.attributes[ATTR_PRESET_MODE] == "Ready"
|
||||
assert state.attributes[ATTR_PRESET_MODE] == "ready"
|
||||
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE
|
||||
|
||||
|
||||
async def test_spa_defaults_fake_tscale(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
"""Test supported features flags."""
|
||||
client.get_tempscale.return_value = 1
|
||||
async def test_spa_temperature(
|
||||
hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test spa temperature settings."""
|
||||
# flip the spa into F
|
||||
# set temp to a valid number
|
||||
state = await _patch_spa_settemp(hass, client, 0, 100)
|
||||
assert state.attributes.get(ATTR_TEMPERATURE) == 38.0
|
||||
|
||||
await init_integration(hass)
|
||||
|
||||
async def test_spa_temperature_unit(
|
||||
hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test temperature unit conversions."""
|
||||
with patch.object(
|
||||
hass.config.units, "temperature_unit", UnitOfTemperature.FAHRENHEIT
|
||||
):
|
||||
state = await _patch_spa_settemp(hass, client, 0, 15.4)
|
||||
assert state.attributes.get(ATTR_TEMPERATURE) == 15.0
|
||||
|
||||
|
||||
async def test_spa_hvac_modes(
|
||||
hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test hvac modes."""
|
||||
# try out the different heat modes
|
||||
for heat_mode in list(HeatMode)[:2]:
|
||||
state = await _patch_spa_heatmode(hass, client, heat_mode)
|
||||
modes = state.attributes.get(ATTR_HVAC_MODES)
|
||||
assert modes == [HVACMode.HEAT, HVACMode.OFF]
|
||||
assert state.state == HVAC_SETTINGS[heat_mode]
|
||||
|
||||
|
||||
async def test_spa_hvac_action(
|
||||
hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test setting of the HVAC action."""
|
||||
# try out the different heat states
|
||||
state = await _patch_spa_heatstate(hass, client, 0)
|
||||
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.OFF
|
||||
|
||||
state = await _patch_spa_heatstate(hass, client, 1)
|
||||
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.HEATING
|
||||
|
||||
state = await _patch_spa_heatstate(hass, client, 2)
|
||||
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE
|
||||
|
||||
|
||||
async def test_spa_preset_modes(
|
||||
hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test the various preset modes."""
|
||||
state = hass.states.get(ENTITY_CLIMATE)
|
||||
|
||||
assert state
|
||||
assert (
|
||||
state.attributes["supported_features"]
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE
|
||||
)
|
||||
assert state.state == HVACMode.HEAT
|
||||
assert state.attributes[ATTR_MIN_TEMP] == 10.0
|
||||
assert state.attributes[ATTR_MAX_TEMP] == 40.0
|
||||
assert state.attributes[ATTR_PRESET_MODE] == "Ready"
|
||||
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE
|
||||
modes = state.attributes.get(ATTR_PRESET_MODES)
|
||||
assert modes == ["ready", "rest"]
|
||||
|
||||
# Put it in Ready and Rest
|
||||
modelist = ["ready", "rest"]
|
||||
for mode in modelist:
|
||||
client.heat_mode.state = HeatMode[mode.upper()]
|
||||
await common.async_set_preset_mode(hass, mode, ENTITY_CLIMATE)
|
||||
|
||||
state = await _client_update(hass, client)
|
||||
assert state
|
||||
assert state.attributes[ATTR_PRESET_MODE] == mode
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
await common.async_set_preset_mode(hass, 2, ENTITY_CLIMATE)
|
||||
|
||||
# put it in RNR and test assertion
|
||||
client.heat_mode.state = HeatMode.READY_IN_REST
|
||||
state = await _client_update(hass, client)
|
||||
assert state
|
||||
assert state.attributes[ATTR_PRESET_MODE] == "ready_in_rest"
|
||||
|
||||
|
||||
async def test_spa_with_blower(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
"""Test supported features flags."""
|
||||
client.have_blower.return_value = True
|
||||
blower = MagicMock(SpaControl)
|
||||
blower.state = OffLowMediumHighState.OFF
|
||||
blower.options = list(OffLowMediumHighState)
|
||||
client.blowers = [blower]
|
||||
|
||||
config_entry = await init_integration(hass)
|
||||
|
||||
# force a refresh
|
||||
await client.new_data_cb()
|
||||
await hass.async_block_till_done()
|
||||
await init_integration(hass)
|
||||
|
||||
state = hass.states.get(ENTITY_CLIMATE)
|
||||
|
||||
@@ -101,149 +174,62 @@ async def test_spa_with_blower(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.FAN_MODE
|
||||
)
|
||||
|
||||
for fan_state in range(4):
|
||||
# set blower
|
||||
state = await _patch_blower(hass, config_entry, fan_state, client)
|
||||
assert state
|
||||
assert state.attributes[ATTR_FAN_MODE] == FAN_SETTINGS[fan_state]
|
||||
|
||||
# test the nonsense checks
|
||||
for fan_state in (None, 70): # type: ignore[assignment]
|
||||
state = await _patch_blower(hass, config_entry, fan_state, client)
|
||||
assert state
|
||||
assert state.attributes[ATTR_FAN_MODE] == FAN_OFF
|
||||
|
||||
|
||||
async def test_spa_temperature(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
"""Test spa temperature settings."""
|
||||
|
||||
config_entry = await init_integration(hass)
|
||||
|
||||
# flip the spa into F
|
||||
# set temp to a valid number
|
||||
state = await _patch_spa_settemp(hass, config_entry, 0, 100.0, client)
|
||||
assert state
|
||||
assert state.attributes.get(ATTR_TEMPERATURE) == 38.0
|
||||
|
||||
|
||||
async def test_spa_temperature_unit(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
"""Test temperature unit conversions."""
|
||||
|
||||
with patch.object(
|
||||
hass.config.units, "temperature_unit", UnitOfTemperature.FAHRENHEIT
|
||||
):
|
||||
config_entry = await init_integration(hass)
|
||||
|
||||
state = await _patch_spa_settemp(hass, config_entry, 0, 15.4, client)
|
||||
assert state
|
||||
assert state.attributes.get(ATTR_TEMPERATURE) == 15.0
|
||||
|
||||
|
||||
async def test_spa_hvac_modes(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
"""Test hvac modes."""
|
||||
|
||||
config_entry = await init_integration(hass)
|
||||
|
||||
# try out the different heat modes
|
||||
for heat_mode in range(2):
|
||||
state = await _patch_spa_heatmode(hass, config_entry, heat_mode, client)
|
||||
assert state
|
||||
modes = state.attributes.get(ATTR_HVAC_MODES)
|
||||
assert [HVACMode.AUTO, HVACMode.HEAT, HVACMode.OFF] == modes
|
||||
assert state.state == HVAC_SETTINGS[heat_mode]
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
await _patch_spa_heatmode(hass, config_entry, 2, client)
|
||||
|
||||
|
||||
async def test_spa_hvac_action(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
"""Test setting of the HVAC action."""
|
||||
|
||||
config_entry = await init_integration(hass)
|
||||
|
||||
# try out the different heat states
|
||||
state = await _patch_spa_heatstate(hass, config_entry, 1, client)
|
||||
assert state
|
||||
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.HEATING
|
||||
|
||||
state = await _patch_spa_heatstate(hass, config_entry, 0, client)
|
||||
assert state.state == HVACMode.HEAT
|
||||
assert state.attributes[ATTR_MIN_TEMP] == 10.0
|
||||
assert state.attributes[ATTR_MAX_TEMP] == 40.0
|
||||
assert state.attributes[ATTR_PRESET_MODE] == "ready"
|
||||
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE
|
||||
assert state.attributes[ATTR_FAN_MODES] == ["off", "low", "medium", "high"]
|
||||
assert state.attributes[ATTR_FAN_MODE] == FAN_OFF
|
||||
|
||||
|
||||
async def test_spa_preset_modes(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
"""Test the various preset modes."""
|
||||
|
||||
await init_integration(hass)
|
||||
|
||||
state = hass.states.get(ENTITY_CLIMATE)
|
||||
assert state
|
||||
modes = state.attributes.get(ATTR_PRESET_MODES)
|
||||
assert ["Ready", "Rest", "Ready in Rest"] == modes
|
||||
|
||||
# Put it in Ready and Rest
|
||||
modelist = ["Ready", "Rest"]
|
||||
for mode in modelist:
|
||||
client.heatmode = modelist.index(mode)
|
||||
await common.async_set_preset_mode(hass, mode, ENTITY_CLIMATE)
|
||||
await client.new_data_cb()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(ENTITY_CLIMATE)
|
||||
assert state
|
||||
assert state.attributes[ATTR_PRESET_MODE] == mode
|
||||
|
||||
# put it in RNR and test assertion
|
||||
client.heatmode = 2
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
await common.async_set_preset_mode(hass, 2, ENTITY_CLIMATE)
|
||||
for fan_mode in (FAN_LOW, FAN_MEDIUM, FAN_HIGH):
|
||||
client.blowers[0].set_state.reset_mock()
|
||||
state = await _patch_blower(hass, client, fan_mode)
|
||||
assert state.attributes[ATTR_FAN_MODE] == fan_mode
|
||||
client.blowers[0].set_state.assert_called_once()
|
||||
|
||||
|
||||
# Helpers
|
||||
async def _patch_blower(hass, config_entry, fan_state, client):
|
||||
"""Patch the blower state."""
|
||||
client.get_blower.return_value = fan_state
|
||||
|
||||
if fan_state is not None and fan_state <= len(FAN_SETTINGS):
|
||||
await common.async_set_fan_mode(hass, FAN_SETTINGS[fan_state])
|
||||
await client.new_data_cb()
|
||||
async def _client_update(hass: HomeAssistant, client: MagicMock) -> State:
|
||||
"""Update the client."""
|
||||
client.emit("")
|
||||
await hass.async_block_till_done()
|
||||
|
||||
return hass.states.get(ENTITY_CLIMATE)
|
||||
assert (state := hass.states.get(ENTITY_CLIMATE)) is not None
|
||||
return state
|
||||
|
||||
|
||||
async def _patch_spa_settemp(hass, config_entry, tscale, settemp, client):
|
||||
async def _patch_blower(hass: HomeAssistant, client: MagicMock, fan_mode: str) -> State:
|
||||
"""Patch the blower state."""
|
||||
client.blowers[0].state = OffLowMediumHighState[fan_mode.upper()]
|
||||
await common.async_set_fan_mode(hass, fan_mode)
|
||||
return await _client_update(hass, client)
|
||||
|
||||
|
||||
async def _patch_spa_settemp(
|
||||
hass: HomeAssistant, client: MagicMock, tscale: int, settemp: float
|
||||
) -> State:
|
||||
"""Patch the settemp."""
|
||||
client.get_tempscale.return_value = tscale
|
||||
client.get_settemp.return_value = settemp
|
||||
|
||||
client.temperature_unit = tscale
|
||||
client.target_temperature = settemp
|
||||
await common.async_set_temperature(
|
||||
hass, temperature=settemp, entity_id=ENTITY_CLIMATE
|
||||
)
|
||||
await client.new_data_cb()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
return hass.states.get(ENTITY_CLIMATE)
|
||||
return await _client_update(hass, client)
|
||||
|
||||
|
||||
async def _patch_spa_heatmode(hass, config_entry, heat_mode, client):
|
||||
async def _patch_spa_heatmode(
|
||||
hass: HomeAssistant, client: MagicMock, heat_mode: int
|
||||
) -> State:
|
||||
"""Patch the heatmode."""
|
||||
client.heatmode = heat_mode
|
||||
|
||||
client.heat_mode.state = heat_mode
|
||||
await common.async_set_hvac_mode(hass, HVAC_SETTINGS[heat_mode], ENTITY_CLIMATE)
|
||||
await client.new_data_cb()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
return hass.states.get(ENTITY_CLIMATE)
|
||||
return await _client_update(hass, client)
|
||||
|
||||
|
||||
async def _patch_spa_heatstate(hass, config_entry, heat_state, client):
|
||||
async def _patch_spa_heatstate(
|
||||
hass: HomeAssistant, client: MagicMock, heat_state: int
|
||||
) -> State:
|
||||
"""Patch the heatmode."""
|
||||
client.get_heatstate.return_value = heat_state
|
||||
|
||||
client.heat_state = heat_state
|
||||
await common.async_set_hvac_mode(hass, HVAC_SETTINGS[heat_state], ENTITY_CLIMATE)
|
||||
await client.new_data_cb()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
return hass.states.get(ENTITY_CLIMATE)
|
||||
return await _client_update(hass, client)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"""Test the Balboa Spa Client config flow."""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from pybalboa.exceptions import SpaConnectionError
|
||||
|
||||
from homeassistant import config_entries, data_entry_flow
|
||||
from homeassistant.components.balboa.const import CONF_SYNC_TIME, DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
@@ -25,7 +27,7 @@ async def test_form(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.balboa.config_flow.BalboaSpaWifi",
|
||||
"homeassistant.components.balboa.config_flow.SpaClient.__aenter__",
|
||||
return_value=client,
|
||||
), patch(
|
||||
"homeassistant.components.balboa.async_setup_entry",
|
||||
@@ -49,17 +51,35 @@ async def test_form_cannot_connect(hass: HomeAssistant, client: MagicMock) -> No
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.balboa.config_flow.BalboaSpaWifi",
|
||||
"homeassistant.components.balboa.config_flow.SpaClient.__aenter__",
|
||||
return_value=client,
|
||||
side_effect=SpaConnectionError(),
|
||||
):
|
||||
client.connect.return_value = False
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
TEST_DATA,
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], TEST_DATA
|
||||
)
|
||||
|
||||
assert result2["type"] == FlowResultType.FORM
|
||||
assert result2["errors"] == {"base": "cannot_connect"}
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
|
||||
async def test_form_spa_not_configured(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
"""Test we handle spa not configured error."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.balboa.config_flow.SpaClient.__aenter__",
|
||||
return_value=client,
|
||||
):
|
||||
client.async_configuration_loaded.return_value = False
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], TEST_DATA
|
||||
)
|
||||
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
|
||||
async def test_unknown_error(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
@@ -69,10 +89,10 @@ async def test_unknown_error(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.balboa.config_flow.BalboaSpaWifi",
|
||||
"homeassistant.components.balboa.config_flow.SpaClient.__aenter__",
|
||||
return_value=client,
|
||||
side_effect=Exception("Boom"),
|
||||
):
|
||||
client.connect.side_effect = Exception("Boom")
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
TEST_DATA,
|
||||
@@ -94,7 +114,7 @@ async def test_already_configured(hass: HomeAssistant, client: MagicMock) -> Non
|
||||
assert result["step_id"] == SOURCE_USER
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.balboa.config_flow.BalboaSpaWifi",
|
||||
"homeassistant.components.balboa.config_flow.SpaClient.__aenter__",
|
||||
return_value=client,
|
||||
), patch(
|
||||
"homeassistant.components.balboa.async_setup_entry",
|
||||
|
||||
@@ -7,20 +7,18 @@ from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import CONF_HOST
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import TEST_HOST, init_integration
|
||||
from . import TEST_HOST
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_setup_entry(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
async def test_setup_entry(
|
||||
hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Validate that setup entry also configure the client."""
|
||||
config_entry = await init_integration(hass)
|
||||
|
||||
assert config_entry.state == ConfigEntryState.LOADED
|
||||
|
||||
await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
|
||||
assert config_entry.state == ConfigEntryState.NOT_LOADED
|
||||
assert integration.state == ConfigEntryState.LOADED
|
||||
await hass.config_entries.async_unload(integration.entry_id)
|
||||
assert integration.state == ConfigEntryState.NOT_LOADED
|
||||
|
||||
|
||||
async def test_setup_entry_fails(hass: HomeAssistant, client: MagicMock) -> None:
|
||||
@@ -39,3 +37,11 @@ async def test_setup_entry_fails(hass: HomeAssistant, client: MagicMock) -> None
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert config_entry.state == ConfigEntryState.SETUP_RETRY
|
||||
|
||||
client.connect.return_value = True
|
||||
client.async_configuration_loaded.return_value = False
|
||||
|
||||
await hass.config_entries.async_reload(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert config_entry.state == ConfigEntryState.SETUP_RETRY
|
||||
|
||||
Reference in New Issue
Block a user