iobroker.statechart 0.2.0 → 0.3.0
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 +21 -21
- package/README.md +42 -530
- package/admin/build/tab.js +118 -117
- package/admin/statechart.png +0 -0
- package/admin/{style.css → tab.css} +0 -2
- package/admin/tab_m.html +1 -1
- package/build/lib/chart-analysis.js +367 -0
- package/build/lib/chart-analysis.js.map +7 -0
- package/build/lib/chart-codegen.js +82 -15
- package/build/lib/chart-codegen.js.map +3 -3
- package/build/lib/chart-helpers.js +12 -0
- package/build/lib/chart-helpers.js.map +2 -2
- package/build/lib/chart-model.js +138 -14
- package/build/lib/chart-model.js.map +2 -2
- package/build/lib/chart-runtime.js +732 -87
- package/build/lib/chart-runtime.js.map +3 -3
- package/build/lib/chart-structure.js +73 -2
- package/build/lib/chart-structure.js.map +2 -2
- package/build/lib/chart-validation.js +86 -17
- package/build/lib/chart-validation.js.map +3 -3
- package/build/main.js +330 -34
- package/build/main.js.map +2 -2
- package/io-package.json +18 -34
- package/package.json +2 -1
- package/admin/i18n/de.json +0 -4
- package/admin/i18n/en.json +0 -4
- package/admin/i18n/es.json +0 -4
- package/admin/i18n/fr.json +0 -4
- package/admin/i18n/it.json +0 -4
- package/admin/i18n/nl.json +0 -4
- package/admin/i18n/pl.json +0 -4
- package/admin/i18n/pt.json +0 -4
- package/admin/i18n/ru.json +0 -4
- package/admin/i18n/uk.json +0 -4
- package/admin/i18n/zh-cn.json +0 -4
- package/admin/jsonConfig.json +0 -19
- package/admin/statechart.svg +0 -38
package/build/main.js
CHANGED
|
@@ -24,6 +24,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
var utils = __toESM(require("@iobroker/adapter-core"));
|
|
25
25
|
var import_chart_runtime = require("./lib/chart-runtime");
|
|
26
26
|
const HISTORY_LENGTH = 200;
|
|
27
|
+
const SIMULATION_TIMEOUT_MS = 2 * 60 * 1e3;
|
|
28
|
+
const CONTROLS = ["enabled", "reset", "event"];
|
|
27
29
|
class Statechart extends utils.Adapter {
|
|
28
30
|
/** running charts by chart ID */
|
|
29
31
|
runtimes = /* @__PURE__ */ new Map();
|
|
@@ -35,6 +37,8 @@ class Statechart extends utils.Adapter {
|
|
|
35
37
|
location = null;
|
|
36
38
|
/** the last events of each chart by chart ID, newest last, also stored in charts.<chart>.history */
|
|
37
39
|
histories = /* @__PURE__ */ new Map();
|
|
40
|
+
/** charts which run as simulation (their runtime is in runtimes), with the timer which ends the simulation */
|
|
41
|
+
simulations = /* @__PURE__ */ new Map();
|
|
38
42
|
constructor(options = {}) {
|
|
39
43
|
super({
|
|
40
44
|
...options,
|
|
@@ -43,6 +47,7 @@ class Statechart extends utils.Adapter {
|
|
|
43
47
|
this.on("ready", this.onReady.bind(this));
|
|
44
48
|
this.on("stateChange", this.onStateChange.bind(this));
|
|
45
49
|
this.on("objectChange", this.onObjectChange.bind(this));
|
|
50
|
+
this.on("message", this.onMessage.bind(this));
|
|
46
51
|
this.on("unload", this.onUnload.bind(this));
|
|
47
52
|
}
|
|
48
53
|
/**
|
|
@@ -64,6 +69,9 @@ class Statechart extends utils.Adapter {
|
|
|
64
69
|
}
|
|
65
70
|
this.subscribeObjects("charts.*");
|
|
66
71
|
this.subscribeStates("charts.*.history");
|
|
72
|
+
for (const control of CONTROLS) {
|
|
73
|
+
this.subscribeStates(`charts.*.${control}`);
|
|
74
|
+
}
|
|
67
75
|
}
|
|
68
76
|
/**
|
|
69
77
|
* Reads the location of the ioBroker system settings, used by isDaytime() and astroTime()
|
|
@@ -94,11 +102,11 @@ class Statechart extends utils.Adapter {
|
|
|
94
102
|
}
|
|
95
103
|
/**
|
|
96
104
|
* @param id State ID
|
|
97
|
-
* @returns the chart ID
|
|
105
|
+
* @returns the chart ID and the name of the state if it is a state of a chart, e.g. "history"
|
|
98
106
|
*/
|
|
99
|
-
|
|
100
|
-
const match = /^charts
|
|
101
|
-
return id.startsWith(`${this.namespace}.`) && match ? match[1] : void 0;
|
|
107
|
+
parseChartStateId(id) {
|
|
108
|
+
const match = /^charts\.([^.]+)\.([^.]+)$/.exec(id.substring(this.namespace.length + 1));
|
|
109
|
+
return id.startsWith(`${this.namespace}.`) && match ? { chartId: match[1], name: match[2] } : void 0;
|
|
102
110
|
}
|
|
103
111
|
/**
|
|
104
112
|
* @param chartId Chart ID
|
|
@@ -113,6 +121,9 @@ class Statechart extends utils.Adapter {
|
|
|
113
121
|
}
|
|
114
122
|
await this.createChartStates(chartId);
|
|
115
123
|
await this.loadHistory(chartId);
|
|
124
|
+
await this.setState(`charts.${chartId}.enabled`, chart.enabled !== false, true);
|
|
125
|
+
await this.setState(`charts.${chartId}.simulation`, false, true);
|
|
126
|
+
await this.setState(`charts.${chartId}.simulationStatus`, "", true);
|
|
116
127
|
const empty = !chart.states?.length;
|
|
117
128
|
if (!chart.enabled || empty) {
|
|
118
129
|
if (empty) {
|
|
@@ -125,30 +136,7 @@ class Statechart extends utils.Adapter {
|
|
|
125
136
|
await this.setState(`charts.${chartId}.values`, "{}", true);
|
|
126
137
|
return;
|
|
127
138
|
}
|
|
128
|
-
const runtime =
|
|
129
|
-
readState: async (id) => (await this.getForeignStateAsync(id))?.val ?? null,
|
|
130
|
-
writeState: async (id, val, ack = false) => {
|
|
131
|
-
await this.setForeignStateAsync(id, val, ack);
|
|
132
|
-
},
|
|
133
|
-
sendTo: (instance, command, message) => this.sendTo(instance, command, message),
|
|
134
|
-
getLocation: () => this.location,
|
|
135
|
-
onActiveChange: ({ names, ids }) => {
|
|
136
|
-
void this.setState(`charts.${chartId}.activeState`, names, true);
|
|
137
|
-
void this.setState(`charts.${chartId}.activeStateIds`, JSON.stringify(ids), true);
|
|
138
|
-
},
|
|
139
|
-
persist: (data) => {
|
|
140
|
-
void this.setState(`charts.${chartId}.snapshot`, JSON.stringify(data), true);
|
|
141
|
-
},
|
|
142
|
-
onValues: (values) => {
|
|
143
|
-
void this.setState(`charts.${chartId}.values`, JSON.stringify(values), true);
|
|
144
|
-
},
|
|
145
|
-
onHistory: (entries) => this.addHistory(chartId, entries),
|
|
146
|
-
loadPersisted: async () => {
|
|
147
|
-
const state = await this.getStateAsync(`charts.${chartId}.snapshot`);
|
|
148
|
-
return typeof state?.val === "string" && state.val ? JSON.parse(state.val) : null;
|
|
149
|
-
},
|
|
150
|
-
log: this.log
|
|
151
|
-
});
|
|
139
|
+
const runtime = this.createRuntime(chartId, chart);
|
|
152
140
|
try {
|
|
153
141
|
await runtime.start({ restore });
|
|
154
142
|
} catch (err) {
|
|
@@ -159,6 +147,198 @@ class Statechart extends utils.Adapter {
|
|
|
159
147
|
this.updateSubscriptions();
|
|
160
148
|
this.log.info(`Chart "${chart.name}" started`);
|
|
161
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* @param chartId Chart ID
|
|
152
|
+
* @param chart The chart
|
|
153
|
+
* @param simulated Run it as simulation, see ChartRuntime
|
|
154
|
+
*/
|
|
155
|
+
createRuntime(chartId, chart, simulated = false) {
|
|
156
|
+
return new import_chart_runtime.ChartRuntime(
|
|
157
|
+
chartId,
|
|
158
|
+
chart,
|
|
159
|
+
{
|
|
160
|
+
readState: async (id) => (await this.getForeignStateAsync(id))?.val ?? null,
|
|
161
|
+
getState: (id) => this.getForeignStateAsync(id),
|
|
162
|
+
writeState: async (id, val, ack = false) => {
|
|
163
|
+
await this.setForeignStateAsync(id, val, ack);
|
|
164
|
+
},
|
|
165
|
+
sendTo: (instance, command, message) => this.sendTo(instance, command, message),
|
|
166
|
+
getLocation: () => this.location,
|
|
167
|
+
onActiveChange: ({ names, ids }) => {
|
|
168
|
+
void this.setState(`charts.${chartId}.activeState`, names, true);
|
|
169
|
+
void this.setState(`charts.${chartId}.activeStateIds`, JSON.stringify(ids), true);
|
|
170
|
+
},
|
|
171
|
+
persist: (data) => {
|
|
172
|
+
void this.setState(`charts.${chartId}.snapshot`, JSON.stringify(data), true);
|
|
173
|
+
},
|
|
174
|
+
onValues: (values) => {
|
|
175
|
+
void this.setState(`charts.${chartId}.values`, JSON.stringify(values), true);
|
|
176
|
+
},
|
|
177
|
+
onHistory: (entries) => this.addHistory(chartId, entries),
|
|
178
|
+
onSimulationStatus: (status) => {
|
|
179
|
+
void this.setState(`charts.${chartId}.simulationStatus`, JSON.stringify(status), true);
|
|
180
|
+
},
|
|
181
|
+
loadPersisted: async () => {
|
|
182
|
+
const state = await this.getStateAsync(`charts.${chartId}.snapshot`);
|
|
183
|
+
return typeof state?.val === "string" && state.val ? JSON.parse(state.val) : null;
|
|
184
|
+
},
|
|
185
|
+
log: this.log,
|
|
186
|
+
// the timers of the adapter are cleared when it is unloaded
|
|
187
|
+
setTimeout: (callback, ms) => this.setTimeout(callback, ms),
|
|
188
|
+
clearTimeout: (handle) => this.clearTimeout(handle)
|
|
189
|
+
},
|
|
190
|
+
simulated
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Stops the chart and runs the given version of it as simulation, see ChartRuntime
|
|
195
|
+
*
|
|
196
|
+
* @param chartId Chart ID
|
|
197
|
+
* @param chart The chart as shown in the editor, may have unsaved changes
|
|
198
|
+
* @param breakpoints IDs of the states and transitions with a breakpoint
|
|
199
|
+
*/
|
|
200
|
+
async startSimulation(chartId, chart, breakpoints = []) {
|
|
201
|
+
if (!chart?.states?.length) {
|
|
202
|
+
throw new Error("The chart has no states");
|
|
203
|
+
}
|
|
204
|
+
this.stopChart(chartId);
|
|
205
|
+
this.endSimulationTimer(chartId);
|
|
206
|
+
const runtime = this.createRuntime(chartId, chart, true);
|
|
207
|
+
runtime.breakpoints = new Set(breakpoints);
|
|
208
|
+
this.simulations.set(
|
|
209
|
+
chartId,
|
|
210
|
+
this.setTimeout(() => this.onSimulationTimeout(chartId), SIMULATION_TIMEOUT_MS)
|
|
211
|
+
);
|
|
212
|
+
try {
|
|
213
|
+
await runtime.start();
|
|
214
|
+
} catch (err) {
|
|
215
|
+
this.endSimulationTimer(chartId);
|
|
216
|
+
await this.restartChart(chartId);
|
|
217
|
+
throw err;
|
|
218
|
+
}
|
|
219
|
+
this.runtimes.set(chartId, runtime);
|
|
220
|
+
this.updateSubscriptions();
|
|
221
|
+
await this.setState(`charts.${chartId}.simulation`, true, true);
|
|
222
|
+
this.log.info(`Chart "${chart.name}" runs as simulation, its outputs are not written`);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Ends the simulation of a chart, the real chart continues where it was before
|
|
226
|
+
*
|
|
227
|
+
* @param chartId Chart ID
|
|
228
|
+
*/
|
|
229
|
+
async stopSimulation(chartId) {
|
|
230
|
+
if (!this.simulations.has(chartId)) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
this.endSimulationTimer(chartId);
|
|
234
|
+
this.stopChart(chartId);
|
|
235
|
+
this.log.info(`Simulation of chart ${chartId} ended`);
|
|
236
|
+
await this.restartChart(chartId, true);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* @param chartId Chart ID
|
|
240
|
+
*/
|
|
241
|
+
endSimulationTimer(chartId) {
|
|
242
|
+
this.clearTimeout(this.simulations.get(chartId));
|
|
243
|
+
this.simulations.delete(chartId);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* @param chartId Chart ID
|
|
247
|
+
*/
|
|
248
|
+
onSimulationTimeout(chartId) {
|
|
249
|
+
this.log.info(`Simulation of chart ${chartId} ended, the editor did not answer anymore`);
|
|
250
|
+
this.chartQueue = this.chartQueue.then(() => this.stopSimulation(chartId)).catch((err) => this.log.error(`Cannot end the simulation of chart ${chartId}: ${err.message}`));
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Starts a chart with the stored version
|
|
254
|
+
*
|
|
255
|
+
* @param chartId Chart ID
|
|
256
|
+
* @param restore Continue with the persisted state instead of the initial state
|
|
257
|
+
*/
|
|
258
|
+
async restartChart(chartId, restore = false) {
|
|
259
|
+
await this.startChart(chartId, await this.getObjectAsync(`charts.${chartId}`), restore);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Messages of the editor, for the simulation
|
|
263
|
+
*
|
|
264
|
+
* @param obj The message
|
|
265
|
+
*/
|
|
266
|
+
onMessage(obj) {
|
|
267
|
+
if (typeof obj !== "object" || !obj.command) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const message = obj.message || {};
|
|
271
|
+
const chartId = String(message.chartId || "");
|
|
272
|
+
const reply = (response) => {
|
|
273
|
+
if (obj.callback) {
|
|
274
|
+
this.sendTo(obj.from, obj.command, response, obj.callback);
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
const simulating = this.simulations.has(chartId);
|
|
278
|
+
if (simulating) {
|
|
279
|
+
this.clearTimeout(this.simulations.get(chartId));
|
|
280
|
+
this.simulations.set(
|
|
281
|
+
chartId,
|
|
282
|
+
this.setTimeout(() => this.onSimulationTimeout(chartId), SIMULATION_TIMEOUT_MS)
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
const runtime = this.runtimes.get(chartId);
|
|
286
|
+
switch (obj.command) {
|
|
287
|
+
case "simulationStart":
|
|
288
|
+
this.chartQueue = this.chartQueue.then(() => this.startSimulation(chartId, message.chart, message.breakpoints)).then(() => reply({ ok: true })).catch((err) => reply({ error: err.message }));
|
|
289
|
+
return;
|
|
290
|
+
case "simulationStop":
|
|
291
|
+
this.chartQueue = this.chartQueue.then(() => this.stopSimulation(chartId)).then(() => reply({ ok: true })).catch((err) => reply({ error: err.message }));
|
|
292
|
+
return;
|
|
293
|
+
case "simulationInput":
|
|
294
|
+
if (!simulating || !runtime) {
|
|
295
|
+
reply({ error: "No simulation is running" });
|
|
296
|
+
} else if (!runtime.simulateInput(String(message.name), message.value)) {
|
|
297
|
+
reply({ error: `Unknown input "${message.name}"` });
|
|
298
|
+
} else {
|
|
299
|
+
reply({ ok: true });
|
|
300
|
+
}
|
|
301
|
+
return;
|
|
302
|
+
case "simulationEvent":
|
|
303
|
+
if (!simulating || !runtime) {
|
|
304
|
+
reply({ error: "No simulation is running" });
|
|
305
|
+
} else if (!runtime.handleEvent(String(message.name))) {
|
|
306
|
+
reply({ error: `Unknown input "${message.name}"` });
|
|
307
|
+
} else {
|
|
308
|
+
reply({ ok: true });
|
|
309
|
+
}
|
|
310
|
+
return;
|
|
311
|
+
case "simulationPing":
|
|
312
|
+
reply({ ok: simulating });
|
|
313
|
+
return;
|
|
314
|
+
case "simulationBreakpoints":
|
|
315
|
+
case "simulationPause":
|
|
316
|
+
case "simulationResume":
|
|
317
|
+
case "simulationStep":
|
|
318
|
+
case "simulationAdvance":
|
|
319
|
+
if (!simulating || !runtime) {
|
|
320
|
+
reply({ error: "No simulation is running" });
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if (obj.command === "simulationBreakpoints") {
|
|
324
|
+
runtime.breakpoints = new Set(Array.isArray(message.breakpoints) ? message.breakpoints : []);
|
|
325
|
+
} else if (obj.command === "simulationPause") {
|
|
326
|
+
runtime.pauseSimulation();
|
|
327
|
+
} else if (obj.command === "simulationResume") {
|
|
328
|
+
runtime.resumeSimulation();
|
|
329
|
+
} else if (obj.command === "simulationStep") {
|
|
330
|
+
runtime.stepSimulation();
|
|
331
|
+
} else if (typeof message.ms === "number" && message.ms > 0) {
|
|
332
|
+
runtime.advanceTime(message.ms);
|
|
333
|
+
} else {
|
|
334
|
+
runtime.advanceToNextTimer();
|
|
335
|
+
}
|
|
336
|
+
reply({ ok: true });
|
|
337
|
+
return;
|
|
338
|
+
default:
|
|
339
|
+
reply({ error: `Unknown command "${obj.command}"` });
|
|
340
|
+
}
|
|
341
|
+
}
|
|
162
342
|
/**
|
|
163
343
|
* Reads the stored history of a chart, if it is not known yet
|
|
164
344
|
*
|
|
@@ -260,12 +440,115 @@ class Statechart extends utils.Adapter {
|
|
|
260
440
|
},
|
|
261
441
|
native: {}
|
|
262
442
|
});
|
|
443
|
+
await this.setObjectNotExistsAsync(`charts.${chartId}.enabled`, {
|
|
444
|
+
type: "state",
|
|
445
|
+
common: {
|
|
446
|
+
name: "Chart runs: false pauses it, true starts it in its initial state",
|
|
447
|
+
type: "boolean",
|
|
448
|
+
role: "switch.enable",
|
|
449
|
+
read: true,
|
|
450
|
+
write: true
|
|
451
|
+
},
|
|
452
|
+
native: {}
|
|
453
|
+
});
|
|
454
|
+
await this.setObjectNotExistsAsync(`charts.${chartId}.reset`, {
|
|
455
|
+
type: "state",
|
|
456
|
+
common: {
|
|
457
|
+
name: "Restart the running chart in its initial state",
|
|
458
|
+
type: "boolean",
|
|
459
|
+
role: "button",
|
|
460
|
+
read: false,
|
|
461
|
+
write: true
|
|
462
|
+
},
|
|
463
|
+
native: {}
|
|
464
|
+
});
|
|
465
|
+
await this.setObjectNotExistsAsync(`charts.${chartId}.simulation`, {
|
|
466
|
+
type: "state",
|
|
467
|
+
common: {
|
|
468
|
+
name: "The chart runs as simulation from the editor, its outputs are not written",
|
|
469
|
+
type: "boolean",
|
|
470
|
+
role: "indicator",
|
|
471
|
+
read: true,
|
|
472
|
+
write: false
|
|
473
|
+
},
|
|
474
|
+
native: {}
|
|
475
|
+
});
|
|
476
|
+
await this.setObjectNotExistsAsync(`charts.${chartId}.simulationStatus`, {
|
|
477
|
+
type: "state",
|
|
478
|
+
common: {
|
|
479
|
+
name: "Status of the simulation as JSON: paused, time offset, queued wakeups, next timer, breakpoint",
|
|
480
|
+
type: "string",
|
|
481
|
+
role: "json",
|
|
482
|
+
read: true,
|
|
483
|
+
write: false
|
|
484
|
+
},
|
|
485
|
+
native: {}
|
|
486
|
+
});
|
|
487
|
+
await this.setObjectNotExistsAsync(`charts.${chartId}.event`, {
|
|
488
|
+
type: "state",
|
|
489
|
+
common: {
|
|
490
|
+
name: "Name of an input: wakes up the chart with this event, without changing the value of the input",
|
|
491
|
+
type: "string",
|
|
492
|
+
role: "text",
|
|
493
|
+
read: true,
|
|
494
|
+
write: true
|
|
495
|
+
},
|
|
496
|
+
native: {}
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Executes a command written to a control state of a chart
|
|
501
|
+
*
|
|
502
|
+
* @param chartId Chart ID
|
|
503
|
+
* @param control Name of the state
|
|
504
|
+
* @param val The written value
|
|
505
|
+
*/
|
|
506
|
+
async handleControl(chartId, control, val) {
|
|
507
|
+
const id = `charts.${chartId}.${control}`;
|
|
508
|
+
const obj = await this.getObjectAsync(`charts.${chartId}`);
|
|
509
|
+
const chart = obj?.type === "channel" ? obj.native?.chart : void 0;
|
|
510
|
+
if (!chart) {
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
if (control === "enabled") {
|
|
514
|
+
const enabled = val === true || val === "true" || val === 1;
|
|
515
|
+
if (enabled === (chart.enabled !== false)) {
|
|
516
|
+
await this.setState(id, enabled, true);
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
await this.extendObjectAsync(`charts.${chartId}`, { native: { chart: { enabled } } });
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
const runtime = this.runtimes.get(chartId);
|
|
523
|
+
if (control === "reset") {
|
|
524
|
+
if (this.simulations.has(chartId)) {
|
|
525
|
+
this.log.info(`Chart "${chart.name}" is not reset, it runs as simulation`);
|
|
526
|
+
} else if (runtime) {
|
|
527
|
+
this.log.info(`Chart "${chart.name}" is reset`);
|
|
528
|
+
this.chartQueue = this.chartQueue.then(async () => {
|
|
529
|
+
this.stopChart(chartId);
|
|
530
|
+
await this.startChart(chartId, obj);
|
|
531
|
+
}).catch((err) => this.log.error(`Cannot reset chart ${chartId}: ${err.message}`));
|
|
532
|
+
await this.chartQueue;
|
|
533
|
+
} else {
|
|
534
|
+
this.log.info(`Chart "${chart.name}" is not reset, it does not run`);
|
|
535
|
+
}
|
|
536
|
+
await this.setState(id, false, true);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
const name = String(val ?? "").trim();
|
|
540
|
+
if (!runtime) {
|
|
541
|
+
this.log.info(`Event "${name}" ignored, chart "${chart.name}" does not run`);
|
|
542
|
+
} else if (!runtime.handleEvent(name)) {
|
|
543
|
+
this.log.warn(`Chart "${chart.name}": unknown event "${name}", use the name of an input`);
|
|
544
|
+
}
|
|
545
|
+
await this.setState(id, name, true);
|
|
263
546
|
}
|
|
264
547
|
/**
|
|
265
548
|
* Subscribes to all inputs of the running charts and unsubscribes from the ones no longer used
|
|
266
549
|
*/
|
|
267
550
|
updateSubscriptions() {
|
|
268
|
-
const needed = new Set([...this.runtimes.values()].flatMap((runtime) => runtime.
|
|
551
|
+
const needed = new Set([...this.runtimes.values()].flatMap((runtime) => runtime.subscribedStateIds));
|
|
269
552
|
for (const id of needed) {
|
|
270
553
|
if (!this.subscribedInputs.has(id)) {
|
|
271
554
|
this.subscribeForeignStates(id);
|
|
@@ -285,6 +568,10 @@ class Statechart extends utils.Adapter {
|
|
|
285
568
|
*/
|
|
286
569
|
onUnload(callback) {
|
|
287
570
|
try {
|
|
571
|
+
for (const timer of this.simulations.values()) {
|
|
572
|
+
this.clearTimeout(timer);
|
|
573
|
+
}
|
|
574
|
+
this.simulations.clear();
|
|
288
575
|
for (const runtime of this.runtimes.values()) {
|
|
289
576
|
runtime.stop();
|
|
290
577
|
}
|
|
@@ -307,6 +594,7 @@ class Statechart extends utils.Adapter {
|
|
|
307
594
|
return;
|
|
308
595
|
}
|
|
309
596
|
this.chartQueue = this.chartQueue.then(async () => {
|
|
597
|
+
this.endSimulationTimer(chartId);
|
|
310
598
|
this.stopChart(chartId);
|
|
311
599
|
await this.startChart(chartId, obj);
|
|
312
600
|
}).catch((err) => this.log.error(`Cannot restart chart ${chartId}: ${err.message}`));
|
|
@@ -321,16 +609,24 @@ class Statechart extends utils.Adapter {
|
|
|
321
609
|
if (!state) {
|
|
322
610
|
return;
|
|
323
611
|
}
|
|
324
|
-
const
|
|
325
|
-
if (
|
|
612
|
+
const own = this.parseChartStateId(id);
|
|
613
|
+
if (own?.name === "history") {
|
|
614
|
+
if (!state.ack) {
|
|
615
|
+
this.histories.set(own.chartId, []);
|
|
616
|
+
void this.setState(`charts.${own.chartId}.history`, "[]", true);
|
|
617
|
+
}
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
if (own && CONTROLS.includes(own.name)) {
|
|
326
621
|
if (!state.ack) {
|
|
327
|
-
this.
|
|
328
|
-
|
|
622
|
+
this.handleControl(own.chartId, own.name, state.val).catch(
|
|
623
|
+
(err) => this.log.error(`Cannot execute ${id}: ${err.message}`)
|
|
624
|
+
);
|
|
329
625
|
}
|
|
330
626
|
return;
|
|
331
627
|
}
|
|
332
628
|
for (const runtime of this.runtimes.values()) {
|
|
333
|
-
runtime.
|
|
629
|
+
runtime.handleStateChange(id, state);
|
|
334
630
|
}
|
|
335
631
|
}
|
|
336
632
|
}
|
package/build/main.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/main.ts"],
|
|
4
|
-
"sourcesContent": ["/*\n * Created with @iobroker/create-adapter v3.1.5\n */\n\n// The adapter-core module gives you access to the core ioBroker functions\n// you need to create an adapter\nimport * as utils from \"@iobroker/adapter-core\";\nimport type { Chart } from \"./lib/chart-model\";\nimport { ChartRuntime } from \"./lib/chart-runtime\";\nimport type { HistoryEntry, Location } from \"./lib/chart-runtime\";\n\n/** Maximum number of entries in the history of a chart (state charts.<chart>.history) */\nconst HISTORY_LENGTH = 200;\n\nclass Statechart extends utils.Adapter {\n /** running charts by chart ID */\n private runtimes = new Map<string, ChartRuntime>();\n /** foreign states we are subscribed to */\n private subscribedInputs = new Set<string>();\n /** chart (re)starts are executed one after another */\n private chartQueue = Promise.resolve();\n /** for the astro helper functions */\n private location: Location | null = null;\n /** the last events of each chart by chart ID, newest last, also stored in charts.<chart>.history */\n private histories = new Map<string, HistoryEntry[]>();\n\n public constructor(options: Partial<utils.AdapterOptions> = {}) {\n super({\n ...options,\n name: \"statechart\",\n });\n this.on(\"ready\", this.onReady.bind(this));\n this.on(\"stateChange\", this.onStateChange.bind(this));\n this.on(\"objectChange\", this.onObjectChange.bind(this));\n this.on(\"unload\", this.onUnload.bind(this));\n }\n\n /**\n * Is called when databases are connected and adapter received configuration.\n */\n private async onReady(): Promise<void> {\n await this.setObjectNotExistsAsync(\"charts\", {\n type: \"folder\",\n common: { name: \"Charts\" },\n native: {},\n });\n await this.loadLocation();\n\n const objects = await this.getForeignObjectsAsync(`${this.namespace}.charts.*`, \"channel\");\n for (const [id, obj] of Object.entries(objects)) {\n const chartId = this.getChartId(id);\n if (chartId) {\n // continue where the chart was before the adapter stopped\n await this.startChart(chartId, obj, true);\n }\n }\n\n // the editor saves charts as objects, restart a chart (in its initial state) whenever it changes\n this.subscribeObjects(\"charts.*\");\n // the editor clears the history by writing to it\n this.subscribeStates(\"charts.*.history\");\n }\n\n /**\n * Reads the location of the ioBroker system settings, used by isDaytime() and astroTime()\n */\n private async loadLocation(): Promise<void> {\n const config = await this.getForeignObjectAsync(\"system.config\");\n const latitude = parseFloat(String(config?.common?.latitude ?? \"\"));\n const longitude = parseFloat(String(config?.common?.longitude ?? \"\"));\n if (Number.isFinite(latitude) && Number.isFinite(longitude)) {\n this.location = { latitude, longitude };\n } else {\n this.log.info(\"No location configured in the system settings, isDaytime() and astroTime() do not work\");\n }\n }\n\n /**\n * Extracts the chart ID from the ID of a chart object\n *\n * @param id Object ID\n * @returns undefined if the ID is no chart object\n */\n private getChartId(id: string): string | undefined {\n const prefix = `${this.namespace}.charts.`;\n if (!id.startsWith(prefix)) {\n return undefined;\n }\n const chartId = id.substring(prefix.length);\n return chartId.includes(\".\") ? undefined : chartId;\n }\n\n /**\n * @param id State ID\n * @returns the chart ID if the state is the history of a chart\n */\n private getHistoryChartId(id: string): string | undefined {\n const match = /^charts.([^.]+).history$/.exec(id.substring(this.namespace.length + 1));\n return id.startsWith(`${this.namespace}.`) && match ? match[1] : undefined;\n }\n\n /**\n * @param chartId Chart ID\n * @param obj Chart object\n * @param restore Continue with the persisted state instead of the initial state\n */\n private async startChart(chartId: string, obj: ioBroker.Object | null | undefined, restore = false): Promise<void> {\n const chart: Chart | undefined = obj?.type === \"channel\" ? obj.native?.chart : undefined;\n if (!chart) {\n // e.g. the chart was deleted\n this.histories.delete(chartId);\n return;\n }\n\n await this.createChartStates(chartId);\n await this.loadHistory(chartId);\n // e.g. a new chart, which was just created in the editor: nothing to execute, but no error either\n const empty = !chart.states?.length;\n if (!chart.enabled || empty) {\n if (empty) {\n this.log.warn(`Chart \"${chart.name}\" has no states, it is not started`);\n } else {\n this.log.info(`Chart \"${chart.name}\" is paused`);\n }\n // no state is active, so the editor does not highlight the last active state anymore\n await this.setState(`charts.${chartId}.activeState`, \"\", true);\n await this.setState(`charts.${chartId}.activeStateIds`, \"[]\", true);\n // the editor shows no values of a chart which does not run\n await this.setState(`charts.${chartId}.values`, \"{}\", true);\n return;\n }\n\n const runtime = new ChartRuntime(chartId, chart, {\n readState: async id => (await this.getForeignStateAsync(id))?.val ?? null,\n writeState: async (id, val, ack = false) => {\n await this.setForeignStateAsync(id, val, ack);\n },\n sendTo: (instance, command, message) => this.sendTo(instance, command, message),\n getLocation: () => this.location,\n onActiveChange: ({ names, ids }) => {\n void this.setState(`charts.${chartId}.activeState`, names, true);\n void this.setState(`charts.${chartId}.activeStateIds`, JSON.stringify(ids), true);\n },\n persist: data => {\n void this.setState(`charts.${chartId}.snapshot`, JSON.stringify(data), true);\n },\n onValues: values => {\n void this.setState(`charts.${chartId}.values`, JSON.stringify(values), true);\n },\n onHistory: entries => this.addHistory(chartId, entries),\n loadPersisted: async () => {\n const state = await this.getStateAsync(`charts.${chartId}.snapshot`);\n return typeof state?.val === \"string\" && state.val ? JSON.parse(state.val) : null;\n },\n log: this.log,\n });\n try {\n await runtime.start({ restore });\n } catch (err) {\n this.log.error(`Cannot start chart \"${chart.name}\": ${err.message}`);\n return;\n }\n this.runtimes.set(chartId, runtime);\n this.updateSubscriptions();\n this.log.info(`Chart \"${chart.name}\" started`);\n }\n\n /**\n * Reads the stored history of a chart, if it is not known yet\n *\n * @param chartId Chart ID\n */\n private async loadHistory(chartId: string): Promise<void> {\n if (this.histories.has(chartId)) {\n return;\n }\n let history: HistoryEntry[] = [];\n try {\n const state = await this.getStateAsync(`charts.${chartId}.history`);\n const parsed = typeof state?.val === \"string\" && state.val ? JSON.parse(state.val) : [];\n history = Array.isArray(parsed) ? parsed : [];\n } catch {\n // an invalid history is replaced by a new one\n }\n this.histories.set(chartId, history);\n }\n\n /**\n * Appends events to the history of a chart and stores it\n *\n * @param chartId Chart ID\n * @param entries The new events\n */\n private addHistory(chartId: string, entries: HistoryEntry[]): void {\n const history = [...(this.histories.get(chartId) || []), ...entries].slice(-HISTORY_LENGTH);\n this.histories.set(chartId, history);\n void this.setState(`charts.${chartId}.history`, JSON.stringify(history), true);\n }\n\n /**\n * @param chartId Chart ID\n */\n private stopChart(chartId: string): void {\n const runtime = this.runtimes.get(chartId);\n if (runtime) {\n runtime.stop();\n this.runtimes.delete(chartId);\n this.updateSubscriptions();\n }\n }\n\n /**\n * Creates the states which show the current status of a chart\n *\n * @param chartId Chart ID\n */\n private async createChartStates(chartId: string): Promise<void> {\n await this.setObjectNotExistsAsync(`charts.${chartId}.activeState`, {\n type: \"state\",\n common: {\n name: \"Active state\",\n type: \"string\",\n role: \"text\",\n read: true,\n write: false,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.snapshot`, {\n type: \"state\",\n common: {\n name: \"Stored state of the chart, restored after a restart of the adapter\",\n type: \"string\",\n role: \"json\",\n read: true,\n write: false,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.activeStateIds`, {\n type: \"state\",\n common: {\n name: \"IDs of all active states\",\n type: \"string\",\n role: \"json\",\n read: true,\n write: false,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.values`, {\n type: \"state\",\n common: {\n name: \"Current values of all variables\",\n type: \"string\",\n role: \"json\",\n read: true,\n write: false,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.history`, {\n type: \"state\",\n common: {\n name: `Last ${HISTORY_LENGTH} events: starts and transitions taken, write anything to clear it`,\n type: \"string\",\n role: \"json\",\n read: true,\n write: true,\n },\n native: {},\n });\n }\n\n /**\n * Subscribes to all inputs of the running charts and unsubscribes from the ones no longer used\n */\n private updateSubscriptions(): void {\n const needed = new Set([...this.runtimes.values()].flatMap(runtime => runtime.inputStateIds));\n for (const id of needed) {\n if (!this.subscribedInputs.has(id)) {\n this.subscribeForeignStates(id);\n }\n }\n for (const id of this.subscribedInputs) {\n if (!needed.has(id)) {\n this.unsubscribeForeignStates(id);\n }\n }\n this.subscribedInputs = needed;\n }\n\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n *\n * @param callback Callback function\n */\n private onUnload(callback: () => void): void {\n try {\n for (const runtime of this.runtimes.values()) {\n runtime.stop();\n }\n this.runtimes.clear();\n callback();\n } catch (error) {\n this.log.error(`Error during unloading: ${error.message}`);\n callback();\n }\n }\n\n /**\n * Is called if a subscribed object changes\n *\n * @param id Object ID\n * @param obj Object\n */\n private onObjectChange(id: string, obj: ioBroker.Object | null | undefined): void {\n const chartId = this.getChartId(id);\n if (!chartId) {\n return;\n }\n this.chartQueue = this.chartQueue\n .then(async () => {\n this.stopChart(chartId);\n await this.startChart(chartId, obj);\n })\n .catch(err => this.log.error(`Cannot restart chart ${chartId}: ${err.message}`));\n }\n\n /**\n * Is called if a subscribed state changes\n *\n * @param id State ID\n * @param state State object\n */\n private onStateChange(id: string, state: ioBroker.State | null | undefined): void {\n if (!state) {\n return;\n }\n const historyOf = this.getHistoryChartId(id);\n if (historyOf) {\n // written by the editor (\"clear\"), the adapter's own updates are acknowledged\n if (!state.ack) {\n this.histories.set(historyOf, []);\n void this.setState(`charts.${historyOf}.history`, \"[]\", true);\n }\n return;\n }\n for (const runtime of this.runtimes.values()) {\n runtime.handleInput(id, state.val, { ack: state.ack });\n }\n }\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial<utils.AdapterOptions> | undefined) => new Statechart(options);\n} else {\n // otherwise start the instance directly\n (() => new Statechart())();\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/*\n * Created with @iobroker/create-adapter v3.1.5\n */\n\n// The adapter-core module gives you access to the core ioBroker functions\n// you need to create an adapter\nimport * as utils from \"@iobroker/adapter-core\";\nimport type { Chart } from \"./lib/chart-model\";\nimport { ChartRuntime } from \"./lib/chart-runtime\";\nimport type { HistoryEntry, Location } from \"./lib/chart-runtime\";\n\n/** Maximum number of entries in the history of a chart (state charts.<chart>.history) */\nconst HISTORY_LENGTH = 200;\n\n/** A simulation ends when the editor did not send a message for this time, e.g. because it was closed */\nconst SIMULATION_TIMEOUT_MS = 2 * 60 * 1000;\n\n/** States of each chart which control it, written by vis, scripts etc. (without ack) */\nconst CONTROLS = [\"enabled\", \"reset\", \"event\"] as const;\ntype Control = (typeof CONTROLS)[number];\n\nclass Statechart extends utils.Adapter {\n /** running charts by chart ID */\n private runtimes = new Map<string, ChartRuntime>();\n /** foreign states we are subscribed to */\n private subscribedInputs = new Set<string>();\n /** chart (re)starts are executed one after another */\n private chartQueue = Promise.resolve();\n /** for the astro helper functions */\n private location: Location | null = null;\n /** the last events of each chart by chart ID, newest last, also stored in charts.<chart>.history */\n private histories = new Map<string, HistoryEntry[]>();\n /** charts which run as simulation (their runtime is in runtimes), with the timer which ends the simulation */\n private simulations = new Map<string, ioBroker.Timeout | undefined>();\n\n public constructor(options: Partial<utils.AdapterOptions> = {}) {\n super({\n ...options,\n name: \"statechart\",\n });\n this.on(\"ready\", this.onReady.bind(this));\n this.on(\"stateChange\", this.onStateChange.bind(this));\n this.on(\"objectChange\", this.onObjectChange.bind(this));\n this.on(\"message\", this.onMessage.bind(this));\n this.on(\"unload\", this.onUnload.bind(this));\n }\n\n /**\n * Is called when databases are connected and adapter received configuration.\n */\n private async onReady(): Promise<void> {\n await this.setObjectNotExistsAsync(\"charts\", {\n type: \"folder\",\n common: { name: \"Charts\" },\n native: {},\n });\n await this.loadLocation();\n\n const objects = await this.getForeignObjectsAsync(`${this.namespace}.charts.*`, \"channel\");\n for (const [id, obj] of Object.entries(objects)) {\n const chartId = this.getChartId(id);\n if (chartId) {\n // continue where the chart was before the adapter stopped\n await this.startChart(chartId, obj, true);\n }\n }\n\n // the editor saves charts as objects, restart a chart (in its initial state) whenever it changes\n this.subscribeObjects(\"charts.*\");\n // the editor clears the history by writing to it\n this.subscribeStates(\"charts.*.history\");\n for (const control of CONTROLS) {\n this.subscribeStates(`charts.*.${control}`);\n }\n }\n\n /**\n * Reads the location of the ioBroker system settings, used by isDaytime() and astroTime()\n */\n private async loadLocation(): Promise<void> {\n const config = await this.getForeignObjectAsync(\"system.config\");\n const latitude = parseFloat(String(config?.common?.latitude ?? \"\"));\n const longitude = parseFloat(String(config?.common?.longitude ?? \"\"));\n if (Number.isFinite(latitude) && Number.isFinite(longitude)) {\n this.location = { latitude, longitude };\n } else {\n this.log.info(\"No location configured in the system settings, isDaytime() and astroTime() do not work\");\n }\n }\n\n /**\n * Extracts the chart ID from the ID of a chart object\n *\n * @param id Object ID\n * @returns undefined if the ID is no chart object\n */\n private getChartId(id: string): string | undefined {\n const prefix = `${this.namespace}.charts.`;\n if (!id.startsWith(prefix)) {\n return undefined;\n }\n const chartId = id.substring(prefix.length);\n return chartId.includes(\".\") ? undefined : chartId;\n }\n\n /**\n * @param id State ID\n * @returns the chart ID and the name of the state if it is a state of a chart, e.g. \"history\"\n */\n private parseChartStateId(id: string): { chartId: string; name: string } | undefined {\n const match = /^charts\\.([^.]+)\\.([^.]+)$/.exec(id.substring(this.namespace.length + 1));\n return id.startsWith(`${this.namespace}.`) && match ? { chartId: match[1], name: match[2] } : undefined;\n }\n\n /**\n * @param chartId Chart ID\n * @param obj Chart object\n * @param restore Continue with the persisted state instead of the initial state\n */\n private async startChart(chartId: string, obj: ioBroker.Object | null | undefined, restore = false): Promise<void> {\n const chart: Chart | undefined = obj?.type === \"channel\" ? obj.native?.chart : undefined;\n if (!chart) {\n // e.g. the chart was deleted\n this.histories.delete(chartId);\n return;\n }\n\n await this.createChartStates(chartId);\n await this.loadHistory(chartId);\n await this.setState(`charts.${chartId}.enabled`, chart.enabled !== false, true);\n await this.setState(`charts.${chartId}.simulation`, false, true);\n await this.setState(`charts.${chartId}.simulationStatus`, \"\", true);\n // e.g. a new chart, which was just created in the editor: nothing to execute, but no error either\n const empty = !chart.states?.length;\n if (!chart.enabled || empty) {\n if (empty) {\n this.log.warn(`Chart \"${chart.name}\" has no states, it is not started`);\n } else {\n this.log.info(`Chart \"${chart.name}\" is paused`);\n }\n // no state is active, so the editor does not highlight the last active state anymore\n await this.setState(`charts.${chartId}.activeState`, \"\", true);\n await this.setState(`charts.${chartId}.activeStateIds`, \"[]\", true);\n // the editor shows no values of a chart which does not run\n await this.setState(`charts.${chartId}.values`, \"{}\", true);\n return;\n }\n\n const runtime = this.createRuntime(chartId, chart);\n try {\n await runtime.start({ restore });\n } catch (err) {\n this.log.error(`Cannot start chart \"${chart.name}\": ${err.message}`);\n return;\n }\n this.runtimes.set(chartId, runtime);\n this.updateSubscriptions();\n this.log.info(`Chart \"${chart.name}\" started`);\n }\n\n /**\n * @param chartId Chart ID\n * @param chart The chart\n * @param simulated Run it as simulation, see ChartRuntime\n */\n private createRuntime(chartId: string, chart: Chart, simulated = false): ChartRuntime {\n return new ChartRuntime(\n chartId,\n chart,\n {\n readState: async id => (await this.getForeignStateAsync(id))?.val ?? null,\n getState: id => this.getForeignStateAsync(id),\n writeState: async (id, val, ack = false) => {\n await this.setForeignStateAsync(id, val, ack);\n },\n sendTo: (instance, command, message) => this.sendTo(instance, command, message),\n getLocation: () => this.location,\n onActiveChange: ({ names, ids }) => {\n void this.setState(`charts.${chartId}.activeState`, names, true);\n void this.setState(`charts.${chartId}.activeStateIds`, JSON.stringify(ids), true);\n },\n persist: data => {\n void this.setState(`charts.${chartId}.snapshot`, JSON.stringify(data), true);\n },\n onValues: values => {\n void this.setState(`charts.${chartId}.values`, JSON.stringify(values), true);\n },\n onHistory: entries => this.addHistory(chartId, entries),\n onSimulationStatus: status => {\n void this.setState(`charts.${chartId}.simulationStatus`, JSON.stringify(status), true);\n },\n loadPersisted: async () => {\n const state = await this.getStateAsync(`charts.${chartId}.snapshot`);\n return typeof state?.val === \"string\" && state.val ? JSON.parse(state.val) : null;\n },\n log: this.log,\n // the timers of the adapter are cleared when it is unloaded\n setTimeout: (callback, ms) => this.setTimeout(callback, ms),\n clearTimeout: handle => this.clearTimeout(handle as ioBroker.Timeout | undefined),\n },\n simulated,\n );\n }\n\n /**\n * Stops the chart and runs the given version of it as simulation, see ChartRuntime\n *\n * @param chartId Chart ID\n * @param chart The chart as shown in the editor, may have unsaved changes\n * @param breakpoints IDs of the states and transitions with a breakpoint\n */\n private async startSimulation(chartId: string, chart: Chart, breakpoints: string[] = []): Promise<void> {\n if (!chart?.states?.length) {\n throw new Error(\"The chart has no states\");\n }\n this.stopChart(chartId);\n this.endSimulationTimer(chartId);\n const runtime = this.createRuntime(chartId, chart, true);\n // also for the initial states\n runtime.breakpoints = new Set(breakpoints);\n // registered before the start, so the start can be cancelled like a running simulation\n this.simulations.set(\n chartId,\n this.setTimeout(() => this.onSimulationTimeout(chartId), SIMULATION_TIMEOUT_MS),\n );\n try {\n await runtime.start();\n } catch (err) {\n this.endSimulationTimer(chartId);\n await this.restartChart(chartId);\n throw err;\n }\n this.runtimes.set(chartId, runtime);\n this.updateSubscriptions();\n await this.setState(`charts.${chartId}.simulation`, true, true);\n this.log.info(`Chart \"${chart.name}\" runs as simulation, its outputs are not written`);\n }\n\n /**\n * Ends the simulation of a chart, the real chart continues where it was before\n *\n * @param chartId Chart ID\n */\n private async stopSimulation(chartId: string): Promise<void> {\n if (!this.simulations.has(chartId)) {\n return;\n }\n this.endSimulationTimer(chartId);\n this.stopChart(chartId);\n this.log.info(`Simulation of chart ${chartId} ended`);\n await this.restartChart(chartId, true);\n }\n\n /**\n * @param chartId Chart ID\n */\n private endSimulationTimer(chartId: string): void {\n this.clearTimeout(this.simulations.get(chartId));\n this.simulations.delete(chartId);\n }\n\n /**\n * @param chartId Chart ID\n */\n private onSimulationTimeout(chartId: string): void {\n this.log.info(`Simulation of chart ${chartId} ended, the editor did not answer anymore`);\n this.chartQueue = this.chartQueue\n .then(() => this.stopSimulation(chartId))\n .catch(err => this.log.error(`Cannot end the simulation of chart ${chartId}: ${err.message}`));\n }\n\n /**\n * Starts a chart with the stored version\n *\n * @param chartId Chart ID\n * @param restore Continue with the persisted state instead of the initial state\n */\n private async restartChart(chartId: string, restore = false): Promise<void> {\n await this.startChart(chartId, await this.getObjectAsync(`charts.${chartId}`), restore);\n }\n\n /**\n * Messages of the editor, for the simulation\n *\n * @param obj The message\n */\n private onMessage(obj: ioBroker.Message): void {\n if (typeof obj !== \"object\" || !obj.command) {\n return;\n }\n const message = (obj.message || {}) as {\n chartId?: string;\n chart?: Chart;\n name?: string;\n value?: any;\n breakpoints?: string[];\n ms?: number;\n };\n const chartId = String(message.chartId || \"\");\n const reply = (response: Record<string, any>): void => {\n if (obj.callback) {\n this.sendTo(obj.from, obj.command, response, obj.callback);\n }\n };\n const simulating = this.simulations.has(chartId);\n if (simulating) {\n // every message of the editor keeps the simulation alive\n this.clearTimeout(this.simulations.get(chartId));\n this.simulations.set(\n chartId,\n this.setTimeout(() => this.onSimulationTimeout(chartId), SIMULATION_TIMEOUT_MS),\n );\n }\n const runtime = this.runtimes.get(chartId);\n switch (obj.command) {\n case \"simulationStart\":\n this.chartQueue = this.chartQueue\n .then(() => this.startSimulation(chartId, message.chart as Chart, message.breakpoints))\n .then(() => reply({ ok: true }))\n .catch(err => reply({ error: err.message }));\n return;\n case \"simulationStop\":\n this.chartQueue = this.chartQueue\n .then(() => this.stopSimulation(chartId))\n .then(() => reply({ ok: true }))\n .catch(err => reply({ error: err.message }));\n return;\n case \"simulationInput\":\n if (!simulating || !runtime) {\n reply({ error: \"No simulation is running\" });\n } else if (!runtime.simulateInput(String(message.name), message.value)) {\n reply({ error: `Unknown input \"${message.name}\"` });\n } else {\n reply({ ok: true });\n }\n return;\n case \"simulationEvent\":\n if (!simulating || !runtime) {\n reply({ error: \"No simulation is running\" });\n } else if (!runtime.handleEvent(String(message.name))) {\n reply({ error: `Unknown input \"${message.name}\"` });\n } else {\n reply({ ok: true });\n }\n return;\n case \"simulationPing\":\n reply({ ok: simulating });\n return;\n case \"simulationBreakpoints\":\n case \"simulationPause\":\n case \"simulationResume\":\n case \"simulationStep\":\n case \"simulationAdvance\":\n if (!simulating || !runtime) {\n reply({ error: \"No simulation is running\" });\n return;\n }\n if (obj.command === \"simulationBreakpoints\") {\n runtime.breakpoints = new Set(Array.isArray(message.breakpoints) ? message.breakpoints : []);\n } else if (obj.command === \"simulationPause\") {\n runtime.pauseSimulation();\n } else if (obj.command === \"simulationResume\") {\n runtime.resumeSimulation();\n } else if (obj.command === \"simulationStep\") {\n runtime.stepSimulation();\n } else if (typeof message.ms === \"number\" && message.ms > 0) {\n runtime.advanceTime(message.ms);\n } else {\n // without a time: to the next timer\n runtime.advanceToNextTimer();\n }\n reply({ ok: true });\n return;\n default:\n reply({ error: `Unknown command \"${obj.command}\"` });\n }\n }\n\n /**\n * Reads the stored history of a chart, if it is not known yet\n *\n * @param chartId Chart ID\n */\n private async loadHistory(chartId: string): Promise<void> {\n if (this.histories.has(chartId)) {\n return;\n }\n let history: HistoryEntry[] = [];\n try {\n const state = await this.getStateAsync(`charts.${chartId}.history`);\n const parsed = typeof state?.val === \"string\" && state.val ? JSON.parse(state.val) : [];\n history = Array.isArray(parsed) ? parsed : [];\n } catch {\n // an invalid history is replaced by a new one\n }\n this.histories.set(chartId, history);\n }\n\n /**\n * Appends events to the history of a chart and stores it\n *\n * @param chartId Chart ID\n * @param entries The new events\n */\n private addHistory(chartId: string, entries: HistoryEntry[]): void {\n const history = [...(this.histories.get(chartId) || []), ...entries].slice(-HISTORY_LENGTH);\n this.histories.set(chartId, history);\n void this.setState(`charts.${chartId}.history`, JSON.stringify(history), true);\n }\n\n /**\n * @param chartId Chart ID\n */\n private stopChart(chartId: string): void {\n const runtime = this.runtimes.get(chartId);\n if (runtime) {\n runtime.stop();\n this.runtimes.delete(chartId);\n this.updateSubscriptions();\n }\n }\n\n /**\n * Creates the states which show the current status of a chart\n *\n * @param chartId Chart ID\n */\n private async createChartStates(chartId: string): Promise<void> {\n await this.setObjectNotExistsAsync(`charts.${chartId}.activeState`, {\n type: \"state\",\n common: {\n name: \"Active state\",\n type: \"string\",\n role: \"text\",\n read: true,\n write: false,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.snapshot`, {\n type: \"state\",\n common: {\n name: \"Stored state of the chart, restored after a restart of the adapter\",\n type: \"string\",\n role: \"json\",\n read: true,\n write: false,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.activeStateIds`, {\n type: \"state\",\n common: {\n name: \"IDs of all active states\",\n type: \"string\",\n role: \"json\",\n read: true,\n write: false,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.values`, {\n type: \"state\",\n common: {\n name: \"Current values of all variables\",\n type: \"string\",\n role: \"json\",\n read: true,\n write: false,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.history`, {\n type: \"state\",\n common: {\n name: `Last ${HISTORY_LENGTH} events: starts and transitions taken, write anything to clear it`,\n type: \"string\",\n role: \"json\",\n read: true,\n write: true,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.enabled`, {\n type: \"state\",\n common: {\n name: \"Chart runs: false pauses it, true starts it in its initial state\",\n type: \"boolean\",\n role: \"switch.enable\",\n read: true,\n write: true,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.reset`, {\n type: \"state\",\n common: {\n name: \"Restart the running chart in its initial state\",\n type: \"boolean\",\n role: \"button\",\n read: false,\n write: true,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.simulation`, {\n type: \"state\",\n common: {\n name: \"The chart runs as simulation from the editor, its outputs are not written\",\n type: \"boolean\",\n role: \"indicator\",\n read: true,\n write: false,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.simulationStatus`, {\n type: \"state\",\n common: {\n name: \"Status of the simulation as JSON: paused, time offset, queued wakeups, next timer, breakpoint\",\n type: \"string\",\n role: \"json\",\n read: true,\n write: false,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(`charts.${chartId}.event`, {\n type: \"state\",\n common: {\n name: \"Name of an input: wakes up the chart with this event, without changing the value of the input\",\n type: \"string\",\n role: \"text\",\n read: true,\n write: true,\n },\n native: {},\n });\n }\n\n /**\n * Executes a command written to a control state of a chart\n *\n * @param chartId Chart ID\n * @param control Name of the state\n * @param val The written value\n */\n private async handleControl(chartId: string, control: Control, val: ioBroker.StateValue): Promise<void> {\n const id = `charts.${chartId}.${control}`;\n const obj = await this.getObjectAsync(`charts.${chartId}`);\n const chart: Chart | undefined = obj?.type === \"channel\" ? obj.native?.chart : undefined;\n if (!chart) {\n return;\n }\n if (control === \"enabled\") {\n const enabled = val === true || val === \"true\" || val === 1;\n if (enabled === (chart.enabled !== false)) {\n await this.setState(id, enabled, true);\n return;\n }\n // like the button in the editor: the change of the object stops or restarts the chart, which also\n // confirms the state, see startChart()\n await this.extendObjectAsync(`charts.${chartId}`, { native: { chart: { enabled } } });\n return;\n }\n const runtime = this.runtimes.get(chartId);\n if (control === \"reset\") {\n if (this.simulations.has(chartId)) {\n this.log.info(`Chart \"${chart.name}\" is not reset, it runs as simulation`);\n } else if (runtime) {\n this.log.info(`Chart \"${chart.name}\" is reset`);\n this.chartQueue = this.chartQueue\n .then(async () => {\n this.stopChart(chartId);\n await this.startChart(chartId, obj);\n })\n .catch(err => this.log.error(`Cannot reset chart ${chartId}: ${err.message}`));\n await this.chartQueue;\n } else {\n this.log.info(`Chart \"${chart.name}\" is not reset, it does not run`);\n }\n await this.setState(id, false, true);\n return;\n }\n // event\n const name = String(val ?? \"\").trim();\n if (!runtime) {\n this.log.info(`Event \"${name}\" ignored, chart \"${chart.name}\" does not run`);\n } else if (!runtime.handleEvent(name)) {\n this.log.warn(`Chart \"${chart.name}\": unknown event \"${name}\", use the name of an input`);\n }\n await this.setState(id, name, true);\n }\n\n /**\n * Subscribes to all inputs of the running charts and unsubscribes from the ones no longer used\n */\n private updateSubscriptions(): void {\n const needed = new Set([...this.runtimes.values()].flatMap(runtime => runtime.subscribedStateIds));\n for (const id of needed) {\n if (!this.subscribedInputs.has(id)) {\n this.subscribeForeignStates(id);\n }\n }\n for (const id of this.subscribedInputs) {\n if (!needed.has(id)) {\n this.unsubscribeForeignStates(id);\n }\n }\n this.subscribedInputs = needed;\n }\n\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n *\n * @param callback Callback function\n */\n private onUnload(callback: () => void): void {\n try {\n for (const timer of this.simulations.values()) {\n this.clearTimeout(timer);\n }\n this.simulations.clear();\n for (const runtime of this.runtimes.values()) {\n runtime.stop();\n }\n this.runtimes.clear();\n callback();\n } catch (error) {\n this.log.error(`Error during unloading: ${error.message}`);\n callback();\n }\n }\n\n /**\n * Is called if a subscribed object changes\n *\n * @param id Object ID\n * @param obj Object\n */\n private onObjectChange(id: string, obj: ioBroker.Object | null | undefined): void {\n const chartId = this.getChartId(id);\n if (!chartId) {\n return;\n }\n this.chartQueue = this.chartQueue\n .then(async () => {\n // e.g. saved in the editor: a simulation ends, the new version starts\n this.endSimulationTimer(chartId);\n this.stopChart(chartId);\n await this.startChart(chartId, obj);\n })\n .catch(err => this.log.error(`Cannot restart chart ${chartId}: ${err.message}`));\n }\n\n /**\n * Is called if a subscribed state changes\n *\n * @param id State ID\n * @param state State object\n */\n private onStateChange(id: string, state: ioBroker.State | null | undefined): void {\n if (!state) {\n return;\n }\n const own = this.parseChartStateId(id);\n if (own?.name === \"history\") {\n // written by the editor (\"clear\"), the adapter's own updates are acknowledged\n if (!state.ack) {\n this.histories.set(own.chartId, []);\n void this.setState(`charts.${own.chartId}.history`, \"[]\", true);\n }\n return;\n }\n if (own && CONTROLS.includes(own.name as Control)) {\n // commands only, the adapter confirms them with ack\n if (!state.ack) {\n this.handleControl(own.chartId, own.name as Control, state.val).catch(err =>\n this.log.error(`Cannot execute ${id}: ${err.message}`),\n );\n }\n return;\n }\n for (const runtime of this.runtimes.values()) {\n runtime.handleStateChange(id, state);\n }\n }\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial<utils.AdapterOptions> | undefined) => new Statechart(options);\n} else {\n // otherwise start the instance directly\n (() => new Statechart())();\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|