This commit is contained in:
Sergey Yarkov 2023-11-02 10:43:57 +03:00
parent fdc195d7dd
commit 076e3b7aba
6 changed files with 58 additions and 23 deletions

View File

@ -224,7 +224,7 @@ export const modbusController = {
const streamInterval = setInterval(async () => { const streamInterval = setInterval(async () => {
try { try {
device.display_values = await db.all(`SELECT * FROM "display_values" WHERE slave_id = ?`, [slave_id]) device.display_values = await db.all(`SELECT * FROM "display_values" WHERE slave_id = ?`, [slave_id])
const data = await modbusService.readDataFromDevice(device, device.g_display_reg_type); const data = await modbusService.readDataFromDevice(device);
res.write("event: message\n"); res.write("event: message\n");
res.write(`data: ${JSON.stringify(data)}\n\n`); res.write(`data: ${JSON.stringify(data)}\n\n`);
} catch (error) { } catch (error) {

BIN
data.db

Binary file not shown.

5
index.d.ts vendored
View File

@ -31,3 +31,8 @@ export type ModbusDevice = {
is_logging: boolean; is_logging: boolean;
display_values?: DisplayValue[] display_values?: DisplayValue[]
} }
export type EventDataStream = {
graph: { value: number; format: NumberType } | null;
displayValues: DisplayValue[];
}

View File

@ -22,7 +22,7 @@ CREATE TABLE IF NOT EXISTS "modbus_slaves" (
"id" INTEGER CHECK (id >= 1 AND id <= 255), "id" INTEGER CHECK (id >= 1 AND id <= 255),
"name" VARCHAR(256) NOT NULL, "name" VARCHAR(256) NOT NULL,
"g_display_reg_addr" INTEGER CHECK(g_display_reg_addr >= 0 AND g_display_reg_addr <= 65534) DEFAULT NULL, "g_display_reg_addr" INTEGER CHECK(g_display_reg_addr >= 0 AND g_display_reg_addr <= 65534) DEFAULT NULL,
"g_display_reg_type" VARCHAR(3) CHECK(g_display_reg_type IN("HR", "IR")) DEFAULT "HR", "g_display_reg_type" VARCHAR(3) CHECK(g_display_reg_type IN("HR", "IR")) DEFAULT "IR",
"g_display_reg_format" VARCHAR(5) CHECK(g_display_reg_format IN("UI16", "I16", "UI32", "I32", "FP32")) DEFAULT "UI16", "g_display_reg_format" VARCHAR(5) CHECK(g_display_reg_format IN("UI16", "I16", "UI32", "I32", "FP32")) DEFAULT "UI16",
"g_y_label" VARCHAR(40) DEFAULT "Label", "g_y_label" VARCHAR(40) DEFAULT "Label",
"is_logging" BOOLEAN NOT NULL DEFAULT FALSE, "is_logging" BOOLEAN NOT NULL DEFAULT FALSE,
@ -34,6 +34,7 @@ CREATE TABLE IF NOT EXISTS "display_values" (
"name" VARCHAR(32) NOT NULL, "name" VARCHAR(32) NOT NULL,
"slave_id" INTEGER NOT NULL, "slave_id" INTEGER NOT NULL,
"reg_addr" INTEGER DEFAULT 0 NOT NULL CHECK(reg_addr >= 0 AND reg_addr <= 65534), "reg_addr" INTEGER DEFAULT 0 NOT NULL CHECK(reg_addr >= 0 AND reg_addr <= 65534),
-- "reg_type" VARCHAR(3) CHECK(reg_type IN("HR", "IR", "DI", "DO")) DEFAULT "IR",
"reg_format" INTEGER NOT NULL CHECK(reg_format IN(16, 32)) DEFAULT 16, "reg_format" INTEGER NOT NULL CHECK(reg_format IN(16, 32)) DEFAULT 16,
PRIMARY KEY("id"), PRIMARY KEY("id"),
FOREIGN KEY("slave_id") REFERENCES modbus_slaves("id") ON DELETE CASCADE FOREIGN KEY("slave_id") REFERENCES modbus_slaves("id") ON DELETE CASCADE

View File

@ -148,7 +148,7 @@ document.addEventListener("alpine:init", async () => {
} }
dataStreamSource.onmessage = (e) => { dataStreamSource.onmessage = (e) => {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
console.log('[SSE Message]', data);
if (data.graph !== null) { if (data.graph !== null) {
graphData.push([new Date(), data.graph.value]); graphData.push([new Date(), data.graph.value]);
if (g === null) { if (g === null) {

View File

@ -4,36 +4,65 @@ import * as utils from '#root/utils/index.js'
export const modbusService = { export const modbusService = {
/** /**
* @param {import("..").ModbusDevice} device * @param {import("..").ModbusDevice} device
* @param {"HR" | "IR"} type * @return {Promise<import("..").EventDataStream>}
*/ */
async readDataFromDevice(device, type = 'HR') { async readDataFromDevice(device) {
const { g_display_reg_format: g_format, g_display_reg_addr: g_reg_addr } = device; const { g_display_reg_format, g_display_reg_addr, g_display_reg_type } = device;
let readLength = 1; // 16 bits default
/** @type {import("..").EventDataStream} */
const data = { graph: null, displayValues: [] };
modbusClient.setID(device.id); modbusClient.setID(device.id);
if (g_format?.includes('32')) readLength = 2; /* Read data for graph */
if (g_format?.includes('64')) readLength = 4; if (g_display_reg_addr !== null) {
if (g_format?.includes('128')) readLength = 8; const graphValue = await this.readModbusRegisters(g_display_reg_addr, g_display_reg_type, g_display_reg_format);
data.graph = {
let graphValue; value: utils.readNumberFromBuf(graphValue, device.g_display_reg_format, 'BE'),
if (type === 'HR') graphValue = await modbusClient.readHoldingRegisters(g_reg_addr, readLength); format: g_display_reg_format
if (type === 'IR') graphValue = await modbusClient.readInputRegisters(g_reg_addr, readLength); }
}
/* Read data for display values */
if (device.display_values) { if (device.display_values) {
for (const value of device.display_values) { for (const value of device.display_values) {
value.data = Buffer.from((await modbusClient.readHoldingRegisters(value.reg_addr, 1)).buffer).readUInt16BE(); value.data = Buffer.from((await this.readModbusRegisters(value.reg_addr, 'HR', 'UI16'))).readUInt16BE();
} }
} }
const graph = (g_reg_addr !== null ? { data.displayValues = device.display_values;
value: utils.readNumberFromBuf(graphValue.buffer, device.g_display_reg_format, 'BE'),
format: g_format
} : null);
return { return data;
graph, },
displayValues: device.display_values
/**
* @param {number} addr
* @param {"HR" | "IR" | "DI"} type
* @param {import("..").NumberType} format
* @return {Promise<Buffer>} buffer data
*/
async readModbusRegisters(addr, type, format) {
let data;
let len = 1;
if (format.includes('32')) len = 2;
if (format.includes('64')) len = 4;
if (format.includes('128')) len = 8;
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, len);
break;
default:
throw new Error('Incorrect modbus register type!');
} }
return data.buffer;
} }
} }