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