From f209d75f2c0ef4ed35a6b016164c7c0ab04d5e5f Mon Sep 17 00:00:00 2001
From: Joost Lekkerkerker <joostlek@outlook.com>
Date: Sat, 8 Mar 2025 11:27:26 +0100
Subject: [PATCH] Support null supported Thermostat modes in SmartThings
 (#140101)

---
 .../components/smartthings/climate.py         |  10 +-
 tests/components/smartthings/conftest.py      |   1 +
 .../device_status/generic_ef00_v1.json        |  76 +++++++++
 .../fixtures/devices/generic_ef00_v1.json     |  95 +++++++++++
 .../smartthings/snapshots/test_climate.ambr   |  61 +++++++
 .../smartthings/snapshots/test_init.ambr      |  33 ++++
 .../smartthings/snapshots/test_sensor.ambr    | 154 ++++++++++++++++++
 .../smartthings/snapshots/test_switch.ambr    |  47 ++++++
 8 files changed, 474 insertions(+), 3 deletions(-)
 create mode 100644 tests/components/smartthings/fixtures/device_status/generic_ef00_v1.json
 create mode 100644 tests/components/smartthings/fixtures/devices/generic_ef00_v1.json

diff --git a/homeassistant/components/smartthings/climate.py b/homeassistant/components/smartthings/climate.py
index 14e26e23dc1..650b0c5540a 100644
--- a/homeassistant/components/smartthings/climate.py
+++ b/homeassistant/components/smartthings/climate.py
@@ -275,11 +275,15 @@ class SmartThingsThermostat(SmartThingsEntity, ClimateEntity):
     @property
     def hvac_modes(self) -> list[HVACMode]:
         """Return the list of available operation modes."""
-        return [
-            state
-            for mode in self.get_attribute_value(
+        if (
+            supported_thermostat_modes := self.get_attribute_value(
                 Capability.THERMOSTAT_MODE, Attribute.SUPPORTED_THERMOSTAT_MODES
             )
+        ) is None:
+            return []
+        return [
+            state
+            for mode in supported_thermostat_modes
             if (state := AC_MODE_TO_STATE.get(mode)) is not None
         ]
 
diff --git a/tests/components/smartthings/conftest.py b/tests/components/smartthings/conftest.py
index a659e69a2cc..d3b91d058a9 100644
--- a/tests/components/smartthings/conftest.py
+++ b/tests/components/smartthings/conftest.py
@@ -122,6 +122,7 @@ def mock_smartthings() -> Generator[AsyncMock]:
         "fake_fan",
         "generic_fan_3_speed",
         "heatit_ztrm3_thermostat",
+        "generic_ef00_v1",
         "bosch_radiator_thermostat_ii",
     ]
 )
diff --git a/tests/components/smartthings/fixtures/device_status/generic_ef00_v1.json b/tests/components/smartthings/fixtures/device_status/generic_ef00_v1.json
new file mode 100644
index 00000000000..cbfdf0d9092
--- /dev/null
+++ b/tests/components/smartthings/fixtures/device_status/generic_ef00_v1.json
@@ -0,0 +1,76 @@
+{
+  "components": {
+    "main02": {
+      "temperatureMeasurement": {
+        "temperatureRange": {
+          "value": null
+        },
+        "temperature": {
+          "value": 200.0,
+          "unit": "C",
+          "timestamp": "2024-12-02T20:18:52.095Z"
+        }
+      }
+    },
+    "main": {
+      "thermostatOperatingState": {
+        "thermostatOperatingState": {
+          "value": null
+        }
+      },
+      "signalStrength": {
+        "rssi": {
+          "value": -84,
+          "unit": "dBm",
+          "timestamp": "2025-03-07T20:53:55.346Z"
+        },
+        "lqi": {
+          "value": 255,
+          "timestamp": "2025-03-07T20:53:55.387Z"
+        }
+      },
+      "temperatureMeasurement": {
+        "temperatureRange": {
+          "value": null
+        },
+        "temperature": {
+          "value": 21.0,
+          "unit": "C",
+          "timestamp": "2025-03-07T16:58:23.773Z"
+        }
+      },
+      "thermostatHeatingSetpoint": {
+        "heatingSetpoint": {
+          "value": 23.0,
+          "unit": "C",
+          "timestamp": "2025-02-10T17:48:38.299Z"
+        },
+        "heatingSetpointRange": {
+          "value": null
+        }
+      },
+      "refresh": {},
+      "valleyboard16460.debug": {
+        "value": {
+          "value": "<table style=\"font-size:0.6em;min-width:100%\"><tbody>\n        <tr><th align=\"left\" style=\"width:35%\">Actual</th><td style=\"width:65%\">_TZE200_rxntag7i</td></tr>\n        <tr><th align=\"left\">Expected</th><td>_TZE200_4hbx5cvx</td></tr>\n        <tr><th align=\"left\">Profile</th><td>normal-thermostat-v3</td></tr>\n        <tr><th align=\"left\">Mode</th><td>Similarity</td></tr>\n        <tr><th align=\"left\">Preferences</th><td>Modified</td></tr>\n        <tr><th align=\"left\">Exposes EF00</th><td>Yes</td></tr>\n        <tr><th align=\"left\">Default DP</th><td>No</td></tr>\n        </tbody></table>",
+          "timestamp": "2025-03-05T03:04:54.025Z"
+        }
+      },
+      "thermostatMode": {
+        "thermostatMode": {
+          "value": "heat",
+          "data": {},
+          "timestamp": "2024-12-30T08:22:19.273Z"
+        },
+        "supportedThermostatModes": {
+          "value": null
+        }
+      },
+      "switch": {
+        "switch": {
+          "value": null
+        }
+      }
+    }
+  }
+}
diff --git a/tests/components/smartthings/fixtures/devices/generic_ef00_v1.json b/tests/components/smartthings/fixtures/devices/generic_ef00_v1.json
new file mode 100644
index 00000000000..96937769b41
--- /dev/null
+++ b/tests/components/smartthings/fixtures/devices/generic_ef00_v1.json
@@ -0,0 +1,95 @@
+{
+  "items": [
+    {
+      "deviceId": "656569c2-7976-4232-a789-34b4d1176c3a",
+      "name": "generic-ef00-v1",
+      "label": "Thermostat K\u00fcche",
+      "manufacturerName": "SmartThingsCommunity",
+      "presentationId": "be641577-f796-315b-af6f-b3ad14dd7a58",
+      "deviceManufacturerCode": "_TZE200_rxntag7i",
+      "locationId": "0b6618a6-c3ab-4b6e-968d-59cc8c2761bc",
+      "ownerId": "8a20b799-9d87-ecdc-39de-c93c6e4d3ea1",
+      "roomId": "eeb2f9d2-19cc-4dad-9f23-28ec807de97e",
+      "components": [
+        {
+          "id": "main",
+          "label": "Thermostat",
+          "capabilities": [
+            {
+              "id": "switch",
+              "version": 1
+            },
+            {
+              "id": "thermostatMode",
+              "version": 1
+            },
+            {
+              "id": "temperatureMeasurement",
+              "version": 1
+            },
+            {
+              "id": "thermostatHeatingSetpoint",
+              "version": 1
+            },
+            {
+              "id": "thermostatOperatingState",
+              "version": 1
+            },
+            {
+              "id": "signalStrength",
+              "version": 1
+            },
+            {
+              "id": "refresh",
+              "version": 1
+            },
+            {
+              "id": "valleyboard16460.debug",
+              "version": 1
+            }
+          ],
+          "categories": [
+            {
+              "name": "Thermostat",
+              "categoryType": "manufacturer"
+            }
+          ]
+        },
+        {
+          "id": "main02",
+          "label": "Floor",
+          "capabilities": [
+            {
+              "id": "temperatureMeasurement",
+              "version": 1
+            }
+          ],
+          "categories": [
+            {
+              "name": "Thermostat",
+              "categoryType": "manufacturer"
+            }
+          ]
+        }
+      ],
+      "createTime": "2024-12-02T15:58:01.598Z",
+      "profile": {
+        "id": "3ad2e1e3-8867-332c-85b5-b291602c324f"
+      },
+      "zigbee": {
+        "eui": "A4C1388B31017B5F",
+        "networkId": "162F",
+        "driverId": "585328e6-ac85-4ac5-bce4-286efd0ab980",
+        "executingLocally": true,
+        "hubId": "61bd280e-71c4-44fb-9b6e-53fdf14718a2",
+        "provisioningState": "DRIVER_SWITCH"
+      },
+      "type": "ZIGBEE",
+      "restrictionTier": 0,
+      "allowed": null,
+      "executionContext": "LOCAL",
+      "relationships": []
+    }
+  ],
+  "_links": {}
+}
diff --git a/tests/components/smartthings/snapshots/test_climate.ambr b/tests/components/smartthings/snapshots/test_climate.ambr
index 4d3fd15aeb9..6b512f93d39 100644
--- a/tests/components/smartthings/snapshots/test_climate.ambr
+++ b/tests/components/smartthings/snapshots/test_climate.ambr
@@ -432,6 +432,67 @@
     'state': 'heat',
   })
 # ---
