Extend Nextcloud integration (#94066)

This commit is contained in:
escoand 2023-08-27 18:51:31 +02:00 committed by GitHub
parent f42b8e217b
commit d21ee30ddf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 311 additions and 68 deletions

View file

@ -1,5 +1,7 @@
"""The Nextcloud integration."""
import logging
from nextcloudmonitor import (
NextcloudMonitor,
NextcloudMonitorAuthorizationError,
@ -17,7 +19,7 @@ from homeassistant.const import (
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers import config_validation as cv, entity_registry as er
from .const import DOMAIN
from .coordinator import NextcloudDataUpdateCoordinator
@ -26,10 +28,25 @@ PLATFORMS = (Platform.SENSOR, Platform.BINARY_SENSOR)
CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False)
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up the Nextcloud integration."""
# migrate old entity unique ids
entity_reg = er.async_get(hass)
entities: list[er.RegistryEntry] = er.async_entries_for_config_entry(
entity_reg, entry.entry_id
)
for entity in entities:
old_uid_start = f"{entry.data[CONF_URL]}#nextcloud_"
new_uid_start = f"{entry.data[CONF_URL]}#"
if entity.unique_id.startswith(old_uid_start):
new_uid = entity.unique_id.replace(old_uid_start, new_uid_start)
_LOGGER.debug("migrate unique id '%s' to '%s'", entity.unique_id, new_uid)
entity_reg.async_update_entity(entity.entity_id, new_unique_id=new_uid)
def _connect_nc():
return NextcloudMonitor(
entry.data[CONF_URL],

View file

@ -1,8 +1,14 @@
"""Summary binary data from Nextcoud."""
from __future__ import annotations
from homeassistant.components.binary_sensor import BinarySensorEntity
from typing import Final
from homeassistant.components.binary_sensor import (
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -10,12 +16,28 @@ from .const import DOMAIN
from .coordinator import NextcloudDataUpdateCoordinator
from .entity import NextcloudEntity
BINARY_SENSORS = (
"nextcloud_system_enable_avatars",
"nextcloud_system_enable_previews",
"nextcloud_system_filelocking.enabled",
"nextcloud_system_debug",
)
BINARY_SENSORS: Final[dict[str, BinarySensorEntityDescription]] = {
"system_debug": BinarySensorEntityDescription(
key="system_debug",
translation_key="nextcloud_system_debug",
entity_category=EntityCategory.DIAGNOSTIC,
),
"system_enable_avatars": BinarySensorEntityDescription(
key="system_enable_avatars",
translation_key="nextcloud_system_enable_avatars",
entity_category=EntityCategory.DIAGNOSTIC,
),
"system_enable_previews": BinarySensorEntityDescription(
key="system_enable_previews",
translation_key="nextcloud_system_enable_previews",
entity_category=EntityCategory.DIAGNOSTIC,
),
"system_filelocking.enabled": BinarySensorEntityDescription(
key="system_filelocking.enabled",
translation_key="nextcloud_system_filelocking_enabled",
entity_category=EntityCategory.DIAGNOSTIC,
),
}
async def async_setup_entry(
@ -25,7 +47,7 @@ async def async_setup_entry(
coordinator: NextcloudDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities(
[
NextcloudBinarySensor(coordinator, name, entry)
NextcloudBinarySensor(coordinator, name, entry, BINARY_SENSORS[name])
for name in coordinator.data
if name in BINARY_SENSORS
]
@ -38,4 +60,5 @@ class NextcloudBinarySensor(NextcloudEntity, BinarySensorEntity):
@property
def is_on(self) -> bool:
"""Return true if the binary sensor is on."""
return self.coordinator.data.get(self.item) == "yes"
val = self.coordinator.data.get(self.item)
return val is True or val == "yes"

View file

@ -10,7 +10,7 @@ from homeassistant.const import CONF_URL
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DEFAULT_SCAN_INTERVAL, DOMAIN
from .const import DEFAULT_SCAN_INTERVAL
_LOGGER = logging.getLogger(__name__)
@ -55,7 +55,7 @@ class NextcloudDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
leaf = True
result.update(self._get_data_points(value, key_path, leaf))
else:
result[f"{DOMAIN}_{key_path}{key}"] = value
result[f"{key_path}{key}"] = value
leaf = False
return result

View file

@ -1,8 +1,10 @@
"""Base entity for the Nextcloud integration."""
from urllib.parse import urlparse
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util import slugify
from .const import DOMAIN
from .coordinator import NextcloudDataUpdateCoordinator
@ -12,19 +14,22 @@ class NextcloudEntity(CoordinatorEntity[NextcloudDataUpdateCoordinator]):
"""Base Nextcloud entity."""
_attr_has_entity_name = True
_attr_icon = "mdi:cloud"
def __init__(
self, coordinator: NextcloudDataUpdateCoordinator, item: str, entry: ConfigEntry
self,
coordinator: NextcloudDataUpdateCoordinator,
item: str,
entry: ConfigEntry,
desc: EntityDescription,
) -> None:
"""Initialize the Nextcloud sensor."""
super().__init__(coordinator)
self.item = item
self._attr_translation_key = slugify(item)
self._attr_unique_id = f"{coordinator.url}#{item}"
self._attr_device_info = DeviceInfo(
name="Nextcloud",
identifiers={(DOMAIN, entry.entry_id)},
sw_version=coordinator.data.get("nextcloud_system_version"),
configuration_url=coordinator.url,
identifiers={(DOMAIN, entry.entry_id)},
name=urlparse(coordinator.url).netloc,
sw_version=coordinator.data.get("system_version"),
)
self.entity_description = desc

View file

@ -1,8 +1,16 @@
"""Summary data from Nextcoud."""
from __future__ import annotations
from homeassistant.components.sensor import SensorEntity
from datetime import UTC, datetime
from typing import Final, cast
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory, UnitOfInformation, UnitOfTime
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
@ -11,51 +19,235 @@ from .const import DOMAIN
from .coordinator import NextcloudDataUpdateCoordinator
from .entity import NextcloudEntity
SENSORS = (
"nextcloud_system_version",
"nextcloud_system_theme",
"nextcloud_system_memcache.local",
"nextcloud_system_memcache.distributed",
"nextcloud_system_memcache.locking",
"nextcloud_system_freespace",
"nextcloud_system_cpuload",
"nextcloud_system_mem_total",
"nextcloud_system_mem_free",
"nextcloud_system_swap_total",
"nextcloud_system_swap_free",
"nextcloud_system_apps_num_installed",
"nextcloud_system_apps_num_updates_available",
"nextcloud_system_apps_app_updates_calendar",
"nextcloud_system_apps_app_updates_contacts",
"nextcloud_system_apps_app_updates_tasks",
"nextcloud_system_apps_app_updates_twofactor_totp",
"nextcloud_storage_num_users",
"nextcloud_storage_num_files",
"nextcloud_storage_num_storages",
"nextcloud_storage_num_storages_local",
"nextcloud_storage_num_storages_home",
"nextcloud_storage_num_storages_other",
"nextcloud_shares_num_shares",
"nextcloud_shares_num_shares_user",
"nextcloud_shares_num_shares_groups",
"nextcloud_shares_num_shares_link",
"nextcloud_shares_num_shares_mail",
"nextcloud_shares_num_shares_room",
"nextcloud_shares_num_shares_link_no_password",
"nextcloud_shares_num_fed_shares_sent",
"nextcloud_shares_num_fed_shares_received",
"nextcloud_shares_permissions_3_1",
"nextcloud_server_webserver",
"nextcloud_server_php_version",
"nextcloud_server_php_memory_limit",
"nextcloud_server_php_max_execution_time",
"nextcloud_server_php_upload_max_filesize",
"nextcloud_database_type",
"nextcloud_database_version",
"nextcloud_activeUsers_last5minutes",
"nextcloud_activeUsers_last1hour",
"nextcloud_activeUsers_last24hours",
)
UNIT_OF_LOAD: Final[str] = "load"
SENSORS: Final[dict[str, SensorEntityDescription]] = {
"activeUsers_last1hour": SensorEntityDescription(
key="activeUsers_last1hour",
translation_key="nextcloud_activeusers_last1hour",
entity_category=EntityCategory.DIAGNOSTIC,
icon="mdi:account-multiple",
),
"activeUsers_last24hours": SensorEntityDescription(
key="activeUsers_last24hours",
translation_key="nextcloud_activeusers_last24hours",
entity_category=EntityCategory.DIAGNOSTIC,
icon="mdi:account-multiple",
),
"activeUsers_last5minutes": SensorEntityDescription(
key="activeUsers_last5minutes",
translation_key="nextcloud_activeusers_last5minutes",
entity_category=EntityCategory.DIAGNOSTIC,
icon="mdi:account-multiple",
),
"database_type": SensorEntityDescription(
key="database_type",
translation_key="nextcloud_database_type",
entity_category=EntityCategory.DIAGNOSTIC,
icon="mdi:database",
),
"database_version": SensorEntityDescription(
key="database_version",
translation_key="nextcloud_database_version",
entity_category=EntityCategory.DIAGNOSTIC,
icon="mdi:database",
),
"server_php_max_execution_time": SensorEntityDescription(
key="server_php_max_execution_time",
translation_key="nextcloud_server_php_max_execution_time",
device_class=SensorDeviceClass.DURATION,
entity_category=EntityCategory.CONFIG,
icon="mdi:language-php",
native_unit_of_measurement=UnitOfTime.SECONDS,
),
"server_php_memory_limit": SensorEntityDescription(
key="server_php_memory_limit",
translation_key="nextcloud_server_php_memory_limit",
device_class=SensorDeviceClass.DATA_SIZE,
entity_category=EntityCategory.CONFIG,
icon="mdi:language-php",
native_unit_of_measurement=UnitOfInformation.BYTES,
suggested_display_precision=1,
suggested_unit_of_measurement=UnitOfInformation.MEGABYTES,
),
"server_php_upload_max_filesize": SensorEntityDescription(
key="server_php_upload_max_filesize",
translation_key="nextcloud_server_php_upload_max_filesize",
device_class=SensorDeviceClass.DATA_SIZE,
entity_category=EntityCategory.CONFIG,
icon="mdi:language-php",
native_unit_of_measurement=UnitOfInformation.BYTES,
suggested_display_precision=1,
suggested_unit_of_measurement=UnitOfInformation.MEGABYTES,
),
"server_php_version": SensorEntityDescription(
key="server_php_version",
translation_key="nextcloud_server_php_version",
entity_category=EntityCategory.DIAGNOSTIC,
icon="mdi:language-php",
),
"server_webserver": SensorEntityDescription(
key="server_webserver",
translation_key="nextcloud_server_webserver",
entity_category=EntityCategory.DIAGNOSTIC,
),
"shares_num_fed_shares_sent": SensorEntityDescription(
key="shares_num_fed_shares_sent",
translation_key="nextcloud_shares_num_fed_shares_sent",
entity_category=EntityCategory.DIAGNOSTIC,
),
"shares_num_fed_shares_received": SensorEntityDescription(
key="shares_num_fed_shares_received",
translation_key="nextcloud_shares_num_fed_shares_received",
entity_category=EntityCategory.DIAGNOSTIC,
),
"shares_num_shares": SensorEntityDescription(
key="shares_num_shares",
translation_key="nextcloud_shares_num_shares",
),
"shares_num_shares_groups": SensorEntityDescription(
key="shares_num_shares_groups",
translation_key="nextcloud_shares_num_shares_groups",
entity_category=EntityCategory.DIAGNOSTIC,
),
"shares_num_shares_link": SensorEntityDescription(
key="shares_num_shares_link",
translation_key="nextcloud_shares_num_shares_link",
entity_category=EntityCategory.DIAGNOSTIC,
),
"shares_num_shares_link_no_password": SensorEntityDescription(
key="shares_num_shares_link_no_password",
translation_key="nextcloud_shares_num_shares_link_no_password",
entity_category=EntityCategory.DIAGNOSTIC,
),
"shares_num_shares_mail": SensorEntityDescription(
key="shares_num_shares_mail",
translation_key="nextcloud_shares_num_shares_mail",
entity_category=EntityCategory.DIAGNOSTIC,
),
"shares_num_shares_room": SensorEntityDescription(
key="shares_num_shares_room",
translation_key="nextcloud_shares_num_shares_room",
entity_category=EntityCategory.DIAGNOSTIC,
),
"shares_num_shares_user": SensorEntityDescription(
key="server_num_shares_user",
translation_key="nextcloud_shares_num_shares_user",
entity_category=EntityCategory.DIAGNOSTIC,
),
"storage_num_files": SensorEntityDescription(
key="storage_num_files",
translation_key="nextcloud_storage_num_files",
),
"storage_num_storages": SensorEntityDescription(
key="storage_num_storages",
translation_key="nextcloud_storage_num_storages",
),
"storage_num_storages_home": SensorEntityDescription(
key="storage_num_storages_home",
translation_key="nextcloud_storage_num_storages_home",
entity_category=EntityCategory.DIAGNOSTIC,
),
"storage_num_storages_local": SensorEntityDescription(
key="storage_num_storages_local",
translation_key="nextcloud_storage_num_storages_local",
entity_category=EntityCategory.DIAGNOSTIC,
),
"storage_num_storages_other": SensorEntityDescription(
key="storage_num_storages_other",
translation_key="nextcloud_storage_num_storages_other",
entity_category=EntityCategory.DIAGNOSTIC,
),
"storage_num_users": SensorEntityDescription(
key="storage_num_users",
translation_key="nextcloud_storage_num_users",
),
"system_apps_num_installed": SensorEntityDescription(
key="system_apps_num_installed",
translation_key="nextcloud_system_apps_num_installed",
),
"system_apps_num_updates_available": SensorEntityDescription(
key="system_apps_num_updates_available",
translation_key="nextcloud_system_apps_num_updates_available",
icon="mdi:update",
),
"system_cpuload": SensorEntityDescription(
key="system_cpuload",
translation_key="nextcloud_system_cpuload",
icon="mdi:chip",
),
"system_freespace": SensorEntityDescription(
key="system_freespace",
translation_key="nextcloud_system_freespace",
device_class=SensorDeviceClass.DATA_SIZE,
icon="mdi:harddisk",
native_unit_of_measurement=UnitOfInformation.BYTES,
suggested_display_precision=2,
suggested_unit_of_measurement=UnitOfInformation.GIGABYTES,
),
"system_mem_free": SensorEntityDescription(
key="system_mem_free",
translation_key="nextcloud_system_mem_free",
device_class=SensorDeviceClass.DATA_SIZE,
icon="mdi:memory",
native_unit_of_measurement=UnitOfInformation.KILOBYTES,
suggested_display_precision=2,
suggested_unit_of_measurement=UnitOfInformation.GIGABYTES,
),
"system_mem_total": SensorEntityDescription(
key="system_mem_total",
translation_key="nextcloud_system_mem_total",
device_class=SensorDeviceClass.DATA_SIZE,
icon="mdi:memory",
native_unit_of_measurement=UnitOfInformation.KILOBYTES,
suggested_display_precision=2,
suggested_unit_of_measurement=UnitOfInformation.GIGABYTES,
),
"system_memcache.distributed": SensorEntityDescription(
key="system_memcache.distributed",
translation_key="nextcloud_system_memcache_distributed",
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
),
"system_memcache.local": SensorEntityDescription(
key="system_memcache.local",
translation_key="nextcloud_system_memcache_local",
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
),
"system_memcache.locking": SensorEntityDescription(
key="system_memcache.locking",
translation_key="nextcloud_system_memcache_locking",
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
),
"system_swap_total": SensorEntityDescription(
key="system_swap_total",
translation_key="nextcloud_system_swap_total",
device_class=SensorDeviceClass.DATA_SIZE,
icon="mdi:memory",
native_unit_of_measurement=UnitOfInformation.KILOBYTES,
suggested_display_precision=2,
suggested_unit_of_measurement=UnitOfInformation.GIGABYTES,
),
"system_swap_free": SensorEntityDescription(
key="system_swap_free",
translation_key="nextcloud_system_swap_free",
device_class=SensorDeviceClass.DATA_SIZE,
icon="mdi:memory",
native_unit_of_measurement=UnitOfInformation.KILOBYTES,
suggested_display_precision=2,
suggested_unit_of_measurement=UnitOfInformation.GIGABYTES,
),
"system_theme": SensorEntityDescription(
key="system_theme",
translation_key="nextcloud_system_theme",
),
"system_version": SensorEntityDescription(
key="system_version",
translation_key="nextcloud_system_version",
),
}
async def async_setup_entry(
@ -65,7 +257,7 @@ async def async_setup_entry(
coordinator: NextcloudDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities(
[
NextcloudSensor(coordinator, name, entry)
NextcloudSensor(coordinator, name, entry, SENSORS[name])
for name in coordinator.data
if name in SENSORS
]
@ -76,6 +268,12 @@ class NextcloudSensor(NextcloudEntity, SensorEntity):
"""Represents a Nextcloud sensor."""
@property
def native_value(self) -> StateType:
def native_value(self) -> StateType | datetime:
"""Return the state for this sensor."""
return self.coordinator.data.get(self.item)
val = self.coordinator.data.get(self.item)
if (
getattr(self.entity_description, "device_class", None)
== SensorDeviceClass.TIMESTAMP
):
return datetime.fromtimestamp(cast(int, val), tz=UTC)
return val