Skip to content

Instantly share code, notes, and snippets.

@tylermenezes
Last active October 12, 2021 01:52
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tylermenezes/05399a37acd744138da1ca7a5560676a to your computer and use it in GitHub Desktop.
Save tylermenezes/05399a37acd744138da1ca7a5560676a to your computer and use it in GitHub Desktop.
Proxmox VM State Controller for Home Assistant
import voluptuous as vol
import logging
from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA)
from homeassistant.const import (
STATE_ON, STATE_OFF, STATE_UNKNOWN, CONF_NAME, CONF_FILENAME)
import homeassistant.helpers.config_validation as cv
from base64 import b64encode
from time import time
import urllib.request
import urllib.parse
import json
import ssl
DOMAIN = 'proxmox_vm'
DEFAULT_NAME = 'Proxmox VM'
ICON = 'mdi:server-network'
_LOGGER = logging.getLogger(__name__)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required('server'): cv.string,
vol.Required('username'): cv.string,
vol.Required('provider'): cv.string,
vol.Required('password'): cv.string,
vol.Required('node'): cv.string,
vol.Required('vmtype'): cv.string,
vol.Required('vmid'): cv.string,
})
def setup_platform(hass, config, add_devices, discovery_info=None):
add_devices([Proxmox(config.get('server'), config.get('username'), config.get('provider'), config.get('password'), config.get('node'), config.get('vmtype'), config.get('vmid'))])
class Proxmox(SwitchDevice):
def __init__(self, server, username, provider, password, node, vmtype, vmid):
self.server = server
self.username = username
self.provider = provider
self.password = password
self.node = node
self.vmtype = vmtype
self.vmid = vmid
self.base = 'https://{}:8006/api2/json/'.format(server)
self.creds = urllib.parse.urlencode({'username': '{}@{}'.format(self.username, self.provider), 'password': self.password})
self.ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
self._state = False
@property
def available(self):
return True
@property
def name(self):
return "Proxmox VM {}".format(self.vmid)
@property
def is_on(self):
return self._state
@property
def state_attributes(self):
return False
def update(self):
self._state = self.getStatus() == 'running'
def turn_on(self):
self.changeStatus('start')
self._state = True
def turn_off(self):
self.changeStatus('shutdown')
self._state = False
def changeStatus(self, status):
self.request('POST', 'nodes/{}/{}/{}/status/{}'.format(self.node, self.vmtype, self.vmid, status))
def getStatus(self):
return self.request('GET', 'nodes/{}/{}/{}/status/current'.format(self.node, self.vmtype, self.vmid))['status']
def request(self, method, endpoint):
try:
return self._request(method, endpoint)
except:
self.authenticate()
return self._request(method, endpoint)
def _request(self, method, endpoint):
headers = {'Cookie': 'PVEAuthCookie={}'.format(self.ticket), 'CSRFPreventionToken': self.csrf}
req = urllib.request.Request('{}{}'.format(self.base, endpoint), headers=headers, method=method)
resp = json.loads(urllib.request.urlopen(req, context=self.ctx).read().decode('utf8'))['data']
if resp == None:
raise Exception("Proxmox API exception")
return resp
def authenticate(self):
res = urllib.request.urlopen('{}access/ticket'.format(self.base), data=self.creds.encode('utf8'), context=self.ctx).read()
auth = json.loads(res.decode('utf8'))
if auth['data'] == None:
raise Exception("Authentication error")
self.ticket = auth['data']['ticket']
self.csrf = auth['data']['CSRFPreventionToken']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment