Skip to content

Split washer and dryer class #96

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jun 25, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
21 changes: 15 additions & 6 deletions cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import aiohttp

from cli_ac_menu import show_aircon_menu
from cli_dryer_menu import show_dryer_menu
from cli_oven_menu import show_oven_menu
from cli_refrigerator_menu import show_refrigerator_menu
from cli_washerdryer_menu import show_washerdryer_menu
from cli_washer_menu import show_washer_menu
from whirlpool.appliancesmanager import AppliancesManager
from whirlpool.auth import Auth
from whirlpool.backendselector import BackendSelector, Brand, Region
Expand Down Expand Up @@ -69,8 +70,11 @@ async def start():
if appliance_manager.aircons:
print("\n".join(map(str, appliance_manager.aircons)))

if appliance_manager.washer_dryers:
print("\n".join(map(str, appliance_manager.washer_dryers)))
if appliance_manager.dryers:
print("\n".join(map(str, appliance_manager.dryers)))

if appliance_manager.washers:
print("\n".join(map(str, appliance_manager.washers)))

if appliance_manager.ovens:
print("\n".join(map(str, appliance_manager.ovens)))
Expand Down Expand Up @@ -99,9 +103,14 @@ async def __aexit__(self, *args) -> None:
await show_aircon_menu(ac_data)
return

for wd_data in appliance_manager.washer_dryers:
if wd_data.said == args.said:
await show_washerdryer_menu(wd_data)
for dr_data in appliance_manager.dryers:
if dr_data.said == args.said:
await show_dryer_menu(dr_data)
return

for wr_data in appliance_manager.washers:
if wr_data.said == args.said:
await show_washer_menu(wr_data)
return

for mo_data in appliance_manager.ovens:
Expand Down
76 changes: 76 additions & 0 deletions cli_dryer_menu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import json

import aioconsole

from whirlpool.dryer import Dryer


async def show_dryer_menu(dr: Dryer) -> None:
def print_menu():
print("\n")
print(30 * "-", "MENU", 30 * "-")
print("u. Update status from server")
print("p. Print status")
print("v. Print raw status")
print("c. Custom command")
print("q. Exit")
print(67 * "-")

def print_status(dr: Dryer):
print(f"online: {dr.get_online()}")
print(f"state: {dr.get_machine_state_value()}")
print(f"door open: {dr.get_op_status_dooropen()}")
print(f"est time remaining: {dr.get_time_status_est_time_remaining()}")
print(f"extra power changeable: {dr.get_change_status_extrapowerchangeable()}")
print(f"steam changeable: {dr.get_change_status_steamchangeable()}")
print(f"cycle select: {dr.get_change_status_cycleselect()}")
print(f"dryness: {dr.get_change_status_dryness()}")
print(f"manual dry time: {dr.get_change_status_manualdrytime()}")
print(f"static guard: {dr.get_change_status_staticguard()}")
print(f"temperature: {dr.get_change_status_temperature()}")
print(f"wrinkle shield: {dr.get_change_status_wrinkleshield()}")
print(f"airflow status: {dr.get_cycle_status_airflow_status()}")
print(f"cool down: {dr.get_cycle_status_cool_down()}")
print(f"damp: {dr.get_cycle_status_damp()}")
print(f"drying: {dr.get_cycle_status_drying()}")
print(f"limited cycle: {dr.get_cycle_status_limited_cycle()}")
print(f"sensing: {dr.get_cycle_status_sensing()}")
print(f"static reduce: {dr.get_cycle_status_static_reduce()}")
print(f"steaming: {dr.get_cycle_status_steaming()}")
print(f"wet: {dr.get_cycle_status_wet()}")
print(f"cycle count: {dr.get_odometer_status_cycle_count()}")
print(f"running hours: {dr.get_odometer_status_running_hours()}")
print(f"total hours: {dr.get_odometer_status_total_hours()}")
print(f"isp check: {dr.get_wifi_status_isp_check()}")
print(f"rssi antenna diversity: {dr.get_wifi_status_rssi_antenna_diversity()}")

