Modbus – protokół komunikacyjny stworzony przez firmę Modicon. Służy do komunikacji z programowalnymi kontrolerami tej firmy, a także innych producentów. Umożliwia zarządzanie siecią takich urządzeń jak np. system sterowania temperatury i wilgotności. Powstały wersje dla portu szeregowego i dla sieci IP. W sieciach IP używany jest protokół TCP na porcie 502. Modbus jest protokołem typu Master-Slave. Modbus jest obecnie standardem otwartym.

Poniżej znajduje się struktura systemu

Rodzaje protokołów komunikacyjnych Modbus:

Rodzaje protokołów komunikacyjnych Modbus:

1. Modbus TCP/IP – klasyczny Ethernet TCP/IP o szybkości 10/100 Mbit/s.

2. Modbus RTU – szeregowy binarny protokół typu Master/Slave

3. Modbus ASCII – szeregowy ASCII protokół typu Master/Slave

4. JBUS – ograniczony zbór wiadomości komunikacyjnych typu Modbus RTU

5. MODBUS PLUS – deterministyczny token LAN, protokół peer to peer, 1Mbit/s.

Filmik prezentujący

Filmik prezentujący działanie zaimplementowanej funkcjonalności

Opis działania naszej implementacji:

Nasza aplikacja, którą zaimplementowaliśmy jest przykładem protokołu komunikacyjnego typu Modbus TCP/IP w języku Python, która ma za zadanie odczytywać z pliku tekstowego pierwszą linię i zamieniać ją na zmienną liczbową. Następnie klient łączy się i pobiera tę zmienną. Plik tekstowy jest monitorowany w czasie rzeczywistym.

Uproszczony schemat komunikacji pomiędzy klientem, a serwerem

Zajmując się protokołem Modbus warto wiedzieć, że ramka protokołu Modbus ADU (application data unit) znajduje się w warstwie aplikacji modelu sieciowego TCP/IP. Takie usytuowanie ramki oznacza, że gdy wysyłamy dane przy pomocy protokołu Modbus TCP dane przechodzą przez każdą następną warstwę modu sieciowego i są zaopatrywane w kolejne nagłówki protokołów tych warstw. Proces ten nazywamy hermetyzacją danych (ang. encapsulated). Gdy ramka dojdzie do najniższej warstwy modelu sieciowego (warstwy fizycznej) dane zamieniane są na sygnały elektryczne i przesyłane do punktu docelowego. W urządzeniu docelowym odbywa się odwrotny proces, to znaczy dane są odpakowywane aż w warstwie aplikacji zostanie jedynie ramka protokołu Modbus – ADU.

Listing

#!/usr/bin/env python

# --------------------------------------------------------------------------- #
# import the various server implementations
# --------------------------------------------------------------------------- #
from pymodbus.server.asynchronous import StartTcpServer
from pymodbus.datastore import ModbusSparseDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from twisted.internet import threads

# --------------------------------------------------------------------------- #
# configure the service logging
# --------------------------------------------------------------------------- #
import logging

FORMAT = ('%(asctime)-15s %(threadName)-15s'
          ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)


# --------------------------------------------------------------------------- #
# Set up class for data
# --------------------------------------------------------------------------- #

class Device(object):
    def __init__(self, path, device_type, callback):
        self.path = path
        self.device_type = device_type
        self.callback = callback
        self.value = -1

    def update(self):
        self.value = self.callback(self.path)

# --------------------------------------------------------------------------- #
# Read value from file
# --------------------------------------------------------------------------- #


def read_value_from_file(file_path):
    try:
        f = open(file_path)
    except IOError as e:
        return -1

    lines = f.readlines()
    f.close()
    value = int(lines[0])
    return value

# --------------------------------------------------------------------------- #
# Data block - stores value in memory and it passes operation to a queue for future
# --------------------------------------------------------------------------- #


class CallbackDataBlock(ModbusSparseDataBlock):

    def __init__(self, devices):
        self.devices = devices
        self.devices[0xbeef] = len(self.devices)  # the number of devices
        self.get_line()
        # values = [k:0 ]
        self.values = {k: 0 for k in self.devices.keys()}
        # self.values = {k: 0 for k in self.devices.}
        super(CallbackDataBlock, self).__init__(self.values)

    def get_lines(self, devices):
        values = {}
        for device in devices:
            device.update()
            values[device.register] = device.value
            print(device.path, device.value)
        return values

    def get_line(self):
        print('getting value from file')
        temp_files = []
        devices_registers = filter(lambda d: d != 0xbeef, self.devices)
        for registers in devices_registers:
            if self.devices[registers].device_type == 'file':
                self.devices[registers].register = registers
                temp_files.append(self.devices[registers])
        d = threads.deferToThread(self.get_lines, temp_files)
        d.addCallback(self.update_line_value)

    def update_line_value(self, values):
        for register in values:
            self.values[register] = values[register]
        self.get_line()

# --------------------------------------------------------------------------- #
# Mapping devices
# --------------------------------------------------------------------------- #


def get_devices_map():
    devices = {
        0x0001: Device("/home/pi/modbus/data.dat", "file", read_value_from_file)
    }
    return devices

# --------------------------------------------------------------------------- #
# Run method
# --------------------------------------------------------------------------- #


if __name__ == "__main__":
    devices = get_devices_map()
    block = CallbackDataBlock(devices)
    store = ModbusSlaveContext(di=None, co=None, hr=None, ir=block)
    context = ModbusServerContext(slaves=store, single=True)
    StartTcpServer(context, address=("0.0.0.0", 5020))
from pymodbus.client.sync import ModbusTcpClient as ModbusClient


 if __name__ == "__main__":
 client = ModbusClient("172.20.10.5", 5020)  
 line = client.read_input_registers(0, 1)
 print(line)  
 print(line.registers)