top of page

Integracja urządzeń Modbus

IoT | Modbus | Odczyt i zapis cewek Modbus | Komputer brzegowy | JSON | Baza danych SQL | Grafana | Dashboardy w czasie rzeczywistym

Jednominutowa integracja Modbus z SQL za pomocą InDriver — prosty samouczek

Dołącz do Jane z inanalytics.io, która zaprezentuje szybką i wydajną integrację urządzenia Modbus z SQL, w zaledwie minutę, wykorzystując zaawansowane możliwości InDriver. Ten samouczek krok po kroku jest przeznaczony zarówno dla początkujących, jak i doświadczonych profesjonalistów, którzy chcą usprawnić proces integracji Modbus z SQL.

Przykład 1: Odczyt/zapis urządzenia Modbus, rejestrowanie Microsoft Azure i integracja pulpitu nawigacyjnego Grafana.

Integracja urządzeń Modbus z bazą danych SQL i Grafana przy użyciu InDriver

W tym rozwiązaniu InDriver, zainstalowany na komputerze z systemem Windows 11 Edge, zbiera dane z czujnika Moxa IOLogic E1212 podłączonego przez Modbus TCP. Binarna reprezentacja wartości sekund bieżącego znacznika czasu jest zapisywana w urządzeniu Moxa w 8-bajtowym wyjściu cewki co sekundę. Co 5 sekund urządzenie jest odczytywane, a dane są zapisywane w bazie danych SQL w formacie JSON.

Opis przykładowego algorytmu integracji Modbus

onStartup: Tworzenie tabeli SQL, jeśli nie istnieje i instalowanie haków timera.

Poniższe linie kodu:

  • Importuj ModbusApi z biblioteki obiektów komunikacji Modbus InDriver.

  • Utwórz tabelę „public.modbus” przy użyciu TSApi z kolumnami: source (tekst), ts (znacznik czasu) i data (JSON).

  • Usuń wszystkie wiersze z danymi z tabeli „public.modbus” w celach przykładowych.

  • Zainstaluj haki, aby wyzwalać blok onHook co 1 sekundę (1000 ms) i co 5 sekund (5000 ms) synchronicznie z zegarem komputera.

  • Połącz się z urządzeniem Modbus „Moxa” pod adresem 192.168.1.22.

InDriver.import('ModbusApi');

InDriver.sqlExecute("AzurePGSQL","select tsapicreatetable('public','modbus');");

InDriver.sqlExecute("AzurePGSQL","delete from public.modbus;");

InDriver.installHook(1000);

InDriver.installHook(5000);

ModbusApi.connectDevice( 'Moxa','{ "mode": "TCP", "networkAddress": "192.168.0.22"}');

onHook: ustawianie cewek urządzenia Modbus co 1 sekundę, odczytywanie i rejestrowanie wartości cewek w tabeli SQL co 5 sekund.

The following lines of code:

  • Generate an array with bit values representing the current time seconds value every 1s, synchronously with the clock (e.g., 00:00:01, 00:00:02, etc.) and write the generated array to the device using ModbusApi.writeDevice('Moxa', '{ "name": "coils", "type": "COILS", "address": 1, "data":' + JSON.stringify(array) + ' }'), which writes to coils from 1 to 8 bits.

  • Read coils' values from the device using ModbusApi.readDevice('Moxa', '{"name": "coils", "type": "COILS", "address": 1, "size": 8}') every 5 seconds, log the retrieved values in JSON format to an SQL table using InDriver.sqlExecute("AzurePGSQL", ["select tsapiinsert('public','modbus','IOLogicE1212', '", ts.toUTCString(), "','", ModbusApi.getDeviceData("Moxa"), "' );"]) and send a message to other InDriver tasks containing the acquired Modbus Coils Values.

if (InDriver.isHook(1000)) {

let seconds = ts.getSeconds()

InDriver.debug('write: ' + seconds)

let array = new Array(8)

for (var i = 0; i < 8; i++) {

array[i] = (seconds >> i) & 0x1

}

InDriver.debug('data: ' + JSON.stringify(array))

ModbusApi.writeDevice('Moxa','{ "name": "coils", "type": "COILS", "address": 1, "data":' + JSON.stringify(

array) + ' }')

}

