diff --git a/README.md b/README.md
index 594e3032..cc70fef2 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[![](https://img.shields.io/badge/COMMUNITY-FORUM-success?style=for-the-badge)](https://community.home-assistant.io)
# LG ThinQ Devices integration for HomeAssistant
-A Homeassistant custom component to monitor LG Air Conditioner, Washer, Dryer, DishWasher, Refrigerator, Styler and Range
+A Homeassistant custom component to monitor and control LG Air Conditioner, Washer, Dryer, DishWasher, Refrigerator, Styler and Range
using ThinQ API based on [WideQ project][wideq].
**Important Version note:**
diff --git a/custom_components/smartthinq_sensors/const.py b/custom_components/smartthinq_sensors/const.py
index 16520dd2..726902d4 100644
--- a/custom_components/smartthinq_sensors/const.py
+++ b/custom_components/smartthinq_sensors/const.py
@@ -2,7 +2,7 @@
Support to interface with LGE ThinQ Devices.
"""
-__version__ = "0.8.10"
+__version__ = "0.8.11"
PROJECT_URL = "https://github.com/ollo69/ha-smartthinq-sensors/"
ISSUE_URL = "{}issues".format(PROJECT_URL)
diff --git a/custom_components/smartthinq_sensors/manifest.json b/custom_components/smartthinq_sensors/manifest.json
index ca0daf4c..bc0bbad7 100644
--- a/custom_components/smartthinq_sensors/manifest.json
+++ b/custom_components/smartthinq_sensors/manifest.json
@@ -8,5 +8,5 @@
"requirements": ["pycountry>=20.7.3"],
"config_flow": true,
"iot_class": "cloud_polling",
- "version": "0.8.10"
+ "version": "0.8.11"
}
diff --git a/custom_components/smartthinq_sensors/sensor.py b/custom_components/smartthinq_sensors/sensor.py
index d37dbe26..5071797b 100644
--- a/custom_components/smartthinq_sensors/sensor.py
+++ b/custom_components/smartthinq_sensors/sensor.py
@@ -32,7 +32,9 @@
FEAT_COOKTOP_CENTER_STATE,
FEAT_COOKTOP_RIGHT_FRONT_STATE,
FEAT_COOKTOP_RIGHT_REAR_STATE,
+ FEAT_OVEN_LOWER_CURRENT_TEMP,
FEAT_OVEN_LOWER_STATE,
+ FEAT_OVEN_UPPER_CURRENT_TEMP,
FEAT_OVEN_UPPER_STATE,
)
@@ -147,6 +149,12 @@
ATTR_VALUE_FN: lambda x: x._power_state,
ATTR_ENABLED: True,
},
+ ATTR_CURRENT_COURSE: {
+ ATTR_MEASUREMENT_NAME: "Current Course",
+ ATTR_ICON: "mdi:pin-outline",
+ ATTR_VALUE_FN: lambda x: x._current_course,
+ ATTR_ENABLED: True,
+ },
FEAT_RUN_STATE: {
ATTR_MEASUREMENT_NAME: "Run State",
ATTR_ICON: DEFAULT_ICON,
@@ -159,51 +167,51 @@
ATTR_VALUE_FEAT: FEAT_PROCESS_STATE,
ATTR_ENABLED: True,
},
- FEAT_PRE_STATE: {
- ATTR_MEASUREMENT_NAME: "Pre State",
- ATTR_ICON: DEFAULT_ICON,
- ATTR_VALUE_FEAT: FEAT_PRE_STATE,
- },
- FEAT_ERROR_MSG: {
- ATTR_MEASUREMENT_NAME: "Error Message",
- ATTR_ICON: "mdi:alert-circle-outline",
- ATTR_VALUE_FEAT: FEAT_ERROR_MSG,
- },
- FEAT_TUBCLEAN_COUNT: {
- ATTR_MEASUREMENT_NAME: "Tube Clean Counter",
- ATTR_ICON: DEFAULT_ICON,
- ATTR_VALUE_FEAT: FEAT_TUBCLEAN_COUNT,
- },
FEAT_SPINSPEED: {
ATTR_MEASUREMENT_NAME: "Spin Speed",
ATTR_ICON: "mdi:rotate-3d",
ATTR_VALUE_FEAT: FEAT_SPINSPEED,
+ ATTR_ENABLED: True,
},
FEAT_WATERTEMP: {
ATTR_MEASUREMENT_NAME: "Water Temp",
ATTR_ICON: "mdi:thermometer-lines",
ATTR_VALUE_FEAT: FEAT_WATERTEMP,
+ ATTR_ENABLED: True,
},
FEAT_TEMPCONTROL: {
ATTR_MEASUREMENT_NAME: "Temp Control",
ATTR_ICON: "mdi:thermometer-lines",
ATTR_VALUE_FEAT: FEAT_TEMPCONTROL,
+ ATTR_ENABLED: True,
},
FEAT_DRYLEVEL: {
ATTR_MEASUREMENT_NAME: "Dry Level",
ATTR_ICON: "mdi:tumble-dryer",
ATTR_VALUE_FEAT: FEAT_DRYLEVEL,
+ ATTR_ENABLED: True,
+ },
+ FEAT_ERROR_MSG: {
+ ATTR_MEASUREMENT_NAME: "Error Message",
+ ATTR_ICON: "mdi:alert-circle-outline",
+ ATTR_VALUE_FEAT: FEAT_ERROR_MSG,
+ ATTR_ENABLED: True,
+ },
+ FEAT_PRE_STATE: {
+ ATTR_MEASUREMENT_NAME: "Pre State",
+ ATTR_ICON: DEFAULT_ICON,
+ ATTR_VALUE_FEAT: FEAT_PRE_STATE,
+ },
+ FEAT_TUBCLEAN_COUNT: {
+ ATTR_MEASUREMENT_NAME: "Tube Clean Counter",
+ ATTR_ICON: DEFAULT_ICON,
+ ATTR_VALUE_FEAT: FEAT_TUBCLEAN_COUNT,
},
FEAT_HALFLOAD: {
ATTR_MEASUREMENT_NAME: "Half Load",
ATTR_ICON: "mdi:circle-half-full",
ATTR_VALUE_FEAT: FEAT_HALFLOAD,
},
- ATTR_CURRENT_COURSE: {
- ATTR_MEASUREMENT_NAME: "Current Course",
- ATTR_ICON: "mdi:pin-outline",
- ATTR_VALUE_FN: lambda x: x._current_course,
- },
ATTR_INITIAL_TIME: {
ATTR_MEASUREMENT_NAME: "Initial Time",
ATTR_ICON: "mdi:clock-outline",
@@ -394,6 +402,13 @@
ATTR_VALUE_FN: lambda x: x._oven_lower_target_temp,
ATTR_ENABLED: True,
},
+ FEAT_OVEN_LOWER_CURRENT_TEMP: {
+ ATTR_MEASUREMENT_NAME: "Oven Lower Current Temperature",
+ ATTR_UNIT_FN: lambda x: x._oven_temp_unit,
+ ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
+ ATTR_VALUE_FEAT: FEAT_OVEN_LOWER_CURRENT_TEMP,
+ ATTR_ENABLED: True,
+ },
ATTR_OVEN_UPPER_TARGET_TEMP: {
ATTR_MEASUREMENT_NAME: "Oven Upper Target Temperature",
ATTR_UNIT_FN: lambda x: x._oven_temp_unit,
@@ -401,6 +416,13 @@
ATTR_VALUE_FN: lambda x: x._oven_upper_target_temp,
ATTR_ENABLED: True,
},
+ FEAT_OVEN_UPPER_CURRENT_TEMP: {
+ ATTR_MEASUREMENT_NAME: "Oven Upper Current Temperature",
+ ATTR_UNIT_FN: lambda x: x._oven_temp_unit,
+ ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
+ ATTR_VALUE_FEAT: FEAT_OVEN_UPPER_CURRENT_TEMP,
+ ATTR_ENABLED: True,
+ },
}
RANGE_BINARY_SENSORS = {
diff --git a/custom_components/smartthinq_sensors/wideq/__init__.py b/custom_components/smartthinq_sensors/wideq/__init__.py
index 140c69e2..3108e3e1 100644
--- a/custom_components/smartthinq_sensors/wideq/__init__.py
+++ b/custom_components/smartthinq_sensors/wideq/__init__.py
@@ -66,9 +66,12 @@
FEAT_COOKTOP_CENTER_STATE = "cooktop_center_state"
FEAT_COOKTOP_RIGHT_FRONT_STATE = "cooktop_right_front_state"
FEAT_COOKTOP_RIGHT_REAR_STATE = "cooktop_right_rear_state"
+FEAT_OVEN_LOWER_CURRENT_TEMP = "oven_lower_current_temp"
FEAT_OVEN_LOWER_STATE = "oven_lower_state"
+FEAT_OVEN_UPPER_CURRENT_TEMP = "oven_upper_current_temp"
FEAT_OVEN_UPPER_STATE = "oven_upper_state"
+
# request ciphers settings
CIPHERS = ":HIGH:!DH:!aNULL"
diff --git a/custom_components/smartthinq_sensors/wideq/device.py b/custom_components/smartthinq_sensors/wideq/device.py
index fa9d7501..a3eb7add 100644
--- a/custom_components/smartthinq_sensors/wideq/device.py
+++ b/custom_components/smartthinq_sensors/wideq/device.py
@@ -367,7 +367,12 @@ def value(self, name):
elif d["type"] == "String":
pass
else:
- assert False, "unsupported value type {}".format(d["type"])
+ _LOGGER.error(
+ "ModelInfo: unsupported value type (%s) - value: %s",
+ d["type"],
+ d,
+ )
+ return None
def default(self, name):
"""Get the default value, if it exists, for a given value.
@@ -537,6 +542,23 @@ def decode_monitor(self, data):
else:
return self.decode_monitor_json(data)
+ @staticmethod
+ def _get_current_temp_key(key: str, data):
+ """Special case for oven current temperature, that in protocol
+ is represented with a suffix "F" or "C" depending from the unit
+ """
+ if key.count("CurrentTemperature") == 0:
+ return key
+ new_key = key[:-1]
+ if not new_key.endswith("CurrentTemperature"):
+ return key
+ unit_key = f"{new_key}Unit"
+ if unit_key not in data:
+ return key
+ if data[unit_key][0] == key[-1]:
+ return f"{new_key}Value"
+ return key
+
def decode_snapshot(self, data, key):
"""Decode status data."""
decoded = {}
@@ -545,6 +567,7 @@ def decode_snapshot(self, data, key):
info = data.get(key)
if not info:
return decoded
+
protocol = self._data["Monitoring"]["protocol"]
if isinstance(protocol, list):
for elem in protocol:
@@ -552,18 +575,21 @@ def decode_snapshot(self, data, key):
key = elem["value"]
value = data
for ident in elem["superSet"].split("."):
- if value is not None:
- value = value.get(ident)
+ if value is None:
+ break
+ pr_key = self._get_current_temp_key(ident, value)
+ value = value.get(pr_key)
if value is not None:
if isinstance(value, Number):
value = int(value)
decoded[key] = str(value)
- else:
- for data_key, value_key in protocol.items():
- value = info.get(data_key, "")
- if value is not None and isinstance(value, Number):
- value = int(value)
- decoded[value_key] = str(value)
+ return decoded
+
+ for data_key, value_key in protocol.items():
+ value = info.get(data_key, "")
+ if value is not None and isinstance(value, Number):
+ value = int(value)
+ decoded[value_key] = str(value)
return decoded
@@ -628,12 +654,17 @@ def value(self, data):
# return ReferenceValue(
# self.data[ref]
# )
- # elif d['dataType'] == 'Boolean':
- # return EnumValue({'0': 'False', '1' : 'True'})
+ elif data_type in ("Boolean", "boolean"):
+ return {"0": {"label": LABEL_BIT_OFF}, "1": {"label": LABEL_BIT_ON}}
# elif d['dataType'] == 'String':
# pass
else:
- assert False, "unsupported value type {}".format(data_type)
+ _LOGGER.error(
+ "ModelInfoV2: unsupported value type (%s) - value: %s",
+ data_type,
+ data,
+ )
+ return None
def default(self, name):
"""Get the default value, if it exists, for a given value.
diff --git a/custom_components/smartthinq_sensors/wideq/range.py b/custom_components/smartthinq_sensors/wideq/range.py
index 192607b9..909ac19d 100644
--- a/custom_components/smartthinq_sensors/wideq/range.py
+++ b/custom_components/smartthinq_sensors/wideq/range.py
@@ -9,7 +9,9 @@
FEAT_COOKTOP_CENTER_STATE,
FEAT_COOKTOP_RIGHT_FRONT_STATE,
FEAT_COOKTOP_RIGHT_REAR_STATE,
+ FEAT_OVEN_LOWER_CURRENT_TEMP,
FEAT_OVEN_LOWER_STATE,
+ FEAT_OVEN_UPPER_CURRENT_TEMP,
FEAT_OVEN_UPPER_STATE,
)
@@ -200,6 +202,34 @@ def oven_upper_target_temp(self):
return None
return self._data.get(key)
+ @property
+ def oven_lower_current_temp(self):
+ unit = self.oven_temp_unit
+ if unit == UNIT_TEMP_FAHRENHEIT:
+ key = "LowerCookTemp_F"
+ elif unit == UNIT_TEMP_CELSIUS:
+ key = "LowerCookTemp_C"
+ else:
+ return None
+ status = self._data.get(key)
+ return self._update_feature(
+ FEAT_OVEN_LOWER_CURRENT_TEMP, status, False
+ )
+
+ @property
+ def oven_upper_current_temp(self):
+ unit = self.oven_temp_unit
+ if unit == UNIT_TEMP_FAHRENHEIT:
+ key = "UpperCookTemp_F"
+ elif unit == UNIT_TEMP_CELSIUS:
+ key = "UpperCookTemp_C"
+ else:
+ return None
+ status = self._data.get(key)
+ return self._update_feature(
+ FEAT_OVEN_UPPER_CURRENT_TEMP, status, False
+ )
+
def _update_features(self):
result = [
self.cooktop_left_front_state,
@@ -208,6 +238,8 @@ def _update_features(self):
self.cooktop_right_front_state,
self.cooktop_right_rear_state,
self.oven_lower_state,
+ self.oven_lower_current_temp,
self.oven_upper_state,
+ self.oven_upper_current_temp,
]
return
diff --git a/info.md b/info.md
index 394cdce6..28af55bc 100644
--- a/info.md
+++ b/info.md
@@ -1,5 +1,5 @@
# LG ThinQ Devices integration for HomeAssistant
-A Homeassistant custom component to monitor LG Air Conditioner, Washer, Dryer, DishWasher, Refrigerator, Styler and Range
+A Homeassistant custom component to monitor and control LG Air Conditioner, Washer, Dryer, DishWasher, Refrigerator, Styler and Range
using ThinQ API based on [WideQ project][wideq].
**Important Version note:**