diff --git a/controllers/modbus.controller.js b/controllers/modbus.controller.js index d4d1e89..43ffdb4 100644 --- a/controllers/modbus.controller.js +++ b/controllers/modbus.controller.js @@ -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 diff --git a/data.db b/data.db index 45ad0ee..97fe14e 100644 Binary files a/data.db and b/data.db differ diff --git a/migrations/001-init.sql b/migrations/001-init.sql index 0feed69..a1adddb 100644 --- a/migrations/001-init.sql +++ b/migrations/001-init.sql @@ -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 -------------------------------------------------------------------------------- diff --git a/models/base.model.js b/models/base.model.js new file mode 100644 index 0000000..4b678c0 --- /dev/null +++ b/models/base.model.js @@ -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} + */ + 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} + */ + 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} + */ + 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; + } +} \ No newline at end of file diff --git a/models/display-value.model.js b/models/display-value.model.js new file mode 100644 index 0000000..8aa3b10 --- /dev/null +++ b/models/display-value.model.js @@ -0,0 +1,7 @@ +import { BaseModel } from './base.model.js' + +export class DisplayValueModel extends BaseModel { + constructor() { + super('display_values') + } +} \ No newline at end of file diff --git a/models/index.js b/models/index.js index e024dba..e81ad5b 100644 --- a/models/index.js +++ b/models/index.js @@ -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} - */ - 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} - */ - 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} - */ - 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'); \ No newline at end of file +export const modbusDeviceModel = new ModbusDeviceModel(); +export const displayValueModel = new DisplayValueModel(); \ No newline at end of file diff --git a/models/modbus-device.model.js b/models/modbus-device.model.js new file mode 100644 index 0000000..6fa82b2 --- /dev/null +++ b/models/modbus-device.model.js @@ -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} + */ + 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; + } +} \ No newline at end of file diff --git a/public/index.html b/public/index.html index 32f59cf..e1fd011 100644 --- a/public/index.html +++ b/public/index.html @@ -326,9 +326,10 @@ - Reg Addr: - Reg Type: + Addr: + Type: Format: + diff --git a/public/js/app.js b/public/js/app.js index f62a3a4..7e3a7f1 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -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();