mirror of
https://github.com/home-assistant/core.git
synced 2025-06-25 01:21:51 +02:00
Add Nextcloud Integration (#30871)
* some sensors working in homeassistant * bring up to date * add codeowner * update requirements * overhaul data imports from api & sensor discovery * remove print statement * delete requirements_test_all * add requrements_test_all.txt * Update homeassistant/components/nextcloud/sensor.py Co-Authored-By: springstan <46536646+springstan@users.noreply.github.com> * Update homeassistant/components/nextcloud/sensor.py Co-Authored-By: springstan <46536646+springstan@users.noreply.github.com> * describe recursive function * clarify that dict is returned * remove requirements from requirements_test_all * improve and simplify sensor naming * add basic tests * restore pre-commit config * update requirements_test_all * remove codespell requirement * update pre-commit-config * add-back codespell * rename class variables as suggested by @springstan * add dev branch to no-commit-to-branch git hook Because my fork had the same 'dev' branch i wasn't able to push. Going forward I should probably name my branches differently. * move config logic to __init__.py * restore .pre-commit-config.yaml * remove tests * remove nextcloud test requirement * remove debugging code * implement binary sensors * restore .pre-commit-config.yaml * bump dependency version * bump requirements files * bump nextcloud reqirement to latest * update possible exceptions, use fstrings * add list of sensors & fix inconsistency in get_data_points * use domain for config * fix guard clause * repair pre-commit-config * Remove period from logging * include url in unique_id * update requirements_all.txt Co-authored-by: springstan <46536646+springstan@users.noreply.github.com>
This commit is contained in:
@ -468,6 +468,7 @@ omit =
|
||||
homeassistant/components/netgear_lte/*
|
||||
homeassistant/components/netio/switch.py
|
||||
homeassistant/components/neurio_energy/sensor.py
|
||||
homeassistant/components/nextcloud/*
|
||||
homeassistant/components/nfandroidtv/notify.py
|
||||
homeassistant/components/niko_home_control/light.py
|
||||
homeassistant/components/nilu/air_quality.py
|
||||
|
@ -247,6 +247,7 @@ homeassistant/components/netatmo/* @cgtobi
|
||||
homeassistant/components/netdata/* @fabaff
|
||||
homeassistant/components/nexia/* @ryannazaretian @bdraco
|
||||
homeassistant/components/nextbus/* @vividboarder
|
||||
homeassistant/components/nextcloud/* @meichthys
|
||||
homeassistant/components/nilu/* @hfurubotten
|
||||
homeassistant/components/nissan_leaf/* @filcole
|
||||
homeassistant/components/nmbs/* @thibmaek
|
||||
|
147
homeassistant/components/nextcloud/__init__.py
Normal file
147
homeassistant/components/nextcloud/__init__.py
Normal file
@ -0,0 +1,147 @@
|
||||
"""The Nextcloud integration."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from nextcloudmonitor import NextcloudMonitor, NextcloudMonitorError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_PASSWORD,
|
||||
CONF_SCAN_INTERVAL,
|
||||
CONF_URL,
|
||||
CONF_USERNAME,
|
||||
)
|
||||
from homeassistant.helpers import config_validation as cv, discovery
|
||||
from homeassistant.helpers.event import track_time_interval
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = "nextcloud"
|
||||
NEXTCLOUD_COMPONENTS = ("sensor", "binary_sensor")
|
||||
SCAN_INTERVAL = timedelta(seconds=60)
|
||||
|
||||
# Validate user configuration
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
DOMAIN: vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_URL): cv.url,
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): cv.time_period,
|
||||
}
|
||||
)
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
BINARY_SENSORS = (
|
||||
"nextcloud_system_enable_avatars",
|
||||
"nextcloud_system_enable_previews",
|
||||
"nextcloud_system_filelocking.enabled",
|
||||
"nextcloud_system_debug",
|
||||
)
|
||||
|
||||
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_storage_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_database_version",
|
||||
"nextcloud_activeusers_last5minutes",
|
||||
"nextcloud_activeusers_last1hour",
|
||||
"nextcloud_activeusers_last24hours",
|
||||
)
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
"""Set up the Nextcloud integration."""
|
||||
# Fetch Nextcloud Monitor api data
|
||||
conf = config[DOMAIN]
|
||||
|
||||
try:
|
||||
ncm = NextcloudMonitor(conf[CONF_URL], conf[CONF_USERNAME], conf[CONF_PASSWORD])
|
||||
except NextcloudMonitorError:
|
||||
_LOGGER.error("Nextcloud setup failed - Check configuration")
|
||||
|
||||
hass.data[DOMAIN] = get_data_points(ncm.data)
|
||||
hass.data[DOMAIN]["instance"] = conf[CONF_URL]
|
||||
|
||||
def nextcloud_update(event_time):
|
||||
"""Update data from nextcloud api."""
|
||||
try:
|
||||
ncm.update()
|
||||
except NextcloudMonitorError:
|
||||
_LOGGER.error("Nextcloud update failed")
|
||||
return False
|
||||
|
||||
hass.data[DOMAIN] = get_data_points(ncm.data)
|
||||
|
||||
# Update sensors on time interval
|
||||
track_time_interval(hass, nextcloud_update, conf[CONF_SCAN_INTERVAL])
|
||||
|
||||
for component in NEXTCLOUD_COMPONENTS:
|
||||
discovery.load_platform(hass, component, DOMAIN, {}, config)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# Use recursion to create list of sensors & values based on nextcloud api data
|
||||
def get_data_points(api_data, key_path="", leaf=False):
|
||||
"""Use Recursion to discover data-points and values.
|
||||
|
||||
Get dictionary of data-points by recursing through dict returned by api until
|
||||
the dictionary value does not contain another dictionary and use the
|
||||
resulting path of dictionary keys and resulting value as the name/value
|
||||
for the data-point.
|
||||
|
||||
returns: dictionary of data-point/values
|
||||
"""
|
||||
result = {}
|
||||
for key, value in api_data.items():
|
||||
if isinstance(value, dict):
|
||||
if leaf:
|
||||
key_path = f"{key}_"
|
||||
if not leaf:
|
||||
key_path += f"{key}_"
|
||||
leaf = True
|
||||
result.update(get_data_points(value, key_path, leaf))
|
||||
else:
|
||||
result[f"{DOMAIN}_{key_path}{key}"] = value
|
||||
leaf = False
|
||||
return result
|
52
homeassistant/components/nextcloud/binary_sensor.py
Normal file
52
homeassistant/components/nextcloud/binary_sensor.py
Normal file
@ -0,0 +1,52 @@
|
||||
"""Summary binary data from Nextcoud."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||
|
||||
from . import BINARY_SENSORS, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Nextcloud sensors."""
|
||||
if discovery_info is None:
|
||||
return
|
||||
binary_sensors = []
|
||||
for name in hass.data[DOMAIN]:
|
||||
if name in BINARY_SENSORS:
|
||||
binary_sensors.append(NextcloudBinarySensor(name))
|
||||
add_entities(binary_sensors, True)
|
||||
|
||||
|
||||
class NextcloudBinarySensor(BinarySensorDevice):
|
||||
"""Represents a Nextcloud binary sensor."""
|
||||
|
||||
def __init__(self, item):
|
||||
"""Initialize the Nextcloud binary sensor."""
|
||||
self._name = item
|
||||
self._is_on = None
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Return the icon for this binary sensor."""
|
||||
return "mdi:cloud"
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name for this binary sensor."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if the binary sensor is on."""
|
||||
return self._is_on == "yes"
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the unique ID for this binary sensor."""
|
||||
return f"{self.hass.data[DOMAIN]['instance']}#{self._name}"
|
||||
|
||||
def update(self):
|
||||
"""Update the binary sensor."""
|
||||
self._is_on = self.hass.data[DOMAIN][self._name]
|
12
homeassistant/components/nextcloud/manifest.json
Normal file
12
homeassistant/components/nextcloud/manifest.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"domain": "nextcloud",
|
||||
"name": "Nextcloud",
|
||||
"documentation": "https://www.home-assistant.io/integrations/nextcloud",
|
||||
"requirements": [
|
||||
"nextcloudmonitor==1.1.0"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": [
|
||||
"@meichthys"
|
||||
]
|
||||
}
|
52
homeassistant/components/nextcloud/sensor.py
Normal file
52
homeassistant/components/nextcloud/sensor.py
Normal file
@ -0,0 +1,52 @@
|
||||
"""Summary data from Nextcoud."""
|
||||
import logging
|
||||
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from . import DOMAIN, SENSORS
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Nextcloud sensors."""
|
||||
if discovery_info is None:
|
||||
return
|
||||
sensors = []
|
||||
for name in hass.data[DOMAIN]:
|
||||
if name in SENSORS:
|
||||
sensors.append(NextcloudSensor(name))
|
||||
add_entities(sensors, True)
|
||||
|
||||
|
||||
class NextcloudSensor(Entity):
|
||||
"""Represents a Nextcloud sensor."""
|
||||
|
||||
def __init__(self, item):
|
||||
"""Initialize the Nextcloud sensor."""
|
||||
self._name = item
|
||||
self._state = None
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Return the icon for this sensor."""
|
||||
return "mdi:cloud"
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name for this sensor."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state for this sensor."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the unique ID for this sensor."""
|
||||
return f"{self.hass.data[DOMAIN]['instance']}#{self._name}"
|
||||
|
||||
def update(self):
|
||||
"""Update the sensor."""
|
||||
self._state = self.hass.data[DOMAIN][self._name]
|
@ -924,6 +924,9 @@ neurio==0.3.1
|
||||
# homeassistant.components.nexia
|
||||
nexia==0.7.1
|
||||
|
||||
# homeassistant.components.nextcloud
|
||||
nextcloudmonitor==1.1.0
|
||||
|
||||
# homeassistant.components.niko_home_control
|
||||
niko-home-control==0.2.1
|
||||
|
||||
|
Reference in New Issue
Block a user