Skip to content

Commit

Permalink
Use StateUpdate and SystemUpdate models to set state and system in v1
Browse files Browse the repository at this point in the history
  • Loading branch information
DCSBL committed Jan 1, 2025
1 parent 389b9e1 commit 100ede2
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 58 deletions.
25 changes: 23 additions & 2 deletions homewizard_energy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,27 @@ class DeviceType(Enum):
)


@dataclass(kw_only=True)
class StateUpdate(BaseModel):
"""Represent State update config."""

power_on: bool | None = field(default=None)
switch_lock: bool | None = field(default=None)
brightness: int | None = field(default=None)

def as_dict(self) -> dict[str, bool | int]:
"""Return StateUpdate object as dict.
Only include values that are not None.
"""
_dict = {k: v for k, v in asdict(self).items() if v is not None}

if not _dict:
raise ValueError("No values to update")

return _dict


@dataclass(kw_only=True)
class State(BaseModel):
"""Represent current state."""
Expand All @@ -439,8 +460,8 @@ class State(BaseModel):
class SystemUpdate(BaseModel):
"""Represent System update config."""

cloud_enabled: bool = field(default=None)
status_led_brightness_pct: int = field(default=None)
cloud_enabled: bool | None = field(default=None)
status_led_brightness_pct: int | None = field(default=None)
api_v1_enabled: bool | None = field(default=None)

def as_dict(self) -> dict[str, bool | int]:
Expand Down
75 changes: 33 additions & 42 deletions homewizard_energy/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
)

from ..const import LOGGER
from ..models import Device, Measurement, State, System
from ..models import Device, Measurement, State, StateUpdate, System, SystemUpdate
from .const import SUPPORTED_API_VERSION

T = TypeVar("T")
Expand Down Expand Up @@ -90,57 +90,48 @@ async def data(self) -> Measurement:
return Measurement.from_json(response)

@optional_method
async def state(self) -> State | None:
async def state(self, update: StateUpdate | None = None) -> State:
"""Return the state object."""
_, response = await self._request("api/v1/state")
return State.from_json(response)

@optional_method
async def state_set(
self,
power_on: bool | None = None,
switch_lock: bool | None = None,
brightness: int | None = None,
) -> bool:
"""Set state of device."""
state: dict[str, bool | str] = {}
if update is not None:
data = update.as_dict()
status, response = await self._request(
"api/v1/state", method=METH_PUT, data=data
)

if power_on is not None:
state["power_on"] = power_on
if switch_lock is not None:
state["switch_lock"] = switch_lock
if brightness is not None:
state["brightness"] = brightness
else:
status, response = await self._request("api/v1/state")

if not state:
LOGGER.error("At least one state update is required")
return False
if status != HTTPStatus.OK:
raise RequestError("Failed to get/set state")

Check warning on line 105 in homewizard_energy/v1/__init__.py

View check run for this annotation

Codecov / codecov/patch

homewizard_energy/v1/__init__.py#L105

Added line #L105 was not covered by tests

await self._request("api/v1/state", method=METH_PUT, data=state)
return True
state = State.from_json(response)
return state

@optional_method
async def system(self) -> System:
async def system(self, update: SystemUpdate | None = None) -> System:
"""Return the system object."""
_, response = await self._request("api/v1/system")
return System.from_json(response)
if update is not None:
if (
update.status_led_brightness_pct is not None
or update.api_v1_enabled is not None
):
raise UnsupportedError(
"Setting status_led_brightness_pct and api_v1_enabled is not supported in v1"
)

@optional_method
async def system_set(
self,
cloud_enabled: bool | None = None,
) -> bool:
"""Set state of device."""
state = {}
if cloud_enabled is not None:
state["cloud_enabled"] = cloud_enabled
data = update.as_dict()
status, response = await self._request(
"api/v1/system", method=METH_PUT, data=data
)

if not state:
LOGGER.error("At least one state update is required")
return False
else:
status, response = await self._request("api/v1/system")

await self._request("api/v1/system", method=METH_PUT, data=state)
return True
if status != HTTPStatus.OK:
raise RequestError("Failed to get/set system")

Check warning on line 131 in homewizard_energy/v1/__init__.py

View check run for this annotation

Codecov / codecov/patch

homewizard_energy/v1/__init__.py#L131

Added line #L131 was not covered by tests

