discrete input and outputs monitor

This commit is contained in:
Sergey Yarkov 2023-11-03 09:53:22 +03:00
parent d6f7444266
commit 8f1404c299
7 changed files with 25 additions and 17 deletions

BIN
data.db

Binary file not shown.

4
index.d.ts vendored
View File

@ -10,8 +10,8 @@ export type AppConfig = {
log_interval_ms: number; log_interval_ms: number;
}; };
export type RegisterType = "HR" | "IR" export type RegisterType = "HR" | "IR" | "DI" | "DO";
export type NumberType = 'UI16' | 'I16' | 'UI32' | 'I32' | 'FP32' export type NumberType = 'UI16' | 'I16' | 'UI32' | 'I32' | 'FP32' | 'BOOL';
export type DisplayValue = { export type DisplayValue = {
data?: number; data?: number;

View File

@ -34,8 +34,8 @@ CREATE TABLE IF NOT EXISTS "display_values" (
"name" VARCHAR(32) NOT NULL, "name" VARCHAR(32) NOT NULL,
"slave_id" INTEGER NOT NULL, "slave_id" INTEGER NOT NULL,
"reg_addr" INTEGER DEFAULT 0 NOT NULL CHECK(reg_addr >= 0 AND reg_addr <= 65534), "reg_addr" INTEGER DEFAULT 0 NOT NULL CHECK(reg_addr >= 0 AND reg_addr <= 65534),
"reg_type" VARCHAR(3) NOT NULL CHECK(reg_type IN("HR", "IR")) DEFAULT "IR", "reg_type" VARCHAR(3) NOT NULL CHECK(reg_type IN("HR", "IR", "DI", "DO")) DEFAULT "IR",
"reg_format" VARCHAR(5) NOT NULL CHECK(reg_format IN("UI16", "I16", "UI32", "I32", "FP32")) DEFAULT "UI16", "reg_format" VARCHAR(5) NOT NULL CHECK(reg_format IN("UI16", "I16", "UI32", "I32", "FP32", "BOOL")) DEFAULT "UI16",
PRIMARY KEY("id"), PRIMARY KEY("id"),
FOREIGN KEY("slave_id") REFERENCES modbus_slaves("id") ON DELETE CASCADE FOREIGN KEY("slave_id") REFERENCES modbus_slaves("id") ON DELETE CASCADE
); );
@ -48,7 +48,7 @@ CREATE TABLE IF NOT EXISTS "display_values" (
-- -- JSON Format: -- -- JSON Format:
-- -- { -- -- {
-- -- graph: [{ reg_addr: 1 value: 4 }], -- -- graph: [{ reg_addr: 1 value: 4 }],
-- -- display_values: [{ reg_addr: 1, name: "CV1" }] -- -- display_values: [{ ... }]
-- -- } -- -- }
-- "data" TEXT NOT NULL, -- "data" TEXT NOT NULL,
-- PRIMARY KEY("id"), -- PRIMARY KEY("id"),
@ -74,7 +74,10 @@ INSERT INTO "display_values" (
(6, "SP", 2, 15, "UI16", "IR"), (6, "SP", 2, 15, "UI16", "IR"),
(7, "CV1", 3, 16, "UI16", "HR"), (7, "CV1", 3, 16, "UI16", "HR"),
(8, "CV2", 3, 17, "FP32", "HR"), (8, "CV2", 3, 17, "FP32", "HR"),
(9, "SP", 3, 15, "UI16", "IR"); (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");
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Down -- Down
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@ -287,7 +287,7 @@
<template x-for="value in selectedDevice?.display_values" :key="value.id"> <template x-for="value in selectedDevice?.display_values" :key="value.id">
<div class="border-2 p-2.5 rounded-sm"> <div class="border-2 p-2.5 rounded-sm">
<div class="flex justify-between items-start"> <div class="flex justify-between items-start">
<h3 x-text="value.name" class="text-xl font-bold"></h3> <h3 x-text="value.name" class="text-lg font-bold"></h3>
<div class="flex"> <div class="flex">
<!-- Edit display value --> <!-- Edit display value -->
<button> <button>
@ -318,19 +318,19 @@
</div> </div>
<hr /> <hr />
<div class="flex flex-col"> <div class="flex flex-col">
<span <span>Value:
>Value: <span x-show="value?.reg_format === 'BOOL'"><input :value="Boolean(value?.data)" type="checkbox" onclick="return false;" /></span>
<span <span x-show="value?.reg_format !== 'BOOL'" x-text="Number.isInteger(value?.data) ? value?.data : value?.data?.toFixed(3)"></span>
x-text="Number.isInteger(value?.data) ? value?.data : value?.data?.toFixed(3)" </span>
></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>
</div> </div>
</div> </div>
</template> </template>
<!-- Create Display -->
<div <div
@click="$dispatch('open-create-display-value-modal')"
class="flex justify-center min-h-[140px] items-center border-4 text-center border-dashed p-2.5 rounded-sm cursor-pointer hover:bg-gray-50" class="flex justify-center min-h-[140px] items-center border-4 text-center border-dashed p-2.5 rounded-sm cursor-pointer hover:bg-gray-50"
> >
<span class="text-5xl text-gray-400 font-bold select-none">+</span> <span class="text-5xl text-gray-400 font-bold select-none">+</span>

View File

@ -82,7 +82,7 @@ export const modbusService = {
/** /**
* @param {number} addr * @param {number} addr
* @param {"HR" | "IR" | "DI"} type * @param {import("..").RegisterType} type
* @param {import("..").NumberType} format * @param {import("..").NumberType} format
* @return {Promise<Buffer>} buffer data * @return {Promise<Buffer>} buffer data
*/ */
@ -108,7 +108,10 @@ export const modbusService = {
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, 1);
break;
case "DO":
data = await modbusClient.readCoils(addr, 1);
break; break;
default: default:
throw new Error("Incorrect modbus register type!"); throw new Error("Incorrect modbus register type!");

View File

@ -18,4 +18,6 @@ export function readNumberFromBuf(buf, type, order) {
if (type === 'UI32' && order === 'LE') return Buffer.from(buf).readUint32LE(); if (type === 'UI32' && order === 'LE') return Buffer.from(buf).readUint32LE();
if (type === 'I32' && order === 'LE') return Buffer.from(buf).readInt32LE(); if (type === 'I32' && order === 'LE') return Buffer.from(buf).readInt32LE();
if (type === 'FP32' && order === 'LE') return Buffer.from(buf).readFloatLE(); if (type === 'FP32' && order === 'LE') return Buffer.from(buf).readFloatLE();
if (type === 'BOOL') return Buffer.from(buf).readUint8();
} }

View File

@ -5,8 +5,8 @@ export const displayValueSchema = object({
name: string().required(), name: string().required(),
slave_id: number().required(), slave_id: number().required(),
reg_addr: number().min(0).max(65534).required(), reg_addr: number().min(0).max(65534).required(),
reg_format: string().oneOf(["UI16", "I16", "UI32", "I32", "FP32"]).required(), reg_format: string().oneOf(["UI16", "I16", "UI32", "I32", "FP32", "BOOL"]).required(),
reg_type: string().oneOf(["HR", "IR"]).required() reg_type: string().oneOf(["HR", "IR", "DI", "DO"]).required()
}) })
export const removeDisplayValueSchema = displayValueSchema.pick(['id']); export const removeDisplayValueSchema = displayValueSchema.pick(['id']);