mirror of
https://github.com/no2chem/wideq.git
synced 2025-05-16 23:30: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