miravo 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +199 -0
- package/README.md +29 -59
- package/bin/miravo.js +84 -0
- package/package.json +21 -37
- package/console-dist/assets/activity-DsWeRq4h.js +0 -1
- package/console-dist/assets/api-4AqKvsm9.js +0 -1
- package/console-dist/assets/arrow-right-Ea_UhTNi.js +0 -1
- package/console-dist/assets/arrow-up-down-DFSjzzl2.js +0 -1
- package/console-dist/assets/blueprint-card-classes-DBFCDy0M.js +0 -1
- package/console-dist/assets/box-C1WaoOMF.js +0 -1
- package/console-dist/assets/card-BjeP32PN.js +0 -1
- package/console-dist/assets/catalog-BJzyzbLR.js +0 -1
- package/console-dist/assets/catalog-DKjEm-c4.js +0 -1
- package/console-dist/assets/catalog-template-icons-BrUeHaCY.js +0 -1
- package/console-dist/assets/checkbox-DZlJXTE4.js +0 -1
- package/console-dist/assets/chunk-OE4NN4TA-CEjpfhS6.js +0 -3
- package/console-dist/assets/combobox-BGnuCYxO.js +0 -1
- package/console-dist/assets/control-CPhvwx9o.js +0 -1
- package/console-dist/assets/control-Cg2up9NA.js +0 -1
- package/console-dist/assets/copy-button-WkbNkMcd.js +0 -1
- package/console-dist/assets/createLucideIcon-Bwxw859K.js +0 -1
- package/console-dist/assets/deploy-tab-JeWDwPoZ.js +0 -1
- package/console-dist/assets/dist-BhbDML0a.js +0 -1
- package/console-dist/assets/dist-Cy8XTNFT.js +0 -2
- package/console-dist/assets/download-DQ6NH16U.js +0 -1
- package/console-dist/assets/engine-store-CrLnz692.js +0 -1
- package/console-dist/assets/events-CXm29Ok4.js +0 -1
- package/console-dist/assets/events-D01IxhnP.js +0 -1
- package/console-dist/assets/fira-code-cyrillic-ext-wght-normal-DhYMMuQd.woff2 +0 -0
- package/console-dist/assets/fira-code-cyrillic-wght-normal-Y3u8pIsh.woff2 +0 -0
- package/console-dist/assets/fira-code-greek-ext-wght-normal-wWus70Ix.woff2 +0 -0
- package/console-dist/assets/fira-code-greek-wght-normal-B2SviObF.woff2 +0 -0
- package/console-dist/assets/fira-code-latin-ext-wght-normal-Dvfvaomy.woff2 +0 -0
- package/console-dist/assets/fira-code-latin-wght-normal-CHoedHDv.woff2 +0 -0
- package/console-dist/assets/fira-code-symbols2-wght-normal-CE6EOz_n.woff2 +0 -0
- package/console-dist/assets/fleet-CfxbKXt9.js +0 -1
- package/console-dist/assets/fleet-lotMGVqe.js +0 -1
- package/console-dist/assets/format-kXTonpDJ.js +0 -1
- package/console-dist/assets/gauge-Ci8zNZlk.js +0 -1
- package/console-dist/assets/get-error-message-3Q5Q-2G5.js +0 -1
- package/console-dist/assets/index-CVPKSDvJ.js +0 -12
- package/console-dist/assets/index-DJkgDeun.css +0 -2
- package/console-dist/assets/input-BWEQFptx.js +0 -1
- package/console-dist/assets/instance-detail-C5IVwuh3.js +0 -1
- package/console-dist/assets/karla-latin-ext-wght-normal-Dq0rrjgs.woff2 +0 -0
- package/console-dist/assets/karla-latin-wght-normal-C3-ma4ov.woff2 +0 -0
- package/console-dist/assets/label-uephX5ZG.js +0 -1
- package/console-dist/assets/layers-CUsLQ1fq.js +0 -1
- package/console-dist/assets/login-C3RJli0m.js +0 -126
- package/console-dist/assets/models-B_UioWQ5.js +0 -1
- package/console-dist/assets/models-_IPlPiZ7.js +0 -1
- package/console-dist/assets/not-found-B8gAm08S.js +0 -1
- package/console-dist/assets/platform-targets-R3T-4eJ7.js +0 -1
- package/console-dist/assets/platforms-BWh0BQ3Y.js +0 -1
- package/console-dist/assets/platforms-DStNbtVc.js +0 -1
- package/console-dist/assets/proxy-CsnYqnPp.js +0 -9
- package/console-dist/assets/query-keys-BvtE7BMs.js +0 -1
- package/console-dist/assets/radio-CoHegOv5.js +0 -1
- package/console-dist/assets/rolldown-runtime-COnpUsM8.js +0 -1
- package/console-dist/assets/schibsted-grotesk-latin-ext-wght-normal-hsMS0n0O.woff2 +0 -0
- package/console-dist/assets/schibsted-grotesk-latin-wght-normal-Bb8VGrTG.woff2 +0 -0
- package/console-dist/assets/select-CeO4vP0G.js +0 -1
- package/console-dist/assets/select-display-items-CIzY8953.js +0 -1
- package/console-dist/assets/server-D9Kfn8fQ.js +0 -1
- package/console-dist/assets/shallow-6lGjQhtJ.js +0 -1
- package/console-dist/assets/tags-CiXOIHtY.js +0 -4
- package/console-dist/assets/tags-FQCXIxrP.js +0 -1
- package/console-dist/assets/tooltip-HGLF366Q.js +0 -1
- package/console-dist/assets/transition-nav-link-Df4Rk6vV.js +0 -1
- package/console-dist/assets/transition-types-CPlGtM8w.js +0 -1
- package/console-dist/assets/triangle-alert-adNk_sea.js +0 -1
- package/console-dist/assets/use-platform-stream-DGbK1k2L.js +0 -2
- package/console-dist/assets/use-transition-navigate-CCpcWXB0.js +0 -2
- package/console-dist/assets/validation-Blvud9_O.js +0 -1
- package/console-dist/assets/vendor-charts-CAZdaPlq.js +0 -60
- package/console-dist/assets/vendor-table-wd8JuMmT.js +0 -4
- package/console-dist/assets/vendor-ui-ByahnaY0.js +0 -1
- package/console-dist/favicon.svg +0 -37
- package/console-dist/index.html +0 -82
- package/console-dist/miravo-logo.png +0 -0
- package/src/__tests__/integration/executable-methods-runner.ts +0 -262
- package/src/__tests__/integration/executable-methods.integration.ts +0 -2348
- package/src/__tests__/integration/opcua-concurrent-clients.integration.ts +0 -314
- package/src/commands/adapter.ts +0 -249
- package/src/commands/apply.test.ts +0 -62
- package/src/commands/apply.ts +0 -216
- package/src/commands/cleanup.test.ts +0 -34
- package/src/commands/cleanup.ts +0 -201
- package/src/commands/cli-test-setup.ts +0 -91
- package/src/commands/export.test.ts +0 -51
- package/src/commands/export.ts +0 -404
- package/src/commands/fork.ts +0 -219
- package/src/commands/inject.test.ts +0 -57
- package/src/commands/inject.ts +0 -212
- package/src/commands/load.ts +0 -167
- package/src/commands/logs.ts +0 -173
- package/src/commands/models.test.ts +0 -162
- package/src/commands/models.ts +0 -338
- package/src/commands/pause.ts +0 -67
- package/src/commands/platforms.test.ts +0 -186
- package/src/commands/platforms.ts +0 -371
- package/src/commands/ps.ts +0 -116
- package/src/commands/remove.ts +0 -38
- package/src/commands/reset.ts +0 -44
- package/src/commands/rm.ts +0 -97
- package/src/commands/spawn.ts +0 -45
- package/src/commands/speed.ts +0 -40
- package/src/commands/start/adapter-config.ts +0 -157
- package/src/commands/start/catalog-le-dt.test.ts +0 -50
- package/src/commands/start/catalog-le-dt.ts +0 -187
- package/src/commands/start/catalog-model-schema.ts +0 -89
- package/src/commands/start/catalog-template-detail.ts +0 -54
- package/src/commands/start/daemon.ts +0 -255
- package/src/commands/start/display.ts +0 -150
- package/src/commands/start/engine-setup.ts +0 -247
- package/src/commands/start/events.ts +0 -126
- package/src/commands/start/index.ts +0 -897
- package/src/commands/start/protocol-plans.ts +0 -239
- package/src/commands/start/template-loader.ts +0 -197
- package/src/commands/start/template-resolver.ts +0 -185
- package/src/commands/start/types.ts +0 -73
- package/src/commands/start.test.ts +0 -480
- package/src/commands/status.test.ts +0 -20
- package/src/commands/status.ts +0 -470
- package/src/commands/stop.test.ts +0 -84
- package/src/commands/stop.ts +0 -169
- package/src/commands/templates.test.ts +0 -58
- package/src/commands/templates.ts +0 -277
- package/src/index.ts +0 -166
- package/src/lib/admin-auth.ts +0 -157
- package/src/lib/admin-client.test.ts +0 -51
- package/src/lib/admin-client.ts +0 -326
- package/src/lib/admin-platform-routes.ts +0 -1017
- package/src/lib/admin-platform-stream.test.ts +0 -434
- package/src/lib/admin-platform-stream.ts +0 -788
- package/src/lib/admin-responses.ts +0 -211
- package/src/lib/admin-server.test.ts +0 -781
- package/src/lib/admin-server.ts +0 -797
- package/src/lib/auth-store.ts +0 -87
- package/src/lib/daemon-registry.test.ts +0 -429
- package/src/lib/daemon-registry.ts +0 -343
- package/src/lib/le/le-apply.test.ts +0 -591
- package/src/lib/le/le-apply.ts +0 -832
- package/src/lib/le/le-auth.ts +0 -89
- package/src/lib/le/le-cleanup.test.ts +0 -168
- package/src/lib/le/le-cleanup.ts +0 -399
- package/src/lib/le/le-cli-helpers.ts +0 -77
- package/src/lib/le/le-client.ts +0 -184
- package/src/lib/le/le-concurrency.test.ts +0 -157
- package/src/lib/le/le-concurrency.ts +0 -78
- package/src/lib/le/le-connection-test.ts +0 -42
- package/src/lib/le/le-devicehub-properties.test.ts +0 -53
- package/src/lib/le/le-devicehub-properties.ts +0 -33
- package/src/lib/le/le-devicehub.ts +0 -213
- package/src/lib/le/le-digital-twins.ts +0 -285
- package/src/lib/le/le-drivers.ts +0 -23
- package/src/lib/le/le-endpoint.ts +0 -40
- package/src/lib/le/le-environments.test.ts +0 -73
- package/src/lib/le/le-environments.ts +0 -156
- package/src/lib/le/le-markers.ts +0 -87
- package/src/lib/le/le-plan.test.ts +0 -26
- package/src/lib/le/le-plan.ts +0 -109
- package/src/lib/le/le-platform-operations.test.ts +0 -198
- package/src/lib/le/le-platform-operations.ts +0 -340
- package/src/lib/le/le-static-model-schema.ts +0 -78
- package/src/lib/le/le-static-planner.test.ts +0 -255
- package/src/lib/le/le-static-planner.ts +0 -442
- package/src/lib/le/le-template-exporter.test.ts +0 -527
- package/src/lib/le/le-template-exporter.ts +0 -459
- package/src/lib/le/le-value-types.ts +0 -23
- package/src/lib/mqtt-client.ts +0 -115
- package/src/lib/parse.test.ts +0 -123
- package/src/lib/parse.ts +0 -87
- package/src/lib/resolve-simulation.test.ts +0 -118
- package/src/lib/resolve-simulation.ts +0 -181
- package/src/lib/session-store.ts +0 -110
- package/src/lib/shutdown.test.ts +0 -562
- package/src/lib/shutdown.ts +0 -621
- package/src/lib/template-category.test.ts +0 -71
- package/src/lib/template-category.ts +0 -72
- package/src/lib/template-locator.ts +0 -55
- package/src/lib/template-utils.ts +0 -45
- package/src/lib/ws-hub.ts +0 -281
- package/src/logger.test.ts +0 -172
- package/src/logger.ts +0 -402
- package/src/output.test.ts +0 -64
- package/src/output.ts +0 -160
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
import type { Engine } from "@miravo/core";
|
|
2
|
-
import type { MiravoTemplate } from "@miravo/shared";
|
|
3
|
-
import { MiravoError } from "@miravo/shared";
|
|
4
|
-
import type { Command } from "commander";
|
|
5
|
-
import { colors } from "consola/utils";
|
|
6
|
-
import { modbusLog, mqttLog, opcuaLog } from "../../logger.ts";
|
|
7
|
-
import {
|
|
8
|
-
buildModbusDefaultConfig,
|
|
9
|
-
buildMQTTDefaultConfig,
|
|
10
|
-
buildOPCUADefaultConfig,
|
|
11
|
-
} from "./adapter-config.ts";
|
|
12
|
-
import type {
|
|
13
|
-
MqttRunOverrides,
|
|
14
|
-
ProtocolBootPlan,
|
|
15
|
-
ProtocolOptionSource,
|
|
16
|
-
StartOptions,
|
|
17
|
-
} from "./types.ts";
|
|
18
|
-
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
|
-
// Protocol boot plans
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
|
-
|
|
23
|
-
interface ResolvedDetachAdapterConfigs {
|
|
24
|
-
readonly mqtt: {
|
|
25
|
-
readonly port: number | undefined;
|
|
26
|
-
readonly host: string | undefined;
|
|
27
|
-
readonly embedded: boolean;
|
|
28
|
-
};
|
|
29
|
-
readonly opcua: {
|
|
30
|
-
readonly port: number | undefined;
|
|
31
|
-
readonly host: string | undefined;
|
|
32
|
-
};
|
|
33
|
-
readonly modbus: {
|
|
34
|
-
readonly port: number | undefined;
|
|
35
|
-
readonly host: string | undefined;
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function getCommandOptionSource(
|
|
40
|
-
command: Command | undefined,
|
|
41
|
-
optionName: ProtocolOptionSource,
|
|
42
|
-
): string | undefined {
|
|
43
|
-
const maybeGetOptionValueSource = (
|
|
44
|
-
command as Command & { getOptionValueSource?: (key: string) => string | undefined }
|
|
45
|
-
)?.getOptionValueSource;
|
|
46
|
-
return maybeGetOptionValueSource?.call(command, optionName);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function resolveProtocolBootPlans(input: {
|
|
50
|
-
readonly options: StartOptions & { readonly command?: Command | undefined };
|
|
51
|
-
readonly optionSources: Partial<Record<ProtocolOptionSource, string | undefined>>;
|
|
52
|
-
readonly restoredFromPersistence: boolean;
|
|
53
|
-
readonly persistedDisabledAdapters?: ReadonlySet<string> | undefined;
|
|
54
|
-
readonly templateProtocols?: MiravoTemplate["protocols"] | undefined;
|
|
55
|
-
}): readonly ProtocolBootPlan[] {
|
|
56
|
-
const mqttConfigExplicit = [
|
|
57
|
-
"mqttPort",
|
|
58
|
-
"mqttHost",
|
|
59
|
-
"mqttMode",
|
|
60
|
-
"mqttUrl",
|
|
61
|
-
"mqttUsername",
|
|
62
|
-
"mqttPassword",
|
|
63
|
-
].some((option) => input.optionSources[option as ProtocolOptionSource] === "cli");
|
|
64
|
-
|
|
65
|
-
const opcuaConfigExplicit =
|
|
66
|
-
input.options.opcua === true &&
|
|
67
|
-
["opcuaPort", "opcuaHost"].some(
|
|
68
|
-
(option) => input.optionSources[option as ProtocolOptionSource] === "cli",
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
const modbusConfigExplicit =
|
|
72
|
-
input.options.modbus === true &&
|
|
73
|
-
["modbusPort", "modbusHost"].some(
|
|
74
|
-
(option) => input.optionSources[option as ProtocolOptionSource] === "cli",
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
const mqttOverrideRestore =
|
|
78
|
-
!input.restoredFromPersistence || input.optionSources["mqtt"] === "cli" || mqttConfigExplicit;
|
|
79
|
-
const opcuaOverrideRestore =
|
|
80
|
-
!input.restoredFromPersistence || input.optionSources["opcua"] === "cli" || opcuaConfigExplicit;
|
|
81
|
-
const modbusOverrideRestore =
|
|
82
|
-
!input.restoredFromPersistence ||
|
|
83
|
-
input.optionSources["modbus"] === "cli" ||
|
|
84
|
-
modbusConfigExplicit;
|
|
85
|
-
|
|
86
|
-
// When restoring without a CLI override, an adapter explicitly saved as disabled must
|
|
87
|
-
// stay disabled — the user turned it off and that decision should survive restarts.
|
|
88
|
-
const persistedDisabled = input.persistedDisabledAdapters ?? new Set<string>();
|
|
89
|
-
|
|
90
|
-
return [
|
|
91
|
-
{
|
|
92
|
-
name: "mqtt",
|
|
93
|
-
shouldEnable:
|
|
94
|
-
input.options.mqtt !== false && (mqttOverrideRestore || !persistedDisabled.has("mqtt")),
|
|
95
|
-
overrideRestore: mqttOverrideRestore,
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
name: "opcua",
|
|
99
|
-
shouldEnable:
|
|
100
|
-
(input.options.opcua === true ||
|
|
101
|
-
(input.options.opcua === undefined && input.templateProtocols?.opcua !== undefined)) &&
|
|
102
|
-
(opcuaOverrideRestore || !persistedDisabled.has("opcua")),
|
|
103
|
-
overrideRestore: opcuaOverrideRestore,
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
name: "modbus",
|
|
107
|
-
shouldEnable:
|
|
108
|
-
(input.options.modbus === true ||
|
|
109
|
-
(input.options.modbus === undefined && input.templateProtocols?.modbus !== undefined)) &&
|
|
110
|
-
(modbusOverrideRestore || !persistedDisabled.has("modbus")),
|
|
111
|
-
overrideRestore: modbusOverrideRestore,
|
|
112
|
-
},
|
|
113
|
-
];
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function resolveDetachAdapterConfigs(input: {
|
|
117
|
-
readonly template: MiravoTemplate;
|
|
118
|
-
readonly simulationName: string;
|
|
119
|
-
readonly mqtt: {
|
|
120
|
-
readonly enabled: boolean;
|
|
121
|
-
readonly portOverride: number | undefined;
|
|
122
|
-
readonly overrides: MqttRunOverrides;
|
|
123
|
-
};
|
|
124
|
-
readonly opcua: {
|
|
125
|
-
readonly enabled: boolean;
|
|
126
|
-
readonly portOverride: number | undefined;
|
|
127
|
-
readonly hostOverride: string | undefined;
|
|
128
|
-
readonly writeBudgetOverride: number | undefined;
|
|
129
|
-
};
|
|
130
|
-
readonly modbus: {
|
|
131
|
-
readonly enabled: boolean;
|
|
132
|
-
readonly portOverride: number | undefined;
|
|
133
|
-
readonly hostOverride: string | undefined;
|
|
134
|
-
};
|
|
135
|
-
}): ResolvedDetachAdapterConfigs {
|
|
136
|
-
const mqttConfig = input.mqtt.enabled
|
|
137
|
-
? buildMQTTDefaultConfig(
|
|
138
|
-
input.template,
|
|
139
|
-
input.mqtt.portOverride,
|
|
140
|
-
input.mqtt.overrides,
|
|
141
|
-
input.simulationName,
|
|
142
|
-
)
|
|
143
|
-
: null;
|
|
144
|
-
const opcuaConfig = input.opcua.enabled
|
|
145
|
-
? buildOPCUADefaultConfig(
|
|
146
|
-
input.template,
|
|
147
|
-
input.opcua.portOverride,
|
|
148
|
-
input.opcua.hostOverride,
|
|
149
|
-
input.simulationName,
|
|
150
|
-
input.opcua.writeBudgetOverride,
|
|
151
|
-
)
|
|
152
|
-
: null;
|
|
153
|
-
const modbusConfig = input.modbus.enabled
|
|
154
|
-
? buildModbusDefaultConfig(input.template, input.modbus.portOverride, input.modbus.hostOverride)
|
|
155
|
-
: null;
|
|
156
|
-
|
|
157
|
-
return {
|
|
158
|
-
mqtt: {
|
|
159
|
-
port: mqttConfig ? ((mqttConfig as { port?: number }).port ?? 1883) : undefined,
|
|
160
|
-
host: mqttConfig ? ((mqttConfig as { host?: string }).host ?? "0.0.0.0") : undefined,
|
|
161
|
-
embedded: mqttConfig ? ((mqttConfig as { embedded?: boolean }).embedded ?? true) : false,
|
|
162
|
-
},
|
|
163
|
-
opcua: {
|
|
164
|
-
port: opcuaConfig ? ((opcuaConfig as { port?: number }).port ?? 4840) : undefined,
|
|
165
|
-
host: opcuaConfig ? ((opcuaConfig as { host?: string }).host ?? "0.0.0.0") : undefined,
|
|
166
|
-
},
|
|
167
|
-
modbus: {
|
|
168
|
-
port: modbusConfig ? ((modbusConfig as { port?: number }).port ?? 502) : undefined,
|
|
169
|
-
host: modbusConfig ? ((modbusConfig as { host?: string }).host ?? "0.0.0.0") : undefined,
|
|
170
|
-
},
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export async function reconcileProtocolBootPlan(
|
|
175
|
-
engine: Engine,
|
|
176
|
-
plan: ProtocolBootPlan,
|
|
177
|
-
): Promise<void> {
|
|
178
|
-
const adapter = engine.getAvailableAdapters().find((candidate) => candidate.name === plan.name);
|
|
179
|
-
const isEnabled = adapter?.enabled === true;
|
|
180
|
-
|
|
181
|
-
if (!plan.shouldEnable) {
|
|
182
|
-
if (!isEnabled || !plan.overrideRestore) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const result = await engine.disableAdapter(plan.name);
|
|
187
|
-
if (!result.success) {
|
|
188
|
-
throw new MiravoError(
|
|
189
|
-
result.message,
|
|
190
|
-
result.error ?? `Disable adapter "${plan.name}" manually and retry startup.`,
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (plan.overrideRestore && isEnabled) {
|
|
197
|
-
const disableResult = await engine.disableAdapter(plan.name);
|
|
198
|
-
if (!disableResult.success) {
|
|
199
|
-
throw new MiravoError(
|
|
200
|
-
disableResult.message,
|
|
201
|
-
disableResult.error ?? `Disable adapter "${plan.name}" manually and retry startup.`,
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
if ((disableResult.data as { stopWarning?: boolean } | undefined)?.stopWarning === true) {
|
|
205
|
-
throw new MiravoError(
|
|
206
|
-
`Failed to safely reconfigure adapter "${plan.name}" during startup.`,
|
|
207
|
-
`The previous ${plan.name.toUpperCase()} adapter instance did not stop cleanly. Free the port or clear the persisted adapter state before retrying.`,
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
} else if (isEnabled) {
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const result = await engine.enableAdapter(plan.name);
|
|
215
|
-
if (!result.success) {
|
|
216
|
-
throw new MiravoError(
|
|
217
|
-
result.message,
|
|
218
|
-
result.error ?? `Check ${plan.name.toUpperCase()} configuration.`,
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (plan.name === "mqtt") {
|
|
223
|
-
mqttLog.ready(
|
|
224
|
-
`connected · broker: ${colors.cyan(String((result.data as Record<string, unknown>)?.["endpoint"] ?? ""))}`,
|
|
225
|
-
);
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (plan.name === "modbus") {
|
|
230
|
-
modbusLog.ready(
|
|
231
|
-
`server ready · endpoint: ${colors.cyan(String((result.data as Record<string, unknown>)?.["endpoint"] ?? ""))}`,
|
|
232
|
-
);
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
opcuaLog.ready(
|
|
237
|
-
`server ready · endpoint: ${colors.cyan(String((result.data as Record<string, unknown>)?.["endpoint"] ?? ""))}`,
|
|
238
|
-
);
|
|
239
|
-
}
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { basename, resolve } from "node:path";
|
|
3
|
-
import type { ContentCatalog, TwinRuntime } from "@miravo/core";
|
|
4
|
-
import { discoverTemplates } from "@miravo/core";
|
|
5
|
-
import type { CatalogTemplate, MiravoTemplate, TemplateRun } from "@miravo/shared";
|
|
6
|
-
import {
|
|
7
|
-
MiravoError,
|
|
8
|
-
MiravoTemplateSchema,
|
|
9
|
-
TWIN_FILE_EXTENSION,
|
|
10
|
-
TwinModelSchema,
|
|
11
|
-
} from "@miravo/shared";
|
|
12
|
-
import { parse as parseYAML } from "yaml";
|
|
13
|
-
import { isTemplatePathLike } from "../../lib/template-locator.ts";
|
|
14
|
-
import {
|
|
15
|
-
buildUNSBasePath,
|
|
16
|
-
collectReferencedModels,
|
|
17
|
-
forEachTwin,
|
|
18
|
-
} from "../../lib/template-utils.ts";
|
|
19
|
-
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
// Runtime template loader (for loadTemplate command from console/API)
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
|
|
24
|
-
interface CachedTemplate {
|
|
25
|
-
readonly id: string;
|
|
26
|
-
readonly name: string;
|
|
27
|
-
readonly path: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface TemplateCacheResult {
|
|
31
|
-
readonly pathCache: Map<string, CachedTemplate>;
|
|
32
|
-
readonly catalog: readonly CatalogTemplate[];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Discover templates once and build both the path lookup cache (for runtime
|
|
37
|
-
* template loading) and the catalog (for the REST API) in a single pass.
|
|
38
|
-
* All data comes from discovery metadata — no additional file I/O.
|
|
39
|
-
*/
|
|
40
|
-
export async function buildTemplateCacheAndCatalog(
|
|
41
|
-
contentCatalog: ContentCatalog,
|
|
42
|
-
): Promise<TemplateCacheResult> {
|
|
43
|
-
const pathCache = new Map<string, CachedTemplate>();
|
|
44
|
-
const catalogEntries: CatalogTemplate[] = [];
|
|
45
|
-
const discovered = await discoverTemplates(contentCatalog.getBuiltinTemplatesDir());
|
|
46
|
-
|
|
47
|
-
for (const t of discovered) {
|
|
48
|
-
const entry: CachedTemplate = { id: t.id, name: t.name, path: t.path };
|
|
49
|
-
pathCache.set(t.id, entry);
|
|
50
|
-
pathCache.set(t.name, entry);
|
|
51
|
-
|
|
52
|
-
catalogEntries.push({
|
|
53
|
-
id: t.id,
|
|
54
|
-
name: t.name,
|
|
55
|
-
description: t.description ?? null,
|
|
56
|
-
category: "Industrial",
|
|
57
|
-
models: t.modelNames,
|
|
58
|
-
instanceCount: t.totalTwinCount,
|
|
59
|
-
memberCount: 0,
|
|
60
|
-
source: "builtin",
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return { pathCache, catalog: catalogEntries };
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function createRuntimeTemplateLoader(
|
|
68
|
-
catalog: ContentCatalog,
|
|
69
|
-
templatePathCache: Map<string, CachedTemplate>,
|
|
70
|
-
): (templatePath: string, count: number, runId: number, runtime: TwinRuntime) => TemplateRun {
|
|
71
|
-
return (templateIdentifier, count, runId, runtime) => {
|
|
72
|
-
// Resolve template path from pre-built cache or as a file path
|
|
73
|
-
let templatePath: string;
|
|
74
|
-
let slugName: string;
|
|
75
|
-
if (isTemplatePathLike(templateIdentifier)) {
|
|
76
|
-
templatePath = resolve(templateIdentifier);
|
|
77
|
-
slugName = basename(templatePath).replace(/\.miravo\.yaml$/, "");
|
|
78
|
-
} else {
|
|
79
|
-
const cached = templatePathCache.get(templateIdentifier);
|
|
80
|
-
if (!cached) {
|
|
81
|
-
const ids = [...new Set([...templatePathCache.values()].map((e) => e.id))];
|
|
82
|
-
throw new MiravoError(
|
|
83
|
-
`Template "${templateIdentifier}" not found.`,
|
|
84
|
-
`Available templates: ${ids.join(", ") || "(none)"}`,
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
templatePath = cached.path;
|
|
88
|
-
slugName = cached.id;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const template = loadTemplateSync(templatePath);
|
|
92
|
-
const referencedModels = registerTemplateModels(catalog, templatePath, template, runtime);
|
|
93
|
-
|
|
94
|
-
// Spawn instances with auto-prefix using kebab-case slug
|
|
95
|
-
const prefix = `${slugName}-${runId}`;
|
|
96
|
-
const allInstanceIds: string[] = [];
|
|
97
|
-
|
|
98
|
-
for (let c = 0; c < count; c++) {
|
|
99
|
-
const runPrefix = count > 1 ? `${prefix}-${c + 1}` : prefix;
|
|
100
|
-
forEachTwin(template, (area, line, twin) => {
|
|
101
|
-
const unsBasePath = `${runPrefix}/${buildUNSBasePath(template, area.name, line.name)}`;
|
|
102
|
-
const spawned = runtime.spawn(twin.model, twin.count, {
|
|
103
|
-
variation: twin.variation,
|
|
104
|
-
unsBasePath,
|
|
105
|
-
...(twin.parameters !== undefined ? { parameterOverrides: twin.parameters } : {}),
|
|
106
|
-
...(twin.starting_hours !== undefined ? { startingHours: twin.starting_hours } : {}),
|
|
107
|
-
templateRunId: runId,
|
|
108
|
-
});
|
|
109
|
-
for (const node of spawned) {
|
|
110
|
-
allInstanceIds.push(node.id);
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
templateRunId: runId,
|
|
117
|
-
templateName: template.name,
|
|
118
|
-
templatePath,
|
|
119
|
-
prefix,
|
|
120
|
-
instanceIds: allInstanceIds,
|
|
121
|
-
models: [...referencedModels],
|
|
122
|
-
};
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function loadTemplateSync(templatePath: string): MiravoTemplate {
|
|
127
|
-
try {
|
|
128
|
-
return MiravoTemplateSchema.parse(parseYAML(readFileSync(templatePath, "utf-8")));
|
|
129
|
-
} catch (err) {
|
|
130
|
-
throw new MiravoError(
|
|
131
|
-
`Failed to load template "${templatePath}".`,
|
|
132
|
-
err instanceof Error ? err.message : "Check that the file is valid YAML.",
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export function registerModelFromSearchPaths(
|
|
138
|
-
runtime: TwinRuntime,
|
|
139
|
-
modelName: string,
|
|
140
|
-
searchPaths: readonly string[],
|
|
141
|
-
): void {
|
|
142
|
-
if (runtime.getModel(modelName)) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const { path: modelPath, content: modelContent } = loadModelSync(modelName, searchPaths);
|
|
147
|
-
try {
|
|
148
|
-
const model = TwinModelSchema.parse(parseYAML(modelContent));
|
|
149
|
-
runtime.registerModel(model);
|
|
150
|
-
} catch (err) {
|
|
151
|
-
throw new MiravoError(
|
|
152
|
-
`Failed to load model "${modelName}" from "${modelPath}".`,
|
|
153
|
-
err instanceof Error ? err.message : "Check that the model file is valid YAML.",
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export function loadTemplateModels(
|
|
159
|
-
catalog: ContentCatalog,
|
|
160
|
-
templatePath: string,
|
|
161
|
-
runtime: TwinRuntime,
|
|
162
|
-
): readonly string[] {
|
|
163
|
-
const template = loadTemplateSync(templatePath);
|
|
164
|
-
return registerTemplateModels(catalog, templatePath, template, runtime);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function registerTemplateModels(
|
|
168
|
-
catalog: ContentCatalog,
|
|
169
|
-
templatePath: string,
|
|
170
|
-
template: MiravoTemplate,
|
|
171
|
-
runtime: TwinRuntime,
|
|
172
|
-
): readonly string[] {
|
|
173
|
-
const referencedModels = collectReferencedModels(template);
|
|
174
|
-
const searchPaths = catalog.getTemplateValidationSearchPaths(templatePath);
|
|
175
|
-
for (const modelName of referencedModels) {
|
|
176
|
-
registerModelFromSearchPaths(runtime, modelName, searchPaths);
|
|
177
|
-
}
|
|
178
|
-
return [...referencedModels];
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function loadModelSync(
|
|
182
|
-
modelName: string,
|
|
183
|
-
searchPaths: readonly string[],
|
|
184
|
-
): { path: string; content: string } {
|
|
185
|
-
for (const dir of searchPaths) {
|
|
186
|
-
const candidate = resolve(dir, `${modelName}${TWIN_FILE_EXTENSION}`);
|
|
187
|
-
try {
|
|
188
|
-
return { path: candidate, content: readFileSync(candidate, "utf-8") };
|
|
189
|
-
} catch {
|
|
190
|
-
// File doesn't exist or can't be read — try next path
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
throw new MiravoError(
|
|
194
|
-
`Model "${modelName}" not found in search paths.`,
|
|
195
|
-
`Searched: ${searchPaths.join(", ")}. Ensure the model file exists as "${modelName}${TWIN_FILE_EXTENSION}".`,
|
|
196
|
-
);
|
|
197
|
-
}
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import { basename } from "node:path";
|
|
2
|
-
import type { Option as ClackOption } from "@clack/prompts";
|
|
3
|
-
import { isCancel, select } from "@clack/prompts";
|
|
4
|
-
import type { ContentCatalog } from "@miravo/core";
|
|
5
|
-
import { discoverTemplates, resolveMiravoHome } from "@miravo/core";
|
|
6
|
-
import type { DiscoveredTemplate } from "@miravo/shared";
|
|
7
|
-
import { ConfigNotFoundError, MiravoError, PersistedStateSchema } from "@miravo/shared";
|
|
8
|
-
import { Glob } from "bun";
|
|
9
|
-
import {
|
|
10
|
-
groupTemplatesByCategory,
|
|
11
|
-
isStressBenchmarkTemplate,
|
|
12
|
-
sortTemplatesByCategoryAndName,
|
|
13
|
-
} from "../../lib/template-category.ts";
|
|
14
|
-
import {
|
|
15
|
-
discoverPreferredLocalTemplates,
|
|
16
|
-
resolveTemplateIdentifier,
|
|
17
|
-
} from "../../lib/template-locator.ts";
|
|
18
|
-
import { configLog } from "../../logger.ts";
|
|
19
|
-
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
// Step 1: Template resolution
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
|
|
24
|
-
export async function peekStateTemplatePath(simulationName: string): Promise<string | undefined> {
|
|
25
|
-
const stateDir = `${resolveMiravoHome()}/state`;
|
|
26
|
-
const file = Bun.file(`${stateDir}/${simulationName}.json`);
|
|
27
|
-
if (!(await file.exists())) return undefined;
|
|
28
|
-
try {
|
|
29
|
-
const parsed = JSON.parse(await file.text()) as unknown;
|
|
30
|
-
const result = PersistedStateSchema.safeParse(parsed);
|
|
31
|
-
if (!result.success) return undefined;
|
|
32
|
-
return result.data.templateRuns.find((r) => r.templatePath.trim().length > 0)?.templatePath;
|
|
33
|
-
} catch {
|
|
34
|
-
return undefined;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function peekSingleStateTemplatePath(): Promise<string | undefined> {
|
|
39
|
-
const stateDir = `${resolveMiravoHome()}/state`;
|
|
40
|
-
let bestTemplatePath: string | undefined;
|
|
41
|
-
let bestSavedAt = "";
|
|
42
|
-
try {
|
|
43
|
-
const glob = new Glob("*.json");
|
|
44
|
-
for await (const file of glob.scan({ cwd: stateDir, onlyFiles: true })) {
|
|
45
|
-
try {
|
|
46
|
-
const parsed = JSON.parse(await Bun.file(`${stateDir}/${file}`).text()) as unknown;
|
|
47
|
-
const result = PersistedStateSchema.safeParse(parsed);
|
|
48
|
-
if (!result.success) continue;
|
|
49
|
-
const templatePath = result.data.templateRuns.find(
|
|
50
|
-
(r) => r.templatePath.trim().length > 0,
|
|
51
|
-
)?.templatePath;
|
|
52
|
-
if (!templatePath) continue;
|
|
53
|
-
if (result.data.savedAt > bestSavedAt) {
|
|
54
|
-
bestSavedAt = result.data.savedAt;
|
|
55
|
-
bestTemplatePath = templatePath;
|
|
56
|
-
}
|
|
57
|
-
} catch {}
|
|
58
|
-
}
|
|
59
|
-
} catch {
|
|
60
|
-
return undefined; // state dir doesn't exist yet (first-ever run)
|
|
61
|
-
}
|
|
62
|
-
return bestTemplatePath;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export async function resolveTemplatePath(
|
|
66
|
-
templateOption: string | undefined,
|
|
67
|
-
catalog: ContentCatalog,
|
|
68
|
-
): Promise<string> {
|
|
69
|
-
// 1. Explicit --template identifier or path
|
|
70
|
-
if (templateOption) {
|
|
71
|
-
return resolveTemplateIdentifier(templateOption, catalog);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// 2. Auto-discover local templates from content dir (if configured) and CWD
|
|
75
|
-
const discovered = await discoverPreferredLocalTemplates(catalog);
|
|
76
|
-
if (discovered.length === 1) {
|
|
77
|
-
const first = discovered[0];
|
|
78
|
-
if (first !== undefined) {
|
|
79
|
-
configLog.debug(`Found template: ${first.name} (${first.path})`);
|
|
80
|
-
return first.path;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (discovered.length > 1) {
|
|
84
|
-
if (!process.stdout.isTTY || !process.stdin.isTTY) {
|
|
85
|
-
const names = discovered.map((t) => t.name).join(", ");
|
|
86
|
-
throw new MiravoError(
|
|
87
|
-
`Found ${discovered.length} templates: ${names}.`,
|
|
88
|
-
"Use '--template <name|path>' to specify which template to use.",
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
const first = discovered[0];
|
|
92
|
-
if (first !== undefined) {
|
|
93
|
-
configLog.warn(
|
|
94
|
-
`Found ${discovered.length} templates: ${discovered.map((t) => t.name).join(", ")}. Using ${first.name}. Use '--template <name|path>' to specify.`,
|
|
95
|
-
);
|
|
96
|
-
return first.path;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// 3. Fall back to built-in templates
|
|
101
|
-
const builtinTemplateDir = catalog.getBuiltinTemplatesDir();
|
|
102
|
-
let builtinTemplates: readonly DiscoveredTemplate[] = [];
|
|
103
|
-
try {
|
|
104
|
-
const discovered = await discoverTemplates(builtinTemplateDir);
|
|
105
|
-
// Exclude stress/benchmark templates from built-in list (same as standalone binaries).
|
|
106
|
-
builtinTemplates = discovered.filter((t) => !isStressBenchmarkTemplate(t.id));
|
|
107
|
-
} catch {
|
|
108
|
-
// Builtin dir may not exist in edge cases (e.g. standalone binary extraction failure)
|
|
109
|
-
}
|
|
110
|
-
if (builtinTemplates.length > 0) {
|
|
111
|
-
if (process.stdout.isTTY && process.stdin.isTTY) {
|
|
112
|
-
return pickBuiltinTemplate(builtinTemplates);
|
|
113
|
-
}
|
|
114
|
-
const selected = selectDefaultBuiltinTemplate(builtinTemplates);
|
|
115
|
-
if (selected !== undefined) {
|
|
116
|
-
configLog.debug(`No template specified. Using built-in "${selected.name}".`);
|
|
117
|
-
configLog.debug(
|
|
118
|
-
"Run 'miravo templates list' to see all options, or use --template <name|path>.",
|
|
119
|
-
);
|
|
120
|
-
return selected.path;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// 4. Nothing available
|
|
125
|
-
throw new ConfigNotFoundError(
|
|
126
|
-
"No template found. Use 'miravo templates list' to find built-ins or pass 'miravo start --template <name|path>'.",
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async function pickBuiltinTemplate(templates: readonly DiscoveredTemplate[]): Promise<string> {
|
|
131
|
-
configLog.info("No template found in current directory.\n");
|
|
132
|
-
|
|
133
|
-
const choice = await select({
|
|
134
|
-
message: "Choose a built-in template to get started:",
|
|
135
|
-
options: buildBuiltinTemplateChoices(templates),
|
|
136
|
-
maxItems: 9,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
if (isCancel(choice)) {
|
|
140
|
-
process.exit(0);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
configLog.info("Tip: use --template <id> to skip this prompt next time.");
|
|
144
|
-
|
|
145
|
-
return choice as string;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export function buildBuiltinTemplateChoices(
|
|
149
|
-
templates: readonly DiscoveredTemplate[],
|
|
150
|
-
): Array<ClackOption<string>> {
|
|
151
|
-
const groupedTemplates = groupTemplatesByCategory(sortTemplatesByCategoryAndName(templates));
|
|
152
|
-
const choices: ClackOption<string>[] = [];
|
|
153
|
-
|
|
154
|
-
for (const group of groupedTemplates) {
|
|
155
|
-
choices.push({
|
|
156
|
-
value: `__header__${group.category}`,
|
|
157
|
-
label: group.category,
|
|
158
|
-
hint: `${group.templates.length} templates`,
|
|
159
|
-
disabled: true,
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
for (const [index, template] of group.templates.entries()) {
|
|
163
|
-
const isLast = index === group.templates.length - 1;
|
|
164
|
-
const branch = isLast ? "\u2514\u2500" : "\u251C\u2500";
|
|
165
|
-
const label = ` ${branch} ${template.name}`;
|
|
166
|
-
const hintPrefix = template.description ?? template.id;
|
|
167
|
-
choices.push({
|
|
168
|
-
value: template.path,
|
|
169
|
-
label,
|
|
170
|
-
hint: `${hintPrefix} \u00B7 ${template.uniqueModelCount} models \u00B7 ${template.totalTwinCount} twins`,
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return choices;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function selectDefaultBuiltinTemplate(
|
|
179
|
-
templates: readonly DiscoveredTemplate[],
|
|
180
|
-
): DiscoveredTemplate | undefined {
|
|
181
|
-
const preferredFilename = "smart-factory.miravo.yaml";
|
|
182
|
-
return (
|
|
183
|
-
templates.find((template) => basename(template.path) === preferredFilename) ?? templates[0]
|
|
184
|
-
);
|
|
185
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import type { Command } from "commander";
|
|
2
|
-
|
|
3
|
-
export interface StartOptions {
|
|
4
|
-
readonly name?: string;
|
|
5
|
-
readonly template?: string;
|
|
6
|
-
readonly modelsDir?: string;
|
|
7
|
-
readonly speed?: number;
|
|
8
|
-
readonly seed?: number;
|
|
9
|
-
readonly tick?: number;
|
|
10
|
-
readonly mqttPort?: number;
|
|
11
|
-
readonly mqttHost?: string;
|
|
12
|
-
readonly mqttMode?: string;
|
|
13
|
-
readonly mqttUrl?: string;
|
|
14
|
-
readonly mqttUsername?: string;
|
|
15
|
-
readonly mqttPassword?: string;
|
|
16
|
-
readonly mqtt?: boolean;
|
|
17
|
-
readonly opcuaPort?: number;
|
|
18
|
-
readonly opcuaHost?: string;
|
|
19
|
-
readonly opcua?: boolean;
|
|
20
|
-
readonly modbusPort?: number;
|
|
21
|
-
readonly modbusHost?: string;
|
|
22
|
-
readonly modbus?: boolean;
|
|
23
|
-
readonly adminHost?: string;
|
|
24
|
-
readonly adminPort?: number;
|
|
25
|
-
readonly dryRun?: boolean;
|
|
26
|
-
readonly summaryInterval?: number;
|
|
27
|
-
readonly ui?: boolean;
|
|
28
|
-
readonly auth?: boolean;
|
|
29
|
-
readonly resetState?: boolean;
|
|
30
|
-
readonly detach?: boolean;
|
|
31
|
-
readonly command?: Command;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface RestoreSummary {
|
|
35
|
-
readonly instanceCount: number;
|
|
36
|
-
readonly templateRunCount: number;
|
|
37
|
-
readonly adapterCount: number;
|
|
38
|
-
readonly stateFilePath: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface ProtocolBootPlan {
|
|
42
|
-
readonly name: "mqtt" | "opcua" | "modbus";
|
|
43
|
-
readonly shouldEnable: boolean;
|
|
44
|
-
readonly overrideRestore: boolean;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export type ProtocolOptionSource =
|
|
48
|
-
| "mqtt"
|
|
49
|
-
| "opcua"
|
|
50
|
-
| "modbus"
|
|
51
|
-
| "mqttPort"
|
|
52
|
-
| "mqttHost"
|
|
53
|
-
| "mqttMode"
|
|
54
|
-
| "mqttUrl"
|
|
55
|
-
| "mqttUsername"
|
|
56
|
-
| "mqttPassword"
|
|
57
|
-
| "opcuaPort"
|
|
58
|
-
| "opcuaHost"
|
|
59
|
-
| "modbusPort"
|
|
60
|
-
| "modbusHost";
|
|
61
|
-
|
|
62
|
-
export type MqttMode = "embedded" | "external";
|
|
63
|
-
|
|
64
|
-
export interface MqttRunOverrides {
|
|
65
|
-
readonly mode?: MqttMode;
|
|
66
|
-
readonly host?: string;
|
|
67
|
-
readonly url?: string;
|
|
68
|
-
readonly username?: string;
|
|
69
|
-
readonly password?: string;
|
|
70
|
-
readonly drainBudget?: number;
|
|
71
|
-
readonly batchSize?: number;
|
|
72
|
-
readonly brokerConcurrency?: number;
|
|
73
|
-
}
|