diff --git a/homeassistant/components/glances/__init__.py b/homeassistant/components/glances/__init__.py index 2b52cdeef8b..0747db89cd2 100644 --- a/homeassistant/components/glances/__init__.py +++ b/homeassistant/components/glances/__init__.py @@ -129,7 +129,7 @@ class GlancesData: def get_api(hass, entry): """Return the api from glances_api.""" params = entry.copy() - params.pop(CONF_NAME) + params.pop(CONF_NAME, None) verify_ssl = params.pop(CONF_VERIFY_SSL, True) httpx_client = get_async_client(hass, verify_ssl=verify_ssl) return Glances(httpx_client=httpx_client, **params) diff --git a/homeassistant/components/glances/config_flow.py b/homeassistant/components/glances/config_flow.py index a4a345116eb..16c33182c25 100644 --- a/homeassistant/components/glances/config_flow.py +++ b/homeassistant/components/glances/config_flow.py @@ -1,13 +1,14 @@ """Config flow for Glances.""" from __future__ import annotations +from typing import Any + import glances_api import voluptuous as vol from homeassistant import config_entries, core, exceptions from homeassistant.const import ( CONF_HOST, - CONF_NAME, CONF_PASSWORD, CONF_PORT, CONF_SCAN_INTERVAL, @@ -18,10 +19,10 @@ from homeassistant.const import ( from homeassistant.core import callback from . import get_api +from ...data_entry_flow import FlowResult from .const import ( CONF_VERSION, DEFAULT_HOST, - DEFAULT_NAME, DEFAULT_PORT, DEFAULT_SCAN_INTERVAL, DEFAULT_VERSION, @@ -31,7 +32,6 @@ from .const import ( DATA_SCHEMA = vol.Schema( { - vol.Required(CONF_NAME, default=DEFAULT_NAME): str, vol.Required(CONF_HOST, default=DEFAULT_HOST): str, vol.Optional(CONF_USERNAME): str, vol.Optional(CONF_PASSWORD): str, @@ -67,7 +67,7 @@ class GlancesFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Get the options flow for this handler.""" return GlancesOptionsFlowHandler(config_entry) - async def async_step_user(self, user_input=None): + async def async_step_user(self, user_input: dict[str, Any] = None) -> FlowResult: """Handle the initial step.""" errors = {} if user_input is not None: @@ -75,7 +75,7 @@ class GlancesFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): try: await validate_input(self.hass, user_input) return self.async_create_entry( - title=user_input[CONF_NAME], data=user_input + title=user_input[CONF_HOST], data=user_input ) except CannotConnect: errors["base"] = "cannot_connect" @@ -94,7 +94,7 @@ class GlancesOptionsFlowHandler(config_entries.OptionsFlow): """Initialize Glances options flow.""" self.config_entry = config_entry - async def async_step_init(self, user_input=None): + async def async_step_init(self, user_input: dict[str, Any] = None) -> FlowResult: """Manage the Glances options.""" if user_input is not None: return self.async_create_entry(title="", data=user_input) diff --git a/homeassistant/components/glances/const.py b/homeassistant/components/glances/const.py index d28c7395a43..92fe8ba91f6 100644 --- a/homeassistant/components/glances/const.py +++ b/homeassistant/components/glances/const.py @@ -1,21 +1,11 @@ """Constants for Glances component.""" -from __future__ import annotations -from dataclasses import dataclass import sys -from homeassistant.components.sensor import ( - SensorDeviceClass, - SensorEntityDescription, - SensorStateClass, -) -from homeassistant.const import DATA_GIBIBYTES, DATA_MEBIBYTES, PERCENTAGE, TEMP_CELSIUS - DOMAIN = "glances" CONF_VERSION = "version" DEFAULT_HOST = "localhost" -DEFAULT_NAME = "Glances" DEFAULT_PORT = 61208 DEFAULT_VERSION = 3 DEFAULT_SCAN_INTERVAL = 60 @@ -27,199 +17,3 @@ if sys.maxsize > 2**32: CPU_ICON = "mdi:cpu-64-bit" else: CPU_ICON = "mdi:cpu-32-bit" - - -@dataclass -class GlancesSensorEntityDescription(SensorEntityDescription): - """Describe Glances sensor entity.""" - - type: str | None = None - name_suffix: str | None = None - - -SENSOR_TYPES: tuple[GlancesSensorEntityDescription, ...] = ( - GlancesSensorEntityDescription( - key="disk_use_percent", - type="fs", - name_suffix="used percent", - native_unit_of_measurement=PERCENTAGE, - icon="mdi:harddisk", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="disk_use", - type="fs", - name_suffix="used", - native_unit_of_measurement=DATA_GIBIBYTES, - icon="mdi:harddisk", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="disk_free", - type="fs", - name_suffix="free", - native_unit_of_measurement=DATA_GIBIBYTES, - icon="mdi:harddisk", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="memory_use_percent", - type="mem", - name_suffix="RAM used percent", - native_unit_of_measurement=PERCENTAGE, - icon="mdi:memory", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="memory_use", - type="mem", - name_suffix="RAM used", - native_unit_of_measurement=DATA_MEBIBYTES, - icon="mdi:memory", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="memory_free", - type="mem", - name_suffix="RAM free", - native_unit_of_measurement=DATA_MEBIBYTES, - icon="mdi:memory", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="swap_use_percent", - type="memswap", - name_suffix="Swap used percent", - native_unit_of_measurement=PERCENTAGE, - icon="mdi:memory", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="swap_use", - type="memswap", - name_suffix="Swap used", - native_unit_of_measurement=DATA_GIBIBYTES, - icon="mdi:memory", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="swap_free", - type="memswap", - name_suffix="Swap free", - native_unit_of_measurement=DATA_GIBIBYTES, - icon="mdi:memory", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="processor_load", - type="load", - name_suffix="CPU load", - icon=CPU_ICON, - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="process_running", - type="processcount", - name_suffix="Running", - icon=CPU_ICON, - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="process_total", - type="processcount", - name_suffix="Total", - icon=CPU_ICON, - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="process_thread", - type="processcount", - name_suffix="Thread", - icon=CPU_ICON, - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="process_sleeping", - type="processcount", - name_suffix="Sleeping", - icon=CPU_ICON, - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="cpu_use_percent", - type="cpu", - name_suffix="CPU used", - native_unit_of_measurement=PERCENTAGE, - icon=CPU_ICON, - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="temperature_core", - type="sensors", - name_suffix="Temperature", - native_unit_of_measurement=TEMP_CELSIUS, - device_class=SensorDeviceClass.TEMPERATURE, - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="temperature_hdd", - type="sensors", - name_suffix="Temperature", - native_unit_of_measurement=TEMP_CELSIUS, - device_class=SensorDeviceClass.TEMPERATURE, - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="fan_speed", - type="sensors", - name_suffix="Fan speed", - native_unit_of_measurement="RPM", - icon="mdi:fan", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="battery", - type="sensors", - name_suffix="Charge", - native_unit_of_measurement=PERCENTAGE, - icon="mdi:battery", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="docker_active", - type="docker", - name_suffix="Containers active", - icon="mdi:docker", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="docker_cpu_use", - type="docker", - name_suffix="Containers CPU used", - native_unit_of_measurement=PERCENTAGE, - icon="mdi:docker", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="docker_memory_use", - type="docker", - name_suffix="Containers RAM used", - native_unit_of_measurement=DATA_MEBIBYTES, - icon="mdi:docker", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="used", - type="raid", - name_suffix="Raid used", - icon="mdi:harddisk", - state_class=SensorStateClass.MEASUREMENT, - ), - GlancesSensorEntityDescription( - key="available", - type="raid", - name_suffix="Raid available", - icon="mdi:harddisk", - state_class=SensorStateClass.MEASUREMENT, - ), -) diff --git a/homeassistant/components/glances/sensor.py b/homeassistant/components/glances/sensor.py index e37cfaca211..af6f307ef3a 100644 --- a/homeassistant/components/glances/sensor.py +++ b/homeassistant/components/glances/sensor.py @@ -1,7 +1,25 @@ """Support gathering system information of hosts which are running glances.""" -from homeassistant.components.sensor import SensorEntity +from __future__ import annotations + +from dataclasses import dataclass + +from homeassistant.components.sensor import ( + SensorDeviceClass, + SensorEntity, + SensorEntityDescription, + SensorStateClass, +) from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_NAME, STATE_UNAVAILABLE, Platform +from homeassistant.const import ( + CONF_HOST, + CONF_NAME, + DATA_GIBIBYTES, + DATA_MEBIBYTES, + PERCENTAGE, + STATE_UNAVAILABLE, + TEMP_CELSIUS, + Platform, +) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import entity_registry from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -9,7 +27,203 @@ from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import GlancesData -from .const import DATA_UPDATED, DOMAIN, SENSOR_TYPES, GlancesSensorEntityDescription +from .const import CPU_ICON, DATA_UPDATED, DOMAIN + + +@dataclass +class GlancesSensorEntityDescription(SensorEntityDescription): + """Describe Glances sensor entity.""" + + type: str | None = None + name_suffix: str | None = None + + +SENSOR_TYPES: tuple[GlancesSensorEntityDescription, ...] = ( + GlancesSensorEntityDescription( + key="disk_use_percent", + type="fs", + name_suffix="used percent", + native_unit_of_measurement=PERCENTAGE, + icon="mdi:harddisk", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="disk_use", + type="fs", + name_suffix="used", + native_unit_of_measurement=DATA_GIBIBYTES, + icon="mdi:harddisk", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="disk_free", + type="fs", + name_suffix="free", + native_unit_of_measurement=DATA_GIBIBYTES, + icon="mdi:harddisk", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="memory_use_percent", + type="mem", + name_suffix="RAM used percent", + native_unit_of_measurement=PERCENTAGE, + icon="mdi:memory", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="memory_use", + type="mem", + name_suffix="RAM used", + native_unit_of_measurement=DATA_MEBIBYTES, + icon="mdi:memory", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="memory_free", + type="mem", + name_suffix="RAM free", + native_unit_of_measurement=DATA_MEBIBYTES, + icon="mdi:memory", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="swap_use_percent", + type="memswap", + name_suffix="Swap used percent", + native_unit_of_measurement=PERCENTAGE, + icon="mdi:memory", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="swap_use", + type="memswap", + name_suffix="Swap used", + native_unit_of_measurement=DATA_GIBIBYTES, + icon="mdi:memory", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="swap_free", + type="memswap", + name_suffix="Swap free", + native_unit_of_measurement=DATA_GIBIBYTES, + icon="mdi:memory", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="processor_load", + type="load", + name_suffix="CPU load", + icon=CPU_ICON, + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="process_running", + type="processcount", + name_suffix="Running", + icon=CPU_ICON, + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="process_total", + type="processcount", + name_suffix="Total", + icon=CPU_ICON, + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="process_thread", + type="processcount", + name_suffix="Thread", + icon=CPU_ICON, + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="process_sleeping", + type="processcount", + name_suffix="Sleeping", + icon=CPU_ICON, + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="cpu_use_percent", + type="cpu", + name_suffix="CPU used", + native_unit_of_measurement=PERCENTAGE, + icon=CPU_ICON, + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="temperature_core", + type="sensors", + name_suffix="Temperature", + native_unit_of_measurement=TEMP_CELSIUS, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="temperature_hdd", + type="sensors", + name_suffix="Temperature", + native_unit_of_measurement=TEMP_CELSIUS, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="fan_speed", + type="sensors", + name_suffix="Fan speed", + native_unit_of_measurement="RPM", + icon="mdi:fan", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="battery", + type="sensors", + name_suffix="Charge", + native_unit_of_measurement=PERCENTAGE, + icon="mdi:battery", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="docker_active", + type="docker", + name_suffix="Containers active", + icon="mdi:docker", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="docker_cpu_use", + type="docker", + name_suffix="Containers CPU used", + native_unit_of_measurement=PERCENTAGE, + icon="mdi:docker", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="docker_memory_use", + type="docker", + name_suffix="Containers RAM used", + native_unit_of_measurement=DATA_MEBIBYTES, + icon="mdi:docker", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="used", + type="raid", + name_suffix="Raid used", + icon="mdi:harddisk", + state_class=SensorStateClass.MEASUREMENT, + ), + GlancesSensorEntityDescription( + key="available", + type="raid", + name_suffix="Raid available", + icon="mdi:harddisk", + state_class=SensorStateClass.MEASUREMENT, + ), +) async def async_setup_entry( @@ -20,7 +234,7 @@ async def async_setup_entry( """Set up the Glances sensors.""" client: GlancesData = hass.data[DOMAIN][config_entry.entry_id] - name = config_entry.data[CONF_NAME] + name = config_entry.data.get(CONF_NAME) dev = [] @callback @@ -102,11 +316,13 @@ class GlancesSensor(SensorEntity): """Implementation of a Glances sensor.""" entity_description: GlancesSensorEntityDescription + _attr_has_entity_name = True + _attr_should_poll = False def __init__( self, glances_data: GlancesData, - name: str, + name: str | None, sensor_name_prefix: str, description: GlancesSensorEntityDescription, ) -> None: @@ -117,11 +333,11 @@ class GlancesSensor(SensorEntity): self.unsub_update = None self.entity_description = description - self._attr_name = f"{name} {sensor_name_prefix} {description.name_suffix}" + self._attr_name = f"{sensor_name_prefix} {description.name_suffix}" self._attr_device_info = DeviceInfo( identifiers={(DOMAIN, glances_data.config_entry.entry_id)}, manufacturer="Glances", - name=name, + name=name or glances_data.config_entry.data[CONF_HOST], ) self._attr_unique_id = f"{self.glances_data.config_entry.entry_id}-{sensor_name_prefix}-{description.key}" @@ -135,11 +351,6 @@ class GlancesSensor(SensorEntity): """Return the state of the resources.""" return self._state - @property - def should_poll(self): - """Return the polling requirement for this sensor.""" - return False - async def async_added_to_hass(self): """Handle entity which will be added.""" self.unsub_update = async_dispatcher_connect( diff --git a/homeassistant/components/glances/strings.json b/homeassistant/components/glances/strings.json index 5d96b1ae57e..11c9792f364 100644 --- a/homeassistant/components/glances/strings.json +++ b/homeassistant/components/glances/strings.json @@ -2,9 +2,7 @@ "config": { "step": { "user": { - "title": "Setup Glances", "data": { - "name": "[%key:common::config_flow::data::name%]", "host": "[%key:common::config_flow::data::host%]", "username": "[%key:common::config_flow::data::username%]", "password": "[%key:common::config_flow::data::password%]", diff --git a/homeassistant/components/glances/translations/en.json b/homeassistant/components/glances/translations/en.json index 87c53c3cf48..aa7005bddea 100644 --- a/homeassistant/components/glances/translations/en.json +++ b/homeassistant/components/glances/translations/en.json @@ -11,15 +11,13 @@ "user": { "data": { "host": "Host", - "name": "Name", "password": "Password", "port": "Port", "ssl": "Uses an SSL certificate", "username": "Username", "verify_ssl": "Verify SSL certificate", "version": "Glances API Version (2 or 3)" - }, - "title": "Setup Glances" + } } } }, diff --git a/tests/components/glances/test_config_flow.py b/tests/components/glances/test_config_flow.py index d996c3af533..8ee669ae84e 100644 --- a/tests/components/glances/test_config_flow.py +++ b/tests/components/glances/test_config_flow.py @@ -2,6 +2,7 @@ from unittest.mock import patch from glances_api import exceptions +import pytest from homeassistant import config_entries, data_entry_flow from homeassistant.components import glances @@ -18,7 +19,6 @@ VERSION = 3 SCAN_INTERVAL = 10 DEMO_USER_INPUT = { - "name": NAME, "host": HOST, "username": USERNAME, "password": PASSWORD, @@ -29,6 +29,13 @@ DEMO_USER_INPUT = { } +@pytest.fixture(autouse=True) +def glances_setup_fixture(): + """Mock transmission entry setup.""" + with patch("homeassistant.components.glances.async_setup_entry", return_value=True): + yield + + async def test_form(hass): """Test config entry configured successfully.""" @@ -45,7 +52,7 @@ async def test_form(hass): ) assert result["type"] == "create_entry" - assert result["title"] == NAME + assert result["title"] == HOST assert result["data"] == DEMO_USER_INPUT