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.

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

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.

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


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 } } }
}