if (InDriver.isHook(5000)) {

ModbusApi.readDevice( 'Moxa','{"name": "coils", "type": "COILS", "address":1, "size":8}')

let data = ModbusApi.getDeviceData("Moxa")

InDriver.debug("read: ",data)

let ts = InDriver.hookTs()

InDriver.sqlExecute("AzurePGSQL",["select tsapiinsert('public','modbus','IOLogicE1212', '", ts.toUTCString(), "','", data, "' );"])

InDriver.sendMessage(ts, '["device data","arch"]', data)

}

Wizualizacja danych Modbus w Grafanie

Wizualizacja Modbus IO, tabela i szereg czasowy w Grafana

W Grafanie proces ten obejmuje umieszczanie wizualizacji i konfigurowanie zapytań SQL, jak pokazano poniżej.

W tym przykładzie wykorzystano zarówno wizualizację tabelaryczną, jak i szeregów czasowych. Wizualizacja tabelaryczna zawiera kolumny takie jak ts (znacznik czasu), sekundy (liczba całkowita) reprezentujące sekundy uzyskane z reprezentacji bitowej cewek oraz pojedyncze kolumny dla wartości cewek od 1 do 8.

Podobnie, wizualizacja szeregów czasowych wykorzystuje niemal identyczne zapytanie SQL, prezentujące zmiany wartości cewek w czasie.

Edycja zapytania SQL w celu wyświetlenia Modbus IO na wykresie szeregu czasowego Grafana

Poniżej przedstawiono zapytanie SQL zastosowane w tabeli:

wybierz ts,

(((data->'Moxa'->'Read'->'coils'->>'1'='true')::integer << 0) |

((data->'Moxa'->'Read'->'coils'->>'2'='true')::integer << 1) |

((data->'Moxa'->'Read'->'coils'->>'3'='true')::integer << 2) |

((data->'Moxa'->'Read'->'coils'->>'4'='true')::integer << 3) |

((data->'Moxa'->'Read'->'coils'->>'5'='true')::integer << 4) |

((data->'Moxa'->'Read'->'coils'->>'6'='true')::integer << 5) |

((data->'Moxa'->'Read'->'coils'->>'7'='true')::integer << 6) |

((data->'Moxa'->'Read'->'coils'->>'8'='true')::integer << 7)

) jako sekundy,

(data->'Moxa'->'Read'->'coils'->>'8'='true')::integer as "coil8",

(data->'Moxa'->'Read'->'coils'->>'7'='true')::integer as "coil7",

(data->'Moxa'->'Read'->'coils'->>'6'='true')::integer as "coil6",

(data->'Moxa'->'Read'->'coils'->>'5'='true')::integer as "coil5",

(data->'Moxa'->'Read'->'coils'->>'4'='true')::integer as "coil4",

(data->'Moxa'->'Read'->'coils'->>'3'='true')::integer as "coil3",

(data->'Moxa'->'Read'->'coils'->>'2'='true')::integer as "coil2",

(data->'Moxa'->'Read'->'coils'->>'1'='true')::integer as "coil1"

z modbus gdzie source = 'IOLogicE1212' zamów według ts desc;

Przykład 2: Unikalna funkcja InDriver – Jednoczesny odczyt wielu urządzeń Modbus

Schemat jednoczesnego odczytu urządzeń Modbus
Dane Modbus w formacie JSON

W tym scenariuszu trzy moduły Moxa IOLogic Ethernet I/O są połączone z komputerem brzegowym z InDriver. Wymagania systemowe obejmują równoczesny odczyt wejść dyskretnych ze wszystkich urządzeń, co zapewnia jednoczesne pobieranie danych, a nie sekwencyjne skanowanie.

Opis przykładowego algorytmu

