tuya-local
tuya-local copied to clipboard
Add T5E-WF thermostat, assistance needed
Hi!
Trying to add support for this Wifi thermostat for equal level of control from HA as in the Tuya app. https://www.alibaba.com/product-detail/EU-Standard-230V-Indoor-Electric-Floor_1600385798775.html?spm=a2700.shop_index.82.10.52962bc2aaT4SB
The thermostat is wrongly identified as a simple switch in the "tuya-local" component. In the "local tuya" component it is correctly identified as a thermostat allthough with very limited functionality.
Appreciate if anyone could gives some pointers to in order to get the dps mapping file in usable condition for the "local tuya" component.
Below are some excerpts from the Tuya developer portal as well as my attempted yaml mapping-file.
name: T5E-WF thermostat
primary_entity:
entity: climate
dps:
- id: 1
type: boolean
name: Switch
mapping:
- dps_val: False
value: OFF
icon: "mdi:fire-off"
- dps_val: True
value: ON
icon: "mdi:fire"
- id: 2
type: string
name: Mode
mapping:
- dps_val: cold
value: Cool
- dps_val: hot
value: Heat
- id: 3
entity: sensor
name: Working status
type: string
mapping:
- dps_val: auto
value: Auto
- dps_val: auxiliary_heat
value: Opened
- dps_val: cold
value: Cooling
- dps_val: comfortable
value: Comfortable
- dps_val: dry
value: Dry
- dps_val: eco
value: ECO
- dps_val: energy
value: Energy
- dps_val: floor_heat
value: Floor heat
- dps_val: holiday
value: Holiday
- dps_val: hot
value: Heating
- dps_val: manual
value: Manual
- dps_val: program
value: Program
- dps_val: sleep
value: Sleep
- dps_val: wind
value: Wind
- dps_val: wait
value: Wait
- id: 4
type: boolean
name: ECO mode
mapping:
- dps_val: True
value: Eco
- dps_val: False
value: Normal
- id: 8
type: boolean
name: window_check
mapping:
- dps_val: True
value: ON
- dps_val: False
value: OFF
- id: 10
type: boolean
name: Frost protection
mapping:
- dps_val: True
value: ON
- dps_val: False
value: OFF
- id: 16
type: integer
name: temperature
class: temperature
unit: C
range:
min: 0
max: 400
mapping:
- scale: 1
- step: 5
- id: 17
type: integer
name: temperature_f
class: temperature
unit: F
range:
min: 320
max: 1040
mapping:
- scale: 1
- step: 10
- id: 18
type: integer
name: upper_temp_f
class: temperature
unit: F
range:
min: 370
max: 1040
mapping:
- scale: 1
- step: 10
- id: 19
type: integer
name: upper_temp
class: temperature
unit: C
range:
min: 25
max: 400
mapping:
- scale: 1
- step: 5
- id: 20
type: integer
name: lower_temp_f
class: temperature
unit: F
range:
min: 330
max: 1000
mapping:
- scale: 1
- step: 10
- id: 22
type: Integer
name: Current power
class: energy
unit: W
icon: "mdi:lightning"
range:
min: 0
max: 50000
mapping:
- scale: 1
- step: 1
- id: 23
type: string
name: Temperature Unit
icon: "mdi:temperature-celsius"
mapping:
- dps_val: c
value: C
- dps_val: f
value: F
- id: 24
name: Current temperature
class: temperature
type: integer
unit: C
readonly: true
- id: 25
name: Window sensor
class: window
type: string
mapping:
- dps_val: close
value: Closed
- dps_val: open
value: Opened
- id: 26
type: integer
name: lower_temp
class: temperature
unit: C
range:
min: 5
max: 380
mapping:
- scale: 1
- step: 5
- id: 27
type: integer
name: Temperature correction
range:
min: -10
max: 10
mapping:
- scale: 0
- step: 1
- id: 29
name: Current temperature_F
class: temperature
unit: F
type: integer
readonly: true
- id: 31
type: string
name: Working day setting
mapping:
- dps_val: 5_2
value: 5+2
- dps_val: 6_1
value: 6+1
- id: 44
type: integer
name: Backlight brightness
range:
min: 10
max: 100
mapping:
- scale: 0
- step: 10
- id: 45
type: boolean
name: Fault alarm
mapping:
- dps_val: 0
value: OK
- dps_val: e_r1
value: ER1
- dps_val: e_r2
value: ER2
- dps_val: e_r3
value: ER3
- dps_val: e_r4
value: ER5
- dps_val: e_r5
value: ER5
- dps_val: e_r6
value: ER6
- dps_val: e_r7
value: ER7
- id: 40
name: Child Lock
category: config
type: boolean
mapping:
- dps_val: true
icon: "mdi:hand-back-right-off"
- dps_val: false
icon: "mdi:hand-back-right"
- id: 39
type: boolean
category: config
name: Factory Reset
icon: "mdi:cog-refresh"
- id: 43
type: boolean
name: uknown
mapping:
- dps_val: F
value: F
- id: 58
type: boolean
name: uknown_2
mapping:
- dps_val: pro
value: pro
{
"result": {
"category": "wk",
"functions": [
{
"code": "switch",
"dp_id": 1,
"type": "Boolean",
"values": "{}"
},
{
"code": "mode",
"dp_id": 2,
"type": "Enum",
"values": "{\"range\":[\"cold\",\"hot\"]}"
},
{
"code": "eco",
"dp_id": 4,
"type": "Boolean",
"values": "{}"
},
{
"code": "window_check",
"dp_id": 8,
"type": "Boolean",
"values": "{}"
},
{
"code": "frost",
"dp_id": 10,
"type": "Boolean",
"values": "{}"
},
{
"code": "temp_set",
"dp_id": 16,
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":0,\"max\":400,\"scale\":1,\"step\":5}"
},
{
"code": "temp_set_f",
"dp_id": 17,
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":320,\"max\":1040,\"scale\":1,\"step\":10}"
},
{
"code": "upper_temp_f",
"dp_id": 18,
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":370,\"max\":1040,\"scale\":1,\"step\":10}"
},
{
"code": "upper_temp",
"dp_id": 19,
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":25,\"max\":400,\"scale\":1,\"step\":5}"
},
{
"code": "lower_temp_f",
"dp_id": 20,
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":330,\"max\":1000,\"scale\":1,\"step\":10}"
},
{
"code": "temp_unit_convert",
"dp_id": 23,
"type": "Enum",
"values": "{\"range\":[\"c\",\"f\"]}"
},
{
"code": "lower_temp",
"dp_id": 26,
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":5,\"max\":380,\"scale\":1,\"step\":5}"
},
{
"code": "temp_correction",
"dp_id": 27,
"type": "Integer",
"values": "{\"unit\":\"\",\"min\":-10,\"max\":10,\"scale\":0,\"step\":1}"
},
{
"code": "work_days",
"dp_id": 31,
"type": "Enum",
"values": "{\"range\":[\"5_2\",\"6_1\"]}"
},
{
"code": "factory_reset",
"dp_id": 39,
"type": "Boolean",
"values": "{}"
},
{
"code": "child_lock",
"dp_id": 40,
"type": "Boolean",
"values": "{}"
},
{
"code": "backlight",
"dp_id": 44,
"type": "Integer",
"values": "{\"unit\":\"%\",\"min\":10,\"max\":100,\"scale\":0,\"step\":10}"
}
],
"status": [
{
"code": "switch",
"dp_id": 1,
"type": "Boolean",
"values": "{}"
},
{
"code": "mode",
"dp_id": 2,
"type": "Enum",
"values": "{\"range\":[\"cold\",\"hot\"]}"
},
{
"code": "work_state",
"dp_id": 3,
"type": "Enum",
"values": "{\"range\":[\"cold\",\"hot\",\"wind\",\"comfortable\",\"energy\",\"auto\",\"holiday\",\"manual\",\"eco\",\"sleep\",\"dry\",\"program\",\"floor_heat\",\"auxiliary_heat\"]}"
},
{
"code": "eco",
"dp_id": 4,
"type": "Boolean",
"values": "{}"
},
{
"code": "window_check",
"dp_id": 8,
"type": "Boolean",
"values": "{}"
},
{
"code": "frost",
"dp_id": 10,
"type": "Boolean",
"values": "{}"
},
{
"code": "temp_set",
"dp_id": 16,
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":0,\"max\":400,\"scale\":1,\"step\":5}"
},
{
"code": "temp_set_f",
"dp_id": 17,
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":320,\"max\":1040,\"scale\":1,\"step\":10}"
},
{
"code": "upper_temp_f",
"dp_id": 18,
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":370,\"max\":1040,\"scale\":1,\"step\":10}"
},
{
"code": "upper_temp",
"dp_id": 19,
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":25,\"max\":400,\"scale\":1,\"step\":5}"
},
{
"code": "lower_temp_f",
"dp_id": 20,
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":330,\"max\":1000,\"scale\":1,\"step\":10}"
},
{
"code": "work_power",
"dp_id": 22,
"type": "Integer",
"values": "{\"unit\":\"W\",\"min\":0,\"max\":50000,\"scale\":1,\"step\":1}"
},
{
"code": "temp_unit_convert",
"dp_id": 23,
"type": "Enum",
"values": "{\"range\":[\"c\",\"f\"]}"
},
{
"code": "temp_current",
"dp_id": 24,
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":-100,\"max\":600,\"scale\":1,\"step\":5}"
},
{
"code": "window_state",
"dp_id": 25,
"type": "Enum",
"values": "{\"range\":[\"close\",\"open\"]}"
},
{
"code": "lower_temp",
"dp_id": 26,
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":5,\"max\":380,\"scale\":1,\"step\":5}"
},
{
"code": "temp_correction",
"dp_id": 27,
"type": "Integer",
"values": "{\"unit\":\"\",\"min\":-10,\"max\":10,\"scale\":0,\"step\":1}"
},
{
"code": "temp_current_f",
"dp_id": 29,
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":140,\"max\":1400,\"scale\":1,\"step\":10}"
},
{
"code": "work_days",
"dp_id": 31,
"type": "Enum",
"values": "{\"range\":[\"5_2\",\"6_1\"]}"
},
{
"code": "factory_reset",
"dp_id": 39,
"type": "Boolean",
"values": "{}"
},
{
"code": "child_lock",
"dp_id": 40,
"type": "Boolean",
"values": "{}"
},
{
"code": "backlight",
"dp_id": 44,
"type": "Integer",
"values": "{\"unit\":\"%\",\"min\":10,\"max\":100,\"scale\":0,\"step\":10}"
},
{
"code": "fault",
"dp_id": 45,
"type": "Bitmap",
"values": "{\"label\":[\"ER1\",\"ER2\",\"ER3\",\"ER4\",\"ER5\",\"ER6\",\"ER7\"]}"
}
]
},
"success": true,
"t": 1658010658453,
"tid": "f6ca2fe7055611edbf8a7eeb5c0b2a19"
}
{
"result": {
"category": "wk",
"functions": [
{
"code": "switch",
"lang_config": {
"false": "OFF",
"true": "ON"
},
"name": "Switch",
"type": "Boolean",
"values": "{}"
},
{
"code": "mode",
"lang_config": {
"cold": "Cool",
"hot": "Heat"
},
"name": "Mode",
"type": "Enum",
"values": "{\"range\":[\"cold\",\"hot\"]}"
},
{
"code": "eco",
"lang_config": {
"false": "OFF",
"true": "ON"
},
"name": "ECO mode",
"type": "Boolean",
"values": "{}"
},
{
"code": "window_check",
"lang_config": {
"false": "OFF",
"true": "ON"
},
"name": "Window check",
"type": "Boolean",
"values": "{}"
},
{
"code": "frost",
"lang_config": {
"false": "OFF",
"true": "ON"
},
"name": "Frost protection",
"type": "Boolean",
"values": "{}"
},
{
"code": "temp_set",
"lang_config": {
"unit": "°C"
},
"name": "Set temperature",
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":0,\"max\":400,\"scale\":1,\"step\":5}"
},
{
"code": "temp_set_f",
"lang_config": {
"unit": "°F"
},
"name": "Set temperature _F",
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":320,\"max\":1040,\"scale\":1,\"step\":10}"
},
{
"code": "upper_temp_f",
"lang_config": {
"unit": "℉"
},
"name": "Set temperature upper limit -℉",
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":370,\"max\":1040,\"scale\":1,\"step\":10}"
},
{
"code": "upper_temp",
"lang_config": {
"unit": "℃"
},
"name": "Set temperature ceiling",
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":25,\"max\":400,\"scale\":1,\"step\":5}"
},
{
"code": "lower_temp_f",
"lang_config": {
"unit": "℉"
},
"name": "Set the lower limit -℉",
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":330,\"max\":1000,\"scale\":1,\"step\":10}"
},
{
"code": "temp_unit_convert",
"lang_config": {
"c": "℃",
"f": "℉"
},
"name": "Temperature scale",
"type": "Enum",
"values": "{\"range\":[\"c\",\"f\"]}"
},
{
"code": "lower_temp",
"lang_config": {
"unit": "°C"
},
"name": "The lower limit of temperature",
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":5,\"max\":380,\"scale\":1,\"step\":5}"
},
{
"code": "temp_correction",
"lang_config": {
"unit": ""
},
"name": "Temperature correction",
"type": "Integer",
"values": "{\"unit\":\"\",\"min\":-10,\"max\":10,\"scale\":0,\"step\":1}"
},
{
"code": "work_days",
"lang_config": {
"5_2": "5+2",
"6_1": "6+1"
},
"name": "Working day setting",
"type": "Enum",
"values": "{\"range\":[\"5_2\",\"6_1\"]}"
},
{
"code": "factory_reset",
"lang_config": {
"false": "OFF",
"true": "ON"
},
"name": "Factory data reset",
"type": "Boolean",
"values": "{}"
},
{
"code": "child_lock",
"lang_config": {
"false": "OFF",
"true": "ON"
},
"name": "Child lock",
"type": "Boolean",
"values": "{}"
},
{
"code": "backlight",
"lang_config": {
"unit": "%"
},
"name": "Backlight brightness",
"type": "Integer",
"values": "{\"unit\":\"%\",\"min\":10,\"max\":100,\"scale\":0,\"step\":10}"
}
],
"status": [
{
"code": "switch",
"lang_config": {
"false": "OFF",
"true": "ON"
},
"name": "Switch",
"type": "Boolean",
"values": "{}"
},
{
"code": "mode",
"lang_config": {
"cold": "Cool",
"hot": "Heat"
},
"name": "Mode",
"type": "Enum",
"values": "{\"range\":[\"cold\",\"hot\"]}"
},
{
"code": "work_state",
"lang_config": {
"auto": "Auto",
"auxiliary_heat": "Auxiliary heat",
"cold": "Cooling",
"comfortable": "Comfortable",
"dry": "Dry",
"eco": "ECO",
"energy": "Energy",
"floor_heat": "Floor heat",
"holiday": "Holiday",
"hot": "Heating",
"manual": "Manual",
"program": "Program",
"sleep": "Sleep",
"wind": "Wind"
},
"name": "Working status",
"type": "Enum",
"values": "{\"range\":[\"cold\",\"hot\",\"wind\",\"comfortable\",\"energy\",\"auto\",\"holiday\",\"manual\",\"eco\",\"sleep\",\"dry\",\"program\",\"floor_heat\",\"auxiliary_heat\"]}"
},
{
"code": "eco",
"lang_config": {
"false": "OFF",
"true": "ON"
},
"name": "ECO mode",
"type": "Boolean",
"values": "{}"
},
{
"code": "window_check",
"lang_config": {
"false": "OFF",
"true": "ON"
},
"name": "Window check",
"type": "Boolean",
"values": "{}"
},
{
"code": "frost",
"lang_config": {
"false": "OFF",
"true": "ON"
},
"name": "Frost protection",
"type": "Boolean",
"values": "{}"
},
{
"code": "temp_set",
"lang_config": {
"unit": "°C"
},
"name": "Set temperature",
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":0,\"max\":400,\"scale\":1,\"step\":5}"
},
{
"code": "temp_set_f",
"lang_config": {
"unit": "°F"
},
"name": "Set temperature _F",
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":320,\"max\":1040,\"scale\":1,\"step\":10}"
},
{
"code": "upper_temp_f",
"lang_config": {
"unit": "℉"
},
"name": "Set temperature upper limit -℉",
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":370,\"max\":1040,\"scale\":1,\"step\":10}"
},
{
"code": "upper_temp",
"lang_config": {
"unit": "℃"
},
"name": "Set temperature ceiling",
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":25,\"max\":400,\"scale\":1,\"step\":5}"
},
{
"code": "lower_temp_f",
"lang_config": {
"unit": "℉"
},
"name": "Set the lower limit -℉",
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":330,\"max\":1000,\"scale\":1,\"step\":10}"
},
{
"code": "work_power",
"lang_config": {
"unit": "w"
},
"name": "Current power",
"type": "Integer",
"values": "{\"unit\":\"W\",\"min\":0,\"max\":50000,\"scale\":1,\"step\":1}"
},
{
"code": "temp_unit_convert",
"lang_config": {
"c": "℃",
"f": "℉"
},
"name": "Temperature scale",
"type": "Enum",
"values": "{\"range\":[\"c\",\"f\"]}"
},
{
"code": "temp_current",
"lang_config": {
"unit": "°C"
},
"name": "Current temperature",
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":-100,\"max\":600,\"scale\":1,\"step\":5}"
},
{
"code": "window_state",
"lang_config": {
"close": "Closed",
"open": "Opened"
},
"name": "State of the window",
"type": "Enum",
"values": "{\"range\":[\"close\",\"open\"]}"
},
{
"code": "lower_temp",
"lang_config": {
"unit": "°C"
},
"name": "The lower limit of temperature",
"type": "Integer",
"values": "{\"unit\":\"℃\",\"min\":5,\"max\":380,\"scale\":1,\"step\":5}"
},
{
"code": "temp_correction",
"lang_config": {
"unit": ""
},
"name": "Temperature correction",
"type": "Integer",
"values": "{\"unit\":\"\",\"min\":-10,\"max\":10,\"scale\":0,\"step\":1}"
},
{
"code": "temp_current_f",
"lang_config": {
"unit": "°F"
},
"name": "Current temperature_F",
"type": "Integer",
"values": "{\"unit\":\"℉\",\"min\":140,\"max\":1400,\"scale\":1,\"step\":10}"
},
{
"code": "work_days",
"lang_config": {
"5_2": "5+2",
"6_1": "6+1"
},
"name": "Working day setting",
"type": "Enum",
"values": "{\"range\":[\"5_2\",\"6_1\"]}"
},
{
"code": "factory_reset",
"lang_config": {
"false": "OFF",
"true": "ON"
},
"name": "Factory data reset",
"type": "Boolean",
"values": "{}"
},
{
"code": "child_lock",
"lang_config": {
"false": "OFF",
"true": "ON"
},
"name": "Child lock",
"type": "Boolean",
"values": "{}"
},
{
"code": "backlight",
"lang_config": {
"unit": "%"
},
"name": "Backlight brightness",
"type": "Integer",
"values": "{\"unit\":\"%\",\"min\":10,\"max\":100,\"scale\":0,\"step\":10}"
},
{
"code": "fault",
"lang_config": {
"e_r1": "",
"e_r2": "",
"e_r3": "",
"e_r4": "",
"e_r5": "",
"e_r6": "",
"e_r7": ""
},
"name": "Fault alarm",
"type": "Bitmap",
"values": "{\"label\":[\"ER1\",\"ER2\",\"ER3\",\"ER4\",\"ER5\",\"ER6\",\"ER7\"]}"
}
]
},
"success": true,
"t": 1658010166838,
"tid": "d1c0b256055511edbf8a7eeb5c0b2a19"
}
I suspect that the config as generated from the iot.tuya.com may not work correctly. Common issues encountered are:
- Enum values listed in iot.tuya.com are often wrong, or are translated to integers in the local API.
- Some fields don't always show up. A common one for climate devices is the Fahrenheit related temperature settings only showing up when the device is set to Fahrenheit.
- fault is listed as a bitmap, which means the value is actually an integer not the values listed. Bits in the integer correspond to the values listed, but in this case the values aren't very informative so it might as well be left as an integer.
There are a lot of temperature settings listed. I'm not sure how they relate to each other, and whether this should be represented as a thermostat with a single temperature setting, or a thermostat which can have a range set.
I think some of these could be cleared up by seeing the dps reported by the device locally. These should be in a Warning message in the Home Assistant log after you start to add the device and are shown the simple switch as the only possible match (you can cancel at that point, as the log message will already be printed).
So apart from creating the new device yaml file as Swellem has done what else is involved in tuya-local? I have not yet been able to determine how when adding a new device the correct device/product mapping file is used (In my case I have just created a new device file for a Kogan LX6 robot vacuum with primary and secondary entities, but no test scripts yet. When trying to add the LX6 I get the response that device is unsupported). Any pointer of how this aspect works in Tuya-local appreciated.
The matching to config files is done by comparing the data returned by the device to the ids and types in the config files. The documentation from iot.tuya.com is useful to get an idea of what everything is, but it is not always correct, in particular some items can be missing sometimes (these can now be marked as "optional: true") or enum types can be represented in the local protocol as quoted integers while in the cloud API they are descriptive strings (depending on the device - some use descriptive strings in the local protocol as well).
In particular for vacuums, the clean_record is often only available when the robot is cleaning, so needs to be marked optional. Have a look at the existing Kyvol and Lefant configs for hints as the Kogan one is likely similar.
Implementing tests can also catch some non-obvious typos in config files.
Thank you, I'll look into this further
thanks for looking into this with me :)
Could you based on this log message point me in the direction to which changes should be done to the config file for Tyua Local? I really appreciate any suggestions you might have.
PS! I will test more as soon as I can get my head around the changes needed to the config file based on your suggestions so far and the logs.
This is the HA log message: Logger: custom_components.tuya_local.config_flow Source: custom_components/tuya_local/config_flow.py:73 Integration: Tuya Local (documentation, issues) First occurred: 23:33:32 (1 occurrences) Last logged: 23:33:32
Device matches simple_switch with quality of 4%. DPS: {'1': True, '2': 'hot', '3': 'wait', '4': False, '8': False, '10': False, '16': 170, '19': 400, '22': 0, '23': 'c', '24': 280, '25': 'close', '26': 50, '27': 0, '31': '5_2', '40': False, '43': 'F', '44': 10, '45': 0, '58': 'program', '118': '30Min', '127': 20, '145': 1345, '147': 0, '183': 0, '188': False, 'updated_at': 1659389612.2063076}
Sorry, there is a lot of information in your original comment to take in. It does look like the local protocol is using the same strings as documented in the cloud API though. You can take a look at existing thermostat and heatpump configs for hints as to naming of dps and the syntax of how to define separate entities where needed.
I am still confused as to how the temperature, upper_temp and lower_temp are supposed to interact on this device. As far as I can tell, Home Assistant can support either a single set temperature, or a dual upper and lower temperature range, but not a combination of the two together. It may require two climate entities to realise this combination.
So Svellem is only getting a match quality of 4%, which seems low. I will try and work through your code to understand the scoring algorithm but from what your said elsewhere the 'optional' attribute can help - presumbably it reduces (eliminates?) the weighting than the omission of a particular DP would otherwise contribute. In my case I am getting 0%, so striving for 4% :) Can just one DP in conflict (eg wrong returned value type) wipe the quality score right out?
Please open a separate issue for this discussion, as it is not related to the device that this issue was opened for.
I've gone ahead and added support for this on the assumption that the upper and lower temperatures are configurable minimum and maximum limits rather than an a target range for the thermostat. This seems like the most likely purpose given that the target temperature is also separately available.