@geolab/server
技術構成
runtime: node.js
package manager: pnpm
language: Typescript
"allowImportingTsExtensions": trueにする
development tools:
Biome, vitest, tsx, @typescript/native-preview
Biomeの設定は、indentをspaceにする以外はdefaultにする
defaultの通信設定
slave ID: 1
baud rate: 38400
任意のbaud rateにできる
data bit: 8
stop bit: 1
parity: none
input register: 0~15
holding register: 0~7
機種によっては0~5の場合もある
実装洗い出し
API endpoints
GET /api/read
{ "raw": { "inputs": [...], "outputs": [...] }, "channels": { ... } }
raw.inputsはinput registerの値を入れた配列
raw.outputsはholding registerの値を入れた配列
channelsは/api/configの設定を適用したデータ
?raw:"raw"だけ取得する
GET /api/status
接続状況やbaud rateなどを返す
GET /api/config
機器構成定義ファイルを返す
構文エラーや循環参照エラーがあればそのエラーを返す
POST /api/config
機器構成定義ファイルを上書き更新する
GET /api/pid
実施中のPID制御のリストを返す
channel_idをkeyにする
POST /api/pid
新しいPID制御指令を出す
"<channel_id>": nullで指令を取り消す
GET /openapi
error handling
SSE endpoint
切断時に切断イベントを返し、再接続するまで何も返さない
再接続したら、再接続イベントを返し、再び各endpointで指定されたデータを流し始める
non-SSE endpoint
errro statusとして切断などの状態を返す
connection
server起動時に自動で接続する
ポートやbaud rateなどは環境変数で渡す
CLI引数でも上書きできるようにする
切断したら再接続を試行する
/api/configで扱う設定ファイル
code:schema.yml
#
# @geolab/server - Device Configuration Schema v1.0
#
title: @geolab/server Device Configuration
description: A configuration file that defines channels and actuators for Modbus communication.
type: object
required:
- channels
- actuators
properties:
channels:
type: array
description: Defines all elements that compute a single output value from one or more inputs (e.g., physical sensors, virtual sensors).
items:
type: object
required:
- id
- inputs
- expression
properties:
id:
type: string
description: A unique identifier for the channel. Used to reference this channel's value.
pattern: "^\\w+$"
description:
type: string
description: A human-readable description of the channel.
unit:
type: string
description: The unit of the calculated physical quantity.
inputs:
type: object
description: A map of input sources. The key becomes the variable name in the expression, and the value is the ID of another channel or a physical port.
patternProperties:
"^\\w+$":
type: string
additionalProperties: false
expression:
type: string
description: A mathematical or conditional expression to compute the output value of this channel.
actuators:
type: array
description: Defines all elements that take a single command value and control multiple physical ports.
items:
type: object
required:
- id
- command
- outputs
properties:
id:
type: string
description: A unique identifier for the actuator.
pattern: "^\\w+$"
description:
type: string
description: A human-readable description of the actuator.
command:
type: object
description: Defines the input command for this actuator.
properties:
unit:
type: string
description: The unit of the command value.
outputs:
type: array
description: A list of physical ports to be controlled by this actuator.
items:
type: object
required:
- port_id
- expression
properties:
port_id:
type: string
description: The identifier of the physical output port.
expression:
type: string
description: An expression to compute the raw value to be written to the port, based on the 'command' variable.
code:config-example.yml
# 機器構成定義ファイル v1.0
# channels: 1つ以上の入力値から、1つの出力値を計算する全ての要素を定義
# (物理センサー、仮想センサー、計算値など)
channels:
# 物理ポートからの生データを物理量に変換するチャンネル (物理センサー)
- id: "LoadCell_kN"
description: "荷重計 (LHA-12)"
unit: "kN"
inputs:
# inputsのキー(raw)が、expression内の変数名になる
# 値("AI_01")は、Modbusの物理ポートIDを示す
raw: "AI_01"
expression: "raw * 0.0025 - 0.15"
- id: "Displacement_Axial_mm"
description: "変位計 (軸方向)"
unit: "mm"
inputs:
raw: "AI_02"
expression: "raw * 0.001"
# 他のチャンネルの値を入力として計算するチャンネル (仮想センサー)
- id: "Strain_Axial_percent"
description: "軸ひずみ"
unit: "%"
inputs:
# 値("Displacement_Axial_mm")は、他のチャンネルのidを示す
disp_mm: "Displacement_Axial_mm"
expression: "disp_mm / 100.2" # 供試体高さ100.2mm
- id: "Strain_Volumetric_percent"
description: "体積ひずみ"
unit: "%"
inputs:
# 複数のチャンネルを入力に取る
axial_strain: "Strain_Axial_percent"
radial_raw: "AI_03" # チャンネルと物理ポートの混在も可能
expression: "axial_strain + 2 * ((radial_raw * 0.001) / 50.1)"
# actuators: 1つの指令値(command)を受け取り、複数の物理ポートを制御する要素を定義
actuators:
- id: "MainMotor"
description: "主軸モーター"
# このアクチュエータが受け取る指令値。commandが変数名となる
command:
unit: "rpm"
# 制御対象となる物理ポートとその出力値を式で定義
outputs:
- port_id: "DO_01" # 電源ON/OFF
expression: "command == 0 ? 5 : 0"
- port_id: "DO_02" # 回転方向
expression: "command < 0 ? 5 : 0"
- port_id: "AO_01" # 回転速度
expression: "command == 0 ? 0 : (abs(command) * 100.0 + 500)"
名前はgeolab-io.yamlとでもしておくか
もう少し一般的な形に書けそう
0個以上の引数を受け取って0個から1個の値を返すノード
物理入力ポートを1個の無次元数を返す定義済みノードと見なす
物理出力ポートも定義済みとする
こいつだけ提示が特殊だ
$GITHUB_OUTPUTにリダイレクトさせている
そもそもこんな概念的なこと詰めても実用性はどうなんだ