This commit is contained in:
Sergey Yarkov 2023-11-02 21:46:50 +03:00
parent d06edd791a
commit d6f7444266
No known key found for this signature in database
GPG Key ID: E91CE1FABC619B6F
6 changed files with 231 additions and 161 deletions

View File

@ -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);
} }

BIN
data.db

Binary file not shown.

View File

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

View File

@ -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>&comma;</span> <span class="italic text-sm"
<span class="italic text-sm">Format: <span x-text="selectedDevice?.g_display_reg_format"></span>&comma;</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>

View File

@ -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 = "";
}, },
})); }));
@ -130,26 +130,27 @@ document.addEventListener("alpine:init", async () => {
} }
}, },
selectDevice(device) { selectDevice(device) {
if (device.id === this.selectedDevice?.id) return; if (device.id === this.selectedDevice?.id) return;
this.error = null; this.error = null;
this.selectedDevice = device; this.selectedDevice = device;
this.resetGraph(); this.resetGraph();
// if (device.g_display_reg_addr !== null) // if (device.g_display_reg_addr !== null)
this.isLoading = true; this.isLoading = true;
dataStreamSource?.close(); dataStreamSource?.close();
dataStreamSource = new EventSource(`/api/modbus/data_stream?slave_id=${device.id}`); dataStreamSource = new EventSource(`/api/modbus/data_stream?slave_id=${device.id}`);
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;
}; };
}, },

View File

@ -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);
} }
} }
@ -42,15 +46,15 @@ export const modbusService = {
*/ */
async connect(appConfig) { async connect(appConfig) {
const { const {
mb_connection_type, mb_connection_type,
mb_tcp_ip, mb_tcp_ip,
mb_tcp_port, mb_tcp_port,
mb_rtu_path, mb_rtu_path,
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,23 +62,21 @@ 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, {
{ baudRate: mb_rtu_baud,
await modbusClient.connectRTU(mb_rtu_path, { dataBits: mb_rtu_data_bits,
baudRate: mb_rtu_baud, parity: mb_rtu_parity,
dataBits: mb_rtu_data_bits, stopBits: mb_rtu_stop_bits,
parity: mb_rtu_parity, });
stopBits: mb_rtu_stop_bits, 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 };
// */ return setInterval(poll, intervalMs);
// 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));
// }
// }
// }
}