Help request for creating Proxmox monitoring integration/add-on

Hi all.
After a very huge amount of time spent on looking for the solution on how to monitor Proxmox properly, light me an idea bulb - why not to try create a new monitoring solution? The problem is that I don’t have any knowledge and experience in programming. So I tried to get a bit help from GPT Chat, and here is whole idea, may be someone will succeed with realization.

Proxmox have its own API:
Documentation - Proxmox VE API - Proxmox VE
API Viewer - Proxmox VE API Documentation

The best & easiest way to connect to Proxmox API (as far as i see) is to use a username configured with read-only privileges + using an API token. The second option is to use pvesh command, but I not tried to do that.

I succeeded to connect and get data using command_line platform and curl command.
Here is example of the sensor:

  - platform: command_line 
    command: 'curl -k -H "Authorization: PVEAPIToken=user@pve!blah-blah-blah=1234a56b-c7d8-9012-345d-67ef890g123h" https://proxmox_ip:8006/api2/json/nodes/pvepc/disks/lvm'
    name: PVE API LVM
    value_template: '{{ value_json }}'
    scan_interval: 20
    command_timeout: 30

Here is the output for state of this sensor

`{'data': {'children': [{'free': 17175674880, 'size': 511570870272, 'leaf': 0, 'children': [{'name': '/dev/sdb3', 'leaf': 1, 'size': 511570870272, 'free': 17175674880}], 'name': 'pve', 'lvcount': 7}], 'leaf': 0}}`

Because I’m noob in programming, I not succeeded to parse that response.

As i said before, I tried to get help from AI GPT Chat. And that what it suggests:

import json
import requests

class ProxmoxSensor(Entity):

    def __init__(self, name, auth_data,endpoint):
        self._name = name
        self._auth_data = auth_data
        self._state = None
        self._endpoint=endpoint

    @property
    def name(self):
        return self._name

    @property
    def state(self):
        return self._state

    def update(self):
        headers = {
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {self._auth_data["token"]}'
        }
        response = requests.get(f'{self._auth_data["address"]}/api2/json/{self._endpoint}', headers=headers)
        response.raise_for_status()
        data = json.loads(response.text)['data']
        self._state = self._get_value(data)

    def _get_value(self, data):
        """This method should be implemented in the subclasses to extract the relevant value from the API response"""
        pass

class ProxmoxHDDSensor(ProxmoxSensor):

    def __init__(self, auth_data):
        self._endpoint = f'nodes/{auth_data["node"]}/storage'
        super().__init__('Proxmox HDD Usage', auth_data,self._endpoint)

    def _get_value(self, data):
        total_size = 0
        used_size = 0
        for storage in data:
            if storage['type'] == 'disk':
                total_size += storage
            used_size += storage['used']
        percent_used = used_size / total_size * 100
        return round(percent_used, 2)

class ProxmoxRAMSensor(ProxmoxSensor):

    def __init__(self, auth_data):
        self._endpoint = f'nodes/{auth_data["node"]}/memory'
        super().__init__('Proxmox RAM Usage', auth_data,self._endpoint)

    def _get_value(self, data):
        total_ram = data['total']
        used_ram = data['used']
        percent_used = used_ram / total_ram * 100
        return round(percent_used, 2)

class ProxmoxCPUSensor(ProxmoxSensor):

    def __init__(self, auth_data):
        self._endpoint = f'nodes/{auth_data["node"]}/cpu'
        super().__init__('Proxmox CPU Usage', auth_data,self._endpoint)

    def _get_value(self, data):
        percent_used = data['load_avg']
        return percent_used

class ProxmoxCPUTempSensor(ProxmoxSensor):

    def __init__(self, auth_data):
        self._endpoint = f'nodes/{auth_data["node"]}/hardware'
        super().__init__('Proxmox CPU Temperature', auth_data,self._endpoint)

    def _get_value(self, data):
        for entry in data['entries']:
            if entry['key'] == 'cpu_temp':
                return entry['value']

def authenticate(address,node_name,username,api_token):
    headers = {
        'Content-Type': 'application/json',
    }
    data = {
        'username': username,
        'password': api_token,
    }
    response = requests.post(f'{address}/api2/json/access/ticket', headers=headers, json=data)
    response.raise_for_status()
    auth_data = json.loads(response.text)['data']
    auth_data.update({"node":node_name,"address":address})
    return auth_data

