Skip to content

Commit 9be84ea

Browse files
ep1cmanEmantor
authored andcommitted
Add support for Waveshare Modbus Relays
Waveshare only implement the ability to query the status of all relays (https://www.waveshare.com/wiki/Modbus_RTU_Relay#Read_States_of_Relays) not just one, so a modification to the existing drivers is required. Signed-off-by: Sebastian Goscik <[email protected]>
1 parent cea524d commit 9be84ea

File tree

5 files changed

+95
-3
lines changed

5 files changed

+95
-3
lines changed

doc/configuration.rst

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,32 @@ Arguments:
416416
Used by:
417417
- `ModbusCoilDriver`_
418418

419+
WaveshareModbusTCPCoil
420+
++++++++++++++++++++++
421+
A :any:`WaveshareModbusTCPCoil` describes a Waveshare branded coil accessible via *Modbus TCP*.
422+
423+
.. code-block:: yaml
424+
425+
WaveshareModbusTCPCoil:
426+
host: '192.168.23.42'
427+
coil: 1
428+
coil_count: 8
429+
430+
The example describes the coil ``1`` (zero indexed) of ``8`` on the Waveshare Modbus TCP relay
431+
module ``192.168.23.42``.
432+
433+
Arguments:
434+
- host (str): hostname of the Modbus TCP server e.g. ``192.168.23.42:502``
435+
- coil (int): index of the coil, e.g. ``3``
436+
- invert (bool, default=False): whether the logic level is inverted
437+
(active-low)
438+
- write_multiple_coils (bool, default=False): whether to perform write
439+
using "write multiple coils" method instead of "write single coil"
440+
441+
Used by:
442+
- `WaveShareModbusCoilDriver`_
443+
444+
419445
DeditecRelais8
420446
++++++++++++++
421447
A :any:`DeditecRelais8` describes a *Deditec USB GPO module* with 8 relays.
@@ -2334,6 +2360,25 @@ Implements:
23342360
Arguments:
23352361
- None
23362362

2363+
WaveShareModbusCoilDriver
2364+
~~~~~~~~~~~~~~~~~~~~~~~~~
2365+
A :any:`WaveShareModbusCoilDriver` controls a `WaveshareModbusTCPCoil`_ resource.
2366+
It can set and get the current state of the resource.
2367+
2368+
Binds to:
2369+
coil:
2370+
- `WaveshareModbusTCPCoil`_
2371+
2372+
Implements:
2373+
- :any:`DigitalOutputProtocol`
2374+
2375+
.. code-block:: yaml
2376+
2377+
WaveShareModbusCoilDriver: {}
2378+
2379+
Arguments:
2380+
- None
2381+
23372382
HIDRelayDriver
23382383
~~~~~~~~~~~~~~
23392384
An :any:`HIDRelayDriver` controls an `HIDRelay`_ or `NetworkHIDRelay`_ resource.

labgrid/driver/modbusdriver.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,34 @@ def get(self):
6060
if self.coil.invert:
6161
status = not status
6262
return status
63+
64+
65+
@target_factory.reg_driver
66+
@attr.s(eq=False)
67+
class WaveShareModbusCoilDriver(ModbusCoilDriver):
68+
"""
69+
Waveshare Modbus Relay driver.
70+
71+
Waveshare only implement the ability to query the status of all relays not just one.
72+
https://www.waveshare.com/wiki/Modbus_RTU_Relay#Read_States_of_Relays
73+
"""
74+
75+
bindings = {
76+
"coil": "WaveshareModbusTCPCoil",
77+
}
78+
79+
@Driver.check_active
80+
def get(self):
81+
status = self.client.read_coils(0x0000, self.coil.coil_count)
82+
if status is None:
83+
self._handle_error("read")
84+
85+
status = status[self.coil.coil]
86+
if self.coil.invert:
87+
status = not status
88+
return status
89+
90+
def __attrs_post_init__(self):
91+
super().__attrs_post_init__()
92+
if self.coil.coil >= self.coil.coil_count:
93+
raise ValueError("Coil exceeds coil count")

labgrid/remote/client.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -904,15 +904,17 @@ def digital_io(self):
904904
action = self.args.action
905905
name = self.args.name
906906
target = self._get_target(place)
907-
from ..resource import ModbusTCPCoil, OneWirePIO, HttpDigitalOutput
907+
from ..resource import ModbusTCPCoil, OneWirePIO, HttpDigitalOutput, WaveshareModbusTCPCoil
908908
from ..resource.remote import NetworkDeditecRelais8, NetworkSysfsGPIO, NetworkLXAIOBusPIO, NetworkHIDRelay
909909

910910
drv = None
911911
try:
912912
drv = target.get_driver("DigitalOutputProtocol", name=name)
913913
except NoDriverFoundError:
914914
for resource in target.resources:
915-
if isinstance(resource, ModbusTCPCoil):
915+
if isinstance(resource, WaveshareModbusTCPCoil):
916+
drv = self._get_driver_or_new(target, "WaveShareModbusCoilDriver", name=name)
917+
elif isinstance(resource, ModbusTCPCoil):
916918
drv = self._get_driver_or_new(target, "ModbusCoilDriver", name=name)
917919
elif isinstance(resource, OneWirePIO):
918920
drv = self._get_driver_or_new(target, "OneWirePIODriver", name=name)

labgrid/resource/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from .base import SerialPort, NetworkInterface, EthernetPort, SysfsGPIO
22
from .ethernetport import SNMPEthernetPort
33
from .serialport import RawSerialPort, NetworkSerialPort
4-
from .modbus import ModbusTCPCoil
4+
from .modbus import ModbusTCPCoil, WaveshareModbusTCPCoil
55
from .modbusrtu import ModbusRTU
66
from .networkservice import NetworkService
77
from .onewireport import OneWirePIO

labgrid/resource/modbus.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,17 @@ class ModbusTCPCoil(Resource):
2121
write_multiple_coils = attr.ib(
2222
default=False, validator=attr.validators.instance_of(bool)
2323
)
24+
25+
@target_factory.reg_resource
26+
@attr.s(eq=False)
27+
class WaveshareModbusTCPCoil(ModbusTCPCoil):
28+
"""This resource describes Waveshare brand Modbus TCP coil.
29+
30+
Args:
31+
host (str): hostname of the Modbus TCP server e.g. "192.168.23.42:502"
32+
coil (int): index of the coil e.g. 3
33+
coil_count (int): The total number of coils on this module.
34+
invert (bool): optional, whether the logic level is be inverted (active-low)
35+
write_multiple_coils (bool): optional, whether write using multiple coils method"""
36+
37+
coil_count = attr.ib(default=8, validator=attr.validators.instance_of(int))

0 commit comments

Comments
 (0)