mirror of
https://github.com/sergeyyarkov/modbus-logger.git
synced 2026-10-11 02:18:51 +03:00
refactor
This commit is contained in:
parent
d06edd791a
commit
d6f7444266
@ -13,7 +13,7 @@ export const modbusController = {
|
||||
try {
|
||||
const appConfig = await appService.getConfig();
|
||||
if (!appConfig) return res.status(400).json({ message: "Application is not configured" });
|
||||
await modbusService.connect(appConfig)
|
||||
await modbusService.connect(appConfig);
|
||||
return res.status(200).json({ message: "Connected." });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@ -60,7 +60,8 @@ 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, is_logging } = req.body;
|
||||
const { id, name, g_display_reg_addr, g_display_reg_format, g_display_reg_type, g_y_label, is_logging } =
|
||||
req.body;
|
||||
await db.run(
|
||||
`INSERT INTO "modbus_slaves" (
|
||||
"id",
|
||||
@ -168,37 +169,46 @@ export const modbusController = {
|
||||
*/
|
||||
async streamData(req, res, next) {
|
||||
try {
|
||||
if (!modbusClient.isOpen) return res.status(503).json({ error: { message: "Modbus connection closed." } });
|
||||
|
||||
const { slave_id } = req.query;
|
||||
|
||||
if (!slave_id)
|
||||
return res.status(400).json({ error: { message: "'slave_id' parameter is required." } });
|
||||
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]);
|
||||
|
||||
if (!device)
|
||||
return res.status(404).json({ error: { message: "Device not found." } });
|
||||
|
||||
// modbusService.createPollInterval(req, res, device).poll(1000);
|
||||
if (!device) return res.status(404).json({ error: { message: "Device not found." } });
|
||||
|
||||
res.setHeader("Cache-Control", "no-cache");
|
||||
res.setHeader("Content-Type", "text/event-stream");
|
||||
res.setHeader("Connection", "keep-alive");
|
||||
|
||||
const streamInterval = setInterval(async () => {
|
||||
try {
|
||||
device.display_values = await db.all(`SELECT * FROM "display_values" WHERE slave_id = ?`, [slave_id])
|
||||
const data = await modbusService.readDataFromDevice(device);
|
||||
const intervalId = modbusService.startDevicePollInterval(
|
||||
device,
|
||||
(data, error) => {
|
||||
if (error) {
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
res.write("event: message\n");
|
||||
res.write(`data: ${JSON.stringify(data)}\n\n`);
|
||||
} catch (error) {
|
||||
clearInterval(streamInterval);
|
||||
next(error);
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
1000,
|
||||
);
|
||||
|
||||
req.on("close", () => clearInterval(streamInterval));
|
||||
req.on("close", () => clearInterval(intervalId));
|
||||
|
||||
// const streamInterval = setInterval(async () => {
|
||||
// try {
|
||||
// device.display_values = await db.all(`SELECT * FROM "display_values" WHERE slave_id = ?`, [slave_id])
|
||||
// const data = await modbusService.readDataFromDevice(device);
|
||||
// res.write("event: message\n");
|
||||
// res.write(`data: ${JSON.stringify(data)}\n\n`);
|
||||
// } catch (error) {
|
||||
// clearInterval(streamInterval);
|
||||
// next(error);
|
||||
// }
|
||||
// }, 1000);
|
||||
|
||||
// req.on("close", () => clearInterval(streamInterval));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
@ -766,18 +766,10 @@ video {
|
||||
min-width: 256px;
|
||||
}
|
||||
|
||||
.max-w-2xl {
|
||||
max-width: 42rem;
|
||||
}
|
||||
|
||||
.max-w-5xl {
|
||||
max-width: 64rem;
|
||||
}
|
||||
|
||||
.max-w-xl {
|
||||
max-width: 36rem;
|
||||
}
|
||||
|
||||
.max-w-md {
|
||||
max-width: 28rem;
|
||||
}
|
||||
@ -854,6 +846,10 @@ video {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.justify-evenly {
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.gap-2 {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
@ -956,6 +952,10 @@ video {
|
||||
padding: 10rem;
|
||||
}
|
||||
|
||||
.p-5 {
|
||||
padding: 1.25rem;
|
||||
}
|
||||
|
||||
.p-60 {
|
||||
padding: 15rem;
|
||||
}
|
||||
@ -964,10 +964,6 @@ video {
|
||||
padding: 20rem;
|
||||
}
|
||||
|
||||
.p-5 {
|
||||
padding: 1.25rem;
|
||||
}
|
||||
|
||||
.px-2 {
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
@ -983,21 +979,6 @@ video {
|
||||
padding-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.px-6 {
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
|
||||
.py-4 {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.px-5 {
|
||||
padding-left: 1.25rem;
|
||||
padding-right: 1.25rem;
|
||||
}
|
||||
|
||||
.pl-0 {
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
@ -28,12 +28,16 @@
|
||||
<span x-show="devices.length === 0" class="text-gray-500 text-sm text-center block">
|
||||
No devices added.
|
||||
</span>
|
||||
<div @add-device.window="devices = [...devices, $event.detail];" class="flex flex-col max-h-[400px] overflow-y-auto space-y-2">
|
||||
<div
|
||||
@add-device.window="devices = [...devices, $event.detail];"
|
||||
class="flex flex-col max-h-[400px] overflow-y-auto space-y-2"
|
||||
>
|
||||
<template x-for="device in devices" :key="device.id">
|
||||
<button
|
||||
@click="selectDevice(device)"
|
||||
:class="{'bg-gray-100': selectedDevice?.id === device.id}"
|
||||
class="w-full min-h-[50px] select-none border px-2.5 py-3 text-left rounded-sm hover:bg-gray-100 cursor-pointer">
|
||||
class="w-full min-h-[50px] select-none border px-2.5 py-3 text-left rounded-sm hover:bg-gray-100 cursor-pointer"
|
||||
>
|
||||
<span x-text="device.name" class="text-md font-bold"></span>
|
||||
</button>
|
||||
</template>
|
||||
@ -45,7 +49,8 @@
|
||||
@open-create-device-modal.window="open()"
|
||||
@keyup.escape.window="close()"
|
||||
class="backdrop z-50"
|
||||
x-show="isOpen">
|
||||
x-show="isOpen"
|
||||
>
|
||||
<div class="modal">
|
||||
<div class="flex justify-between items-center">
|
||||
<h2 class="font-bold text-lg">Create new device</h2>
|
||||
@ -60,14 +65,33 @@
|
||||
</div>
|
||||
<hr />
|
||||
<form @submit.prevent="create(() => graphView = 'none')" action="#">
|
||||
<div x-id="['id', 'name', 'graph-display', 'g_display_reg_addr', 'g_display_reg_format', 'g_y_label', 'is_logging']" class="flex flex-col space-y-2">
|
||||
<div
|
||||
x-id="['id', 'name', 'graph-display', 'g_display_reg_addr', 'g_display_reg_format', 'g_y_label', 'is_logging']"
|
||||
class="flex flex-col space-y-2"
|
||||
>
|
||||
<div>
|
||||
<label :for="$id('id')"><span class="text-red-500">*</span>Slave ID:</label>
|
||||
<input x-model.number="data.id" :id="$id('id')" name="id" placeholder="1" type="number" min="1" max="255" required />
|
||||
<input
|
||||
x-model.number="data.id"
|
||||
:id="$id('id')"
|
||||
name="id"
|
||||
placeholder="1"
|
||||
type="number"
|
||||
min="1"
|
||||
max="255"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label :for="$id('name')"><span class="text-red-500">*</span>Name:</label>
|
||||
<input x-model="data.name" placeholder="Device #1" :id="$id('name')" name="name" type="text" required />
|
||||
<input
|
||||
x-model="data.name"
|
||||
placeholder="Device #1"
|
||||
:id="$id('name')"
|
||||
name="name"
|
||||
type="text"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label :for="$id('graph-display')">Graph Display</label>
|
||||
@ -79,22 +103,54 @@
|
||||
<div x-show="graphView === 'new-value'">
|
||||
<div>
|
||||
<label :for="$id('g_y_label')"><span class="text-red-500">*</span>Value name:</label>
|
||||
<input x-model="data.g_y_label" :id="$id('g_y_label')" :required="graphView === 'new-value'" name="g_y_label" placeholder="PV" type="text" />
|
||||
<input
|
||||
x-model="data.g_y_label"
|
||||
:id="$id('g_y_label')"
|
||||
:required="graphView === 'new-value'"
|
||||
name="g_y_label"
|
||||
placeholder="PV"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label :for="$id('g_display_reg_addr')"><span class="text-red-500">*</span>Register address:</label>
|
||||
<input x-model="data.g_display_reg_addr" :id="$id('g_display_reg_addr')" name="g_display_reg_addr" placeholder="1" type="number" min="0" max="65534" :required="graphView === 'new-value'" />
|
||||
<label :for="$id('g_display_reg_addr')"
|
||||
><span class="text-red-500">*</span>Register address:</label
|
||||
>
|
||||
<input
|
||||
x-model="data.g_display_reg_addr"
|
||||
:id="$id('g_display_reg_addr')"
|
||||
name="g_display_reg_addr"
|
||||
placeholder="1"
|
||||
type="number"
|
||||
min="0"
|
||||
max="65534"
|
||||
:required="graphView === 'new-value'"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label :for="$id('g_display_reg_type')"><span class="text-red-500">*</span>Registers type:</label>
|
||||
<select x-model="data.g_display_reg_type" :id="$id('g_display_reg_type')" name="g_display_reg_type" :required="graphView === 'new-value'">
|
||||
<label :for="$id('g_display_reg_type')"
|
||||
><span class="text-red-500">*</span>Registers type:</label
|
||||
>
|
||||
<select
|
||||
x-model="data.g_display_reg_type"
|
||||
:id="$id('g_display_reg_type')"
|
||||
name="g_display_reg_type"
|
||||
:required="graphView === 'new-value'"
|
||||
>
|
||||
<option value="IR">Input Registers</option>
|
||||
<option value="HR">Holding Registers</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label :for="$id('g_display_reg_format')"><span class="text-red-500">*</span>Format (type):</label>
|
||||
<select x-model="data.g_display_reg_format" :id="$id('g_display_reg_format')" name="g_display_reg_format" :required="graphView === 'new-value'">
|
||||
<label :for="$id('g_display_reg_format')"
|
||||
><span class="text-red-500">*</span>Format (type):</label
|
||||
>
|
||||
<select
|
||||
x-model="data.g_display_reg_format"
|
||||
:id="$id('g_display_reg_format')"
|
||||
name="g_display_reg_format"
|
||||
:required="graphView === 'new-value'"
|
||||
>
|
||||
<option value="UI16">Unsigned Int 16</option>
|
||||
<option value="I16">Signed Int 16</option>
|
||||
<option value="UI32">Unsigned Int 32</option>
|
||||
@ -103,7 +159,12 @@
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<input x-model="data.is_logging" :id="$id('is_logging')" name="is_logging" type="checkbox" />
|
||||
<input
|
||||
x-model="data.is_logging"
|
||||
:id="$id('is_logging')"
|
||||
name="is_logging"
|
||||
type="checkbox"
|
||||
/>
|
||||
<label :for="$id('is_logging')">Logging</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -112,7 +173,14 @@
|
||||
<span x-text="error?.message" class="text-red-500"></span>
|
||||
</div>
|
||||
<div class="mt-4 flex justify-end space-x-2">
|
||||
<button x-bind:disabled="isLoading" x-bind:class="isLoading && 'opacity-70'" type="submit" class="btn">Create</button>
|
||||
<button
|
||||
x-bind:disabled="isLoading"
|
||||
x-bind:class="isLoading && 'opacity-70'"
|
||||
type="submit"
|
||||
class="btn"
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
<button @click="close()" class="btn bg-red-500">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
@ -122,7 +190,8 @@
|
||||
<!-- Create new device -->
|
||||
<button
|
||||
@click="$dispatch('open-create-device-modal')"
|
||||
class="w-full min-h-[50px] text-center border-2 border-dashed rounded-sm hover:bg-gray-50 cursor-pointer">
|
||||
class="w-full min-h-[50px] text-center border-2 border-dashed rounded-sm hover:bg-gray-50 cursor-pointer"
|
||||
>
|
||||
<span class="text-4xl text-gray-400 select-none">+</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -150,14 +219,16 @@
|
||||
<!-- Device create, delete buttons -->
|
||||
<div>
|
||||
<a href="#">Edit</a>
|
||||
<a @click="$dispatch('dialog', {
|
||||
<a
|
||||
@click="$dispatch('dialog', {
|
||||
title: 'Remove device',
|
||||
body: `Remove ${selectedDevice.name}? All logs will be cleared.`,
|
||||
isOpen: true,
|
||||
onConfirm: async () => await removeDevice(selectedDevice.id)
|
||||
});"
|
||||
class="text-red-500"
|
||||
href="#">
|
||||
href="#"
|
||||
>
|
||||
Delete
|
||||
</a>
|
||||
</div>
|
||||
@ -169,10 +240,19 @@
|
||||
<!-- Display Graph -->
|
||||
<div x-show="!isLoading && selectedDevice?.g_display_reg_addr !== null" class="mt-4">
|
||||
<div id="div_g" style="width: 720px; height: 300px"></div>
|
||||
<div class="flex space-x-2 mt-2">
|
||||
<span class="italic text-sm">Register: <span x-text="selectedDevice?.g_display_reg_addr"></span>,</span>
|
||||
<span class="italic text-sm">Format: <span x-text="selectedDevice?.g_display_reg_format"></span>,</span>
|
||||
<span class="italic text-sm">Register type: <span x-text="selectedDevice?.g_display_reg_type"></span></span>
|
||||
<div class="flex justify-evenly space-x-2 mt-3">
|
||||
<span class="italic text-sm"
|
||||
>Value: <span class="font-bold" x-text="selectedDevice?.g_value"></span
|
||||
></span>
|
||||
<span class="italic text-sm">
|
||||
Register: <span x-text="selectedDevice?.g_display_reg_addr"></span
|
||||
></span>
|
||||
<span class="italic text-sm"
|
||||
>Format: <span x-text="selectedDevice?.g_display_reg_format"></span
|
||||
></span>
|
||||
<span class="italic text-sm"
|
||||
>Register type: <span x-text="selectedDevice?.g_display_reg_type"></span
|
||||
></span>
|
||||
</div>
|
||||
<hr class="my-3" />
|
||||
</div>
|
||||
@ -219,12 +299,14 @@
|
||||
</svg>
|
||||
</button>
|
||||
<!-- Remove display value -->
|
||||
<button @click="$dispatch('dialog', {
|
||||
<button
|
||||
@click="$dispatch('dialog', {
|
||||
title: 'Remove display value',
|
||||
body: `Remove display value ${value.name}?`,
|
||||
isOpen: true,
|
||||
onConfirm: async () => await removeDisplayValue(value.id)
|
||||
});">
|
||||
});"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill="#ef4444"
|
||||
@ -236,7 +318,12 @@
|
||||
</div>
|
||||
<hr />
|
||||
<div class="flex flex-col">
|
||||
<span>Value: <span x-text="value?.data"></span></span>
|
||||
<span
|
||||
>Value:
|
||||
<span
|
||||
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>Format: <span x-text="value?.reg_format"></span></span>
|
||||
|
||||
@ -62,13 +62,13 @@ document.addEventListener("alpine:init", async () => {
|
||||
isOpen: false,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
graphView: '',
|
||||
graphView: "",
|
||||
data: {
|
||||
id: null,
|
||||
name: "",
|
||||
g_display_reg_addr: null,
|
||||
g_display_reg_format: "UI16",
|
||||
g_display_reg_type: 'IR',
|
||||
g_display_reg_type: "IR",
|
||||
g_y_label: "",
|
||||
is_logging: false,
|
||||
},
|
||||
@ -77,7 +77,7 @@ document.addEventListener("alpine:init", async () => {
|
||||
this.data.name = "";
|
||||
this.data.g_display_reg_addr = null;
|
||||
this.data.g_display_reg_format = "UI16";
|
||||
this.g_display_reg_type = 'IR';
|
||||
this.g_display_reg_type = "IR";
|
||||
this.data.g_y_label = "";
|
||||
this.data.is_logging = false;
|
||||
},
|
||||
@ -103,7 +103,7 @@ document.addEventListener("alpine:init", async () => {
|
||||
close() {
|
||||
this.isOpen = false;
|
||||
this.resetDataFields();
|
||||
this.graphView = '';
|
||||
this.graphView = "";
|
||||
},
|
||||
}));
|
||||
|
||||
@ -130,26 +130,27 @@ document.addEventListener("alpine:init", async () => {
|
||||
}
|
||||
},
|
||||
selectDevice(device) {
|
||||
if (device.id === this.selectedDevice?.id) return;
|
||||
if (device.id === this.selectedDevice?.id) return;
|
||||
|
||||
this.error = null;
|
||||
this.selectedDevice = device;
|
||||
this.resetGraph();
|
||||
|
||||
// if (device.g_display_reg_addr !== null)
|
||||
this.isLoading = true;
|
||||
this.isLoading = true;
|
||||
|
||||
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.' }
|
||||
}
|
||||
this.error = { message: "Something went wrong." };
|
||||
};
|
||||
dataStreamSource.onmessage = (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
console.log('[SSE Message]', data);
|
||||
console.log("[SSE Message]", data);
|
||||
if (data.graph !== null) {
|
||||
this.selectedDevice.g_value = data.graph.value;
|
||||
graphData.push([new Date(), data.graph.value]);
|
||||
if (g === null) {
|
||||
g = new Dygraph(document.getElementById("div_g"), graphData, {
|
||||
@ -161,7 +162,7 @@ document.addEventListener("alpine:init", async () => {
|
||||
}
|
||||
g.updateOptions({ file: graphData });
|
||||
}
|
||||
data.displayValues.forEach((v, i) => this.selectedDevice.display_values[i] = v);
|
||||
data.displayValues.forEach((v, i) => (this.selectedDevice.display_values[i] = v));
|
||||
this.isLoading = false;
|
||||
};
|
||||
},
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
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 * as utils from "#root/utils/index.js";
|
||||
|
||||
export const modbusService = {
|
||||
/**
|
||||
@ -17,18 +17,22 @@ export const modbusService = {
|
||||
|
||||
/* Read data for graph */
|
||||
if (g_display_reg_addr !== null) {
|
||||
const graphValueBuf = await this.readModbusRegisters(g_display_reg_addr, g_display_reg_type, g_display_reg_format);
|
||||
const graphValueBuf = await this.readModbusRegisters(
|
||||
g_display_reg_addr,
|
||||
g_display_reg_type,
|
||||
g_display_reg_format,
|
||||
);
|
||||
data.graph = {
|
||||
value: utils.readNumberFromBuf(graphValueBuf, device.g_display_reg_format, 'BE'),
|
||||
format: g_display_reg_format
|
||||
}
|
||||
value: utils.readNumberFromBuf(graphValueBuf, device.g_display_reg_format, "BE"),
|
||||
format: g_display_reg_format,
|
||||
};
|
||||
}
|
||||
|
||||
/* Read data for display values */
|
||||
if (display_values) {
|
||||
for (const v of device.display_values) {
|
||||
const displayValueBuf = await this.readModbusRegisters(v.reg_addr, v.reg_type, v.reg_format)
|
||||
v.data = utils.readNumberFromBuf(displayValueBuf, v.reg_format, 'BE')
|
||||
const displayValueBuf = await this.readModbusRegisters(v.reg_addr, v.reg_type, v.reg_format);
|
||||
v.data = utils.readNumberFromBuf(displayValueBuf, v.reg_format, "BE");
|
||||
data.displayValues.push(v);
|
||||
}
|
||||
}
|
||||
@ -42,15 +46,15 @@ export const modbusService = {
|
||||
*/
|
||||
async connect(appConfig) {
|
||||
const {
|
||||
mb_connection_type,
|
||||
mb_tcp_ip,
|
||||
mb_tcp_port,
|
||||
mb_rtu_path,
|
||||
mb_rtu_baud,
|
||||
mb_rtu_data_bits,
|
||||
mb_rtu_parity,
|
||||
mb_rtu_stop_bits
|
||||
} = appConfig
|
||||
mb_connection_type,
|
||||
mb_tcp_ip,
|
||||
mb_tcp_port,
|
||||
mb_rtu_path,
|
||||
mb_rtu_baud,
|
||||
mb_rtu_data_bits,
|
||||
mb_rtu_parity,
|
||||
mb_rtu_stop_bits,
|
||||
} = appConfig;
|
||||
|
||||
if (modbusClient.isOpen) {
|
||||
modbusClient.close(undefined);
|
||||
@ -58,23 +62,21 @@ export const modbusService = {
|
||||
}
|
||||
|
||||
switch (mb_connection_type) {
|
||||
case 'TCP':
|
||||
{
|
||||
await modbusClient.connectTCP(mb_tcp_ip, { port: mb_tcp_port });
|
||||
break;
|
||||
}
|
||||
case "RTU":
|
||||
{
|
||||
await modbusClient.connectRTU(mb_rtu_path, {
|
||||
baudRate: mb_rtu_baud,
|
||||
dataBits: mb_rtu_data_bits,
|
||||
parity: mb_rtu_parity,
|
||||
stopBits: mb_rtu_stop_bits,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "TCP": {
|
||||
await modbusClient.connectTCP(mb_tcp_ip, { port: mb_tcp_port });
|
||||
break;
|
||||
}
|
||||
case "RTU": {
|
||||
await modbusClient.connectRTU(mb_rtu_path, {
|
||||
baudRate: mb_rtu_baud,
|
||||
dataBits: mb_rtu_data_bits,
|
||||
parity: mb_rtu_parity,
|
||||
stopBits: mb_rtu_stop_bits,
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported connection type!')
|
||||
throw new Error("Unsupported connection type!");
|
||||
}
|
||||
},
|
||||
|
||||
@ -89,9 +91,9 @@ export const modbusService = {
|
||||
let len = 1;
|
||||
|
||||
switch (format) {
|
||||
case 'UI32':
|
||||
case 'I32':
|
||||
case 'FP32':
|
||||
case "UI32":
|
||||
case "I32":
|
||||
case "FP32":
|
||||
len = 2;
|
||||
break;
|
||||
default:
|
||||
@ -99,17 +101,17 @@ export const modbusService = {
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'HR':
|
||||
case "HR":
|
||||
data = await modbusClient.readHoldingRegisters(addr, len);
|
||||
break;
|
||||
case 'IR':
|
||||
case "IR":
|
||||
data = await modbusClient.readInputRegisters(addr, len);
|
||||
break;
|
||||
case 'DI':
|
||||
case "DI":
|
||||
data = await modbusClient.readDiscreteInputs(addr, len);
|
||||
break;
|
||||
default:
|
||||
throw new Error('Incorrect modbus register type!');
|
||||
throw new Error("Incorrect modbus register type!");
|
||||
}
|
||||
|
||||
return data.buffer;
|
||||
@ -136,35 +138,24 @@ export const modbusService = {
|
||||
`);
|
||||
// @ts-ignore
|
||||
devices.forEach((s) => (s.display_values = JSON.parse(s.display_values)));
|
||||
return devices
|
||||
return devices;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {import('express').Request} req
|
||||
* @param {import('express').Response} res
|
||||
* @param {import("..").ModbusDevice} device
|
||||
* @param {(data: import("..").EventDataStream, error: any) => void} callback
|
||||
* @param {number} intervalMs
|
||||
*/
|
||||
// createPollInterval(req, res, device, pollIntervalMs) {
|
||||
// let intervalId;
|
||||
|
||||
// res.setHeader("Cache-Control", "no-cache");
|
||||
// res.setHeader("Content-Type", "text/event-stream");
|
||||
// res.setHeader("Connection", "keep-alive");
|
||||
|
||||
// return {
|
||||
// /**
|
||||
// * @param {number} pollIntervalMs
|
||||
// */
|
||||
// poll(pollIntervalMs) {
|
||||
// intervalId = setInterval(async () => {
|
||||
// device.display_values = await db.all(`SELECT * FROM "display_values" WHERE slave_id = ?`, [device.id])
|
||||
// const data = await modbusService.readDataFromDevice(device);
|
||||
// res.write("event: message\n");
|
||||
// res.wriste(`data: ${JSON.stringify(data)}\n\n`);
|
||||
// }, pollIntervalMs)
|
||||
|
||||
// req.on("close", () => clearInterval(intervalId));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
startDevicePollInterval(device, callback, intervalMs) {
|
||||
const poll = async () => {
|
||||
try {
|
||||
device.display_values = await db.all(`SELECT * FROM "display_values" WHERE slave_id = ?`, [device.id]);
|
||||
const data = await this.readDataFromDevice(device);
|
||||
callback(data);
|
||||
} catch (error) {
|
||||
callback(null, error);
|
||||
}
|
||||
};
|
||||
return setInterval(poll, intervalMs);
|
||||
},
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user