Skip to content

Commit fc3afb1

Browse files
author
Nico Orlando
committed
driver: Add TenmaControl power driver and integration support
This patch introduces a new power driver, TenmaControl, providing control support for Tenma power devices. Integration includes: - Implementation of TenmaControl in `powerdriver.py` - Exporter and remote client support for the new driver - Configuration documentation in `configuration.rst` - New unit tests added in `test_tenmacontrol.py` - Minor updates to `pyproject.toml` and man pages This initial draft enables basic functionality and lays the groundwork for full Tenma device intration Signed-off-by: Nico Orlando <nico.orlando@dave.eu>
1 parent 881de63 commit fc3afb1

13 files changed

Lines changed: 181 additions & 3 deletions

doc/configuration.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,27 @@ Arguments:
410410
Used by:
411411
- `TasmotaPowerDriver`_
412412

413+
TenmaControlPort
414+
++++++++++++++++
415+
A :any:`TenmaControlPort` describes a *Tenma* as supported by
416+
`tenca-control <https://multicomp-pro.com/>`_.
417+
418+
.. code-block:: yaml
419+
420+
TenmaControlPort:
421+
match:
422+
ID_PATH: pci-0000:00:15.0-usb-0:3.2:1.0
423+
424+
425+
The example describes port 1 on the hub with the ID_PATH
426+
``pci-0000:00:15.0-usb-0:3.2:1.0``.
427+
428+
Arguments:
429+
- match (dict): key and value pairs for a udev match, see `udev Matching`_
430+
431+
Used by:
432+
- `TenmaControlDriver`_
433+
413434
Digital Outputs
414435
~~~~~~~~~~~~~~~
415436

labgrid/driver/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from .powerdriver import ManualPowerDriver, ExternalPowerDriver, \
1616
DigitalOutputPowerDriver, YKUSHPowerDriver, \
1717
USBPowerDriver, SiSPMPowerDriver, NetworkPowerDriver, \
18-
PDUDaemonDriver
18+
PDUDaemonDriver, TenmaControlDriver
1919
from .usbloader import MXSUSBDriver, IMXUSBDriver, BDIMXUSBDriver, RKUSBDriver, UUUDriver
2020
from .usbsdmuxdriver import USBSDMuxDriver
2121
from .usbsdwiredriver import USBSDWireDriver

labgrid/driver/powerdriver.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import shlex
22
import time
33
import math
4+
import ast
45
from importlib import import_module
56

67
import attr
@@ -109,6 +110,81 @@ def get(self):
109110
return False
110111
raise ExecutionError(f"Did not find port status in sispmctl output ({repr(output)})")
111112

113+
@target_factory.reg_driver
114+
@attr.s(eq=False)
115+
class TenmaControlDriver(Driver, PowerResetMixin, PowerProtocol):
116+
"""TenmaControlDriver - Driver using a Single Output Programmable to control a
117+
target's power using the tenma-control tool https://github.com/kxtells/tenma-serial/"""
118+
119+
bindings = {"port": {"TenmaControlPort", "NetworkTenmaControlPort"}, }
120+
delay = attr.ib(default=2.0, validator=attr.validators.instance_of(float))
121+
ovp = attr.ib(default=False, validator=attr.validators.instance_of(bool))
122+
ocp = attr.ib(default=False, validator=attr.validators.instance_of(bool))
123+
voltage = attr.ib(default=12000, validator=attr.validators.instance_of(int))
124+
current = attr.ib(default=2000, validator=attr.validators.instance_of(int))
125+
126+
def __attrs_post_init__(self):
127+
super().__attrs_post_init__()
128+
if self.target.env:
129+
self.tool = self.target.env.config.get_tool('tenma-control')
130+
else:
131+
self.tool = 'tenma-control'
132+
133+
def _get_tenmacontrol_prefix(self):
134+
options = []
135+
136+
# overvoltage protection (bool)
137+
if self.ovp:
138+
options.append('--ovp-enable')
139+
else:
140+
options.append('--ovp-disable')
141+
142+
# overcurrent protection (bool)
143+
if self.ocp:
144+
options.append('--ocp-enable')
145+
else:
146+
options.append('--ocp-disable')
147+
148+
# set mV (int)
149+
options.append(f'-v {self.voltage}')
150+
151+
# set mA (int)
152+
options.append(f'-c {self.current}')
153+
154+
return self.port.command_prefix + [
155+
self.tool,
156+
str(self.port.path),
157+
] + options
158+
159+
@Driver.check_active
160+
@step()
161+
def on(self):
162+
cmd = ['--on']
163+
processwrapper.check_output(self._get_tenmacontrol_prefix() + cmd)
164+
165+
@Driver.check_active
166+
@step()
167+
def off(self):
168+
cmd = ['--off']
169+
processwrapper.check_output(self._get_tenmacontrol_prefix() + cmd)
170+
171+
@Driver.check_active
172+
@step()
173+
def cycle(self):
174+
self.off()
175+
time.sleep(self.delay)
176+
self.on()
177+
178+
@Driver.check_active
179+
@step()
180+
def get(self):
181+
cmd = ['-S']
182+
output = processwrapper.check_output(self._get_tenmacontrol_prefix() + cmd)
183+
status = ast.literal_eval(output.decode('utf-8').strip().splitlines()[1])
184+
if status['outEnabled']:
185+
return True
186+
else:
187+
return False
112188

113189
@target_factory.reg_driver
114190
@attr.s(eq=False)

