Тестирование соединения Modbus с Python - PullRequest
0 голосов
/ 18 апреля 2020

Я пытаюсь протестировать часть modbus проекта python, который я сейчас реализую. У меня есть два устройства Modbus, которые я читаю, используя pymodbus и ascyio .

Цель этого теста - увидеть отклонение во времени чтения, когда добавляется больше потоков, которые читают данное устройство Modbus. Каждый поток будет читать только одно устройство Modbus, но, учитывая, что у меня есть только два устройства, некоторые потоки будут совместно использовать устройства. Скрипты потока выглядят примерно так, как показано ниже:

# IP address of the smart meter 
meter_IP = "192.168.0.80"

async def main(meter):
    file_name = "results/thread_two_result.csv"
    with open(file_name, mode='a') as csv_file:
        csv_writer = csv.writer(csv_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
        print("Executing thread two event loop")
        while True:
            await meter.read_all(csv_writer)

loop = asyncio.get_event_loop()
loop, client = ModbusClient(schedulers.ASYNC_IO,host =meter_IP, loop=loop)
meter = smart_meter(meter_IP,client)
loop.create_task(main(meter))
loop.run_forever()

Класс для реализации части чтения Modbus содержится в классе smart_meter, и единственная функция, которую я использую, - это функция read_all, которая принимает входной файл CSV, в который записывается отметка времени при получении результата от Modbus. Каждый поток имеет свой собственный CSV-файл. Я читаю 12 регистров с этой функцией в одном запросе Modbus. Это показано во фрагменте кода ниже:


class smart_meter():

    ## __init__ ##
    # Initialiase method to intatiated object 
    # Inputs:
    #   IP - The IP address of the smart meter 
    #   client - A modbus client of type 'pymodbus.client.asynchronous.asyncio.ReconnectingAsyncioModbusTcpClient'
    def __init__(self,IP,client):
        #Create the client object passing the IP address of the slave to it 
        logger.info(f"New instance of smart_meter instantaited with IP of {IP}")
        self.IP = IP
        #self.client - 'pymodbus.client.asynchronous.asyncio.ModbusClientProtocol' 
        self.client = client.protocol

    ## read_all ##
    # Reads the registers:
    # V_2 - 0x1112
    # I_2 - 0x1114
    # kW_2 - 0x1116
    # kvar_2 - 0x1118
    # kVA_2 - 0x111A
    # PF_2  - 0x111C 
    async def read_all(self,file):
        logger.info(f"Attempting to read all registers for channel two")
        try:
            response = await self.client.read_input_registers(0x1112,12) 
            reg_value = dict.fromkeys(["Volts","Current","kW","kvar","kVA","PF"])
            x,y = 0,2
            for key in reg_value:
                reg_value[key] = (BinaryPayloadDecoder.fromRegisters(response.registers[x:y],Endian.Big, wordorder=Endian.Little )).decode_32bit_float()
                x+=2
                y+=2
            file.writerow([datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]])
        except Exception as e:
            logger.exception("Error in reading all regeisters for channel two")

Скрипт запуска для запуска этих потоков представляет собой скрипт оболочки, который выглядит следующим образом:

#!/bin/sh

python thread_one.py &
python thread_two.py &
python thread_three.py &
python thread_four.py &
python thread_five.py &
python thread_six.py &
python thread_seven.py &
python thread_eight.py &

У меня до восьми потоки, работающие в настоящее время с чтениями потоков 1,2,3 и 7 из meter_1 и чтениями потоков 2,4,6 и 8 из meter_2. Тест, в котором реализовано только 7 потоков, прошел успешно, однако тест с 8 потоками начинает проваливаться. Ответ от чтения Modbus начинает возвращать значение None, трассировка от одного из потоков, захваченных в файле журнала, показана ниже:

2020-04-18 16:08:32,599:ERROR:4446:MainProcess:smart_meters.py:Error in reading all regeisters for channel two
Traceback (most recent call last):
  File "/home/openhabian/Environments/env_1/openHAB_Proj/openHAB_Proj/smart_meters.py", line 77, in read_all
    response = await self.client.read_input_registers(0x1112,12)
  File "/home/openhabian/Environments/env_1/lib/python3.7/site-packages/pymodbus/client/common.py", line 125, in read_input_registers
    return self.execute(request)
  File "/home/openhabian/Environments/env_1/lib/python3.7/site-packages/pymodbus/client/asynchronous/asyncio/__init__.py", line 129, in execute
    self.write_transport(packet)
  File "/home/openhabian/Environments/env_1/lib/python3.7/site-packages/pymodbus/client/asynchronous/asyncio/__init__.py", line 119, in write_transport
    return self.transport.write(packet)
AttributeError: 'NoneType' object has no attribute 'write'

Это не приводит к получению результатов для некоторые потоки, поскольку он уже ставит в очередь следующее чтение для этого потока, что снова приводит к возвращению типа None. Я запускаю эти тесты на RasberryPi 3 .

Это то, что я просто достигаю пределов аппаратного / программного обеспечения? Если у кого-то есть предложения о том, как внедрить лучший тест, он будет рад.

РЕДАКТИРОВАТЬ

Файлы потоков в значительной степени одинаковы, единственное отличие состоит в том, что они считывают устройство Modbus и файл CSV, в котором сохраняются значения, в которых я тоже сохраняю переменная file_name. Четные потоки (2,4,6,8) считываются с одного и того же устройства Modbus, ниже показан файл четных потоков для thread_eight.py

# IP address of the smart meter 
meter_IP = "192.168.0.80"

async def main(meter):
    file_name = "results/thread_eight_result.csv"
    with open(file_name, mode='a') as csv_file:
        csv_writer = csv.writer(csv_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
        print("Executing thread eight event loop")
        while True:
            await meter.read_all(csv_writer)

loop = asyncio.get_event_loop()
loop, client = ModbusClient(schedulers.ASYNC_IO,host =meter_IP, loop=loop)
meter = smart_meter(meter_IP,client)
loop.create_task(main(meter))
loop.run_forever()

Файл нечетных потоков (1,3,5 7) все читается с одного устройства. Пример нечетного файла показан в приведенном ниже коде из файла thread_seven.py

# IP address of the smart meter 
meter_IP = "192.168.0.116"

async def main(meter):
    file_name = "results/thread_seven_result.csv"
    with open(file_name, mode='a') as csv_file:
        csv_writer = csv.writer(csv_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
        print("Executing thread seven event loop")
        while True:
            await meter.read_all(csv_writer)

loop = asyncio.get_event_loop()
loop, client = ModbusClient(schedulers.ASYNC_IO,host =meter_IP, loop=loop)
meter = smart_meter(meter_IP,client)
loop.create_task(main(meter))
loop.run_forever()
...