Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ jobs:
echo "Failed to restore Python virtual environment from cache"
exit 1
- name: Download all coverage artifacts
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
- name: Combine coverage results
run: |
. venv/bin/activate
Expand Down
8 changes: 8 additions & 0 deletions homeassistant/components/proxmoxve/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
CONF_NODES = "nodes"
CONF_VMS = "vms"
CONF_CONTAINERS = "containers"
CONF_STORAGE = "storage"

DEFAULT_PORT = 8006
DEFAULT_REALM = "pam"
Expand Down Expand Up @@ -58,6 +59,9 @@
vol.Optional(CONF_CONTAINERS, default=[]): [
cv.positive_int
],
vol.Optional(CONF_STORAGE, default=[]): [
cv.string
],
}
)
],
Expand Down Expand Up @@ -107,6 +111,9 @@ def setup(hass, config):
hass.helpers.discovery.load_platform(
"binary_sensor", DOMAIN, {"entries": config[DOMAIN]}, config
)
hass.helpers.discovery.load_platform(
"sensor", DOMAIN, {"entries": config[DOMAIN]}, config
)
return True

return False
Expand All @@ -117,6 +124,7 @@ class ProxmoxItemType(Enum):

qemu = 0
lxc = 1
storage = 2


class ProxmoxClient:
Expand Down
117 changes: 117 additions & 0 deletions homeassistant/components/proxmoxve/sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"""Sensor to read Proxmox VE data."""
import logging

from homeassistant.const import ATTR_ATTRIBUTION, CONF_HOST, CONF_PORT
from homeassistant.helpers.entity import Entity

from . import CONF_NODES, CONF_STORAGE, PROXMOX_CLIENTS, ProxmoxItemType

ATTRIBUTION = "Data provided by Proxmox VE"
_LOGGER = logging.getLogger(__name__)


def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the sensor platform."""

sensors = []

for entry in discovery_info["entries"]:
port = entry[CONF_PORT]

for node in entry[CONF_NODES]:
for storage in node[CONF_STORAGE]:
sensors.append(
ProxmoxSensor(
hass.data[PROXMOX_CLIENTS][f"{entry[CONF_HOST]}:{port}"],
node["node"],
ProxmoxItemType.storage,
storage,
)
)

add_entities(sensors, True)


class ProxmoxSensor(Entity):
"""A binary sensor for reading Proxmox VE data."""

def __init__(self, proxmox_client, item_node, item_type, item_name):
"""Initialize the binary sensor."""
self._proxmox_client = proxmox_client
self._item_node = item_node
self._item_type = item_type
self._storagename = item_name

self._name = None
self._maxdisk = None
self._usedisk = None
self._state = None
self._total = None
self._used = None
self._avail = None
self._content = None
self._type = None

@property
def name(self):
"""Return the name of the entity."""
return self._name

@property
def unit_of_measurement(self):
"""Return the unit the value is expressed in."""
return "%"

@property
def state(self):
"""Return percent of storage used if storage is available."""
return self._state

@property
def device_state_attributes(self):
"""Return device attributes of the entity."""
return {
"node": self._item_node,
"storagename": self._storagename,
"type": self._type,
"gb_total": self._total,
"gb_used": self._used,
"gb_avail": self._avail,
"content": self._content,
ATTR_ATTRIBUTION: ATTRIBUTION,
}

def update(self):
"""Check if the storage exists."""
item = self.poll_item()

if item is None:
_LOGGER.warning("Failed to poll storage %s", self._storagename)
return

self._state = round(item["used_fraction"] * 100, 1)
self._total = round(item["total"] / 1024 / 1024 / 1024, 1)
self._used = round(item["used"] / 1024 / 1024 / 1024, 1)
self._avail = round(item["avail"] / 1024 / 1024 / 1024, 1)
self._content = item["content"]
self._type = item["type"]

def poll_item(self):
"""Find the storage with the set name."""
items = (
self._proxmox_client.get_api_client()
.nodes(self._item_node)
.get(self._item_type.name)
)
item = next(
(item for item in items if item["storage"] == str(self._storagename)), None
)

if item is None:
_LOGGER.warning("Couldn't find storage with the name %s", self._storagename)
return None

if self._name is None:
self._name = f"{self._item_node} storage {self._storagename}"

return item