onStartup: Podłączenie do trzech urządzeń Modbus i instalacja haka odczytu.

Poniższe linie kodu:

  • Importuj ModbusApi z biblioteki obiektów komunikacji Modbus InDriver.

  • Zainstaluj hak, który będzie wyzwalał blok onHook co 5 sekund (5000 ms) synchronicznie z zegarem komputera.

  • Połącz się z trzema urządzeniami Modbus „MoxaOne”, „MoxaTwo” i „MoxaThree” pod adresami od 192.168.1.22 do 192.168.1.24

InDriver.import('ModbusApi');

InDriver.installHook(5000);

ModbusApi.connectDevice( 'MoxaOne','{ "mode": "TCP", "networkAddress": "192.168.0.22"}');

ModbusApi.connectDevice( 'MoxaTwo','{ "mode": "TCP", "networkAddress": "192.168.0.23"}');

ModbusApi.connectDevice( 'MoxaThree,'{ "mode": "TCP", "networkAddress": "192.168.0.24"}');

onHook: Jednoczesne odczytywanie dyskretnych danych wejściowych i rejestrowanie danych w SQL

Poniższe linie kodu:

  • Podobnie jak w przypadku transakcji SQL, ModbusApi oferuje bloki transakcji begin () i commit () dla funkcji odczytu i zapisu Modbus. Wszystkie funkcje w takim bloku są wykonywane jednocześnie po operacji commit () lub commitWait (). W tym przypadku wiąże się to z jednoczesnym wykonaniem następujących funkcji odczytu ModbusApi: ModbusApi.readDevice('MoxaOne'.....) , ModbusApi.readDevice('MoxaTwo'.....) i ModbusApi.readDevice('MoxaThree'.....) .

  • Sprawdź, czy odczyt został ukończony, używając funkcji ModbusApi.isSucceeded() . Po potwierdzeniu, pobierz wszystkie odczytane dane za pomocą funkcji ModbusApi.getAllData() . Dane te można łatwo zarejestrować w tabeli SQL, a źródło w tym przykładzie określono jako „3xIOLogicE1212”.

if (InDriver.isHook(5000)) {

ModbusApi.begin()

ModbusApi.readDevice( 'MoxaOne','{"name": "inputs", "type": "DISCRETEINPUTS", "address":1, "size":8}')

ModbusApi.readDevice( 'MoxaTwo','{"name": "inputs", "type": "DISCRETEINPUTS", "address":1, "size":8}')

ModbusApi.readDevice( 'MoxaThree','{"name": "inputs", "type": "DISCRETEINPUTS", "address":1, "size":8}')

ModbusApi.commitWait()

if (ModbusApi.isSucceeded()) {

let data = ModbusApi.getAllData()

let ts = InDriver.hookTs()

InDriver.sqlExecute("AzurePGSQL",["select tsapiinsert('public','modbus','3xIOLogicE1212', '", ts.toUTCString(), "','", data, "' );"])

InDriver.sendMessage(ts, '["device data","arch"]', data)

}

}

Blok kodu generuje zarejestrowane dane w formacie JSON, jak pokazano poniżej.
Odczyt odbywa się jednocześnie i zsynchronizowany z zegarem komputera , w regularnych 5-sekundowych odstępach, na przykład o godzinie 00:00:00, 00:00:05, 00:00:10 itd.

{  

"MoxaOne": { "Odczyt": { "dane wejściowe": { "1": prawda, "2": fałsz, "3": prawda, "4": fałsz, "5": prawda, "6": fałsz, "7": prawda, "8": fałsz } } },  

"MoxaTwo": { "Odczyt": { "dane wejściowe": { "1": prawda, "2": fałsz, "3": prawda, "4": fałsz, "5": prawda, "6": fałsz, "7": prawda, "8": fałsz } } },  

"MoxaThree": { "Odczyt": { "dane wejściowe": { "1": prawda, "2": fałsz, "3": prawda, "4": fałsz, "5": prawda, "6": fałsz, "7": prawda, "8": fałsz } } }

}

bottom of page