This commit is contained in:
Sergey Yarkov 2023-11-10 16:31:47 +03:00
parent ffcfe6767d
commit 4edb0f3a9d
9 changed files with 142 additions and 116 deletions

View File

@ -3,7 +3,7 @@ import modbusClient from "#root/config/modbus-client.config.js";
import * as utils from '#root/utils/index.js'
import { RowNotFoundError } from '#root/errors/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 = {
/**
@ -63,19 +63,14 @@ export const modbusController = {
*/
async createDevice(req, res, next) {
try {
const { id, name, g_display_reg_addr, g_display_reg_format, g_display_reg_type, g_y_label } =
req.body;
await db.run(
`INSERT INTO "modbus_slaves" (
"id",
"name",
"g_display_reg_addr",
"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],
);
await modbusDeviceModel.create({
id: req.body.id,
name: req.body.name,
g_display_reg_addr: req.body.g_display_reg_addr,
g_display_reg_format: req.body.g_display_reg_format,
g_display_reg_type: req.body.g_display_reg_type,
g_y_label: req.body.g_y_label
})
return res.status(200).json({ message: "Device created." });
} catch (error) {
next(error);
@ -124,9 +119,10 @@ export const modbusController = {
*/
async removeDevice(req, res, next) {
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();
await db.run(`DELETE FROM "modbus_slaves" WHERE id = ?`, [req.body.id]);
await modbusDeviceModel.delById(id);
return res.status(200).json({ message: "Device removed." });
} catch (error) {
next(error);
@ -167,7 +163,10 @@ export const modbusController = {
*/
async removeDisplayValue(req, res, next) {
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." });
} catch (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').Response} res
* @param {import('express').NextFunction} next

BIN
data.db

Binary file not shown.

View File

@ -57,26 +57,27 @@ CREATE TABLE IF NOT EXISTS "display_values" (
INSERT INTO "modbus_slaves" (
"id", "name", "g_display_reg_addr", "g_display_reg_type", "g_display_reg_format", "g_y_label"
) VALUES
(1, "Device #1", 0, "IR", "UI16", "Label 1"),
(2, "Device #2", 1, "IR", "UI32", "Label 2"),
(3, "Device #3", 3, "IR", "UI16", "Label 3"),
(4, "Device #4", NULL, NULL, NULL, "Label 4");
(1, "MKP #1", 132, "HR", "UI16", "PID Out"),
(2, "Test Device #1", 1, "IR", "UI32", "Label 2"),
(3, "Test Device #2", 3, "IR", "UI16", "Label 3"),
(4, "Test Device #3", NULL, NULL, NULL, "Label 4");
INSERT INTO "display_values" (
"id", "name", "slave_id", "reg_addr", "reg_format", "reg_type"
) VALUES
(1, "CV1", 1, 10, "UI16", "IR"),
(2, "CV2", 1, 11, "I16", "IR"),
(3, "SP", 1, 12, "UI32", "IR"),
(4, "CV1", 2, 13, "I32", "IR"),
(5, "CV2", 2, 14, "I16", "IR"),
(6, "SP", 2, 15, "UI16", "IR"),
(7, "CV1", 3, 16, "UI16", "HR"),
(8, "CV2", 3, 17, "FP32", "HR"),
(9, "SP", 3, 15, "UI16", "IR"),
(10, "Control action type", 3, 0, "BOOL", "DI"),
(11, "Status ALARM1", 3, 1, "BOOL", "DO"),
(12, "Status ALARM2", 3, 2, "BOOL", "DO");
(1, "SP", 1, 138, "UI32", "HR"),
(2, "Status Device", 1, 89, "UI16", "HR"),
(3, "Control action type", 1, 2301, "BOOL", "DI"),
(4, "S.L.Bd", 1, 528, "UI16", "HR"),
(5, "VAL1", 2, 0, "I32", "IR"),
(6, "VAL2", 2, 2, "I16", "IR"),
(7, "VAL3", 2, 3, "UI16", "IR"),
(8, "VAL4", 3, 4, "UI16", "HR"),
(9, "VAL5", 3, 5, "FP32", "HR"),
(10, "VAL6", 3, 7, "UI16", "IR"),
(11, "VAL7", 3, 0, "BOOL", "DI"),
(12, "VAL8", 3, 1, "BOOL", "DO"),
(13, "VAL9", 3, 2, "BOOL", "DO");
--------------------------------------------------------------------------------
-- Down
--------------------------------------------------------------------------------

55
models/base.model.js Normal file
View 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;
}
}

View File

@ -0,0 +1,7 @@
import { BaseModel } from './base.model.js'
export class DisplayValueModel extends BaseModel {
constructor() {
super('display_values')
}
}

View File

@ -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 {
/**
* @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');
export const modbusDeviceModel = new ModbusDeviceModel();
export const displayValueModel = new DisplayValueModel();

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

View File

@ -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'" x-text="Number.isInteger(value?.data) ? value?.data : value?.data?.toFixed(3)"></span>
</span>
<span>Reg Addr: <span x-text="value?.reg_addr"></span></span>
<span>Reg Type: <span x-text="value?.reg_type"></span></span>
<span>Addr: <span x-text="value?.reg_addr"></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 x-show="value.desc" x-text="value?.desc" class="text-sm text-gray-500 italic"></span>
</div>
</div>
</template>

View File

@ -25,6 +25,12 @@ document.addEventListener("alpine:init", async () => {
},
currentPage: "loading",
error: null,
registersTypesMap: {
'IR': 'Input Registers',
'HR': 'Holding Registers',
"DI": "Discrete Input",
"DO": "Coils"
},
async init() {
try {
const connStatusEventSource = new EventSource("/api/modbus/status");
@ -266,8 +272,6 @@ document.addEventListener("alpine:init", async () => {
this.error = null;
this.selectedDevice = device;
this.resetGraph();
// if (device.g_display_reg_addr !== null)
this.isLoading = true;
dataStreamSource?.close();