Блог Синявского
  • Разделы
  • Метки
  • Все статьи

Получаем данные по протоколу modbus

1

Эта статья ни о чём, и немного о Modbus

Modbus - это низкоуровневый протокол позволяющий получить информацию от устройств. Протокол не предусматривает прерывания и ведомое устройство должно быть опрошено с какой-то периодичностью ведущим устройством. Информация может инкапсулирована во фрейм TCP/IP и информация может передаваться по сетям передачи данных - данная реализация Modbus TCP. В спецификации Modbus определено два типа данных, один бит и 16 битное слово. Данные организованы в четыре таблицы с 16 битной адресацией ячеек, адресация в таблицах начинается с 0.

  1. Discrete Inputs (1 бит, только чтение)
  2. Coils (1 бит, чтение и запись)
  3. Input Registers (16 бит, только чтение)
  4. Holding Registers (16 бит, чтение и запись)

Стандарт Modbus предусматривает ряд команд для получение от устройства регистров:

  1. 0x01 — чтение значений из нескольких регистров флагов (Read Coil Status)
  2. 0x02 — чтение значений из нескольких дискретных входов (Read Discrete Inputs)
  3. 0x03 — чтение значений из нескольких регистров хранения (Read Holding Registers)
  4. 0x04 — чтение значений из нескольких регистров ввода (Read Input Registers)

У каждого разработчика может быть своя реализация частей этого протокола, которые не регаламентированы стандартом. Запрос к ведомому устройству не гарантирует, то что устройство поддерживает какую-то команду и вернет данные. Так же необходимо помнить, что некоторые реализации подразумевают возможность записи, только после чтения. Или для простоты реализации возвращают состояние всех регистров сразу. В некоторых случаях, из возможных 65535 адресов, используется часть адресов, при этом начальный адрес имеет смещение например 30000 или 40000, то есть первый адрес в этом случае будет 30001 и 40001 соответственно.

Протокол modbus и python

Для работы с modbus в python есть несколько библиотек:

  1. pymodbus и документация
  2. pymodbus3
  3. minimalmodbus и документация
  4. modbus_tk
  5. pymodbustcp и документация

В интеренте я нашел сравнение библиотек. Однако для моих целей по опросу одного устройства, скорость работы и время декодирования регистров вообще не имели значние и я остановился на тех, у которых была хорошая документация. Я проверял 2 библитеки pymodbus и pymodbustcp.

Изучение устройства при помощи wireshark

Необходимо получать данные с MOXA Ethernet I/O Server E1210. После изучения запросов и ответов текущей системы мониторинга, я пришел к выводу, что всё здесь просто элементарно.

Запрос:

1515    12.686205000    192.168.100.3   192.168.100.2
Modbus/TCP  66     Query: Trans: 27967;
Unit:   1, Func:   2: Read Discrete Inputs
Modbus/TCP
Transaction Identifier: 27967
Protocol Identifier: 0
Length: 6
Unit Identifier: 1

Modbus
Function Code: Read Discrete Inputs (2)
Reference Number: 0
Bit Count: 1

Ответ:

1517    12.699150000    192.168.100.2   192.168.100.3
Modbus/TCP  64  Response: Trans: 27967;
Unit:   1, Func:   2: Read Discrete Inputs
Modbus/TCP
Transaction Identifier: 27967
Protocol Identifier: 0
Length: 4
Unit Identifier: 1

Modbus
Function Code: Read Discrete Inputs (2)
Byte Count: 1
Data: 00

После изучения текущей реализации стало понятно, что по modbus с I/O Server берутся данные о состоянии 15 входов, посредставом чтения нескольких дискретных входов, а именно 1 и 2 (0x00 и 0x01) значения которых соответствуют True или False. Смещения нет.

Установка pymodbustcp

Устанавливаем виртуальное окржение и модуль pymodbustcp.

$ mkdir project && cd project
$ virtualenv -ppython2.7 env
$ source env/bin/activate
(env)$ pip install pymodbustcp
...
Successfully installed pymodbustcp-0.1.1

Программа для опроса

Самый простой вариант, в моем случае, подключиться посмотреть данные и отключиться. Но правильно получать данные непрерывно при поддержке постоянного подключения.

$ nano modbus_test.py
# coding=utf8
from pyModbusTCP.client import ModbusClient
import time
import sys

def main():
    ip_address='192.168.100.2'
    c = ModbusClient()
    if not c.host(ip_address):
        print("host error")
    if not c.port(502):
        print("port error")
    while True:
        if c.is_open():
            rr = c.read_discrete_inputs(0, 2)
            # [False, True]
            if not rr[0] and rr[1]:
                print 'work'
                sys.exit(0)
            # [True, True]
            elif rr[0] and rr[1]:
                print 'not work'
                sys.exit(1)
            print '-'
            sys.exit(-1)
        else:
            c.open()

if __name__ == "__main__":
    main()

Я же запускаю этот скрипт по cron, проверяю пингуется или нет, затем статус по modbus.

$ nano modbus_test.sh
#!/bin/bash
IP='192.168.100.2'
if ping -q -c 2 -n $IP >/dev/null; then
echo $IP'; up' >> /var/log/messages;
if /project/env/bin/python /project/modbus_test.py; then
echo $IP'; work' >> /var/log/messages
else echo $IP'; not work' >> /var/log/messages; fi
else echo $IP'; down' >> /var/log/messages; fi

Для поддержки постоянного подключения мне кажется правильным было бы использование twisted с бесконечным циклом и проверкой этих данных.

Для прочтения по теме modbus

Очень неплохой ресурс с информацией о протоколе modbus

P.S. Надеюсь кому-то будет полезно.



  • ← сюда
  • туда →

comments powered by Disqus

Опубликовано

12.10.2016

Обновление

05.05.2022

Категории

python

Тэги

  • example 16
  • modbus 1
  • python 30

Всегда на связи

  • Блог Синявского - Ничего не переносить на завтра, это тоже проблема с прокастинацией?
  • © Алексей Синявский, по лицензии CC BY-SA если не указано иное.
  • С использованием Pelican. Тема: Elegant от Talha Mansoor