mirror of
https://github.com/sergeyyarkov/modbus-logger.git
synced 2026-10-11 02:18:51 +03:00
progress
This commit is contained in:
parent
ffcfe6767d
commit
4edb0f3a9d
@ -3,7 +3,7 @@ import modbusClient from "#root/config/modbus-client.config.js";
|
|||||||
import * as utils from '#root/utils/index.js'
|
import * as utils from '#root/utils/index.js'
|
||||||
import { RowNotFoundError } from '#root/errors/index.js'
|
import { RowNotFoundError } from '#root/errors/index.js'
|
||||||
import { appService, modbusService } from "#root/services/index.js";
|
import { appService, modbusService } from "#root/services/index.js";
|
||||||
import { modbusDeviceModel } from "#root/models/index.js";
|
import { modbusDeviceModel, displayValueModel } from "#root/models/index.js";
|
||||||
|
|
||||||
export const modbusController = {
|
export const modbusController = {
|
||||||
/**
|
/**
|
||||||
@ -63,19 +63,14 @@ export const modbusController = {
|
|||||||
*/
|
*/
|
||||||
async createDevice(req, res, next) {
|
async createDevice(req, res, next) {
|
||||||
try {
|
try {
|
||||||
const { id, name, g_display_reg_addr, g_display_reg_format, g_display_reg_type, g_y_label } =
|
await modbusDeviceModel.create({
|
||||||
req.body;
|
id: req.body.id,
|
||||||
await db.run(
|
name: req.body.name,
|
||||||
`INSERT INTO "modbus_slaves" (
|
g_display_reg_addr: req.body.g_display_reg_addr,
|
||||||
"id",
|
g_display_reg_format: req.body.g_display_reg_format,
|
||||||
"name",
|
g_display_reg_type: req.body.g_display_reg_type,
|
||||||
"g_display_reg_addr",
|
g_y_label: req.body.g_y_label
|
||||||
"g_display_reg_format",
|
})
|
||||||
"g_display_reg_type",
|
|
||||||
"g_y_label")
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
||||||
[id, name, g_display_reg_addr, g_display_reg_format, g_display_reg_type, g_y_label],
|
|
||||||
);
|
|
||||||
return res.status(200).json({ message: "Device created." });
|
return res.status(200).json({ message: "Device created." });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
@ -124,9 +119,10 @@ export const modbusController = {
|
|||||||
*/
|
*/
|
||||||
async removeDevice(req, res, next) {
|
async removeDevice(req, res, next) {
|
||||||
try {
|
try {
|
||||||
const device = await db.get(`SELECT id FROM "modbus_slaves" WHERE id = ?`, [req.body.id]);
|
const { id } = req.body;
|
||||||
|
const device = await modbusDeviceModel.getById(id)
|
||||||
if (!device) throw new RowNotFoundError();
|
if (!device) throw new RowNotFoundError();
|
||||||
await db.run(`DELETE FROM "modbus_slaves" WHERE id = ?`, [req.body.id]);
|
await modbusDeviceModel.delById(id);
|
||||||
return res.status(200).json({ message: "Device removed." });
|
return res.status(200).json({ message: "Device removed." });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
@ -167,7 +163,10 @@ export const modbusController = {
|
|||||||
*/
|
*/
|
||||||
async removeDisplayValue(req, res, next) {
|
async removeDisplayValue(req, res, next) {
|
||||||
try {
|
try {
|
||||||
await db.run(`DELETE FROM "display_values" WHERE id = ?`, req.body.id);
|
const { id } = req.body;
|
||||||
|
const value = await displayValueModel.getById(id);
|
||||||
|
if (!value) throw new RowNotFoundError();
|
||||||
|
await displayValueModel.delById(id);
|
||||||
return res.status(200).json({ message: "Display value removed." });
|
return res.status(200).json({ message: "Display value removed." });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
@ -199,7 +198,7 @@ export const modbusController = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates event stream aboud modbus connection status
|
* Creates event stream about modbus connection status
|
||||||
* @param {import('express').Request} req
|
* @param {import('express').Request} req
|
||||||
* @param {import('express').Response} res
|
* @param {import('express').Response} res
|
||||||
* @param {import('express').NextFunction} next
|
* @param {import('express').NextFunction} next
|
||||||
|
|||||||
@ -57,26 +57,27 @@ CREATE TABLE IF NOT EXISTS "display_values" (
|
|||||||
INSERT INTO "modbus_slaves" (
|
INSERT INTO "modbus_slaves" (
|
||||||
"id", "name", "g_display_reg_addr", "g_display_reg_type", "g_display_reg_format", "g_y_label"
|
"id", "name", "g_display_reg_addr", "g_display_reg_type", "g_display_reg_format", "g_y_label"
|
||||||
) VALUES
|
) VALUES
|
||||||
(1, "Device #1", 0, "IR", "UI16", "Label 1"),
|
(1, "MKP #1", 132, "HR", "UI16", "PID Out"),
|
||||||
(2, "Device #2", 1, "IR", "UI32", "Label 2"),
|
(2, "Test Device #1", 1, "IR", "UI32", "Label 2"),
|
||||||
(3, "Device #3", 3, "IR", "UI16", "Label 3"),
|
(3, "Test Device #2", 3, "IR", "UI16", "Label 3"),
|
||||||
(4, "Device #4", NULL, NULL, NULL, "Label 4");
|
(4, "Test Device #3", NULL, NULL, NULL, "Label 4");
|
||||||
|
|
||||||
INSERT INTO "display_values" (
|
INSERT INTO "display_values" (
|
||||||
"id", "name", "slave_id", "reg_addr", "reg_format", "reg_type"
|
"id", "name", "slave_id", "reg_addr", "reg_format", "reg_type"
|
||||||
) VALUES
|
) VALUES
|
||||||
(1, "CV1", 1, 10, "UI16", "IR"),
|
(1, "SP", 1, 138, "UI32", "HR"),
|
||||||
(2, "CV2", 1, 11, "I16", "IR"),
|
(2, "Status Device", 1, 89, "UI16", "HR"),
|
||||||
(3, "SP", 1, 12, "UI32", "IR"),
|
(3, "Control action type", 1, 2301, "BOOL", "DI"),
|
||||||
(4, "CV1", 2, 13, "I32", "IR"),
|
(4, "S.L.Bd", 1, 528, "UI16", "HR"),
|
||||||
(5, "CV2", 2, 14, "I16", "IR"),
|
(5, "VAL1", 2, 0, "I32", "IR"),
|
||||||
(6, "SP", 2, 15, "UI16", "IR"),
|
(6, "VAL2", 2, 2, "I16", "IR"),
|
||||||
(7, "CV1", 3, 16, "UI16", "HR"),
|
(7, "VAL3", 2, 3, "UI16", "IR"),
|
||||||
(8, "CV2", 3, 17, "FP32", "HR"),
|
(8, "VAL4", 3, 4, "UI16", "HR"),
|
||||||
(9, "SP", 3, 15, "UI16", "IR"),
|
(9, "VAL5", 3, 5, "FP32", "HR"),
|
||||||
(10, "Control action type", 3, 0, "BOOL", "DI"),
|
(10, "VAL6", 3, 7, "UI16", "IR"),
|
||||||
(11, "Status ALARM1", 3, 1, "BOOL", "DO"),
|
(11, "VAL7", 3, 0, "BOOL", "DI"),
|
||||||
(12, "Status ALARM2", 3, 2, "BOOL", "DO");
|
(12, "VAL8", 3, 1, "BOOL", "DO"),
|
||||||
|
(13, "VAL9", 3, 2, "BOOL", "DO");
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- Down
|
-- Down
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|||||||
55
models/base.model.js
Normal file
55
models/base.model.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import db from '#root/config/database.config.js'
|
||||||
|
|
||||||
|
export class BaseModel {
|
||||||
|
/**
|
||||||
|
* @param {string} table
|
||||||
|
*/
|
||||||
|
constructor(table) {
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number | string} id
|
||||||
|
* @param {string[]} keys
|
||||||
|
* @return {Promise<any>}
|
||||||
|
*/
|
||||||
|
async getById(id, keys = ['*']) {
|
||||||
|
const query = `SELECT ${keys.join(',')} FROM ${this.table} WHERE id = ?`;
|
||||||
|
const params = [id];
|
||||||
|
const res = await db.get(query, params);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number | string} id
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
async delById(id) {
|
||||||
|
const query = `DELETE FROM ${this.table} WHERE id = ?`;
|
||||||
|
await db.run(query, [id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string[]} keys
|
||||||
|
*/
|
||||||
|
async getList(keys = ['*']) {
|
||||||
|
const query = `SELECT ${keys.join(',')} FROM ${this.table}`;
|
||||||
|
const res = await db.all(query);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{ [key: string]: any }} data
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
*/
|
||||||
|
async create(data) {
|
||||||
|
const fields = Object.keys(data);
|
||||||
|
const values = Object.values(data);
|
||||||
|
const query = `
|
||||||
|
INSERT INTO ${this.table}
|
||||||
|
(${fields.join(', ')})
|
||||||
|
VALUES (${values.map(() => '?').join(',')})`;
|
||||||
|
await db.run(query, values);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
models/display-value.model.js
Normal file
7
models/display-value.model.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { BaseModel } from './base.model.js'
|
||||||
|
|
||||||
|
export class DisplayValueModel extends BaseModel {
|
||||||
|
constructor() {
|
||||||
|
super('display_values')
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,79 +1,5 @@
|
|||||||
import db from '#root/config/database.config.js'
|
import { ModbusDeviceModel } from './modbus-device.model.js';
|
||||||
|
import { DisplayValueModel } from './display-value.model.js';
|
||||||
|
|
||||||
class BaseModel {
|
export const modbusDeviceModel = new ModbusDeviceModel();
|
||||||
/**
|
export const displayValueModel = new DisplayValueModel();
|
||||||
* @param {string} table
|
|
||||||
*/
|
|
||||||
constructor(table) {
|
|
||||||
this.table = table;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {number | string} id
|
|
||||||
* @param {string[]} keys
|
|
||||||
* @return {Promise<any>}
|
|
||||||
*/
|
|
||||||
async getById(id, keys = ['*']) {
|
|
||||||
const query = `SELECT ${keys.join(',')} FROM ${this.table} WHERE id = ?`;
|
|
||||||
const params = [id];
|
|
||||||
const res = await db.get(query, params);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {number | string} id
|
|
||||||
* @return {Promise<void>}
|
|
||||||
*/
|
|
||||||
async delById(id) {
|
|
||||||
const query = `DELETE FROM ${this.table} WHERE id = ?`;
|
|
||||||
await db.run(query, [id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getList(keys = ['*']) {
|
|
||||||
const query = `SELECT ${keys.join(',')} FROM ${this.table}`;
|
|
||||||
const res = await db.all(query);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
async create(fields, values) {
|
|
||||||
const query = `
|
|
||||||
INSERT INTO ${this.table}
|
|
||||||
(${fields.join(',')})
|
|
||||||
VALUES (${values.map(() => '?').join(',')})`;
|
|
||||||
await db.run(query, values);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ModbusDeviceModel extends BaseModel {
|
|
||||||
constructor(table) {
|
|
||||||
super(table);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {Promise<import('..').ModbusDevice[]>}
|
|
||||||
*/
|
|
||||||
async getListWithDisplayValues() {
|
|
||||||
const query = `
|
|
||||||
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 ${this.table} AS ms
|
|
||||||
LEFT JOIN display_values AS dv ON dv.slave_id = ms.id
|
|
||||||
GROUP BY ms.id, ms.name;`;
|
|
||||||
const devices = await db.all(query);
|
|
||||||
devices.forEach((s) => (s.display_values = JSON.parse(s.display_values)));
|
|
||||||
return devices;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const modbusDeviceModel = new ModbusDeviceModel('modbus_slaves');
|
|
||||||
33
models/modbus-device.model.js
Normal file
33
models/modbus-device.model.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { BaseModel } from './base.model.js'
|
||||||
|
import db from '#root/config/database.config.js'
|
||||||
|
|
||||||
|
export class ModbusDeviceModel extends BaseModel {
|
||||||
|
constructor() {
|
||||||
|
super('modbus_slaves');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Promise<import('..').ModbusDevice[]>}
|
||||||
|
*/
|
||||||
|
async getListWithDisplayValues() {
|
||||||
|
const query = `
|
||||||
|
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 ${this.table} AS ms
|
||||||
|
LEFT JOIN display_values AS dv ON dv.slave_id = ms.id
|
||||||
|
GROUP BY ms.id, ms.name;`;
|
||||||
|
const devices = await db.all(query);
|
||||||
|
devices.forEach((s) => (s.display_values = JSON.parse(s.display_values)));
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -326,9 +326,10 @@
|
|||||||
<span x-show="value?.reg_format === 'BOOL'"><input :value="Boolean(value?.data)" type="checkbox" onclick="return false;" /></span>
|
<span x-show="value?.reg_format === 'BOOL'"><input :value="Boolean(value?.data)" type="checkbox" onclick="return false;" /></span>
|
||||||
<span x-show="value?.reg_format !== 'BOOL'" x-text="Number.isInteger(value?.data) ? value?.data : value?.data?.toFixed(3)"></span>
|
<span x-show="value?.reg_format !== 'BOOL'" x-text="Number.isInteger(value?.data) ? value?.data : value?.data?.toFixed(3)"></span>
|
||||||
</span>
|
</span>
|
||||||
<span>Reg Addr: <span x-text="value?.reg_addr"></span></span>
|
<span>Addr: <span x-text="value?.reg_addr"></span></span>
|
||||||
<span>Reg Type: <span x-text="value?.reg_type"></span></span>
|
<span>Type: <span x-text="$store.app.registersTypesMap[value?.reg_type]"></span></span>
|
||||||
<span>Format: <span x-text="value?.reg_format"></span></span>
|
<span>Format: <span x-text="value?.reg_format"></span></span>
|
||||||
|
<span x-show="value.desc" x-text="value?.desc" class="text-sm text-gray-500 italic"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -25,6 +25,12 @@ document.addEventListener("alpine:init", async () => {
|
|||||||
},
|
},
|
||||||
currentPage: "loading",
|
currentPage: "loading",
|
||||||
error: null,
|
error: null,
|
||||||
|
registersTypesMap: {
|
||||||
|
'IR': 'Input Registers',
|
||||||
|
'HR': 'Holding Registers',
|
||||||
|
"DI": "Discrete Input",
|
||||||
|
"DO": "Coils"
|
||||||
|
},
|
||||||
async init() {
|
async init() {
|
||||||
try {
|
try {
|
||||||
const connStatusEventSource = new EventSource("/api/modbus/status");
|
const connStatusEventSource = new EventSource("/api/modbus/status");
|
||||||
@ -266,8 +272,6 @@ document.addEventListener("alpine:init", async () => {
|
|||||||
this.error = null;
|
this.error = null;
|
||||||
this.selectedDevice = device;
|
this.selectedDevice = device;
|
||||||
this.resetGraph();
|
this.resetGraph();
|
||||||
|
|
||||||
// if (device.g_display_reg_addr !== null)
|
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
|
|
||||||
dataStreamSource?.close();
|
dataStreamSource?.close();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user