def setup_platform(hass, config, add_entities, discovery_info=None):
    address = input('Enter the Proxmox VE address: ')
    node_name = input('Enter the Proxmox VE node name: ')
    username = input('Enter your Proxmox VE username: ')
api_token = input('Enter your Proxmox VE API Token: ')
auth_data = authenticate(address,node_name,username,api_token)
add_entities([
ProxmoxHDDSensor(auth_data),
ProxmoxRAMSensor(auth_data),
ProxmoxCPUSensor(auth_data),
ProxmoxCPUTempSensor(auth_data),
])

And example of __init__.py file:

import json
import requests

from homeassistant.const import CONF_NAME
from homeassistant.helpers.entity import Entity

class ProxmoxSensor(Entities):
    def __init__(self, name, auth_data,endpoint):
        self._name = name
        self._state = None
        self._auth_data = auth_data
        self._endpoint = endpoint

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

    @property
    def state(self):
        """Return the state of the sensor."""
        return self._state

    def update(self):
        """Fetch new state data for the sensor.

        This is the only method that should fetch new data for Home Assistant.
        """
        response = requests.get(
            f'{self._auth_data["address"]}/api2/json/{self._endpoint}',
            headers={
                'Content-Type': 'application/json',
                'Authorization': f'PVEAPIToken={self._auth_data["ticket"]}',
            },
        )
        response.raise_for_status()
        data = json.loads(response.text)['data']
        self._state = self._get_value(data)

    def _get_value(self, data):
        """Return the value for the sensor.

        Subclasses should override this method to return the appropriate value.
        """
        raise NotImplementedError

class ProxmoxHDDSensor(ProxmoxSensor):

    def __init__(self, auth_data):
        self._endpoint = f'nodes/{auth_data["node"]}/storage'
        super().__init__('Proxmox HDD Usage', auth_data,self._endpoint)

    def _get_value(self, data):
        total_size = 0
        used_size = 0
        for storage in data['storage']:
            total_size += storage['total']
            used_size += storage['used']
        percent_used = used_size / total_size * 100
        return round(percent_used, 2)

class ProxmoxRAMSensor(ProxmoxSensor):

    def __init__(self, auth_data):
        self._endpoint = f'nodes/{auth_data["node"]}/memory'
        super().__init__('Proxmox RAM Usage', auth_data,self._endpoint)

    def _get_value(self, data):
        total_ram = data['total']
        used_ram = data['used']
        percent_used = used_ram / total_ram * 100
return round(percent_used, 2)

class ProxmoxCPUSensor(ProxmoxSensor):
def __init__(self, auth_data):
    self._endpoint = f'nodes/{auth_data["node"]}/status'
    super().__init__('Proxmox CPU Usage', auth_data,self._endpoint)

def _get_value(self, data):
    return data['cpu']

class ProxmoxCPUTempSensor(ProxmoxSensor):
def __init__(self, auth_data):
    self._endpoint = f'nodes/{auth_data["node"]}/status'
    super().__init__('Proxmox CPU Temperature', auth_data,self._endpoint)

def _get_value(self, data):
    return data['temperature']
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Proxmox VE sensor."""
address = input('Enter your Proxmox VE address: ')
node_name = input('Enter your Proxmox VE node name: ')
username = input('Enter your Proxmox VE username: ')
api_token = input('Enter your Proxmox VE API Token: ')
auth_data = authenticate(address,node_name,username,api_token)
add_entities([
ProxmoxHDDSensor(auth_data),
ProxmoxRAMSensor(auth_data),
ProxmoxCPUSensor(auth_data),
ProxmoxCPUTempSensor(auth_data),
])

def authenticate(address,node_name,username,api_token):
data = {
'username':username,
'api_token': api_token
}
response = requests.post(f'{address}/api2/json/access/token', data=data)
response.raise_for_status()
auth_data = json.loads(response.text)['data']
auth_data['address'] = address
auth_data['node'] = node_name
return auth_data

So I hope that it will help someone to build a new add-on for monitoring Proxmox instances

There is an integration:

dougiteixeira/proxmoxve

In my case, since I dont want HA connecting to my Proxmox, I’m working in a MQTT integration to have access to Node status, VM status and VM Start and Shutdown control.
I published a code here:

zimbres/proxmox-hass-mqtt

2 Likes