-
Notifications
You must be signed in to change notification settings - Fork 159
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
Added support to washer-dryers to override some of the settings defined when a course is selected. Partial implementation of feature request #596 #716
base: master
Are you sure you want to change the base?
Changes from 5 commits
4c5ff92
f526c66
8d07178
05b8bac
1305914
b59b000
cac87a0
39db484
52fc0f2
0ada28d
d7c197e
eb8652a
150d273
329d756
c45c3f8
6d8c281
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
"""------------------for Washer and Dryer""" | ||
|
||
from __future__ import annotations | ||
#jl | ||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError | ||
|
||
import base64 | ||
from copy import deepcopy | ||
|
@@ -124,6 +126,13 @@ def __init__( | |
self._course_keys: dict[CourseType, str | None] | None = None | ||
self._course_infos: dict[str, str] | None = None | ||
self._selected_course: str | None = None | ||
self._course_overrides: dict | None = {} | ||
self._course_overrides_lists: dict | None = { | ||
'temp': ['TEMP_COLD', 'TEMP_20', 'TEMP_30', 'TEMP_40', 'TEMP_60', 'TEMP_95'], | ||
'spin': ['NO_SPIN', 'SPIN_400', 'SPIN_800', 'SPIN_1000', 'SPIN_Max'], | ||
'rinse': ['RINSE_NORMAL', 'RINSE_PLUS']} | ||
# Need to initialise this list so that the UI can setup the select drop down. | ||
# A better solution would be to generate this information from the data returned ThinQ API. | ||
lancasterJ marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self._is_cycle_finishing = False | ||
self._stand_by = False | ||
self._remote_start_status: dict | None = None | ||
|
@@ -167,6 +176,36 @@ def selected_course(self) -> str: | |
"""Return current selected course.""" | ||
return self._selected_course or _CURRENT_COURSE | ||
|
||
@property | ||
def temps_list(self) -> list: | ||
"""Return a list of available water temperatures for the selected course.""" | ||
return self._course_overrides_lists.get('temp') | ||
|
||
@property | ||
def selected_temp(self) -> str: | ||
"""Return current selected water temperature.""" | ||
return self._course_overrides.get('temp') | ||
|
||
@property | ||
def rinses_list(self) -> list: | ||
"""Return a list of available rinse options for the selected course.""" | ||
return self._course_overrides_lists.get('rinse') | ||
|
||
@property | ||
def selected_rinse(self) -> str: | ||
"""Return current selected rinse option.""" | ||
return self._course_overrides.get('rinse') | ||
|
||
@property | ||
def spins_list(self) -> list: | ||
"""Return a list of available spin speeds for the selected course.""" | ||
return self._course_overrides_lists.get('spin') | ||
|
||
@property | ||
def selected_spin(self) -> str: | ||
"""Return current selected spin speed.""" | ||
return self._course_overrides.get('spin') | ||
|
||
@property | ||
def run_state(self) -> str: | ||
"""Return calculated pre state.""" | ||
|
@@ -365,7 +404,6 @@ def _prepare_course_info( | |
s_course_key: str | None, | ||
) -> dict: | ||
"""Prepare the course info used to run the command.""" | ||
|
||
ret_data = deepcopy(data) | ||
|
||
# Prepare the course data initializing option for infoV1 device | ||
|
@@ -418,6 +456,11 @@ def _prepare_course_info( | |
continue | ||
ret_data[ckey] = cdata | ||
|
||
# If an override is defeined then apply it | ||
if override_value := self._course_overrides.get(ckey): | ||
ret_data[ckey] = override_value | ||
_LOGGER.debug("_prepare_course_info, course data override: %s: %s", ckey, ret_data[ckey]) | ||
|
||
if not course_set: | ||
ret_data[VT_CTRL_COURSE_INFO] = course_info | ||
|
||
|
@@ -708,6 +751,71 @@ async def select_start_course(self, course_name: str) -> None: | |
raise ValueError(f"Invalid course: {course_name}") | ||
self._selected_course = course_name | ||
|
||
# For the selected course save the permitted values for water temperature | ||
course_id = self._get_course_infos().get(self._selected_course) | ||
n_course_key = self.get_course_key(CourseType.COURSE) | ||
course_info = self._get_course_details(n_course_key, course_id) | ||
if not course_info: | ||
raise ValueError("Course info not available") | ||
# _LOGGER.debug("select_start_course, course_info: %s", course_info) | ||
|
||
self._course_overrides.clear() | ||
self._course_overrides_lists.clear() | ||
for func_key in course_info["function"]: | ||
value = func_key.get("value") | ||
default = func_key.get("default") | ||
selectable = func_key.get("selectable") | ||
|
||
if selectable is None: | ||
continue | ||
|
||
_LOGGER.debug("select_start_course(%s), set overrides for %s - default: %s, selectable: %s", course_name, value, default, selectable) | ||
self._course_overrides[value] = default | ||
self._course_overrides_lists[value] = selectable | ||
|
||
|
||
def _select_enabled(self, select_name: str) -> bool: | ||
"""Return if specified select is enabled.""" | ||
enabled = self.select_course_enabled and self._selected_course and self._course_overrides_lists.get(select_name) | ||
if (not enabled) and (select_name in self._course_overrides): | ||
del self._course_overrides[select_name] | ||
return enabled | ||
|
||
def _select_start_option(self, option: str, option_friendly_name: str, option_selected: str) -> None: | ||
"""Select a secific option for remote start.""" | ||
permitted_options = self._course_overrides_lists.get(option) | ||
if permitted_options and option_selected in permitted_options: | ||
self._course_overrides[option] = option_selected | ||
else: | ||
raise ServiceValidationError(f"{option_selected} is invalid and will be ignored. {option_friendly_name} must be one of {permitted_options}") | ||
|
||
@property | ||
def select_temp_enabled(self) -> bool: | ||
"""Return if select temp is enabled.""" | ||
return self._select_enabled('temp') | ||
|
||
async def select_start_temp(self, temp_name: str) -> None: | ||
"""Select a secific water temperature for remote start.""" | ||
self._select_start_option('temp', 'Water Temp', temp_name) | ||
|
||
@property | ||
def select_rinse_enabled(self) -> bool: | ||
"""Return if select rinse is enabled.""" | ||
return self._select_enabled('rinse') | ||
|
||
async def select_start_rinse(self, rinse_name: str) -> None: | ||
"""Select a secific rinse option for remote start.""" | ||
self._select_start_option('rinse', 'Rinse Option', rinse_name) | ||
|
||
@property | ||
def select_spin_enabled(self) -> bool: | ||
"""Return if select spin is enabled.""" | ||
return self._select_enabled('spin') | ||
|
||
async def select_start_spin(self, spin_name: str) -> None: | ||
"""Select a secific spin for remote start.""" | ||
self._select_start_option('spin', 'Spin Speed', spin_name) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will make all the logic very complex, because there are different combination that can vary depending on selected course. I would prefer to just add some parameter to the service call and allow to change this value calling the HA service with prober parameters, that will be ignored if not valid. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ollo69 ,
You are correct the ability to override a temp, spin or rinse depends on the WM model and the course selected. The PR handles this by extracting the necessary data for course info and storing it in
When I started this work you had not publish the change to I feel it is very easy to add another parameter to If you are happy with the above approach I am happy to modify the PR. I feel it will be a simple change. If you are thinking of something different please let me know. I feel there is one problem we should agree on. For course names users can discover the valid course names that can be passed to In summary:
Regards There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ollo69 I had all the logic in place to add overrides to I have not removed the selectors yet. I am waiting your feed back, see above. |
||
async def power_off(self): | ||
"""Power off the device.""" | ||
keys = self._get_cmd_keys(CMD_POWER_OFF) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in my previous comment, I prefer to not use a select but just provide additional parameter to be used in the
remote_start
service.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see my comments above.