1 """DataUpdateCoordinators for the System monitor integration."""
3 from __future__
import annotations
5 from dataclasses
import dataclass
6 from datetime
import datetime
9 from typing
import Any, NamedTuple
11 from psutil
import Process
12 from psutil._common
import sdiskusage, shwtemp, snetio, snicaddr, sswap
13 import psutil_home_assistant
as ha_psutil
20 _LOGGER = logging.getLogger(__name__)
23 @dataclass(frozen=True, kw_only=True, slots=True)
27 disk_usage: dict[str, sdiskusage]
30 io_counters: dict[str, snetio]
31 addresses: dict[str, list[snicaddr]]
32 load: tuple[float, float, float]
33 cpu_percent: float |
None
35 processes: list[Process]
36 temperatures: dict[str, list[shwtemp]]
42 disk_usage = {k:
str(v)
for k, v
in self.disk_usage.items()}
45 io_counters = {k:
str(v)
for k, v
in self.io_counters.items()}
48 addresses = {k:
str(v)
for k, v
in self.addresses.items()}
51 temperatures = {k:
str(v)
for k, v
in self.temperatures.items()}
53 "disk_usage": disk_usage,
54 "swap":
str(self.swap),
55 "memory":
str(self.memory),
56 "io_counters": io_counters,
57 "addresses": addresses,
58 "load":
str(self.load),
59 "cpu_percent":
str(self.cpu_percent),
60 "boot_time":
str(self.boot_time),
61 "processes":
str(self.processes),
62 "temperatures": temperatures,
67 """Represents virtual memory.
69 psutil defines virtual memory by platform.
70 Create our own definition here to be platform independent.
81 """A System monitor Data Update Coordinator."""
86 psutil_wrapper: ha_psutil.PsutilWrapper,
89 """Initialize the coordinator."""
93 name=
"System Monitor update coordinator",
94 update_interval=DEFAULT_SCAN_INTERVAL,
97 self.
_psutil_psutil = psutil_wrapper.psutil
99 self.
boot_timeboot_time: datetime |
None =
None
102 self.update_subscribers: dict[tuple[str, str], set[str]] = (
107 self, arguments: list[str]
108 ) -> dict[tuple[str, str], set[str]]:
109 """Set tuples in subscribers dictionary."""
110 _disk_defaults: dict[tuple[str, str], set[str]] = {}
111 for argument
in arguments:
112 _disk_defaults[(
"disks", argument)] = set()
116 (
"memory",
""): set(),
117 (
"io_counters",
""): set(),
118 (
"addresses",
""): set(),
120 (
"cpu_percent",
""): set(),
122 (
"processes",
""): set(),
123 (
"temperatures",
""): set(),
128 _LOGGER.debug(
"Update list is: %s", self.update_subscribers)
130 _data = await self.
hasshass.async_add_executor_job(self.
update_dataupdate_data)
132 load: tuple = (
None,
None,
None)
133 if self.update_subscribers[(
"load",
"")]
or self.
_initial_update_initial_update:
134 load = os.getloadavg()
135 _LOGGER.debug(
"Load: %s", load)
137 cpu_percent: float |
None =
None
138 if self.update_subscribers[(
"cpu_percent",
"")]
or self.
_initial_update_initial_update:
139 cpu_percent = self.
_psutil_psutil.cpu_percent(interval=
None)
140 _LOGGER.debug(
"cpu_percent: %s", cpu_percent)
144 disk_usage=_data[
"disks"],
146 memory=_data[
"memory"],
147 io_counters=_data[
"io_counters"],
148 addresses=_data[
"addresses"],
150 cpu_percent=cpu_percent,
151 boot_time=_data[
"boot_time"],
152 processes=_data[
"processes"],
153 temperatures=_data[
"temperatures"],
157 """To be extended by data update coordinators."""
158 disks: dict[str, sdiskusage] = {}
160 if self.update_subscribers[(
"disks", argument)]
or self.
_initial_update_initial_update:
162 usage: sdiskusage = self.
_psutil_psutil.disk_usage(argument)
163 _LOGGER.debug(
"sdiskusagefor %s: %s", argument, usage)
164 except PermissionError
as err:
166 "No permission to access %s, error %s", argument, err
168 except OSError
as err:
169 _LOGGER.warning(
"OS error for %s, error %s", argument, err)
171 disks[argument] = usage
173 swap: sswap |
None =
None
174 if self.update_subscribers[(
"swap",
"")]
or self.
_initial_update_initial_update:
175 swap = self.
_psutil_psutil.swap_memory()
176 _LOGGER.debug(
"sswap: %s", swap)
179 if self.update_subscribers[(
"memory",
"")]
or self.
_initial_update_initial_update:
180 memory = self.
_psutil_psutil.virtual_memory()
181 _LOGGER.debug(
"memory: %s", memory)
183 memory.total, memory.available, memory.percent, memory.used, memory.free
186 io_counters: dict[str, snetio] |
None =
None
187 if self.update_subscribers[(
"io_counters",
"")]
or self.
_initial_update_initial_update:
188 io_counters = self.
_psutil_psutil.net_io_counters(pernic=
True)
189 _LOGGER.debug(
"io_counters: %s", io_counters)
191 addresses: dict[str, list[snicaddr]] |
None =
None
192 if self.update_subscribers[(
"addresses",
"")]
or self.
_initial_update_initial_update:
193 addresses = self.
_psutil_psutil.net_if_addrs()
194 _LOGGER.debug(
"ip_addresses: %s", addresses)
199 _LOGGER.debug(
"boot time: %s", self.
boot_timeboot_time)
202 if self.update_subscribers[(
"processes",
"")]
or self.
_initial_update_initial_update:
203 processes = self.
_psutil_psutil.process_iter()
204 _LOGGER.debug(
"processes: %s", processes)
205 processes =
list(processes)
207 temps: dict[str, list[shwtemp]] = {}
208 if self.update_subscribers[(
"temperatures",
"")]
or self.
_initial_update_initial_update:
210 temps = self.
_psutil_psutil.sensors_temperatures()
211 _LOGGER.debug(
"temps: %s", temps)
212 except AttributeError:
213 _LOGGER.debug(
"OS does not provide temperature sensors")
219 "io_counters": io_counters,
220 "addresses": addresses,
222 "processes": processes,
223 "temperatures": temps,
dict[str, Any] as_dict(self)
dict[tuple[str, str], set[str]] set_subscribers_tuples(self, list[str] arguments)
dict[str, Any] update_data(self)
None __init__(self, HomeAssistant hass, ha_psutil.PsutilWrapper psutil_wrapper, list[str] arguments)
SensorData _async_update_data(self)