Устройство Ethernet / IP: может считывать атрибуты с помощью CPPPO, но не может записывать

#python #protocols #ethernet #industrial

#python #протоколы #ethernet #Рабочая обувь

Вопрос:

Я работаю над созданием скрипта Python для связи с устройством EtherNet / IP (система распыления Graco PD2K). Единственная документация, предоставленная поставщиком, — это как настроить ПЛК Allen Bradley в качестве клиента для связи с устройством.

Конфигурация Аллена-Брэдли

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

 from cpppo.server.enip.get_attribute import proxy_simple

via = proxy_simple('192.168.10.5')
with via:
     data, = via.read( [('@4/100/3','DINT')] )
  

… что приводит к получению ожидаемого массива:

 [0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  

(39 целых чисел размером 32 бита)

При попытке записи в атрибуты в экземпляре сборки 150 я получаю True ответ от контроллера, но контроллер не обновляет параметры. Ожидается, что 25 x 32-разрядный целочисленный массив:

 with via:
    result, = via.read([('@4/150/3=(DINT)4, 1, 0, 0, 1, 0, 0, 0, 1, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0','@4/150/3')],1)
  

Вывод сверху:

 @4/150/3=(DINT)4, 1, 0, 0, 1, 0, 0, 0, 1, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 == True 
  

Если я добавляю одно целое число в массив (или вычитаю, или попытаюсь установить значение, отличное от @4/150/3, я получаю ответ None , поэтому ясно, что я близок к формату, и команда проходит.

Я несколько раз обращался к поставщику, и они настаивают, что это проблема с Python (или, более конкретно, они не поддерживают Python и рекомендуют интеграцию с ПЛК).

Мне интересно, является ли проблемой параметр «Конфигурация» в экземпляре сборки 1 (см. Изображение выше). Я попробовал несколько версий следующего кода, чтобы попытаться записать этот параметр. Не до конца понимая протокол EtherNet / IP, я даже не уверен, что делает этот конкретный экземпляр — однако то, что это параметр в конфигурации Аллена-Брэдли, указывает, что это важно в данном случае.

Попытка создания кода:

 result, = via.read([('@4/1/3=(USINT)0','@4/1/3')],1)
  

Я пытался использовать утилиту Molex EnIP, а также что-то подобное в SourceForge, чтобы исключить Python из уравнения, но результаты аналогичны. Я также пробовал модуль PyComm3, но я даже не могу заставить его возвращать идентификационную информацию. Я также пытался использовать -vvv утилиты командной строки CPPPO:

python -m cpppo.server.enip.get_attribute -a 192.168.10.5 '@4/150/3=(DINT)4, 1, 0, 0, 1, 0, 0, 0, 1, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0' -vv -S

Результаты (наряду с гораздо большим количеством выходных данных, которые, по моему мнению, не имеют значения):

 11-09 12:11:18.119 MainThread enip.cli DETAIL   issue      Sending  1 (Context       b'0')
11-09 12:11:18.120 MainThread enip.cli DETAIL   pipeline   Issuing     0/  1; curr:   0 - last:  -1 ==   1 depth vs. max   0
11-09 12:11:18.124 MainThread enip.cli DETAIL   __next__   Client CIP Rcvd: {
    "send_data.interface": 0,
    "send_data.timeout": 8,
    "send_data.CPF.count": 2,
    "send_data.CPF.item[0].type_id": 0,
    "send_data.CPF.item[0].length": 0,
    "send_data.CPF.item[1].type_id": 178,
    "send_data.CPF.item[1].length": 4,
    "send_data.CPF.item[1].unconnected_send.request.input": "array('B', [144, 0, 0, 0])",
    "send_data.CPF.item[1].unconnected_send.request.service": 144,
    "send_data.CPF.item[1].unconnected_send.request.status": 0,
    "send_data.CPF.item[1].unconnected_send.request.status_ext.size": 0,
    "send_data.CPF.item[1].unconnected_send.request.set_attribute_single": true
}
11-09 12:11:18.124 MainThread enip.cli DETAIL   collect    Receive  1 (Context       b'0')
11-09 12:11:18.124 MainThread enip.cli DETAIL   pipeline   Completed   1/  1; curr:   0 - last:   0 ==   0 depth vs. max   0
Mon Nov  9 12:11:18 2020:   0: Single S_A_S      @0x0004/150/3 == True
11-09 12:11:18.124 MainThread enip.cli DETAIL   pipeline   Pipelined   1/  1; curr:   0 - last:   0 ==   0 depth vs. max   0
11-09 12:11:18.125 MainThread enip.get NORMAL   main         1 requests in   0.006s at pipeline depth  0; 153.919 TPS
  

Опять же, результатом запроса является True , но контроллер не обновляет ни один из параметров.

Я не уверен, что попробовать дальше…