mirror of
https://github.com/sergeyyarkov/modbus-logger.git
synced 2026-10-11 02:18:51 +03:00
165 lines
4.5 KiB
JavaScript
165 lines
4.5 KiB
JavaScript
import modbusClient from "#root/config/modbus-client.config.js";
|
|
import db from "#root/config/database.config.js";
|
|
import * as utils from "#root/utils/index.js";
|
|
|
|
export const modbusService = {
|
|
/**
|
|
* @param {import("..").ModbusDevice} device
|
|
* @return {Promise<import("..").EventDataStream>}
|
|
*/
|
|
async readDataFromDevice(device) {
|
|
const { g_display_reg_format, g_display_reg_addr, g_display_reg_type, display_values } = device;
|
|
|
|
/** @type {import("..").EventDataStream} */
|
|
const data = { graph: null, displayValues: [] };
|
|
|
|
modbusClient.setID(device.id);
|
|
|
|
/* Read data for graph */
|
|
if (g_display_reg_addr !== null) {
|
|
const graphValueBuf = await this.readModbusRegisters(
|
|
g_display_reg_addr,
|
|
g_display_reg_type,
|
|
g_display_reg_format,
|
|
);
|
|
data.graph = {
|
|
value: utils.readNumberFromBuf(graphValueBuf, device.g_display_reg_format, "BE"),
|
|
format: g_display_reg_format,
|
|
};
|
|
}
|
|
|
|
/* Read data for display values */
|
|
if (display_values) {
|
|
for (const v of device.display_values) {
|
|
const displayValueBuf = await this.readModbusRegisters(v.reg_addr, v.reg_type, v.reg_format);
|
|
v.data = utils.readNumberFromBuf(displayValueBuf, v.reg_format, "BE");
|
|
data.displayValues.push(v);
|
|
}
|
|
}
|
|
|
|
return data;
|
|
},
|
|
|
|
/**
|
|
* @param {import("..").AppConfig} appConfig
|
|
* @return {Promise<void>}
|
|
*/
|
|
async connect(appConfig) {
|
|
const {
|
|
mb_connection_type,
|
|
mb_tcp_ip,
|
|
mb_tcp_port,
|
|
mb_rtu_path,
|
|
mb_rtu_baud,
|
|
mb_rtu_data_bits,
|
|
mb_rtu_parity,
|
|
mb_rtu_stop_bits,
|
|
} = appConfig;
|
|
|
|
if (modbusClient.isOpen) {
|
|
modbusClient.close(undefined);
|
|
modbusClient.destroy(undefined);
|
|
}
|
|
|
|
switch (mb_connection_type) {
|
|
case "TCP": {
|
|
await modbusClient.connectTCP(mb_tcp_ip, { port: mb_tcp_port });
|
|
break;
|
|
}
|
|
case "RTU": {
|
|
await modbusClient.connectRTU(mb_rtu_path, {
|
|
baudRate: mb_rtu_baud,
|
|
dataBits: mb_rtu_data_bits,
|
|
parity: mb_rtu_parity,
|
|
stopBits: mb_rtu_stop_bits,
|
|
});
|
|
break;
|
|
}
|
|
default:
|
|
throw new Error("Unsupported connection type!");
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @param {number} addr
|
|
* @param {import("..").RegisterType} type
|
|
* @param {import("..").NumberType} format
|
|
* @return {Promise<Buffer>} buffer data
|
|
*/
|
|
async readModbusRegisters(addr, type, format) {
|
|
let data;
|
|
let len = 1;
|
|
|
|
switch (format) {
|
|
case "UI32":
|
|
case "I32":
|
|
case "FP32":
|
|
len = 2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (type) {
|
|
case "HR":
|
|
data = await modbusClient.readHoldingRegisters(addr, len);
|
|
break;
|
|
case "IR":
|
|
data = await modbusClient.readInputRegisters(addr, len);
|
|
break;
|
|
case "DI":
|
|
data = await modbusClient.readDiscreteInputs(addr, 1);
|
|
break;
|
|
case "DO":
|
|
data = await modbusClient.readCoils(addr, 1);
|
|
break;
|
|
default:
|
|
throw new Error("Incorrect modbus register type!");
|
|
}
|
|
|
|
return data.buffer;
|
|
},
|
|
|
|
async getDevices() {
|
|
/** @type {import("..").ModbusDevice[]} */
|
|
const devices = await db.all(`
|
|
SELECT ms.id AS id, ms.name AS name, g_display_reg_addr, g_display_reg_format, g_display_reg_type, g_y_label,
|
|
CASE
|
|
WHEN COUNT(dv.id) = 0 THEN '[]'
|
|
ELSE '[' || GROUP_CONCAT(
|
|
JSON_OBJECT(
|
|
'id', dv.id,
|
|
'name', dv.name,
|
|
'reg_addr', dv.reg_addr,
|
|
'reg_format', dv.reg_format,
|
|
'reg_type', dv.reg_type
|
|
), ', '
|
|
) || ']' END AS display_values
|
|
FROM modbus_slaves AS ms
|
|
LEFT JOIN display_values AS dv ON dv.slave_id = ms.id
|
|
GROUP BY ms.id, ms.name;
|
|
`);
|
|
// @ts-ignore
|
|
devices.forEach((s) => (s.display_values = JSON.parse(s.display_values)));
|
|
return devices;
|
|
},
|
|
|
|
/**
|
|
* @param {import("..").ModbusDevice} device
|
|
* @param {(data: import("..").EventDataStream, error: any) => void} callback
|
|
* @param {number} intervalMs
|
|
*/
|
|
startDevicePollInterval(device, callback, intervalMs) {
|
|
const poll = async () => {
|
|
try {
|
|
device.display_values = await db.all(`SELECT * FROM "display_values" WHERE slave_id = ?`, [device.id]);
|
|
const data = await this.readDataFromDevice(device);
|
|
callback(data);
|
|
} catch (error) {
|
|
callback(null, error);
|
|
}
|
|
};
|
|
return setInterval(poll, intervalMs);
|
|
},
|
|
};
|