From a2557a57ed63967b19bfb537e951001bdf86043f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20K=C5=99=C3=AD=C5=BE?= Date: Thu, 1 Feb 2024 14:43:16 +0100 Subject: [PATCH] driver/power/pe6216: add support for Aten PE6216 PDU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The support for Aten PDU family is not present in the `pdudameon` at the moment, hence we have to add it here. Signed-off-by: Daniel Kříž [bst: check for HTTP errors, format, document username/password, add import test] Signed-off-by: Bastian Krause --- doc/configuration.rst | 5 ++++ labgrid/driver/power/pe6216.py | 55 ++++++++++++++++++++++++++++++++++ pyproject.toml | 1 + tests/test_powerdriver.py | 1 + 4 files changed, 62 insertions(+) create mode 100644 labgrid/driver/power/pe6216.py diff --git a/doc/configuration.rst b/doc/configuration.rst index c1fb58187..9303d1eed 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -208,6 +208,11 @@ Currently available are: ``netio_kshell`` Controls *NETIO 4C PDUs* via a Telnet interface. +``pe6216`` + Controls an Aten PE6216 PDU via a simple HTTP API. + This backend deliberately uses the standard username ``administrator`` and the default password + ``password`` and is not compatible with other credentials. + ``poe_mib`` Controls PoE switches using the PoE SNMP administration MiBs. diff --git a/labgrid/driver/power/pe6216.py b/labgrid/driver/power/pe6216.py new file mode 100644 index 000000000..f3f367d48 --- /dev/null +++ b/labgrid/driver/power/pe6216.py @@ -0,0 +1,55 @@ +"""Tested with Aten PE6216. + +HTTP API is defined by in the aten PDU PE6216 specification: +https://assets.aten.com/product/manual/Restful-API-Guide-for-PDU_2022-11-18.pdf +""" + +import re +import requests + +from ..exception import ExecutionError + +PORT = 80 + +MIN_OUTLET_INDEX = 1 +MAX_OUTLET_INDEX = 16 +HEADERS = {"Content-Type": "application/x-www-form-urlencoded"} + + +def power_set(host, port, index, value): + index = int(index) + assert MIN_OUTLET_INDEX <= index <= MAX_OUTLET_INDEX + value = "on" if value else "off" + + response = requests.post( + f"http://{host}:{port}/api/outlet/relay", + headers=HEADERS, + data={ + "usr": "administrator", + "pwd": "password", + "index": index, + "method": value, + }, + ) + response.raise_for_status() + + +def power_get(host, port, index): + index = int(index) + assert MIN_OUTLET_INDEX <= index <= MAX_OUTLET_INDEX + + response = requests.get( + f"http://{host}:{port}/api/outlet/relay", + headers=HEADERS, + params={ + "usr": "administrator", + "pwd": "password", + "index": index, + }, + ) + response.raise_for_status() + + m = re.search(r"<\d+>(?P(ON|OFF|PENDING))<.*", response.text) + if m is None: + raise ExecutionError("PE6216: could not match response") + return m.group("state") == "ON" diff --git a/pyproject.toml b/pyproject.toml index 3f3bd67ff..01f56da33 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -222,6 +222,7 @@ include = [ "labgrid/driver/httpvideodriver.py", "labgrid/driver/manualswitchdriver.py", "labgrid/driver/power/gude8031.py", + "labgrid/driver/power/pe6216.py", "labgrid/driver/power/shelly_gen2.py", "labgrid/driver/rawnetworkinterfacedriver.py", "labgrid/protocol/**/*.py", diff --git a/tests/test_powerdriver.py b/tests/test_powerdriver.py index 8fc5105a4..cd87e0713 100644 --- a/tests/test_powerdriver.py +++ b/tests/test_powerdriver.py @@ -291,6 +291,7 @@ def test_import_backends(self): import labgrid.driver.power.gude24 import labgrid.driver.power.netio import labgrid.driver.power.netio_kshell + import labgrid.driver.power.pe6216 import labgrid.driver.power.rest import labgrid.driver.power.sentry import labgrid.driver.power.eg_pms2_network