print(f"set dryness: {dr.get_dryness()}")
print(f"set manual dry time: {dr.get_manual_dry_time()}")
print(f"set cycle select: {dr.get_cycle_select()}")

def attr_upd():
print("Attributes updated")

dr.register_attr_callback(attr_upd)

loop = True
while loop:
print_menu()
choice = await aioconsole.ainput("Enter your choice: ")

if choice == "p":
print_status(dr)
elif choice == "u":
await dr.fetch_data()
print_status(dr)
elif choice == "v":
print(json.dumps(dr._data_dict, indent=4))
elif choice == "c":
cmd = await aioconsole.ainput("Command: ")
val = await aioconsole.ainput("Value: ")
await dr.send_attributes({cmd: val})
elif choice == "q":
print("Bye")
loop = False
else:
print("Wrong option selection. Enter any key to try again..")
34 changes: 17 additions & 17 deletions cli_washerdryer_menu.py → cli_washer_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import aioconsole

from whirlpool.washerdryer import WasherDryer
from whirlpool.washer import Washer


async def show_washerdryer_menu(wd: WasherDryer) -> None:
async def show_washer_menu(wr: Washer) -> None:
def print_menu():
print("\n")
print(30 * "-", "MENU", 30 * "-")
Expand All @@ -16,37 +16,37 @@ def print_menu():
print("q. Exit")
print(67 * "-")

def print_status(wd: WasherDryer):
print("online: " + str(wd.get_online()))
print("state: " + str(wd.get_machine_state()))
print("sensing: " + str(wd.get_cycle_status_sensing()))
print("filling: " + str(wd.get_cycle_status_filling()))
print("soaking: " + str(wd.get_cycle_status_soaking()))
print("washing: " + str(wd.get_cycle_status_washing()))
print("rinsing: " + str(wd.get_cycle_status_rinsing()))
print("spinning: " + str(wd.get_cycle_status_spinning()))
def print_status(wr: Washer):
print("online: " + str(wr.get_online()))
print("state: " + str(wr.get_machine_state()))
print("sensing: " + str(wr.get_cycle_status_sensing()))
print("filling: " + str(wr.get_cycle_status_filling()))
print("soaking: " + str(wr.get_cycle_status_soaking()))
print("washing: " + str(wr.get_cycle_status_washing()))
print("rinsing: " + str(wr.get_cycle_status_rinsing()))
print("spinning: " + str(wr.get_cycle_status_spinning()))

def attr_upd():
print("Attributes updated")

wd.register_attr_callback(attr_upd)
wr.register_attr_callback(attr_upd)

loop = True
while loop:
print_menu()
choice = await aioconsole.ainput("Enter your choice: ")

if choice == "p":
print_status(wd)
print_status(wr)
elif choice == "u":
await wd.fetch_data()
print_status(wd)
await wr.fetch_data()
print_status(wr)
elif choice == "v":
print(json.dumps(wd._data_dict, indent=4))
print(json.dumps(wr._data_dict, indent=4))
elif choice == "c":
cmd = await aioconsole.ainput("Command: ")
val = await aioconsole.ainput("Value: ")
await wd.send_attributes({cmd: val})
await wr.send_attributes({cmd: val})
elif choice == "q":
print("Bye")
loop = False
Expand Down
33 changes: 33 additions & 0 deletions tests/data/owned_appliances.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,39 @@
"CATEGORY_NAME": "Climate",
"MODEL_NO": "CoolMyBeer",
"SERIAL": "FR12345678"
},
{
"DATA_MODEL_KEY": "DDM_LAUNDRY_VMAX20_MAYTAG_DRYER_6_V1",
"CATEGORY_NAME": "FabricCare",
"MODEL_NO": "MGD6230HW3",
"REPLENISHMENT_DEVICE_MODEL": null,
"IMAGE_PATH": null,
"APPLIANCE_ID": 999,
"APPLIANCE_MASTER_ID": 3703,
"MODEL_SKU_ID": null,
"CREATED_AT": 1693943005000,
"UPDATED_AT": 1693943005000,
"APPLIANCE_NAME": "Dryer",
"SAID": "SAIDDRYER1",
"NEST_AWAY": 0,
"CYCLE_HANDOFF": 0,
"NEST_THERMOSTAT_ID": 0,
"THERMOSTAT_INFLUENCE_THRESHOLD": null,
"THERMOSTAT_DESIRED_OFFSET": null,
"THERMOSTAT_OFFSET_NEEDED": null,
"DELETE_FLAG": 0,
"DISPLAY_POSITION": null,
"SERIAL": "MC1234567",
"LOCATION_ID": 999,
"MACHINE_ID": null,
"MACHINE_POSITION": 0,
"ISVOICEDEFAULT": 1,
"DEVICE_ID": "9d83427a-b994-4859-a2b9-2472c5dcbc26",
"IS_ENROLLED": null,
"STATUS": "CLAIMED",
"APPLIANCE_TYPE_ID": null,
"MACHINE_STATUS": null,
"APPLIANCE_MODE": 2
}
]
}
89 changes: 89 additions & 0 deletions tests/test_dryer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from collections.abc import Callable
from typing import Any

