From ba1266a893df9002bd3fbfc0a6afb51845e8bf9c Mon Sep 17 00:00:00 2001
From: Mike Woudenberg <mwoudenberg@xebia.com>
Date: Fri, 7 Jul 2023 05:09:34 +0200
Subject: [PATCH] Add sensors to LOQED integration for battery percentage and
 BLE stength (#95726)

* Add sensors for battery percentage and BLE stength

* Use translatable name for BLE strength, no longer pass enity to sensor
---
 .coveragerc                                 |  1 +
 homeassistant/components/loqed/__init__.py  |  2 +-
 homeassistant/components/loqed/sensor.py    | 71 +++++++++++++++++++++
 homeassistant/components/loqed/strings.json |  7 ++
 tests/components/loqed/conftest.py          |  1 +
 5 files changed, 81 insertions(+), 1 deletion(-)
 create mode 100644 homeassistant/components/loqed/sensor.py

diff --git a/.coveragerc b/.coveragerc
index 5ba8575979d..e69683288a2 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -650,6 +650,7 @@ omit =
     homeassistant/components/lookin/light.py
     homeassistant/components/lookin/media_player.py
     homeassistant/components/lookin/sensor.py
+    homeassistant/components/loqed/sensor.py
     homeassistant/components/luci/device_tracker.py
     homeassistant/components/luftdaten/sensor.py
     homeassistant/components/lupusec/*
diff --git a/homeassistant/components/loqed/__init__.py b/homeassistant/components/loqed/__init__.py
index 1248c75612f..e6c69e0751e 100644
--- a/homeassistant/components/loqed/__init__.py
+++ b/homeassistant/components/loqed/__init__.py
@@ -14,7 +14,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
 from .const import DOMAIN
 from .coordinator import LoqedDataCoordinator
 
-PLATFORMS: list[str] = [Platform.LOCK]
+PLATFORMS: list[str] = [Platform.LOCK, Platform.SENSOR]
 
 
 _LOGGER = logging.getLogger(__name__)
diff --git a/homeassistant/components/loqed/sensor.py b/homeassistant/components/loqed/sensor.py
new file mode 100644
index 00000000000..ee4fa7ecd74
--- /dev/null
+++ b/homeassistant/components/loqed/sensor.py
@@ -0,0 +1,71 @@
+"""Creates LOQED sensors."""
+from typing import Final
+
+from homeassistant.components.sensor import (
+    SensorDeviceClass,
+    SensorEntity,
+    SensorEntityDescription,
+    SensorStateClass,
+)
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.const import (
+    PERCENTAGE,
+    SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
+    EntityCategory,
+)
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.entity_platform import AddEntitiesCallback
+
+from .const import DOMAIN
+from .coordinator import LoqedDataCoordinator, StatusMessage
+from .entity import LoqedEntity
+
+SENSORS: Final[tuple[SensorEntityDescription, ...]] = (
+    SensorEntityDescription(
+        key="ble_strength",
+        translation_key="ble_strength",
+        device_class=SensorDeviceClass.SIGNAL_STRENGTH,
+        native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
+        state_class=SensorStateClass.MEASUREMENT,
+        entity_category=EntityCategory.DIAGNOSTIC,
+        entity_registry_enabled_default=False,
+    ),
+    SensorEntityDescription(
+        key="battery_percentage",
+        device_class=SensorDeviceClass.BATTERY,
+        state_class=SensorStateClass.MEASUREMENT,
+        entity_category=EntityCategory.DIAGNOSTIC,
+        native_unit_of_measurement=PERCENTAGE,
+    ),
+)
+
+
+async def async_setup_entry(
+    hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
+) -> None:
+    """Set up the Loqed lock platform."""
+    coordinator = hass.data[DOMAIN][entry.entry_id]
+
+    async_add_entities(LoqedSensor(coordinator, sensor) for sensor in SENSORS)
+
+
+class LoqedSensor(LoqedEntity, SensorEntity):
+    """Representation of Sensor state."""
+
+    def __init__(
+        self, coordinator: LoqedDataCoordinator, description: SensorEntityDescription
+    ) -> None:
+        """Initialize the sensor."""
+        super().__init__(coordinator)
+        self.entity_description = description
+        self._attr_unique_id = f"{self.coordinator.lock.id}_{description.key}"
+
+    @property
+    def data(self) -> StatusMessage:
+        """Return data object from DataUpdateCoordinator."""
+        return self.coordinator.lock
+
+    @property
+    def native_value(self) -> int:
+        """Return state of sensor."""
+        return getattr(self.data, self.entity_description.key)
diff --git a/homeassistant/components/loqed/strings.json b/homeassistant/components/loqed/strings.json
index 6f3316b283f..3d31194f5a6 100644
--- a/homeassistant/components/loqed/strings.json
+++ b/homeassistant/components/loqed/strings.json
@@ -17,5 +17,12 @@
     "abort": {
       "already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
     }
+  },
+  "entity": {
+    "sensor": {
+      "ble_strength": {
+        "name": "Bluetooth signal"
+      }
+    }
   }
 }
diff --git a/tests/components/loqed/conftest.py b/tests/components/loqed/conftest.py
index da7009a5744..be57237afdc 100644
--- a/tests/components/loqed/conftest.py
+++ b/tests/components/loqed/conftest.py
@@ -48,6 +48,7 @@ def lock_fixture() -> loqed.Lock:
     mock_lock.name = "LOQED smart lock"
     mock_lock.getWebhooks = AsyncMock(return_value=webhooks_fixture)
     mock_lock.bolt_state = "locked"
+    mock_lock.battery_percentage = 90
     return mock_lock
 
 
-- 
GitLab