From 2cde317d59f8c5fd14daa00be05f294765966803 Mon Sep 17 00:00:00 2001
From: Joost Lekkerkerker <joostlek@outlook.com>
Date: Thu, 27 Feb 2025 13:25:55 +0100
Subject: [PATCH] Bump pysmartthings to 2.0.0 (#139418)

* Bump pysmartthings to 2.0.0

* Fix

* Fix

* Fix

* Fix
---
 .../components/smartthings/__init__.py        |  8 +++---
 homeassistant/components/smartthings/cover.py |  2 +-
 .../components/smartthings/entity.py          | 13 +++++++--
 .../components/smartthings/manifest.json      |  2 +-
 .../components/smartthings/sensor.py          | 28 +++++++++++++------
 requirements_all.txt                          |  2 +-
 requirements_test_all.txt                     |  2 +-
 tests/components/smartthings/__init__.py      |  2 +-
 .../smartthings/snapshots/test_sensor.ambr    |  8 +++---
 tests/components/smartthings/test_sensor.py   | 14 +++++-----
 10 files changed, 50 insertions(+), 31 deletions(-)

diff --git a/homeassistant/components/smartthings/__init__.py b/homeassistant/components/smartthings/__init__.py
index 846170552e9..4bc9b270360 100644
--- a/homeassistant/components/smartthings/__init__.py
+++ b/homeassistant/components/smartthings/__init__.py
@@ -46,7 +46,7 @@ class FullDevice:
     """Define an object to hold device data."""
 
     device: Device
-    status: dict[str, dict[Capability, dict[Attribute, Status]]]
+    status: dict[str, dict[Capability | str, dict[Attribute | str, Status]]]
 
 
 type SmartThingsConfigEntry = ConfigEntry[SmartThingsData]
@@ -146,8 +146,8 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
 
 
 def process_status(
-    status: dict[str, dict[Capability, dict[Attribute, Status]]],
-) -> dict[str, dict[Capability, dict[Attribute, Status]]]:
+    status: dict[str, dict[Capability | str, dict[Attribute | str, Status]]],
+) -> dict[str, dict[Capability | str, dict[Attribute | str, Status]]]:
     """Remove disabled capabilities from status."""
     if (main_component := status.get("main")) is None or (
         disabled_capabilities_capability := main_component.get(
@@ -156,7 +156,7 @@ def process_status(
     ) is None:
         return status
     disabled_capabilities = cast(
-        list[Capability],
+        list[Capability | str],
         disabled_capabilities_capability[Attribute.DISABLED_CAPABILITIES].value,
     )
     for capability in disabled_capabilities:
diff --git a/homeassistant/components/smartthings/cover.py b/homeassistant/components/smartthings/cover.py
index fd4752b4e28..0b0f03679eb 100644
--- a/homeassistant/components/smartthings/cover.py
+++ b/homeassistant/components/smartthings/cover.py
@@ -41,7 +41,7 @@ async def async_setup_entry(
     """Add covers for a config entry."""
     entry_data = entry.runtime_data
     async_add_entities(
-        SmartThingsCover(entry_data.client, device, capability)
+        SmartThingsCover(entry_data.client, device, Capability(capability))
         for device in entry_data.devices.values()
         for capability in device.status[MAIN]
         if capability in CAPABILITIES
diff --git a/homeassistant/components/smartthings/entity.py b/homeassistant/components/smartthings/entity.py
index b2e556c6718..1383196ce15 100644
--- a/homeassistant/components/smartthings/entity.py
+++ b/homeassistant/components/smartthings/entity.py
@@ -4,7 +4,14 @@ from __future__ import annotations
 
 from typing import Any, cast
 
-from pysmartthings import Attribute, Capability, Command, DeviceEvent, SmartThings
+from pysmartthings import (
+    Attribute,
+    Capability,
+    Command,
+    DeviceEvent,
+    SmartThings,
+    Status,
+)
 
 from homeassistant.helpers.device_registry import DeviceInfo
 from homeassistant.helpers.entity import Entity
@@ -25,7 +32,7 @@ class SmartThingsEntity(Entity):
         """Initialize the instance."""
         self.client = client
         self.capabilities = capabilities
-        self._internal_state = {
+        self._internal_state: dict[Capability | str, dict[Attribute | str, Status]] = {
             capability: device.status[MAIN][capability]
             for capability in capabilities
             if capability in device.status[MAIN]
@@ -58,7 +65,7 @@ class SmartThingsEntity(Entity):
         await super().async_added_to_hass()
         for capability in self._internal_state:
             self.async_on_remove(
-                self.client.add_device_event_listener(
+                self.client.add_device_capability_event_listener(
                     self.device.device.device_id,
                     MAIN,
                     capability,
diff --git a/homeassistant/components/smartthings/manifest.json b/homeassistant/components/smartthings/manifest.json
index b34ab90ca8c..c5277241aa4 100644
--- a/homeassistant/components/smartthings/manifest.json
+++ b/homeassistant/components/smartthings/manifest.json
@@ -29,5 +29,5 @@
   "documentation": "https://www.home-assistant.io/integrations/smartthings",
   "iot_class": "cloud_push",
   "loggers": ["pysmartthings"],
-  "requirements": ["pysmartthings==1.2.0"]
+  "requirements": ["pysmartthings==2.0.0"]
 }
diff --git a/homeassistant/components/smartthings/sensor.py b/homeassistant/components/smartthings/sensor.py
index d7aaaaa84c5..bc986894045 100644
--- a/homeassistant/components/smartthings/sensor.py
+++ b/homeassistant/components/smartthings/sensor.py
@@ -130,6 +130,7 @@ class SmartThingsSensorEntityDescription(SensorEntityDescription):
     unique_id_separator: str = "."
     capability_ignore_list: list[set[Capability]] | None = None
     options_attribute: Attribute | None = None
+    except_if_state_none: bool = False
 
 
 CAPABILITY_TO_SENSORS: dict[
@@ -579,6 +580,7 @@ CAPABILITY_TO_SENSORS: dict[
                 device_class=SensorDeviceClass.ENERGY,
                 native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
                 value_fn=lambda value: value["energy"] / 1000,
+                except_if_state_none=True,
             ),
             SmartThingsSensorEntityDescription(
                 key="power_meter",
@@ -587,6 +589,7 @@ CAPABILITY_TO_SENSORS: dict[
                 native_unit_of_measurement=UnitOfPower.WATT,
                 value_fn=lambda value: value["power"],
                 extra_state_attributes_fn=power_attributes,
+                except_if_state_none=True,
             ),
             SmartThingsSensorEntityDescription(
                 key="deltaEnergy_meter",
@@ -595,6 +598,7 @@ CAPABILITY_TO_SENSORS: dict[
                 device_class=SensorDeviceClass.ENERGY,
                 native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
                 value_fn=lambda value: value["deltaEnergy"] / 1000,
+                except_if_state_none=True,
             ),
             SmartThingsSensorEntityDescription(
                 key="powerEnergy_meter",
@@ -603,6 +607,7 @@ CAPABILITY_TO_SENSORS: dict[
                 device_class=SensorDeviceClass.ENERGY,
                 native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
                 value_fn=lambda value: value["powerEnergy"] / 1000,
+                except_if_state_none=True,
             ),
             SmartThingsSensorEntityDescription(
                 key="energySaved_meter",
@@ -611,6 +616,7 @@ CAPABILITY_TO_SENSORS: dict[
                 device_class=SensorDeviceClass.ENERGY,
                 native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
                 value_fn=lambda value: value["energySaved"] / 1000,
+                except_if_state_none=True,
             ),
         ]
     },
@@ -953,14 +959,20 @@ async def async_setup_entry(
     async_add_entities(
         SmartThingsSensor(entry_data.client, device, description, capability, attribute)
         for device in entry_data.devices.values()
-        for capability, attributes in device.status[MAIN].items()
-        if capability in CAPABILITY_TO_SENSORS
-        for attribute in attributes
-        for description in CAPABILITY_TO_SENSORS[capability].get(attribute, [])
-        if not description.capability_ignore_list
-        or not any(
-            all(capability in device.status[MAIN] for capability in capability_list)
-            for capability_list in description.capability_ignore_list
+        for capability, attributes in CAPABILITY_TO_SENSORS.items()
+        if capability in device.status[MAIN]
+        for attribute, descriptions in attributes.items()
+        for description in descriptions
+        if (
+            not description.capability_ignore_list
+            or not any(
+                all(capability in device.status[MAIN] for capability in capability_list)
+                for capability_list in description.capability_ignore_list
+            )
+        )
+        and (
+            not description.except_if_state_none
+            or device.status[MAIN][capability][attribute].value is not None
         )
     )
 
diff --git a/requirements_all.txt b/requirements_all.txt
index 577e1cdc578..d4b57e0a2ac 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -2310,7 +2310,7 @@ pysma==0.7.5
 pysmappee==0.2.29
 
 # homeassistant.components.smartthings
-pysmartthings==1.2.0
+pysmartthings==2.0.0
 
 # homeassistant.components.smarty
 pysmarty2==0.10.2
diff --git a/requirements_test_all.txt b/requirements_test_all.txt
index 593ff9203cc..0940b6ceef9 100644
--- a/requirements_test_all.txt
+++ b/requirements_test_all.txt
@@ -1882,7 +1882,7 @@ pysma==0.7.5
 pysmappee==0.2.29
 
 # homeassistant.components.smartthings
-pysmartthings==1.2.0
+pysmartthings==2.0.0
 
 # homeassistant.components.smarty
 pysmarty2==0.10.2
diff --git a/tests/components/smartthings/__init__.py b/tests/components/smartthings/__init__.py
index 94a2e7512f2..a5e51c7d434 100644
--- a/tests/components/smartthings/__init__.py
+++ b/tests/components/smartthings/__init__.py
@@ -57,7 +57,7 @@ async def trigger_update(
     data: dict[str, Any] | None = None,
 ) -> None:
     """Trigger an update."""
-    for call in mock.add_device_event_listener.call_args_list:
+    for call in mock.add_device_capability_event_listener.call_args_list:
         if call[0][0] == device_id and call[0][2] == capability:
             call[0][3](
                 DeviceEvent(
diff --git a/tests/components/smartthings/snapshots/test_sensor.ambr b/tests/components/smartthings/snapshots/test_sensor.ambr
index 778b05fa183..93a683afe82 100644
--- a/tests/components/smartthings/snapshots/test_sensor.ambr
+++ b/tests/components/smartthings/snapshots/test_sensor.ambr
@@ -1,5 +1,5 @@
 # serializer version: 1
-# name: test_all_entities[aeotec_home_energy_meter_gen5][sensor.aeotec_energy_monitor_energy_2-entry]
+# name: test_all_entities[aeotec_home_energy_meter_gen5][sensor.aeotec_energy_monitor_energy-entry]
   EntityRegistryEntrySnapshot({
     'aliases': set({
     }),
@@ -14,7 +14,7 @@
     'disabled_by': None,
     'domain': 'sensor',
     'entity_category': None,
-    'entity_id': 'sensor.aeotec_energy_monitor_energy_2',
+    'entity_id': 'sensor.aeotec_energy_monitor_energy',
     'has_entity_name': True,
     'hidden_by': None,
     'icon': None,
@@ -35,7 +35,7 @@
     'unit_of_measurement': 'kWh',
   })
 # ---
-# name: test_all_entities[aeotec_home_energy_meter_gen5][sensor.aeotec_energy_monitor_energy_2-state]
+# name: test_all_entities[aeotec_home_energy_meter_gen5][sensor.aeotec_energy_monitor_energy-state]
   StateSnapshot({
     'attributes': ReadOnlyDict({
       'device_class': 'energy',
@@ -44,7 +44,7 @@
       'unit_of_measurement': 'kWh',
     }),
     'context': <ANY>,
-    'entity_id': 'sensor.aeotec_energy_monitor_energy_2',
+    'entity_id': 'sensor.aeotec_energy_monitor_energy',
     'last_changed': <ANY>,
     'last_reported': <ANY>,
     'last_updated': <ANY>,
diff --git a/tests/components/smartthings/test_sensor.py b/tests/components/smartthings/test_sensor.py
index 8b8bb8930f4..c83950de9e9 100644
--- a/tests/components/smartthings/test_sensor.py
+++ b/tests/components/smartthings/test_sensor.py
@@ -28,7 +28,7 @@ async def test_all_entities(
     snapshot_smartthings_entities(hass, entity_registry, snapshot, Platform.SENSOR)
 
 
-@pytest.mark.parametrize("device_fixture", ["aeotec_home_energy_meter_gen5"])
+@pytest.mark.parametrize("device_fixture", ["da_ac_rac_000001"])
 async def test_state_update(
     hass: HomeAssistant,
     devices: AsyncMock,
@@ -37,15 +37,15 @@ async def test_state_update(
     """Test state update."""
     await setup_integration(hass, mock_config_entry)
 
-    assert hass.states.get("sensor.aeotec_energy_monitor_energy_2").state == "19978.536"
+    assert hass.states.get("sensor.ac_office_granit_temperature").state == "25"
 
     await trigger_update(
         hass,
         devices,
-        "f0af21a2-d5a1-437c-b10a-b34a87394b71",
-        Capability.ENERGY_METER,
-        Attribute.ENERGY,
-        20000.0,
+        "96a5ef74-5832-a84b-f1f7-ca799957065d",
+        Capability.TEMPERATURE_MEASUREMENT,
+        Attribute.TEMPERATURE,
+        20,
     )
 
-    assert hass.states.get("sensor.aeotec_energy_monitor_energy_2").state == "20000.0"
+    assert hass.states.get("sensor.ac_office_granit_temperature").state == "20"
-- 
GitLab