Skip to content

Commit 4d86c3b

Browse files
Merge pull request #1575 from ep1cman/waveshare_modbus
Add support for Waveshare Modbus Relays
2 parents 430496b + 9be84ea commit 4d86c3b

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
@@ -427,6 +427,32 @@ Arguments:
427427
Used by:
428428
- `ModbusCoilDriver`_
429429

430+
WaveshareModbusTCPCoil
431+
++++++++++++++++++++++
432+
A :any:`WaveshareModbusTCPCoil` describes a Waveshare branded coil accessible via *Modbus TCP*.
433+
434+
.. code-block:: yaml
435+
436+
WaveshareModbusTCPCoil:
437+
host: '192.168.23.42'
438+
coil: 1
439+
coil_count: 8
440+
441+
The example describes the coil ``1`` (zero indexed) of ``8`` on the Waveshare Modbus TCP relay
442+
module ``192.168.23.42``.
443+
444+
Arguments:
445+
- host (str): hostname of the Modbus TCP server e.g. ``192.168.23.42:502``
446+
- coil (int): index of the coil, e.g. ``3``
447+
- invert (bool, default=False): whether the logic level is inverted
448+
(active-low)
449+
- write_multiple_coils (bool, default=False): whether to perform write
450+
using "write multiple coils" method instead of "write single coil"
451+
452+
Used by:
453+
- `WaveShareModbusCoilDriver`_
454+
455+
430456
DeditecRelais8
431457
++++++++++++++
432458
A :any:`DeditecRelais8` describes a *Deditec USB GPO module* with 8 relays.
@@ -2350,6 +2376,25 @@ Implements:
23502376
Arguments:
23512377
- None
23522378

2379+
WaveShareModbusCoilDriver
2380+
~~~~~~~~~~~~~~~~~~~~~~~~~
2381+
A :any:`WaveShareModbusCoilDriver` controls a `WaveshareModbusTCPCoil`_ resource.
2382+
It can set and get the current state of the resource.
2383+
2384+
Binds to:
2385+
coil:
2386+
- `WaveshareModbusTCPCoil`_
2387+
2388+
Implements:
2389+
- :any:`DigitalOutputProtocol`
2390+
2391+
.. code-block:: yaml
2392+
2393+
WaveShareModbusCoilDriver: {}
2394+
2395+
Arguments:
2396+
- None
2397+
23532398
HIDRelayDriver
23542399
~~~~~~~~~~~~~~
23552400
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
@@ -909,15 +909,17 @@ def digital_io(self):
909909
action = self.args.action
910910
name = self.args.name
911911
target = self._get_target(place)
912-
from ..resource import ModbusTCPCoil, OneWirePIO, HttpDigitalOutput
912+
from ..resource import ModbusTCPCoil, OneWirePIO, HttpDigitalOutput, WaveshareModbusTCPCoil
913913
from ..resource.remote import NetworkDeditecRelais8, NetworkSysfsGPIO, NetworkLXAIOBusPIO, NetworkHIDRelay
914914

915915
drv = None
916916
try:
917917
drv = target.get_driver("DigitalOutputProtocol", name=name)
918918
except NoDriverFoundError:
919919
for resource in target.resources:
920-
if isinstance(resource, ModbusTCPCoil):
920+
if isinstance(resource, WaveshareModbusTCPCoil):
921+
drv = self._get_driver_or_new(target, "WaveShareModbusCoilDriver", name=name)
922+
elif isinstance(resource, ModbusTCPCoil):
921923
drv = self._get_driver_or_new(target, "ModbusCoilDriver", name=name)
922924
elif isinstance(resource, OneWirePIO):
923925
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)