Skip to content

Commit 4f0ee20

Browse files
Add config flow to System Monitor (home-assistant#104906)
* Initial commit for config flow to System Monitor * sensors * Fixes * Works * Add import * entity_registry_enabled_default = False * entity_category = diagnostic * Create issue * issue in config flow * Tests * test requirement * codeowner * Fix names * processes * Fix type * reviews * get info during startup once * Select process * Legacy import of resources * requirements * Allow custom * Fix tests * strings * strings * Always enable process sensors * Fix docstrings * skip remove sensors if no sensors * Modify sensors * Fix tests
1 parent 2cd6c2b commit 4f0ee20

15 files changed

+687
-24
lines changed

.coveragerc

+2
Original file line numberDiff line numberDiff line change
@@ -1305,7 +1305,9 @@ omit =
13051305
homeassistant/components/system_bridge/notify.py
13061306
homeassistant/components/system_bridge/sensor.py
13071307
homeassistant/components/system_bridge/update.py
1308+
homeassistant/components/systemmonitor/__init__.py
13081309
homeassistant/components/systemmonitor/sensor.py
1310+
homeassistant/components/systemmonitor/util.py
13091311
homeassistant/components/tado/__init__.py
13101312
homeassistant/components/tado/binary_sensor.py
13111313
homeassistant/components/tado/climate.py

CODEOWNERS

+2
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,8 @@ build.json @home-assistant/supervisor
12971297
/homeassistant/components/synology_srm/ @aerialls
12981298
/homeassistant/components/system_bridge/ @timmo001
12991299
/tests/components/system_bridge/ @timmo001
1300+
/homeassistant/components/systemmonitor/ @gjohansson-ST
1301+
/tests/components/systemmonitor/ @gjohansson-ST
13001302
/homeassistant/components/tado/ @michaelarnauts @chiefdragon
13011303
/tests/components/tado/ @michaelarnauts @chiefdragon
13021304
/homeassistant/components/tag/ @balloob @dmulcahey
Original file line numberDiff line numberDiff line change
@@ -1 +1,25 @@
1-
"""The systemmonitor integration."""
1+
"""The System Monitor integration."""
2+
3+
from homeassistant.config_entries import ConfigEntry
4+
from homeassistant.const import Platform
5+
from homeassistant.core import HomeAssistant
6+
7+
PLATFORMS = [Platform.SENSOR]
8+
9+
10+
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
11+
"""Set up System Monitor from a config entry."""
12+
13+
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
14+
entry.async_on_unload(entry.add_update_listener(update_listener))
15+
return True
16+
17+
18+
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
19+
"""Unload System Monitor config entry."""
20+
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
21+
22+
23+
async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
24+
"""Handle options update."""
25+
await hass.config_entries.async_reload(entry.entry_id)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
"""Adds config flow for System Monitor."""
2+
from __future__ import annotations
3+
4+
from collections.abc import Mapping
5+
from typing import Any
6+
7+
import voluptuous as vol
8+
9+
from homeassistant.components.homeassistant import DOMAIN as HOMEASSISTANT_DOMAIN
10+
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
11+
from homeassistant.core import callback
12+
from homeassistant.data_entry_flow import FlowResult
13+
from homeassistant.helpers import entity_registry as er
14+
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
15+
from homeassistant.helpers.schema_config_entry_flow import (
16+
SchemaCommonFlowHandler,
17+
SchemaConfigFlowHandler,
18+
SchemaFlowFormStep,
19+
)
20+
from homeassistant.helpers.selector import (
21+
SelectSelector,
22+
SelectSelectorConfig,
23+
SelectSelectorMode,
24+
)
25+
from homeassistant.util import slugify
26+
27+
from .const import CONF_PROCESS, DOMAIN
28+
from .util import get_all_running_processes
29+
30+
31+
async def validate_sensor_setup(
32+
handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
33+
) -> dict[str, Any]:
34+
"""Validate sensor input."""
35+
# Standard behavior is to merge the result with the options.
36+
# In this case, we want to add a sub-item so we update the options directly.
37+
sensors: dict[str, list] = handler.options.setdefault(SENSOR_DOMAIN, {})
38+
processes = sensors.setdefault(CONF_PROCESS, [])
39+
previous_processes = processes.copy()
40+
processes.clear()
41+
processes.extend(user_input[CONF_PROCESS])
42+
43+
entity_registry = er.async_get(handler.parent_handler.hass)
44+
for process in previous_processes:
45+
if process not in processes and (
46+
entity_id := entity_registry.async_get_entity_id(
47+
SENSOR_DOMAIN, DOMAIN, slugify(f"process_{process}")
48+
)
49+
):
50+
entity_registry.async_remove(entity_id)
51+
52+
return {}
53+
54+
55+
async def validate_import_sensor_setup(
56+
handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
57+
) -> dict[str, Any]:
58+
"""Validate sensor input."""
59+
# Standard behavior is to merge the result with the options.
60+
# In this case, we want to add a sub-item so we update the options directly.
61+
sensors: dict[str, list] = handler.options.setdefault(SENSOR_DOMAIN, {})
62+
import_processes: list[str] = user_input["processes"]
63+
processes = sensors.setdefault(CONF_PROCESS, [])
64+
processes.extend(import_processes)
65+
legacy_resources: list[str] = handler.options.setdefault("resources", [])
66+
legacy_resources.extend(user_input["legacy_resources"])
67+
68+
async_create_issue(
69+
handler.parent_handler.hass,
70+
HOMEASSISTANT_DOMAIN,
71+
f"deprecated_yaml_{DOMAIN}",
72+
breaks_in_ha_version="2024.7.0",
73+
is_fixable=False,
74+
is_persistent=False,
75+
issue_domain=DOMAIN,
76+
severity=IssueSeverity.WARNING,
77+
translation_key="deprecated_yaml",
78+
translation_placeholders={
79+
"domain": DOMAIN,
80+
"integration_title": "System Monitor",
81+
},
82+
)
83+
return {}
84+
85+
86+
async def get_sensor_setup_schema(handler: SchemaCommonFlowHandler) -> vol.Schema:
87+
"""Return process sensor setup schema."""
88+
hass = handler.parent_handler.hass
89+
processes = await hass.async_add_executor_job(get_all_running_processes)
90+
return vol.Schema(
91+
{
92+
vol.Required(CONF_PROCESS): SelectSelector(
93+
SelectSelectorConfig(
94+
options=processes,
95+
multiple=True,
96+
custom_value=True,
97+
mode=SelectSelectorMode.DROPDOWN,
98+
sort=True,
99+
)
100+
)
101+
}
102+
)
103+
104+
105+
async def get_suggested_value(handler: SchemaCommonFlowHandler) -> dict[str, Any]:
106+
"""Return suggested values for sensor setup."""
107+
sensors: dict[str, list] = handler.options.get(SENSOR_DOMAIN, {})
108+
processes: list[str] = sensors.get(CONF_PROCESS, [])
109+
return {CONF_PROCESS: processes}
110+
111+
112+
CONFIG_FLOW = {
113+
"user": SchemaFlowFormStep(schema=vol.Schema({})),
114+
"import": SchemaFlowFormStep(
115+
schema=vol.Schema({}),
116+
validate_user_input=validate_import_sensor_setup,
117+
),
118+
}
119+
OPTIONS_FLOW = {
120+
"init": SchemaFlowFormStep(
121+
get_sensor_setup_schema,
122+
suggested_values=get_suggested_value,
123+
validate_user_input=validate_sensor_setup,
124+
)
125+
}
126+
127+
128+
class SystemMonitorConfigFlowHandler(SchemaConfigFlowHandler, domain=DOMAIN):
129+
"""Handle a config flow for System Monitor."""
130+
131+
config_flow = CONFIG_FLOW
132+
options_flow = OPTIONS_FLOW
133+
134+
def async_config_entry_title(self, options: Mapping[str, Any]) -> str:
135+
"""Return config entry title."""
136+
return "System Monitor"
137+
138+
@callback
139+
def async_create_entry(self, data: Mapping[str, Any], **kwargs: Any) -> FlowResult:
140+
"""Finish config flow and create a config entry."""
141+
if self._async_current_entries():
142+
return self.async_abort(reason="already_configured")
143+
return super().async_create_entry(data, **kwargs)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""Constants for System Monitor."""
2+
3+
DOMAIN = "systemmonitor"
4+
5+
CONF_INDEX = "index"
6+
CONF_PROCESS = "process"
7+
8+
NETWORK_TYPES = [
9+
"network_in",
10+
"network_out",
11+
"throughput_network_in",
12+
"throughput_network_out",
13+
"packets_in",
14+
"packets_out",
15+
"ipv4_address",
16+
"ipv6_address",
17+
]

homeassistant/components/systemmonitor/manifest.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{
22
"domain": "systemmonitor",
33
"name": "System Monitor",
4-
"codeowners": [],
4+
"codeowners": ["@gjohansson-ST"],
5+
"config_flow": true,
56
"documentation": "https://www.home-assistant.io/integrations/systemmonitor",
67
"iot_class": "local_push",
78
"loggers": ["psutil"],

0 commit comments

Comments
 (0)