labgrid/remote/client.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -883,7 +883,12 @@ def power(self):
883883
name = self.args.name
884884
target = self._get_target(place)
885885
from ..resource.power import NetworkPowerPort, PDUDaemonPort
886-
from ..resource.remote import NetworkUSBPowerPort, NetworkSiSPMPowerPort, NetworkSysfsGPIO
886+
from ..resource.remote import (
887+
NetworkUSBPowerPort,
888+
NetworkSiSPMPowerPort,
889+
NetworkSysfsGPIO,
890+
NetworkTenmaControlPort,
891+
)
887892
from ..resource import TasmotaPowerPort, NetworkYKUSHPowerPort
888893

889894
drv = None
@@ -899,6 +904,8 @@ def power(self):
899904
drv = self._get_driver_or_new(target, "USBPowerDriver", name=name)
900905
elif isinstance(resource, NetworkSiSPMPowerPort):
901906
drv = self._get_driver_or_new(target, "SiSPMPowerDriver", name=name)
907+
elif isinstance(resource, NetworkTenmaControlPort):
908+
drv = self._get_driver_or_new(target, "TenmaControlDriver", name=name)
902909
elif isinstance(resource, PDUDaemonPort):
903910
drv = self._get_driver_or_new(target, "PDUDaemonDriver", name=name)
904911
elif isinstance(resource, TasmotaPowerPort):

labgrid/remote/exporter.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,27 @@ def release(self, *args, **kwargs):
184184
self.poll()
185185

186186

187+
@attr.s(eq=False)
188+
class TenmaControlExport(ResourceExport):
189+
def __attrs_post_init__(self):
190+
super().__attrs_post_init__()
191+
192+
def _get_params(self):
193+
"""Helper function to return parameters"""
194+
return {
195+
"host": self.host,
196+
"busnum": self.local.busnum,
197+
"devnum": self.local.devnum,
198+
"path": self.local.path,
199+
"vendor_id": self.local.vendor_id,
200+
"model_id": self.local.model_id,
201+
"index": self.local.index,
202+
}
203+
204+
205+
exports["TenmaControlPort"] = TenmaControlExport
206+
207+
187208
@attr.s(eq=False)
188209
class SerialPortExport(ResourceExport):
189210
"""ResourceExport for a USB or Raw SerialPort"""
@@ -564,6 +585,7 @@ def __attrs_post_init__(self):
564585
exports["USBAudioInput"] = USBAudioInputExport
565586
exports["USBTMC"] = USBGenericExport
566587
exports["SiSPMPowerPort"] = SiSPMPowerPortExport
588+
exports["TenmaControlPort"] = TenmaControlExport
567589
exports["USBPowerPort"] = USBPowerPortExport
568590
exports["DeditecRelais8"] = USBDeditecRelaisExport
569591
exports["HIDRelay"] = USBHIDRelayExport

labgrid/resource/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
AndroidUSBFastboot,
1313
DFUDevice,
1414
DeditecRelais8,
15+
TenmaControlPort,
1516
HIDRelay,
1617
IMXUSBLoader,
1718
LXAUSBMux,

labgrid/resource/remote.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,16 @@ def __attrs_post_init__(self):
260260
super().__attrs_post_init__()
261261

262262

263+
@target_factory.reg_resource
264+
@attr.s(eq=False)
265+
class NetworkTenmaControlPort(RemoteUSBResource):
266+
"""The TenmaControlPort describes a remotely accessible tenma-contro power port"""
267+
index = attr.ib(default=None, validator=attr.validators.instance_of(int))
268+
def __attrs_post_init__(self):
269+
self.timeout = 10.0
270+
super().__attrs_post_init__()
271+
272+
263273
@target_factory.reg_resource
264274
@attr.s(eq=False)
265275
class NetworkUSBPowerPort(RemoteUSBResource):

labgrid/resource/suggest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
IMXUSBLoader,
1313
AndroidUSBFastboot,
1414
DFUDevice,
15+
TenmaControlPort,
1516
USBSDMuxDevice,
1617
USBSDWireDevice,
1718
AlteraUSBBlaster,
@@ -45,6 +46,7 @@ def __init__(self, args):
4546
self.resources.append(IMXUSBLoader(**args))
4647
self.resources.append(AndroidUSBFastboot(**args))
4748
self.resources.append(DFUDevice(**args))
49+
self.resources.append(TenmaControlPort(**args))
4850
self.resources.append(USBMassStorage(**args))
4951
self.resources.append(USBSDMuxDevice(**args))
5052
self.resources.append(USBSDWireDevice(**args))

labgrid/resource/udev.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,21 @@ def __attrs_post_init__(self):
706706
self.match['ID_MODEL'] = 'DEDITEC_USB-OPT_REL-8'
707707
super().__attrs_post_init__()
708708

709+
@target_factory.reg_resource
710+
@attr.s(eq=False)
711+
class TenmaControlPort(USBResource):
712+
"""This resource describes a tenma-control power port"""
713+
714+
def __attrs_post_init__(self):
715+
self.match['SUBSYSTEM'] = 'tty'
716+
super().__attrs_post_init__()
717+
718+
@property
719+
def path(self):
720+
if self.device is not None:
721+
return self.device.device_node
722+
723+
return None
709724

710725
@target_factory.reg_resource
711726
@attr.s(eq=False)

man/labgrid-device-config.5

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ See: <https://github.com/openssh/openssh\-portable>
156156
Path to the sshfs binary, used by the SSHDriver.
157157
See: <https://github.com/libfuse/sshfs>
158158
.TP
159+
.B \fBtenma\-control\fP
160+
Path to the tenma\-control binary, used by the TenmaControlDriver.
161+
See: <https://github.com/kxtells/tenma\-serial>
162+
.TP
159163
.B \fBuhubctl\fP
160164
Path to the uhubctl binary, used by the USBPowerDriver.
161165
See: <https://github.com/mvp/uhubctl>

0 commit comments

Comments
 (0)