diff --git a/controllers/modbus.controller.js b/controllers/modbus.controller.js index 8dbe8b8..d4d1e89 100644 --- a/controllers/modbus.controller.js +++ b/controllers/modbus.controller.js @@ -3,6 +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"; export const modbusController = { /** @@ -222,11 +223,9 @@ export const modbusController = { async streamData(req, res, next) { try { const { slave_id } = req.query; - - if (!modbusClient.isOpen) return res.status(503).json({ error: { message: "Modbus connection closed." } }); if (!slave_id) return res.status(400).json({ error: { message: "'slave_id' parameter is required." } }); - const device = await db.get(`SELECT * FROM "modbus_slaves" WHERE id = ?`, [slave_id]); + const device = await modbusDeviceModel.getById(slave_id.toString()); if (!device) throw new RowNotFoundError(); utils.setSSEHeaders(res); @@ -235,7 +234,7 @@ export const modbusController = { device, (data, error) => { if (error) { - next(error); + res.write(utils.serializeSSEData({ error: { message: error.message }}, 'message')) return; } res.write(utils.serializeSSEData(data, 'message')); diff --git a/data.db b/data.db index e7d0fa1..45ad0ee 100644 Binary files a/data.db and b/data.db differ diff --git a/models/index.js b/models/index.js new file mode 100644 index 0000000..e024dba --- /dev/null +++ b/models/index.js @@ -0,0 +1,79 @@ +import db from '#root/config/database.config.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 diff --git a/public/js/app.js b/public/js/app.js index 0fa8e70..f62a3a4 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -272,13 +272,18 @@ document.addEventListener("alpine:init", async () => { dataStreamSource?.close(); dataStreamSource = new EventSource(`/api/modbus/data_stream?slave_id=${device.id}`); - dataStreamSource.onerror = (e) => { - dataStreamSource.close(); - this.isLoading = false; - this.error = { message: "Something went wrong." }; - }; dataStreamSource.onmessage = (e) => { const data = JSON.parse(e.data); + + if (data.error) { + this.isLoading = false; + this.error = data.error; + console.error('[Modbus Error]:', data.error); + return; + } + + this.error = null; + console.log("[SSE Message]", data); if (data.graph !== null) { this.selectedDevice.g_value = data.graph.value; diff --git a/services/modbus.service.js b/services/modbus.service.js index 6a9fd45..28e6d4d 100644 --- a/services/modbus.service.js +++ b/services/modbus.service.js @@ -1,6 +1,7 @@ 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"; +import { modbusDeviceModel } from "#root/models/index.js"; export const modbusService = { /** @@ -121,26 +122,7 @@ export const modbusService = { }, 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))); + const devices = modbusDeviceModel.getListWithDisplayValues(); return devices; },