sunspec / pysunspec2

SunSpec Python library for interfacing with SunSpec devices.
Apache License 2.0
57 stars 21 forks source link

after first successful call to modbus.client.scan(), subsequent calls to scan() fail #37

Closed jmmgenerac closed 2 years ago

jmmgenerac commented 3 years ago

When calling scan() a second time, there is no modbus traffic and the following exception arises:

>>> import sunspec2.modbus.client as client
>>> c = client.SunSpecModbusClientDeviceTCP()  # assumes a sunspec/modbus device at localhost:502 having unit_id 1
>>> c.connect()
>>> c.scan()
>>> c.scan()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.8/site-packages/sunspec2/modbus/client.py", line 239, in scan
    model_id = mb.data_to_u16(model_id_data)
  File "/usr/lib/python3.8/site-packages/sunspec2/mb.py", line 112, in data_to_u16
    u16 = struct.unpack('>H', data[:2])
TypeError: a bytes-like object is required, not 'str'

This appears to be related to the assumption that the the data variable has been populated during the base_addr search. However, if self.base_addr has been found on the previous call to scan(), the data variable contains the empty string on the subsequent call. This causes struct.unpack() to throw the exception. This might be resolved easily by simply performing the base_addr search regardless of the pre-existing value of self.base_addr. I.e., removing this optimization.

jmmgenerac commented 3 years ago

On further exploration, it appears there may be another issue: if this is fixed in the way that I proposed, each subsequent call to scan() adds an additional instance of each model to the Device's models dict.

bobfox commented 3 years ago

I think a possible fix is to create a delete_models() function in the Device class that clears models and model_list, and on a scan in the Modbus client, delete_models() should be called and base_addr set to None before starting the scan. In the file client, delete_models() should be called before starting the scan.