2019-04-03 15:40:03 +00:00
|
|
|
"""Support gathering system information of hosts which are running glances."""
|
2021-03-22 18:45:17 +00:00
|
|
|
from homeassistant.components.sensor import SensorEntity
|
2022-01-03 18:13:59 +00:00
|
|
|
from homeassistant.config_entries import ConfigEntry
|
2019-10-21 08:17:21 +00:00
|
|
|
from homeassistant.const import CONF_NAME, STATE_UNAVAILABLE
|
2022-01-03 18:13:59 +00:00
|
|
|
from homeassistant.core import HomeAssistant, callback
|
2019-10-21 08:17:21 +00:00
|
|
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
2022-06-24 23:23:26 +00:00
|
|
|
from homeassistant.helpers.entity import DeviceInfo
|
2022-01-03 18:13:59 +00:00
|
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
2016-08-20 22:40:16 +00:00
|
|
|
|
2022-06-26 10:33:11 +00:00
|
|
|
from . import GlancesData
|
2021-07-27 15:24:18 +00:00
|
|
|
from .const import DATA_UPDATED, DOMAIN, SENSOR_TYPES, GlancesSensorEntityDescription
|
2015-09-14 12:08:30 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
|
2022-01-03 18:13:59 +00:00
|
|
|
async def async_setup_entry(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
config_entry: ConfigEntry,
|
|
|
|
async_add_entities: AddEntitiesCallback,
|
|
|
|
) -> None:
|
2019-10-21 08:17:21 +00:00
|
|
|
"""Set up the Glances sensors."""
|
2015-09-14 12:08:30 +00:00
|
|
|
|
2020-02-10 23:02:14 +00:00
|
|
|
client = hass.data[DOMAIN][config_entry.entry_id]
|
2019-10-21 08:17:21 +00:00
|
|
|
name = config_entry.data[CONF_NAME]
|
2015-09-14 12:08:30 +00:00
|
|
|
dev = []
|
2020-02-10 23:02:14 +00:00
|
|
|
|
2021-07-27 15:24:18 +00:00
|
|
|
for description in SENSOR_TYPES:
|
|
|
|
if description.type == "fs":
|
2021-03-27 11:39:37 +00:00
|
|
|
# fs will provide a list of disks attached
|
2021-07-27 15:24:18 +00:00
|
|
|
for disk in client.api.data[description.type]:
|
2021-03-27 11:39:37 +00:00
|
|
|
dev.append(
|
|
|
|
GlancesSensor(
|
|
|
|
client,
|
|
|
|
name,
|
|
|
|
disk["mnt_point"],
|
2021-07-27 15:24:18 +00:00
|
|
|
description,
|
2021-03-27 11:39:37 +00:00
|
|
|
)
|
|
|
|
)
|
2021-07-27 15:24:18 +00:00
|
|
|
elif description.type == "sensors":
|
2021-03-27 11:39:37 +00:00
|
|
|
# sensors will provide temp for different devices
|
2021-07-27 15:24:18 +00:00
|
|
|
for sensor in client.api.data[description.type]:
|
|
|
|
if sensor["type"] == description.key:
|
2020-02-10 23:02:14 +00:00
|
|
|
dev.append(
|
|
|
|
GlancesSensor(
|
|
|
|
client,
|
|
|
|
name,
|
2021-03-27 11:39:37 +00:00
|
|
|
sensor["label"],
|
2021-07-27 15:24:18 +00:00
|
|
|
description,
|
2020-02-10 23:02:14 +00:00
|
|
|
)
|
|
|
|
)
|
2021-09-28 08:04:08 +00:00
|
|
|
elif description.type == "raid":
|
|
|
|
for raid_device in client.api.data[description.type]:
|
2022-06-26 10:33:11 +00:00
|
|
|
dev.append(GlancesSensor(client, name, raid_device, description))
|
2021-07-27 15:24:18 +00:00
|
|
|
elif client.api.data[description.type]:
|
2021-03-27 11:39:37 +00:00
|
|
|
dev.append(
|
|
|
|
GlancesSensor(
|
|
|
|
client,
|
|
|
|
name,
|
|
|
|
"",
|
2021-07-27 15:24:18 +00:00
|
|
|
description,
|
2020-02-10 23:02:14 +00:00
|
|
|
)
|
2021-03-27 11:39:37 +00:00
|
|
|
)
|
2015-09-14 12:08:30 +00:00
|
|
|
|
2018-08-24 14:37:30 +00:00
|
|
|
async_add_entities(dev, True)
|
2015-09-14 12:08:30 +00:00
|
|
|
|
|
|
|
|
2021-03-22 18:45:17 +00:00
|
|
|
class GlancesSensor(SensorEntity):
|
2016-03-08 15:46:34 +00:00
|
|
|
"""Implementation of a Glances sensor."""
|
2015-09-14 12:08:30 +00:00
|
|
|
|
2021-07-27 15:24:18 +00:00
|
|
|
entity_description: GlancesSensorEntityDescription
|
|
|
|
|
2020-02-10 23:02:14 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
2022-06-26 10:33:11 +00:00
|
|
|
glances_data: GlancesData,
|
|
|
|
name: str,
|
|
|
|
sensor_name_prefix: str,
|
2021-07-27 15:24:18 +00:00
|
|
|
description: GlancesSensorEntityDescription,
|
2022-06-26 10:33:11 +00:00
|
|
|
) -> None:
|
2016-03-08 15:46:34 +00:00
|
|
|
"""Initialize the sensor."""
|
2019-10-21 08:17:21 +00:00
|
|
|
self.glances_data = glances_data
|
2020-02-10 23:02:14 +00:00
|
|
|
self._sensor_name_prefix = sensor_name_prefix
|
2017-10-23 11:12:14 +00:00
|
|
|
self._state = None
|
2020-02-10 23:02:14 +00:00
|
|
|
self.unsub_update = None
|
2015-09-14 12:08:30 +00:00
|
|
|
|
2021-07-27 15:24:18 +00:00
|
|
|
self.entity_description = description
|
|
|
|
self._attr_name = f"{name} {sensor_name_prefix} {description.name_suffix}"
|
2022-06-24 23:23:26 +00:00
|
|
|
self._attr_device_info = DeviceInfo(
|
2022-06-26 10:33:11 +00:00
|
|
|
identifiers={(DOMAIN, glances_data.config_entry.entry_id)},
|
2022-06-24 23:23:26 +00:00
|
|
|
manufacturer="Glances",
|
|
|
|
name=name,
|
|
|
|
)
|
2019-10-21 08:17:21 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def unique_id(self):
|
|
|
|
"""Set unique_id for sensor."""
|
|
|
|
return f"{self.glances_data.host}-{self.name}"
|
2015-09-14 12:08:30 +00:00
|
|
|
|
2017-06-21 20:45:15 +00:00
|
|
|
@property
|
|
|
|
def available(self):
|
|
|
|
"""Could the device be accessed during the last update call."""
|
2019-10-21 08:17:21 +00:00
|
|
|
return self.glances_data.available
|
2017-06-21 20:45:15 +00:00
|
|
|
|
2015-09-14 12:08:30 +00:00
|
|
|
@property
|
2021-08-12 12:23:56 +00:00
|
|
|
def native_value(self):
|
2016-03-08 15:46:34 +00:00
|
|
|
"""Return the state of the resources."""
|
2017-06-27 08:56:25 +00:00
|
|
|
return self._state
|
|
|
|
|
2019-10-21 08:17:21 +00:00
|
|
|
@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."""
|
2020-02-10 23:02:14 +00:00
|
|
|
self.unsub_update = async_dispatcher_connect(
|
2019-10-21 08:17:21 +00:00
|
|
|
self.hass, DATA_UPDATED, self._schedule_immediate_update
|
|
|
|
)
|
|
|
|
|
|
|
|
@callback
|
|
|
|
def _schedule_immediate_update(self):
|
|
|
|
self.async_schedule_update_ha_state(True)
|
|
|
|
|
2020-02-10 23:02:14 +00:00
|
|
|
async def will_remove_from_hass(self):
|
|
|
|
"""Unsubscribe from update dispatcher."""
|
|
|
|
if self.unsub_update:
|
|
|
|
self.unsub_update()
|
|
|
|
self.unsub_update = None
|
|
|
|
|
2021-04-25 10:38:40 +00:00
|
|
|
async def async_update(self): # noqa: C901
|
2017-06-27 08:56:25 +00:00
|
|
|
"""Get the latest data from REST API."""
|
2021-10-17 18:05:11 +00:00
|
|
|
if (value := self.glances_data.api.data) is None:
|
2020-02-10 23:02:14 +00:00
|
|
|
return
|
2015-09-14 12:08:30 +00:00
|
|
|
|
2021-07-27 15:24:18 +00:00
|
|
|
if self.entity_description.type == "fs":
|
2021-03-27 11:39:37 +00:00
|
|
|
for var in value["fs"]:
|
|
|
|
if var["mnt_point"] == self._sensor_name_prefix:
|
|
|
|
disk = var
|
|
|
|
break
|
2021-07-27 15:24:18 +00:00
|
|
|
if self.entity_description.key == "disk_free":
|
2017-03-27 20:11:15 +00:00
|
|
|
try:
|
2022-02-05 13:19:37 +00:00
|
|
|
self._state = round(disk["free"] / 1024**3, 1)
|
2017-03-27 20:11:15 +00:00
|
|
|
except KeyError:
|
2021-03-27 11:39:37 +00:00
|
|
|
self._state = round(
|
2022-02-05 13:19:37 +00:00
|
|
|
(disk["size"] - disk["used"]) / 1024**3,
|
2021-03-27 11:39:37 +00:00
|
|
|
1,
|
|
|
|
)
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "disk_use":
|
2022-02-05 13:19:37 +00:00
|
|
|
self._state = round(disk["used"] / 1024**3, 1)
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "disk_use_percent":
|
2021-03-27 11:39:37 +00:00
|
|
|
self._state = disk["percent"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "battery":
|
2021-03-27 11:39:37 +00:00
|
|
|
for sensor in value["sensors"]:
|
|
|
|
if (
|
|
|
|
sensor["type"] == "battery"
|
|
|
|
and sensor["label"] == self._sensor_name_prefix
|
|
|
|
):
|
|
|
|
self._state = sensor["value"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "fan_speed":
|
2021-03-27 11:39:37 +00:00
|
|
|
for sensor in value["sensors"]:
|
|
|
|
if (
|
|
|
|
sensor["type"] == "fan_speed"
|
|
|
|
and sensor["label"] == self._sensor_name_prefix
|
|
|
|
):
|
|
|
|
self._state = sensor["value"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "temperature_core":
|
2021-03-27 11:39:37 +00:00
|
|
|
for sensor in value["sensors"]:
|
|
|
|
if (
|
|
|
|
sensor["type"] == "temperature_core"
|
|
|
|
and sensor["label"] == self._sensor_name_prefix
|
|
|
|
):
|
|
|
|
self._state = sensor["value"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "temperature_hdd":
|
2021-03-27 11:39:37 +00:00
|
|
|
for sensor in value["sensors"]:
|
|
|
|
if (
|
|
|
|
sensor["type"] == "temperature_hdd"
|
|
|
|
and sensor["label"] == self._sensor_name_prefix
|
|
|
|
):
|
|
|
|
self._state = sensor["value"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "memory_use_percent":
|
2021-03-27 11:39:37 +00:00
|
|
|
self._state = value["mem"]["percent"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "memory_use":
|
2022-02-05 13:19:37 +00:00
|
|
|
self._state = round(value["mem"]["used"] / 1024**2, 1)
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "memory_free":
|
2022-02-05 13:19:37 +00:00
|
|
|
self._state = round(value["mem"]["free"] / 1024**2, 1)
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "swap_use_percent":
|
2021-03-27 11:39:37 +00:00
|
|
|
self._state = value["memswap"]["percent"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "swap_use":
|
2022-02-05 13:19:37 +00:00
|
|
|
self._state = round(value["memswap"]["used"] / 1024**3, 1)
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "swap_free":
|
2022-02-05 13:19:37 +00:00
|
|
|
self._state = round(value["memswap"]["free"] / 1024**3, 1)
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "processor_load":
|
2021-03-27 11:39:37 +00:00
|
|
|
# Windows systems don't provide load details
|
|
|
|
try:
|
|
|
|
self._state = value["load"]["min15"]
|
|
|
|
except KeyError:
|
|
|
|
self._state = value["cpu"]["total"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "process_running":
|
2021-03-27 11:39:37 +00:00
|
|
|
self._state = value["processcount"]["running"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "process_total":
|
2021-03-27 11:39:37 +00:00
|
|
|
self._state = value["processcount"]["total"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "process_thread":
|
2021-03-27 11:39:37 +00:00
|
|
|
self._state = value["processcount"]["thread"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "process_sleeping":
|
2021-03-27 11:39:37 +00:00
|
|
|
self._state = value["processcount"]["sleeping"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "cpu_use_percent":
|
2021-03-27 11:39:37 +00:00
|
|
|
self._state = value["quicklook"]["cpu"]
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "docker_active":
|
2021-03-27 11:39:37 +00:00
|
|
|
count = 0
|
|
|
|
try:
|
|
|
|
for container in value["docker"]["containers"]:
|
|
|
|
if container["Status"] == "running" or "Up" in container["Status"]:
|
|
|
|
count += 1
|
|
|
|
self._state = count
|
|
|
|
except KeyError:
|
|
|
|
self._state = count
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "docker_cpu_use":
|
2021-03-27 11:39:37 +00:00
|
|
|
cpu_use = 0.0
|
|
|
|
try:
|
|
|
|
for container in value["docker"]["containers"]:
|
|
|
|
if container["Status"] == "running" or "Up" in container["Status"]:
|
|
|
|
cpu_use += container["cpu"]["total"]
|
|
|
|
self._state = round(cpu_use, 1)
|
|
|
|
except KeyError:
|
|
|
|
self._state = STATE_UNAVAILABLE
|
2021-07-27 15:24:18 +00:00
|
|
|
elif self.entity_description.key == "docker_memory_use":
|
2021-03-27 11:39:37 +00:00
|
|
|
mem_use = 0.0
|
|
|
|
try:
|
|
|
|
for container in value["docker"]["containers"]:
|
|
|
|
if container["Status"] == "running" or "Up" in container["Status"]:
|
|
|
|
mem_use += container["memory"]["usage"]
|
2022-02-05 13:19:37 +00:00
|
|
|
self._state = round(mem_use / 1024**2, 1)
|
2021-03-27 11:39:37 +00:00
|
|
|
except KeyError:
|
|
|
|
self._state = STATE_UNAVAILABLE
|
2021-09-28 08:04:08 +00:00
|
|
|
elif self.entity_description.type == "raid":
|
|
|
|
for raid_device, raid in value["raid"].items():
|
|
|
|
if raid_device == self._sensor_name_prefix:
|
|
|
|
self._state = raid[self.entity_description.key]
|