system = System.from_json(response)
return system

@optional_method
async def identify(
Expand Down
16 changes: 8 additions & 8 deletions tests/v1/__snapshots__/test_v1_homewizard_energy.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -102,26 +102,26 @@
True
# ---
# name: test_state_set[HWE-SKT-fixtures0]
True
State(power_on=False, switch_lock=False, brightness=255)
# ---
# name: test_system_set[HWE-KWH1]
True
System(wifi_ssid=None, wifi_rssi_db=None, cloud_enabled=True, uptime_s=None, status_led_brightness_pct=None, api_v1_enabled=None)
# ---
# name: test_system_set[HWE-KWH3]
True
System(wifi_ssid=None, wifi_rssi_db=None, cloud_enabled=True, uptime_s=None, status_led_brightness_pct=None, api_v1_enabled=None)
# ---
# name: test_system_set[HWE-P1]
True
System(wifi_ssid=None, wifi_rssi_db=None, cloud_enabled=True, uptime_s=None, status_led_brightness_pct=None, api_v1_enabled=None)
# ---
# name: test_system_set[HWE-SKT]
True
System(wifi_ssid=None, wifi_rssi_db=None, cloud_enabled=True, uptime_s=None, status_led_brightness_pct=None, api_v1_enabled=None)
# ---
# name: test_system_set[HWE-WTR]
True
System(wifi_ssid=None, wifi_rssi_db=None, cloud_enabled=True, uptime_s=None, status_led_brightness_pct=None, api_v1_enabled=None)
# ---
# name: test_system_set[SDM230-wifi]
True
System(wifi_ssid=None, wifi_rssi_db=None, cloud_enabled=True, uptime_s=None, status_led_brightness_pct=None, api_v1_enabled=None)
# ---
# name: test_system_set[SDM630-wifi]
True
System(wifi_ssid=None, wifi_rssi_db=None, cloud_enabled=True, uptime_s=None, status_led_brightness_pct=None, api_v1_enabled=None)
# ---
28 changes: 22 additions & 6 deletions tests/v1/test_v1_homewizard_energy.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from homewizard_energy import HomeWizardEnergyV1
from homewizard_energy.errors import DisabledError, RequestError, UnsupportedError
from homewizard_energy.models import StateUpdate, SystemUpdate

from . import load_fixtures

Expand Down Expand Up @@ -354,8 +355,8 @@ async def test_state_set(
async with aiohttp.ClientSession() as session:
api = HomeWizardEnergyV1("example.com", clientsession=session)

state = await api.state_set(
power_on=False, switch_lock=False, brightness=255
state = await api.state(
StateUpdate(power_on=False, switch_lock=False, brightness=255)
)
assert state

Expand All @@ -370,8 +371,8 @@ async def test_state_set_detects_no_statechange():
async with aiohttp.ClientSession() as session:
api = HomeWizardEnergyV1("example.com", clientsession=session)

state = await api.state_set()
assert not state
with pytest.raises(ValueError):
await api.state(StateUpdate())


@pytest.mark.parametrize(
Expand Down Expand Up @@ -528,7 +529,7 @@ async def test_system_set(model: str, snapshot: SnapshotAssertion, aresponses):
async with aiohttp.ClientSession() as session:
api = HomeWizardEnergyV1("example.com", clientsession=session)

system = await api.system_set(cloud_enabled=False)
system = await api.system(update=SystemUpdate(cloud_enabled=True))
assert system
assert system == snapshot

Expand All @@ -540,7 +541,22 @@ async def test_system_set_missing_arguments():

async with aiohttp.ClientSession() as session:
api = HomeWizardEnergyV1("example.com", clientsession=session)
assert await api.system_set() is False

with pytest.raises(ValueError):
await api.system(update=SystemUpdate())


async def test_system_set_unsupported_arguments():
"""Test system set when no arguments are given."""

async with aiohttp.ClientSession() as session:
api = HomeWizardEnergyV1("example.com", clientsession=session)

with pytest.raises(UnsupportedError):
await api.system(update=SystemUpdate(status_led_brightness_pct=50))

with pytest.raises(UnsupportedError):
await api.system(update=SystemUpdate(api_v1_enabled=True))


# pylint: disable=protected-access
Expand Down

0 comments on commit 100ede2

Please sign in to comment.