mirror of
https://github.com/no2chem/wideq.git
synced 2025-05-17 15:50:10 -07:00
Merge pull request #43 from dermotduffy/master
Add dishwasher device to wideq
This commit is contained in:
commit
0610d0f0b7
1246
tests/fixtures/client.json
vendored
1246
tests/fixtures/client.json
vendored
File diff suppressed because it is too large
Load Diff
58
tests/test_dishwasher.py
Normal file
58
tests/test_dishwasher.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import json
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from wideq.client import Client, DeviceInfo
|
||||||
|
from wideq.dishwasher import DishWasherDevice, DishWasherState, DishWasherStatus
|
||||||
|
|
||||||
|
POLL_DATA = {
|
||||||
|
"16~19": "0",
|
||||||
|
"21~22": "0",
|
||||||
|
"Course": "2",
|
||||||
|
"CourseType": "1",
|
||||||
|
"CurDownload": "2",
|
||||||
|
"Error": "0",
|
||||||
|
"Initial_Time_H": "3",
|
||||||
|
"Initial_Time_M": "14",
|
||||||
|
"Option1": "208",
|
||||||
|
"Option2": "8",
|
||||||
|
"Option3": "0",
|
||||||
|
"Process": "2",
|
||||||
|
"Remain_Time_H": "1",
|
||||||
|
"Remain_Time_M": "59",
|
||||||
|
"Reserve_Time_H": "0",
|
||||||
|
"Reserve_Time_M": "0",
|
||||||
|
"RinseLevel": "2",
|
||||||
|
"SmartCourse": "2",
|
||||||
|
"SofteningLevel": "0",
|
||||||
|
"State": "2",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DishWasherStatusTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
with open('./tests/fixtures/client.json') as fp:
|
||||||
|
state = json.load(fp)
|
||||||
|
self.client = Client.load(state)
|
||||||
|
self.device_info = DeviceInfo({
|
||||||
|
'alias': 'DISHWASHER',
|
||||||
|
'deviceId': '33330ba80-107d-11e9-96c8-0051ede8ad3c',
|
||||||
|
'deviceType': 204,
|
||||||
|
'modelJsonUrl': (
|
||||||
|
'https://aic.lgthinq.com:46030/api/webContents/modelJSON?'
|
||||||
|
'modelName=D3210&countryCode=WW&contentsId='
|
||||||
|
'JS0719082250749334&authKey=thinq'),
|
||||||
|
'modelNm': 'D3210',
|
||||||
|
})
|
||||||
|
self.dishwasher = DishWasherDevice(self.client, self.device_info)
|
||||||
|
|
||||||
|
def test_properties(self):
|
||||||
|
status = DishWasherStatus(self.dishwasher, POLL_DATA)
|
||||||
|
self.assertEqual(DishWasherState.RUNNING, status.state)
|
||||||
|
self.assertTrue(status.is_on)
|
||||||
|
self.assertEqual(119, status.remaining_time)
|
||||||
|
self.assertEqual(194, status.initial_time)
|
||||||
|
self.assertEqual('Heavy', status.course)
|
||||||
|
self.assertEqual('Casseroles', status.smart_course)
|
||||||
|
self.assertEqual('No Error', status.error)
|
157
wideq/dishwasher.py
Normal file
157
wideq/dishwasher.py
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
import enum
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from .client import Device
|
||||||
|
from .util import lookup_enum, lookup_reference
|
||||||
|
|
||||||
|
|
||||||
|
class DishWasherState(enum.Enum):
|
||||||
|
"""The state of the dishwasher device."""
|
||||||
|
INITIAL = '@DW_STATE_INITIAL_W'
|
||||||
|
RUNNING = '@DW_STATE_RUNNING_W'
|
||||||
|
PAUSED = "@DW_STATE_PAUSE_W"
|
||||||
|
OFF = '@DW_STATE_POWER_OFF_W'
|
||||||
|
COMPLETE = '@DW_STATE_COMPLETE_W'
|
||||||
|
POWER_FAIL = "@DW_STATE_POWER_FAIL_W"
|
||||||
|
|
||||||
|
DISHWASHER_STATE_READABLE = {
|
||||||
|
'INITIAL': 'Standby',
|
||||||
|
'RUNNING': 'Running',
|
||||||
|
'PAUSED': 'Paused',
|
||||||
|
'OFF': 'Off',
|
||||||
|
'COMPLETE': 'Complete',
|
||||||
|
'POWER_FAIL': 'Power Failed'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DishWasherProcess(enum.Enum):
|
||||||
|
"""The process within the dishwasher state."""
|
||||||
|
RESERVE = '@DW_STATE_RESERVE_W'
|
||||||
|
RUNNING = '@DW_STATE_RUNNING_W'
|
||||||
|
RINSING = '@DW_STATE_RINSING_W'
|
||||||
|
DRYING = '@DW_STATE_DRYING_W'
|
||||||
|
COMPLETE = '@DW_STATE_COMPLETE_W'
|
||||||
|
NIGHT_DRYING = '@DW_STATE_NIGHTDRY_W'
|
||||||
|
CANCELLED = '@DW_STATE_CANCEL_W'
|
||||||
|
|
||||||
|
DISHWASHER_PROCESS_READABLE = {
|
||||||
|
'RESERVE': 'Delayed Start',
|
||||||
|
'RUNNING': DISHWASHER_STATE_READABLE['RUNNING'],
|
||||||
|
'RINSING': 'Rinsing',
|
||||||
|
'DRYING': 'Drying',
|
||||||
|
'COMPLETE': DISHWASHER_STATE_READABLE['COMPLETE'],
|
||||||
|
'NIGHT_DRYING': 'Night Drying',
|
||||||
|
'CANCELLED': 'Cancelled',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Provide a map to correct typos in the official course names.
|
||||||
|
DISHWASHER_COURSE_MAP = {
|
||||||
|
'Haeavy': 'Heavy',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DishWasherDevice(Device):
|
||||||
|
"""A higher-level interface for a dishwasher."""
|
||||||
|
|
||||||
|
def poll(self) -> Optional['DishWasherStatus']:
|
||||||
|
"""Poll the device's current state.
|
||||||
|
|
||||||
|
Monitoring must be started first with `monitor_start`.
|
||||||
|
|
||||||
|
:returns: Either a `DishWasherStatus` instance or `None` if the status
|
||||||
|
is not yet available.
|
||||||
|
"""
|
||||||
|
# Abort if monitoring has not started yet.
|
||||||
|
if not hasattr(self, 'mon'):
|
||||||
|
return None
|
||||||
|
|
||||||
|
data = self.mon.poll()
|
||||||
|
if data:
|
||||||
|
res = self.model.decode_monitor(data)
|
||||||
|
return DishWasherStatus(self, res)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class DishWasherStatus(object):
|
||||||
|
"""Higher-level information about a dishwasher's current status.
|
||||||
|
|
||||||
|
:param dishwasher: The DishWasherDevice instance.
|
||||||
|
:param data: Binary data from the API.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, dishwasher: DishWasherDevice, data: dict):
|
||||||
|
self.dishwasher = dishwasher
|
||||||
|
self.data = data
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self) -> DishWasherState:
|
||||||
|
"""Get the state of the dishwasher."""
|
||||||
|
return DishWasherState(
|
||||||
|
lookup_enum('State', self.data, self.dishwasher))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def readable_state(self) -> str:
|
||||||
|
"""Get a human readable state of the dishwasher."""
|
||||||
|
return DISHWASHER_STATE_READABLE[self.state.name]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def process(self) -> DishWasherProcess:
|
||||||
|
"""Get the process of the dishwasher."""
|
||||||
|
process = lookup_enum('Process', self.data, self.dishwasher)
|
||||||
|
if process and process != '-':
|
||||||
|
return DishWasherProcess(process)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def readable_process(self) -> str:
|
||||||
|
"""Get a human readable process of the dishwasher."""
|
||||||
|
if self.process:
|
||||||
|
return DISHWASHER_PROCESS_READABLE[self.process.name]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self) -> bool:
|
||||||
|
"""Check if the dishwasher is on or not."""
|
||||||
|
return self.state != DishWasherState.OFF
|
||||||
|
|
||||||
|
@property
|
||||||
|
def remaining_time(self) -> int:
|
||||||
|
"""Get the remaining time in minutes."""
|
||||||
|
return (int(self.data['Remain_Time_H']) * 60 +
|
||||||
|
int(self.data['Remain_Time_M']))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def initial_time(self) -> int:
|
||||||
|
"""Get the initial time in minutes."""
|
||||||
|
return (
|
||||||
|
int(self.data['Initial_Time_H']) * 60 +
|
||||||
|
int(self.data['Initial_Time_M']))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reserve_time(self) -> int:
|
||||||
|
"""Get the reserve time in minutes."""
|
||||||
|
return (
|
||||||
|
int(self.data['Reserve_Time_H']) * 60 +
|
||||||
|
int(self.data['Reserve_Time_M']))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def course(self) -> str:
|
||||||
|
"""Get the current course."""
|
||||||
|
course = lookup_reference('Course', self.data, self.dishwasher)
|
||||||
|
if course in DISHWASHER_COURSE_MAP:
|
||||||
|
return DISHWASHER_COURSE_MAP[course]
|
||||||
|
else:
|
||||||
|
return course
|
||||||
|
|
||||||
|
@property
|
||||||
|
def smart_course(self) -> str:
|
||||||
|
"""Get the current smart course."""
|
||||||
|
return lookup_reference('SmartCourse', self.data, self.dishwasher)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def error(self) -> str:
|
||||||
|
"""Get the current error."""
|
||||||
|
return lookup_reference('Error', self.data, self.dishwasher)
|
Loading…
x
Reference in New Issue
Block a user