+# name: test_all_entities[generic_ef00_v1][climate.thermostat_kuche-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': dict({
+      'hvac_modes': list([
+      ]),
+      'max_temp': 35,
+      'min_temp': 7,
+    }),
+    'config_entry_id': <ANY>,
+    'config_subentry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'climate',
+    'entity_category': None,
+    'entity_id': 'climate.thermostat_kuche',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': None,
+    'original_icon': None,
+    'original_name': None,
+    'platform': 'smartthings',
+    'previous_unique_id': None,
+    'supported_features': <ClimateEntityFeature: 387>,
+    'translation_key': None,
+    'unique_id': '656569c2-7976-4232-a789-34b4d1176c3a',
+    'unit_of_measurement': None,
+  })
+# ---
+# name: test_all_entities[generic_ef00_v1][climate.thermostat_kuche-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'current_temperature': 21.0,
+      'friendly_name': 'Thermostat Küche',
+      'hvac_modes': list([
+      ]),
+      'max_temp': 35,
+      'min_temp': 7,
+      'supported_features': <ClimateEntityFeature: 387>,
+      'target_temp_high': None,
+      'target_temp_low': None,
+      'temperature': 23.0,
+    }),
+    'context': <ANY>,
+    'entity_id': 'climate.thermostat_kuche',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': 'heat',
+  })
+# ---
 # name: test_all_entities[heatit_ztrm3_thermostat][climate.hall_thermostat-entry]
   EntityRegistryEntrySnapshot({
     'aliases': set({
diff --git a/tests/components/smartthings/snapshots/test_init.ambr b/tests/components/smartthings/snapshots/test_init.ambr
index acee145955c..f660e04eb48 100644
--- a/tests/components/smartthings/snapshots/test_init.ambr
+++ b/tests/components/smartthings/snapshots/test_init.ambr
@@ -695,6 +695,39 @@
     'via_device_id': None,
   })
 # ---
+# name: test_devices[generic_ef00_v1]
+  DeviceRegistryEntrySnapshot({
+    'area_id': None,
+    'config_entries': <ANY>,
+    'config_entries_subentries': <ANY>,
+    'configuration_url': 'https://account.smartthings.com',
+    'connections': set({
+    }),
+    'disabled_by': None,
+    'entry_type': None,
+    'hw_version': None,
+    'id': <ANY>,
+    'identifiers': set({
+      tuple(
+        'smartthings',
+        '656569c2-7976-4232-a789-34b4d1176c3a',
+      ),
+    }),
+    'is_new': False,
+    'labels': set({
+    }),
+    'manufacturer': None,
+    'model': None,
+    'model_id': None,
+    'name': 'Thermostat Küche',
+    'name_by_user': None,
+    'primary_config_entry': <ANY>,
+    'serial_number': None,
+    'suggested_area': None,
+    'sw_version': None,
+    'via_device_id': None,
+  })
+# ---
 # name: test_devices[generic_fan_3_speed]
   DeviceRegistryEntrySnapshot({
     'area_id': None,
diff --git a/tests/components/smartthings/snapshots/test_sensor.ambr b/tests/components/smartthings/snapshots/test_sensor.ambr
index cb282e24b27..84092d3f9e3 100644
--- a/tests/components/smartthings/snapshots/test_sensor.ambr
+++ b/tests/components/smartthings/snapshots/test_sensor.ambr
@@ -4625,6 +4625,160 @@
     'state': '22',
   })
 # ---
+# name: test_all_entities[generic_ef00_v1][sensor.thermostat_kuche_link_quality-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': dict({
+      'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
+    }),
+    'config_entry_id': <ANY>,
+    'config_subentry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'sensor',
+    'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
+    'entity_id': 'sensor.thermostat_kuche_link_quality',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': None,
+    'original_icon': None,
+    'original_name': 'Link quality',
+    'platform': 'smartthings',
+    'previous_unique_id': None,
+    'supported_features': 0,
+    'translation_key': 'link_quality',
+    'unique_id': '656569c2-7976-4232-a789-34b4d1176c3a.lqi',
+    'unit_of_measurement': None,
+  })
+# ---
+# name: test_all_entities[generic_ef00_v1][sensor.thermostat_kuche_link_quality-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'friendly_name': 'Thermostat Küche Link quality',
+      'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
+    }),
+    'context': <ANY>,
+    'entity_id': 'sensor.thermostat_kuche_link_quality',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': '255',
+  })
+# ---
+# name: test_all_entities[generic_ef00_v1][sensor.thermostat_kuche_signal_strength-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': dict({
+      'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
+    }),
+    'config_entry_id': <ANY>,
+    'config_subentry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'sensor',
+    'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
+    'entity_id': 'sensor.thermostat_kuche_signal_strength',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': <SensorDeviceClass.SIGNAL_STRENGTH: 'signal_strength'>,
+    'original_icon': None,
+    'original_name': 'Signal strength',
+    'platform': 'smartthings',
+    'previous_unique_id': None,
+    'supported_features': 0,
+    'translation_key': None,
+    'unique_id': '656569c2-7976-4232-a789-34b4d1176c3a.rssi',
+    'unit_of_measurement': 'dBm',
+  })
+# ---
+# name: test_all_entities[generic_ef00_v1][sensor.thermostat_kuche_signal_strength-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'device_class': 'signal_strength',
+      'friendly_name': 'Thermostat Küche Signal strength',
+      'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
+      'unit_of_measurement': 'dBm',
+    }),
+    'context': <ANY>,
+    'entity_id': 'sensor.thermostat_kuche_signal_strength',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': '-84',
+  })
+# ---
+# name: test_all_entities[generic_ef00_v1][sensor.thermostat_kuche_temperature-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': dict({
+      'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
+    }),
+    'config_entry_id': <ANY>,
+    'config_subentry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'sensor',
+    'entity_category': None,
+    'entity_id': 'sensor.thermostat_kuche_temperature',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
+    'original_icon': None,
+    'original_name': 'Temperature',
+    'platform': 'smartthings',
+    'previous_unique_id': None,
+    'supported_features': 0,
+    'translation_key': None,
+    'unique_id': '656569c2-7976-4232-a789-34b4d1176c3a.temperature',
+    'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
+  })
+# ---
+# name: test_all_entities[generic_ef00_v1][sensor.thermostat_kuche_temperature-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'device_class': 'temperature',
+      'friendly_name': 'Thermostat Küche Temperature',
+      'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
+      'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
+    }),
+    'context': <ANY>,
+    'entity_id': 'sensor.thermostat_kuche_temperature',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': '21.0',
+  })
+# ---
 # name: test_all_entities[heatit_ztrm3_thermostat][sensor.hall_thermostat_energy-entry]
   EntityRegistryEntrySnapshot({
     'aliases': set({
diff --git a/tests/components/smartthings/snapshots/test_switch.ambr b/tests/components/smartthings/snapshots/test_switch.ambr
index 00177b3b603..81b73874a6a 100644
--- a/tests/components/smartthings/snapshots/test_switch.ambr
+++ b/tests/components/smartthings/snapshots/test_switch.ambr
@@ -328,6 +328,53 @@
     'state': 'on',
   })
 # ---
+# name: test_all_entities[generic_ef00_v1][switch.thermostat_kuche-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': None,
+    'config_entry_id': <ANY>,
+    'config_subentry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'switch',
+    'entity_category': None,
+    'entity_id': 'switch.thermostat_kuche',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': None,
+    'original_icon': None,
+    'original_name': None,
+    'platform': 'smartthings',
+    'previous_unique_id': None,
+    'supported_features': 0,
+    'translation_key': None,
+    'unique_id': '656569c2-7976-4232-a789-34b4d1176c3a',
+    'unit_of_measurement': None,
+  })
+# ---
+# name: test_all_entities[generic_ef00_v1][switch.thermostat_kuche-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'friendly_name': 'Thermostat Küche',
+    }),
+    'context': <ANY>,
+    'entity_id': 'switch.thermostat_kuche',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': 'off',
+  })
+# ---
 # name: test_all_entities[sensibo_airconditioner_1][switch.office-entry]
   EntityRegistryEntrySnapshot({
     'aliases': set({
-- 
GitLab