Skip to content

Bugfix 105: Use Unit ID name #106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ __pycache__/
*.egg-info/
build/

dist/
dist/

*.code-workspace
12 changes: 6 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -165,20 +165,20 @@ type.

TCP
^^^
The following is how to open and initialize a TCP Device, where the slave ID is set to 1, the IP address of the TCP
The following is how to open and initialize a TCP Device, where the Unit ID is set to 1, the IP address of the TCP
device is
127.0.0.1, and the port is 8502::

>>> import sunspec2.modbus.client as client
>>> d = client.SunSpecModbusClientDeviceTCP(slave_id=1, ipaddr='127.0.0.1', ipport=8502)
>>> d = client.SunSpecModbusClientDeviceTCP(unit_id=1, ipaddr='127.0.0.1', ipport=8502)

RTU
^^^
The following to open and initialize a RTU Device, where the slave ID is set to 1, and the name of the serial port is
The following to open and initialize a RTU Device, where the Unit ID is set to 1, and the name of the serial port is
COM2::

>>> import sunspec2.modbus.client as client
>>> d = client.SunSpecModbusClientDeviceRTU(slave_id=1, name="COM2")
>>> d = client.SunSpecModbusClientDeviceRTU(unit_id=1, name="COM2")

Device Image
^^^^^^^^^^^^
Expand Down Expand Up @@ -209,7 +209,7 @@ model ID. The first key is the model ID as an int, the second key is the model n
that a device may contain more than one model with the same model ID, the dictionary keys refer to a list of model
objects with that ID. Both keys refer to the same model list for a model ID.

>>> d = client.SunSpecModbusClientDeviceTCP(slave_id=1, ipaddr='127.0.0.1', ipport=8502)
>>> d = client.SunSpecModbusClientDeviceTCP(unit_id=1, ipaddr='127.0.0.1', ipport=8502)
>>> d.scan()


Expand Down Expand Up @@ -296,7 +296,7 @@ This section will go over the full steps on how to set a volt-var curve.

Initialize device, and run device discovery with scan(): ::

>>> d = client.SunSpecModbusClientDeviceRTU(slave_id=1, name="COM2")
>>> d = client.SunSpecModbusClientDeviceRTU(unit_id=1, name="COM2")
>>> d.scan()

Confirm that model 705 (DERVoltVar) is on the device: ::
Expand Down
8 changes: 4 additions & 4 deletions scripts/suns.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
-o: output mode for data (text, xml)
-x: export model description (slang, xml)
-t: transport type: tcp or rtu (default: tcp)
-a: modbus slave address (default: 1)
-a: modbus unit identifier (default: 1)
-i: ip address to use for modbus tcp (default: localhost)
-P: port number for modbus tcp (default: 502)
-p: serial port for modbus rtu (default: /dev/ttyUSB0)
Expand Down Expand Up @@ -46,7 +46,7 @@
help='transport type: rtu, tcp, file [default: tcp]')
parser.add_option('-a', metavar=' ', type='int',
default=1,
help='modbus slave address [default: 1]')
help='modbus unit identifier [default: 1]')
parser.add_option('-i', metavar=' ',
default='localhost',
help='ip address to use for modbus tcp [default: localhost]')
Expand All @@ -72,10 +72,10 @@

