Integracja urządzeń Modbus
IoT | Modbus | Odczyt i zapis cewek Modbus | Komputer brzegowy | JSON | Baza danych SQL | Grafana | Pulpity nawigacyjne w czasie rzeczywistym
Jednominutowa integracja Modbus do SQL z InDriver — łatwy samouczek
Dołącz do Jane z inanalytics.io, która zademonstruje szybką i wydajną integrację urządzenia Modbus z SQL, wszystko w ciągu zaledwie jednej minuty, wykorzystując potężne 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.

W tym rozwiązaniu InDriver, zainstalowany na komputerze z systemem Windows 11 Edge, zbiera dane z urządzenia Moxa IOLogic E1212 podłączonego przez Modbus TCP. Reprezentacja binarna wartości drugiej bieżącego znacznika czasu jest przechowywana w urządzeniu Moxa w 8-bajtowym wyjściu cewki co sekundę. Co 5 sekund urządzenie jest odczytywane, a dane są przechowywane w bazie danych SQL w formacie JSON.
Opis przykładowego algorytmu integracji Modbus
onStartup: Creating an SQL table if it doesn't exist and installing timer hooks.
Poniższe wiersze 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 zawierające dane z tabeli „public.modbus”, na potrzeby przykładu.
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” o adresie 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.
Poniższe wiersze kodu:
Generuj tablicę z wartościami bitów reprezentującymi bieżącą wartość sekund co 1 sekundę, synchronicznie z zegarem (np. 00:00:01, 00:00:02 itd.), a następnie zapisz wygenerowaną tablicę w urządzeniu za pomocą ModbusApi.writeDevice ('Moxa', '{ "name": "coils", "type": "COILS", "address": 1, "data":' + JSON.stringify(array) + ' }'), który zapisuje do cewek od 1 do 8 bitów.
Odczytaj wartości cewek z urządzenia za pomocą ModbusApi.readDevice ('Moxa', '{"name": "coils", "type": "COILS", "address": 1, "size": 8}') co 5 sekund, zaloguj pobrane wartości w formacie JSON do tabeli SQL za pomocą InDriver.sqlExecute ("AzurePGSQL", ["select tsapiinsert('public','modbus','IOLogicE1212', '", ts.toUTCString(), "','", ModbusApi.getDeviceData ("Moxa"), "' );"]) i wyślij wiadomość do innych zadań InDriver zawierającą uzyskane wartości cewek Modbus.
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 Grafana

W Grafanie proces ten obejmuje umieszczanie wizualizacji i konfigurowanie zapytań SQL, jak pokazano poniżej.
W tym przykładzie zastosowano zarówno wizualizację tabeli, jak i szeregu czasowego. Wizualizacja tabeli obejmuje 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ąc zmiany wartości cewek w czasie.

Poniżej przedstawiono zapytanie SQL zastosowane w tabeli:
select 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)
) as seconds,
(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"
from modbus where source = 'IOLogicE1212' order by ts desc;
Przykład 2: Unikalna cecha InDriver — Jednoczesny odczyt wielu urządzeń Modbus


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 wiersze kodu:
Importuj ModbusApi z biblioteki obiektów komunikacji Modbus InDriver.
Zainstaluj hak, aby 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 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 wiersze 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 obejmuje to równoczesne wykonywanie następujących funkcji odczytu ModbusApi: ModbusApi.readDevice('MoxaOne'.....) , ModbusApi.readDevice('MoxaTwo'.....) i ModbusApi.readDevice('MoxaThree'.....) .
Sprawdź ukończenie odczytu, używając ModbusApi.isSucceeded() . Po potwierdzeniu pobierz wszystkie odczytane dane, używając ModbusApi.getAllData() . Dane te można bez problemu zalogować do 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 odstępach 5-sekundowych, 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 } } }
}
