mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Overhaul UniFi Protect NVR Disk sensors (#73197)
* Overhauls NVR Disk sensors * Updates from latest version of pyunifiprotect
This commit is contained in:
parent
5c49d0a761
commit
004ff8fb30
@ -6,6 +6,7 @@ from dataclasses import dataclass
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from pyunifiprotect.data import NVR, Camera, Event, Light, MountType, Sensor
|
from pyunifiprotect.data import NVR, Camera, Event, Light, MountType, Sensor
|
||||||
|
from pyunifiprotect.data.nvr import UOSDisk
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import (
|
from homeassistant.components.binary_sensor import (
|
||||||
BinarySensorDeviceClass,
|
BinarySensorDeviceClass,
|
||||||
@ -13,7 +14,6 @@ from homeassistant.components.binary_sensor import (
|
|||||||
BinarySensorEntityDescription,
|
BinarySensorEntityDescription,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ATTR_MODEL
|
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity import EntityCategory
|
from homeassistant.helpers.entity import EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
@ -131,7 +131,6 @@ DOORLOCK_SENSORS: tuple[ProtectBinaryEntityDescription, ...] = (
|
|||||||
DISK_SENSORS: tuple[ProtectBinaryEntityDescription, ...] = (
|
DISK_SENSORS: tuple[ProtectBinaryEntityDescription, ...] = (
|
||||||
ProtectBinaryEntityDescription(
|
ProtectBinaryEntityDescription(
|
||||||
key="disk_health",
|
key="disk_health",
|
||||||
name="Disk {index} Health",
|
|
||||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||||
entity_category=EntityCategory.DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
),
|
),
|
||||||
@ -182,14 +181,18 @@ def _async_nvr_entities(
|
|||||||
) -> list[ProtectDeviceEntity]:
|
) -> list[ProtectDeviceEntity]:
|
||||||
entities: list[ProtectDeviceEntity] = []
|
entities: list[ProtectDeviceEntity] = []
|
||||||
device = data.api.bootstrap.nvr
|
device = data.api.bootstrap.nvr
|
||||||
for index, _ in enumerate(device.system_info.storage.devices):
|
if device.system_info.ustorage is None:
|
||||||
|
return entities
|
||||||
|
|
||||||
|
for disk in device.system_info.ustorage.disks:
|
||||||
for description in DISK_SENSORS:
|
for description in DISK_SENSORS:
|
||||||
entities.append(
|
if not disk.has_disk:
|
||||||
ProtectDiskBinarySensor(data, device, description, index=index)
|
continue
|
||||||
)
|
|
||||||
|
entities.append(ProtectDiskBinarySensor(data, device, description, disk))
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Adding binary sensor entity %s",
|
"Adding binary sensor entity %s",
|
||||||
(description.name or "{index}").format(index=index),
|
f"{disk.type} {disk.slot}",
|
||||||
)
|
)
|
||||||
|
|
||||||
return entities
|
return entities
|
||||||
@ -216,6 +219,7 @@ class ProtectDeviceBinarySensor(ProtectDeviceEntity, BinarySensorEntity):
|
|||||||
class ProtectDiskBinarySensor(ProtectNVREntity, BinarySensorEntity):
|
class ProtectDiskBinarySensor(ProtectNVREntity, BinarySensorEntity):
|
||||||
"""A UniFi Protect NVR Disk Binary Sensor."""
|
"""A UniFi Protect NVR Disk Binary Sensor."""
|
||||||
|
|
||||||
|
_disk: UOSDisk
|
||||||
entity_description: ProtectBinaryEntityDescription
|
entity_description: ProtectBinaryEntityDescription
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -223,26 +227,35 @@ class ProtectDiskBinarySensor(ProtectNVREntity, BinarySensorEntity):
|
|||||||
data: ProtectData,
|
data: ProtectData,
|
||||||
device: NVR,
|
device: NVR,
|
||||||
description: ProtectBinaryEntityDescription,
|
description: ProtectBinaryEntityDescription,
|
||||||
index: int,
|
disk: UOSDisk,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the Binary Sensor."""
|
"""Initialize the Binary Sensor."""
|
||||||
|
self._disk = disk
|
||||||
|
# backwards compat with old unique IDs
|
||||||
|
index = self._disk.slot - 1
|
||||||
|
|
||||||
description = copy(description)
|
description = copy(description)
|
||||||
description.key = f"{description.key}_{index}"
|
description.key = f"{description.key}_{index}"
|
||||||
description.name = (description.name or "{index}").format(index=index)
|
description.name = f"{disk.type} {disk.slot}"
|
||||||
self._index = index
|
|
||||||
super().__init__(data, device, description)
|
super().__init__(data, device, description)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_update_device_from_protect(self) -> None:
|
def _async_update_device_from_protect(self) -> None:
|
||||||
super()._async_update_device_from_protect()
|
super()._async_update_device_from_protect()
|
||||||
|
|
||||||
disks = self.device.system_info.storage.devices
|
slot = self._disk.slot
|
||||||
disk_available = len(disks) > self._index
|
self._attr_available = False
|
||||||
self._attr_available = self._attr_available and disk_available
|
|
||||||
if disk_available:
|
if self.device.system_info.ustorage is None:
|
||||||
disk = disks[self._index]
|
return
|
||||||
self._attr_is_on = not disk.healthy
|
|
||||||
self._attr_extra_state_attributes = {ATTR_MODEL: disk.model}
|
for disk in self.device.system_info.ustorage.disks:
|
||||||
|
if disk.slot == slot:
|
||||||
|
self._disk = disk
|
||||||
|
self._attr_available = True
|
||||||
|
break
|
||||||
|
|
||||||
|
self._attr_is_on = not self._disk.is_healthy
|
||||||
|
|
||||||
|
|
||||||
class ProtectEventBinarySensor(EventThumbnailMixin, ProtectDeviceBinarySensor):
|
class ProtectEventBinarySensor(EventThumbnailMixin, ProtectDeviceBinarySensor):
|
||||||
|
@ -117,6 +117,158 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"ustorage": {
|
||||||
|
"disks": [
|
||||||
|
{
|
||||||
|
"slot": 1,
|
||||||
|
"type": "HDD",
|
||||||
|
"model": "ST16000VE000-2L2103",
|
||||||
|
"serial": "ABCD1234",
|
||||||
|
"firmware": "EV02",
|
||||||
|
"rpm": 7200,
|
||||||
|
"ata": "ACS-4",
|
||||||
|
"sata": "SATA 3.3",
|
||||||
|
"action": "expanding",
|
||||||
|
"healthy": "good",
|
||||||
|
"state": "expanding",
|
||||||
|
"reason": null,
|
||||||
|
"temperature": 52,
|
||||||
|
"poweronhrs": 4242,
|
||||||
|
"life_span": null,
|
||||||
|
"bad_sector": 0,
|
||||||
|
"threshold": 10,
|
||||||
|
"progress": 21.390607518939174,
|
||||||
|
"estimate": 234395.73300748435
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slot": 2,
|
||||||
|
"type": "HDD",
|
||||||
|
"model": "ST16000VE000-2L2103",
|
||||||
|
"serial": "ABCD1234",
|
||||||
|
"firmware": "EV02",
|
||||||
|
"rpm": 7200,
|
||||||
|
"ata": "ACS-4",
|
||||||
|
"sata": "SATA 3.3",
|
||||||
|
"action": "expanding",
|
||||||
|
"healthy": "good",
|
||||||
|
"state": "expanding",
|
||||||
|
"reason": null,
|
||||||
|
"temperature": 52,
|
||||||
|
"poweronhrs": 4242,
|
||||||
|
"life_span": null,
|
||||||
|
"bad_sector": 0,
|
||||||
|
"threshold": 10,
|
||||||
|
"progress": 21.390607518939174,
|
||||||
|
"estimate": 234395.73300748435
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slot": 3,
|
||||||
|
"type": "HDD",
|
||||||
|
"model": "ST16000VE000-2L2103",
|
||||||
|
"serial": "ABCD1234",
|
||||||
|
"firmware": "EV02",
|
||||||
|
"rpm": 7200,
|
||||||
|
"ata": "ACS-4",
|
||||||
|
"sata": "SATA 3.3",
|
||||||
|
"action": "expanding",
|
||||||
|
"healthy": "good",
|
||||||
|
"state": "expanding",
|
||||||
|
"reason": null,
|
||||||
|
"temperature": 51,
|
||||||
|
"poweronhrs": 4242,
|
||||||
|
"life_span": null,
|
||||||
|
"bad_sector": 0,
|
||||||
|
"threshold": 10,
|
||||||
|
"progress": 21.390607518939174,
|
||||||
|
"estimate": 234395.73300748435
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slot": 4,
|
||||||
|
"type": "HDD",
|
||||||
|
"model": "ST16000VE000-2L2103",
|
||||||
|
"serial": "ABCD1234",
|
||||||
|
"firmware": "EV02",
|
||||||
|
"rpm": 7200,
|
||||||
|
"ata": "ACS-4",
|
||||||
|
"sata": "SATA 3.3",
|
||||||
|
"action": "expanding",
|
||||||
|
"healthy": "good",
|
||||||
|
"state": "expanding",
|
||||||
|
"reason": null,
|
||||||
|
"temperature": 50,
|
||||||
|
"poweronhrs": 2443,
|
||||||
|
"life_span": null,
|
||||||
|
"bad_sector": 0,
|
||||||
|
"threshold": 10,
|
||||||
|
"progress": 21.390607518939174,
|
||||||
|
"estimate": 234395.73300748435
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slot": 5,
|
||||||
|
"type": "HDD",
|
||||||
|
"model": "ST16000VE000-2L2103",
|
||||||
|
"serial": "ABCD1234",
|
||||||
|
"firmware": "EV02",
|
||||||
|
"rpm": 7200,
|
||||||
|
"ata": "ACS-4",
|
||||||
|
"sata": "SATA 3.3",
|
||||||
|
"action": "expanding",
|
||||||
|
"healthy": "good",
|
||||||
|
"state": "expanding",
|
||||||
|
"reason": null,
|
||||||
|
"temperature": 50,
|
||||||
|
"poweronhrs": 783,
|
||||||
|
"life_span": null,
|
||||||
|
"bad_sector": 0,
|
||||||
|
"threshold": 10,
|
||||||
|
"progress": 21.390607518939174,
|
||||||
|
"estimate": 234395.73300748435
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slot": 6,
|
||||||
|
"state": "nodisk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slot": 7,
|
||||||
|
"type": "HDD",
|
||||||
|
"model": "ST16000VE002-3BR101",
|
||||||
|
"serial": "ABCD1234",
|
||||||
|
"firmware": "EV01",
|
||||||
|
"rpm": 7200,
|
||||||
|
"ata": "ACS-4",
|
||||||
|
"sata": "SATA 3.3",
|
||||||
|
"action": "expanding",
|
||||||
|
"healthy": "good",
|
||||||
|
"state": "expanding",
|
||||||
|
"reason": null,
|
||||||
|
"temperature": 45,
|
||||||
|
"poweronhrs": 18,
|
||||||
|
"life_span": null,
|
||||||
|
"bad_sector": 0,
|
||||||
|
"threshold": 10,
|
||||||
|
"progress": 21.390607518939174,
|
||||||
|
"estimate": 234395.73300748435
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"space": [
|
||||||
|
{
|
||||||
|
"device": "md3",
|
||||||
|
"total_bytes": 63713403555840,
|
||||||
|
"used_bytes": 57006577086464,
|
||||||
|
"action": "expanding",
|
||||||
|
"progress": 21.390607518939174,
|
||||||
|
"estimate": 234395.73300748435
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"device": "md0",
|
||||||
|
"total_bytes": 0,
|
||||||
|
"used_bytes": 0,
|
||||||
|
"action": "syncing",
|
||||||
|
"progress": 0,
|
||||||
|
"estimate": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"tmpfs": {
|
"tmpfs": {
|
||||||
"available": 934204,
|
"available": 934204,
|
||||||
"total": 1048576,
|
"total": 1048576,
|
||||||
|
@ -71,7 +71,7 @@ async def camera_fixture(
|
|||||||
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert_entity_counts(hass, Platform.BINARY_SENSOR, 3, 3)
|
assert_entity_counts(hass, Platform.BINARY_SENSOR, 9, 9)
|
||||||
|
|
||||||
yield camera_obj
|
yield camera_obj
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ async def light_fixture(
|
|||||||
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert_entity_counts(hass, Platform.BINARY_SENSOR, 2, 2)
|
assert_entity_counts(hass, Platform.BINARY_SENSOR, 8, 8)
|
||||||
|
|
||||||
yield light_obj
|
yield light_obj
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ async def camera_none_fixture(
|
|||||||
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert_entity_counts(hass, Platform.BINARY_SENSOR, 2, 2)
|
assert_entity_counts(hass, Platform.BINARY_SENSOR, 8, 8)
|
||||||
|
|
||||||
yield camera_obj
|
yield camera_obj
|
||||||
|
|
||||||
@ -179,7 +179,7 @@ async def sensor_fixture(
|
|||||||
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert_entity_counts(hass, Platform.BINARY_SENSOR, 4, 4)
|
assert_entity_counts(hass, Platform.BINARY_SENSOR, 10, 10)
|
||||||
|
|
||||||
yield sensor_obj
|
yield sensor_obj
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ async def sensor_none_fixture(
|
|||||||
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert_entity_counts(hass, Platform.BINARY_SENSOR, 4, 4)
|
assert_entity_counts(hass, Platform.BINARY_SENSOR, 10, 10)
|
||||||
|
|
||||||
yield sensor_obj
|
yield sensor_obj
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user