try:
if options.t == 'tcp':
sd = client.SunSpecModbusClientDeviceTCP(slave_id=options.a, ipaddr=options.i, ipport=options.P,
sd = client.SunSpecModbusClientDeviceTCP(unit_id=options.a, ipaddr=options.i, ipport=options.P,
timeout=options.T)
elif options.t == 'rtu':
sd = client.SunSpecModbusClientDeviceRTU(slave_id=options.a, name=options.p, baudrate=options.b,
sd = client.SunSpecModbusClientDeviceRTU(unit_id=options.a, name=options.p, baudrate=options.b,
parity=options.R, timeout=options.T)
elif options.t == 'file':
sd = file_client.FileClientDevice(filename=options.m)
Expand Down
12 changes: 6 additions & 6 deletions sunspec2/docs/pysunspec.rst
Original file line number Diff line number Diff line change
Expand Up @@ -146,20 +146,20 @@ type.

TCP
^^^
The following is how to open and initialize a TCP Device, where the slave ID is set to 1, the IP address of the TCP
The following is how to open and initialize a TCP Device, where the Unit ID is set to 1, the IP address of the TCP
device is
127.0.0.1, and the port is 8502::

>>> import sunspec2.modbus.client as client
>>> d = client.SunSpecModbusClientDeviceTCP(slave_id=1, ipaddr='127.0.0.1', ipport=8502)
>>> d = client.SunSpecModbusClientDeviceTCP(unit_id=1, ipaddr='127.0.0.1', ipport=8502)

RTU
^^^
The following to open and initialize a RTU Device, where the slave ID is set to 1, and the name of the serial port is
The following to open and initialize a RTU Device, where the Unit ID is set to 1, and the name of the serial port is
COM2::

>>> import sunspec2.modbus.client as client
>>> d = client.SunSpecModbusClientDeviceRTU(slave_id=1, name="COM2")
>>> d = client.SunSpecModbusClientDeviceRTU(unit_id=1, name="COM2")

Device Image
^^^^^^^^^^^^
Expand Down Expand Up @@ -190,7 +190,7 @@ model ID. The first key is the model ID as an int, the second key is the model n
that a device may contain more than one model with the same model ID, the dictionary keys refer to a list of model
objects with that ID. Both keys refer to the same model list for a model ID.

>>> d = client.SunSpecModbusClientDeviceTCP(slave_id=1, ipaddr='127.0.0.1', ipport=8502)
>>> d = client.SunSpecModbusClientDeviceTCP(unit_id=1, ipaddr='127.0.0.1', ipport=8502)
>>> d.scan()


Expand Down Expand Up @@ -277,7 +277,7 @@ This section will go over the full steps on how to set a volt-var curve.

Initialize device, and run device discovery with scan(): ::

>>> d = client.SunSpecModbusClientDeviceRTU(slave_id=1, name="COM2")
>>> d = client.SunSpecModbusClientDeviceRTU(unit_id=1, name="COM2")
>>> d.scan()

Confirm that model 705 (DERVoltVar) is on the device: ::
Expand Down
83 changes: 69 additions & 14 deletions sunspec2/modbus/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import time
import uuid
import warnings
from sunspec2 import mdef, device, mb
import sunspec2.modbus.modbus as modbus_client

Expand Down Expand Up @@ -308,13 +309,52 @@ def scan(self, progress=None, delay=None, connect=True, full_model_read=True):
if connected:
self.disconnect()


class SunSpecModbusClientDeviceTCP(SunSpecModbusClientDevice):
def __init__(self, slave_id=1, ipaddr='127.0.0.1', ipport=502, timeout=None, ctx=None, trace_func=None,
"""Provides access to a Modbus RTU device.
Parameters:
unit_id :
Modbus Unit Identifier.
ipaddr :
IP address of the Modbus TCP device.
ipport :
Port number for Modbus TCP. Default is 502 if not specified.
timeout :
Modbus request timeout in seconds. Fractional seconds are permitted
such as .5.
ctx :
Context variable to be used by the object creator. Not used by the
modbus module.
trace_func :
Trace function to use for detailed logging. No detailed logging is
perform is a trace function is not supplied.
max_count :
Maximum register count for a single Modbus request.
max_write_count :
Maximum register count for a single Modbus write request.
model_class :
Model class to use for creating models in the device. Default is
:class:`sunspec2.modbus.client.SunSpecModbusClientModel`.
slave_id : [DEPRECATED] Use unit_id instead.
Raises:
SunSpecModbusClientError: Raised for any general modbus client error.
SunSpecModbusClientTimeoutError: Raised for a modbus client request timeout.
SunSpecModbusClientException: Raised for an exception response to a modbus
client request.
"""

def __init__(self, unit_id=1, ipaddr='127.0.0.1', ipport=502, timeout=None, ctx=None, trace_func=None,
max_count=modbus_client.REQ_COUNT_MAX, max_write_count=modbus_client.REQ_WRITE_COUNT_MAX,
model_class=SunSpecModbusClientModel):
model_class=SunSpecModbusClientModel, slave_id=None):
SunSpecModbusClientDevice.__init__(self, model_class=model_class)
self.slave_id = slave_id
if unit_id == 1 and slave_id is not None:
unit_id = slave_id
if slave_id is not None:
warnings.warn(
"The 'slave_id' parameter is deprecated and will be removed in a future version. Use 'unit_id' instead.",
DeprecationWarning,
stacklevel=2
)
self.unit_id = unit_id
self.ipaddr = ipaddr
self.ipport = ipport
self.timeout = timeout
Expand All @@ -324,7 +364,7 @@ def __init__(self, slave_id=1, ipaddr='127.0.0.1', ipport=502, timeout=None, ctx
self.max_count = max_count
self.max_write_count = max_write_count

self.client = modbus_client.ModbusClientTCP(slave_id=slave_id, ipaddr=ipaddr, ipport=ipport, timeout=timeout,
self.client = modbus_client.ModbusClientTCP(unit_id=unit_id, ipaddr=ipaddr, ipport=ipport, timeout=timeout,
ctx=ctx, trace_func=trace_func,
max_count=modbus_client.REQ_COUNT_MAX,
max_write_count=modbus_client.REQ_WRITE_COUNT_MAX)
Expand All @@ -351,8 +391,8 @@ def write(self, addr, data):
class SunSpecModbusClientDeviceRTU(SunSpecModbusClientDevice):
"""Provides access to a Modbus RTU device.
Parameters:
slave_id :
Modbus slave id.
unit_id :
Modbus Unit Identifier.
name :
Name of the serial port such as 'com4' or '/dev/ttyUSB0'.
baudrate :
Expand All @@ -373,19 +413,34 @@ class SunSpecModbusClientDeviceRTU(SunSpecModbusClientDevice):
perform is a trace function is not supplied.
max_count :
Maximum register count for a single Modbus request.
slave_id : [DEPRECATED] Use unit_id instead.
Raises:
SunSpecModbusClientError: Raised for any general modbus client error.
SunSpecModbusClientTimeoutError: Raised for a modbus client request timeout.
SunSpecModbusClientException: Raised for an exception response to a modbus
client request.
"""

def __init__(self, slave_id, name, baudrate=None, parity=None, timeout=None, ctx=None, trace_func=None,
def __init__(self, unit_id=None, name=None, baudrate=None, parity=None, timeout=None, ctx=None, trace_func=None,
max_count=modbus_client.REQ_COUNT_MAX, max_write_count=modbus_client.REQ_WRITE_COUNT_MAX,
model_class=SunSpecModbusClientModel):
model_class=SunSpecModbusClientModel, slave_id=None):
# test if this super class init is needed
SunSpecModbusClientDevice.__init__(self, model_class=model_class)
self.slave_id = slave_id
# Backward compatibility for slave_id
if unit_id is not None:
self.unit_id = unit_id
elif slave_id is not None:
self.unit_id = slave_id
else:
raise ValueError("unit_id must be provided")
if name is None:
raise ValueError("name must be provided")
if slave_id is not None:
warnings.warn(
"The 'slave_id' parameter is deprecated and will be removed in a future version. Use 'unit_id' instead.",
DeprecationWarning,
stacklevel=2
)
self.name = name
self.client = None
self.ctx = ctx
Expand All @@ -396,7 +451,7 @@ def __init__(self, slave_id, name, baudrate=None, parity=None, timeout=None, ctx
self.client = modbus_client.modbus_rtu_client(name, baudrate, parity, timeout)
if self.client is None:
raise SunSpecModbusClientError('No modbus rtu client set for device')
self.client.add_device(self.slave_id, self)
self.client.add_device(self.unit_id, self)

def open(self):
self.client.open()
Expand All @@ -406,7 +461,7 @@ def close(self):
"""

if self.client:
self.client.remove_device(self.slave_id)
self.client.remove_device(self.unit_id)

def read(self, addr, count, op=modbus_client.FUNC_READ_HOLDING):
"""Read Modbus device registers.
Expand All @@ -421,7 +476,7 @@ def read(self, addr, count, op=modbus_client.FUNC_READ_HOLDING):
Byte string containing register contents.
"""

return self.client.read(self.slave_id, addr, count, op=op, max_count=self.max_count)
return self.client.read(self.unit_id, addr, count, op=op, max_count=self.max_count)

def write(self, addr, data):
"""Write Modbus device registers.
Expand All @@ -432,4 +487,4 @@ def write(self, addr, data):
Byte string containing register contents.
"""

return self.client.write(self.slave_id, addr, data, max_write_count=self.max_write_count)
return self.client.write(self.unit_id, addr, data, max_write_count=self.max_write_count)
Loading