import pytest
from aioresponses import aioresponses
from yarl import URL

from whirlpool.appliancesmanager import AppliancesManager
from whirlpool.auth import Auth
from whirlpool.backendselector import BackendSelector
from whirlpool.dryer import MachineState


async def test_attributes(appliances_manager: AppliancesManager):
dryer1 = appliances_manager.dryers[0]
assert dryer1.get_machine_state() == MachineState.Standby
assert dryer1.get_machine_state_value() == 0
assert dryer1.get_op_status_dooropen() is False
assert dryer1.get_time_status_est_time_remaining() == 1800
assert dryer1.get_drum_light_on() == 0
assert dryer1.get_change_status_steamchangeable() == 1
assert dryer1.get_change_status_cycleselect() == 0
assert dryer1.get_change_status_dryness() == 1
assert dryer1.get_change_status_manualdrytime() == 1
assert dryer1.get_change_status_temperature() == 1
assert dryer1.get_change_status_wrinkleshield() == 1
assert dryer1.get_dryness() == 10
assert dryer1.get_manual_dry_time() == 1800
assert dryer1.get_cycle_select() == 11
assert dryer1.get_cycle_status_airflow_status() == 0
assert dryer1.get_cycle_status_cool_down() == 0
assert dryer1.get_cycle_status_damp() == 0
assert dryer1.get_cycle_status_drying() == 0
assert dryer1.get_cycle_status_limited_cycle() == 0
assert dryer1.get_cycle_status_sensing() == 0
assert dryer1.get_cycle_status_static_reduce() == 0
assert dryer1.get_cycle_status_steaming() == 0
assert dryer1.get_cycle_status_wet() == 0
assert dryer1.get_odometer_status_cycle_count() == 195
assert dryer1.get_odometer_status_running_hours() == 148
assert dryer1.get_odometer_status_total_hours() == 6302
assert dryer1.get_wifi_status_rssi_antenna_diversity() == -51
assert dryer1.get_damp_notification_tone_volume() == 0
assert dryer1.get_alert_tone_volume() == 0
assert dryer1.get_temperature() == 2
assert dryer1.get_wrinkle_shield() == 0


@pytest.mark.parametrize(
["method", "argument", "expected_json"],
[
],
)
async def test_setters(
appliances_manager: AppliancesManager,
auth: Auth,
backend_selector: BackendSelector,
aioresponses_mock: aioresponses,
method: Callable,
argument: Any,
expected_json: dict,
):
dryer = appliances_manager.dryers[0]

expected_payload = {
"json": {
"body": expected_json,
"header": {"said": dryer.said, "command": "setAttributes"},
}
}

post_request_call_kwargs = {
"url": backend_selector.appliance_command_url,
"method": "POST",
"data": None,
"json": expected_payload["json"],
"allow_redirects": True,
"headers": auth.create_headers(),
}

url = backend_selector.appliance_command_url

# add call, call method
aioresponses_mock.post(url, payload=expected_payload)
await method(dryer, argument)

# assert args and length
aioresponses_mock.assert_called_with(**post_request_call_kwargs)
assert len(aioresponses_mock.requests[("POST", URL(url))]) == 1
Loading
Loading