iobroker.javascript 10.2.5 → 10.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.
Files changed (114) hide show
  1. package/README.md +6 -14
  2. package/admin/assets/AiChatPanel-CpY4Bun-.js +27 -0
  3. package/admin/assets/{AiChatService-BOL3J2Jd.js → AiChatService-QKcpW4jQ.js} +1 -1
  4. package/admin/assets/AiDiffView-DscPfZ38.js +1 -0
  5. package/admin/assets/{AiInlineProvider-BIlcrTkS.js → AiInlineProvider-DTSPKoXG.js} +1 -1
  6. package/admin/assets/BlocklyEditor-BZyoN1JE.js +301 -0
  7. package/admin/assets/Compile-B0uHjrBE.css +1 -0
  8. package/admin/assets/Compile-Oss28m_f.js +165 -0
  9. package/admin/assets/{Debugger-DwHHsh9O.js → Debugger-teJTIU-2.js} +4 -4
  10. package/admin/assets/{Documentation-Bc0RmoEF.js → Documentation-uz4Ut9pT.js} +4 -4
  11. package/admin/assets/ExpandMore-V5Ix1QB1.js +1 -0
  12. package/admin/assets/FbEditor-B8S-mCvc.css +1 -0
  13. package/admin/assets/FbEditor-aOZ-RpPV.js +15 -0
  14. package/admin/assets/Import-BIC5Ee9z.js +1 -0
  15. package/admin/assets/NotificationsActive-BdzH44gp.js +1 -0
  16. package/admin/assets/RulesEditor-CcDVthPa.js +1 -0
  17. package/admin/assets/{ScriptEditor-CEHpEFp7.js → ScriptEditor-CviB6Hif.js} +2 -2
  18. package/admin/assets/ScriptEditorVanillaMonaco-ByuXwybM.js +3 -0
  19. package/admin/assets/Send-Mdo32jMb.js +1 -0
  20. package/admin/assets/{_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-CM95r358.js → _virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-BnL93BgK.js} +1 -1
  21. package/admin/assets/{_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BEpNZh4U.js → _virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-NI-3Uv4e.js} +75 -75
  22. package/admin/assets/{_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-FeM77flT.js → _virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-DVaMIZyC.js} +1 -1
  23. package/admin/assets/aiPromptBuilder-yTB6N2VT.js +1 -0
  24. package/admin/assets/blocklyTheme-CGhU3cEO.js +1 -0
  25. package/admin/assets/blocks_action-BQ4O7NRE.js +1 -0
  26. package/admin/assets/{blocks_convert-BP2RjhQH.js → blocks_convert-0VBjfhqQ.js} +1 -1
  27. package/admin/assets/blocks_logic-DAo99xDr.js +1 -0
  28. package/admin/assets/blocks_number-C--e19NU.js +1 -0
  29. package/admin/assets/blocks_object-D0TPhdzg.js +1 -0
  30. package/admin/assets/blocks_procedures-DgTxgXdB.js +3 -0
  31. package/admin/assets/{blocks_sendto-qIKzOAcV.js → blocks_sendto-CRIrtOUc.js} +1 -1
  32. package/admin/assets/blocks_switch-b_GYfF0n.js +2 -0
  33. package/admin/assets/blocks_system-BdkUdSsc.js +1 -0
  34. package/admin/assets/blocks_text-DSFhEVOf.js +1 -0
  35. package/admin/assets/blocks_time-CqALAiJp.js +1 -0
  36. package/admin/assets/blocks_timeout-yrOD2pZp.js +1 -0
  37. package/admin/assets/{blocks_trigger-CnmXLCUE.js → blocks_trigger-DeAYXpSS.js} +1 -1
  38. package/admin/assets/{cronHoverProvider-CcIFAhVy.js → cronHoverProvider-DoO2_tpG.js} +1 -1
  39. package/admin/assets/{field_cron-Ba46q8Qc.js → field_cron-D3Ts_s9M.js} +1 -1
  40. package/admin/assets/{field_oid-lWCjOzuq.js → field_oid-BRNXredg.js} +1 -1
  41. package/admin/assets/{field_script-BCWZHhnW.js → field_script-3X6ousg7.js} +1 -1
  42. package/admin/assets/helpers-BTGaTdnT.js +1 -0
  43. package/admin/assets/{hostInit-CVybS7BB.js → hostInit-2h2Cbsaw.js} +1 -1
  44. package/admin/assets/index-BHhhebRG.css +1 -0
  45. package/admin/assets/index-CbQlIKB_.js +156 -0
  46. package/admin/assets/{inlineChatWidget-N8xIkvxX.js → inlineChatWidget-BwQVCPkx.js} +2 -2
  47. package/admin/assets/{inlineDiffController-BuqYsKKq.js → inlineDiffController-BsDDsDHn.js} +2 -2
  48. package/admin/assets/loadBlocks-RpqM7PwO.js +117 -0
  49. package/admin/assets/loadMonaco-BVOEahNw.js +1 -0
  50. package/admin/assets/{mf-entry-bootstrap-0-a5a39621.js → mf-entry-bootstrap-0-0deef484.js} +3 -3
  51. package/admin/assets/{pendingShares-DOAkyFMS.js → pendingShares-BaAadIDv.js} +1 -1
  52. package/admin/assets/reactour.esm-DX9ZgYlx.js +137 -0
  53. package/admin/assets/{stateHoverProvider-BYAbe1Ay.js → stateHoverProvider-BEadnSXp.js} +1 -1
  54. package/admin/assets/tileFbd-CWAy7R7m.svg +85 -0
  55. package/admin/mf-manifest.json +1 -1
  56. package/admin/mf-stats.json +1 -1
  57. package/admin/remoteEntry.js +2 -2
  58. package/admin/tab.html +3 -7
  59. package/build/lib/fb/analyze.js +288 -0
  60. package/build/lib/fb/analyze.js.map +1 -0
  61. package/build/lib/fb/blocks.js +605 -0
  62. package/build/lib/fb/blocks.js.map +1 -0
  63. package/build/lib/fb/generate.js +326 -0
  64. package/build/lib/fb/generate.js.map +1 -0
  65. package/build/lib/fb/graph.js +240 -0
  66. package/build/lib/fb/graph.js.map +1 -0
  67. package/build/lib/fb/index.js +57 -0
  68. package/build/lib/fb/index.js.map +1 -0
  69. package/build/lib/fb/js.js +33 -0
  70. package/build/lib/fb/js.js.map +1 -0
  71. package/build/lib/fb/layout.js +205 -0
  72. package/build/lib/fb/layout.js.map +1 -0
  73. package/build/lib/fb/library.js +657 -0
  74. package/build/lib/fb/library.js.map +1 -0
  75. package/build/lib/fb/runtime.js +793 -0
  76. package/build/lib/fb/runtime.js.map +1 -0
  77. package/build/lib/fb/time.js +76 -0
  78. package/build/lib/fb/time.js.map +1 -0
  79. package/build/lib/fb/types.js +19 -0
  80. package/build/lib/fb/types.js.map +1 -0
  81. package/build/lib/fb/user.js +78 -0
  82. package/build/lib/fb/user.js.map +1 -0
  83. package/build/lib/javascript.d.ts +1 -1
  84. package/build/lib/mirror.js +4 -0
  85. package/build/lib/mirror.js.map +1 -1
  86. package/build/lib/sandbox.js +44 -0
  87. package/build/lib/sandbox.js.map +1 -1
  88. package/build/main.js +66 -1
  89. package/build/main.js.map +1 -1
  90. package/build/types.d.ts +9 -1
  91. package/docs/de/fbd.md +274 -0
  92. package/docs/en/fbd.md +260 -0
  93. package/io-package.json +39 -15
  94. package/package.json +1 -1
  95. package/admin/assets/AiChatPanel-oBeXbUFv.js +0 -27
  96. package/admin/assets/AiDiffView-C-KKjnJD.js +0 -1
  97. package/admin/assets/Error-DZ4vCykD.js +0 -1
  98. package/admin/assets/Import-Cu02ceLW.js +0 -1
  99. package/admin/assets/RulesEditor-QCbi1lV_.js +0 -1
  100. package/admin/assets/ScriptEditorVanillaMonaco-ChQmnk0p.js +0 -3
  101. package/admin/assets/aiPromptBuilder-DKler0UK.js +0 -1
  102. package/admin/assets/blocks_action-DywZVfRY.js +0 -1
  103. package/admin/assets/blocks_logic-CdTl5YZw.js +0 -1
  104. package/admin/assets/blocks_number-DXFd9Rva.js +0 -1
  105. package/admin/assets/blocks_object-by1uBDHi.js +0 -1
  106. package/admin/assets/blocks_procedures-BcJ7N70D.js +0 -3
  107. package/admin/assets/blocks_switch-dLF6hSJl.js +0 -2
  108. package/admin/assets/blocks_system-DmX-SBy8.js +0 -1
  109. package/admin/assets/blocks_text-BI4zNU3o.js +0 -1
  110. package/admin/assets/blocks_time-BgYA4Y_4.js +0 -1
  111. package/admin/assets/blocks_timeout-DUzgMyAu.js +0 -1
  112. package/admin/assets/helpers-CnEjYAup.js +0 -1
  113. package/admin/assets/index-B3s0zmWC.js +0 -871
  114. package/admin/assets/index-CXaeqPRy.css +0 -1
package/build/types.d.ts CHANGED
@@ -8,6 +8,8 @@ import type { EventObj } from './lib/eventObj';
8
8
  import type { PatternEventCompareFunction } from './lib/patternCompareFunctions';
9
9
  import type { AstroEvent } from './lib/consts';
10
10
  import type { Secrets } from './lib/secrets';
11
+ import type { FbDebugCommand, FbDebugStatus } from './lib/fb/types';
12
+ import type { FbDebugSettings } from './lib/fb/runtime';
11
13
 
12
14
  /** ECMAScript version the user scripts are compiled for */
13
15
  export type TsTarget = 'es2018' | 'es2019' | 'es2020' | 'es2021' | 'es2022' | 'es2023' | 'es2024' | 'es2025' | 'esnext';
@@ -129,7 +131,7 @@ export type JavascriptTimer = {
129
131
  scriptName: string;
130
132
  };
131
133
 
132
- export type ScriptType = 'TypeScript/ts' | 'Blockly' | 'Rules' | 'Javascript/js';
134
+ export type ScriptType = 'TypeScript/ts' | 'Blockly' | 'Rules' | 'FBD' | 'Javascript/js';
133
135
 
134
136
  export type TimeRule = {
135
137
  time: string | { hour: number; minute: number };
@@ -811,6 +813,12 @@ export interface JavascriptContext {
811
813
  prepareStateObject: (id: string, state: ioBroker.SettableState | null) => ioBroker.State;
812
814
  debugMode: string | undefined;
813
815
  rulesOpened: string | null; // opened rules
816
+ /** Function block diagrams shown online in an editor: until when, and which viewer asked last */
817
+ fbdWatch: Map<string, { until: number; viewer: number; paths?: Map<string, number> }>;
818
+ /** The runtimes of the running diagrams take the commands of the online view here, by script */
819
+ fbdDebug: Map<string, (command: FbDebugCommand) => FbDebugStatus>;
820
+ /** Forced values and breakpoints of the online view, kept while a diagram starts again */
821
+ fbdDebugSettings: Map<string, FbDebugSettings>;
814
822
  language: ioBroker.Languages;
815
823
  getAbsoluteDefaultDataDir: () => string;
816
824
  logError: (scriptName: string, msg: string, e: Error, offs?: number) => void;
package/docs/de/fbd.md ADDED
@@ -0,0 +1,274 @@
1
+ # Funktionspläne (FBD)
2
+
3
+ Ein Funktionsplan ist Logik aus Bausteinen, so wie eine SPS in CFC programmiert wird: Timer, Flipflops, Vergleiche
4
+ und Arithmetik, verbunden mit ioBroker-Datenpunkten. Er ist für Logik gedacht, die dauerhaft läuft - Verzögerungen,
5
+ Selbsthaltungen, Schwellwerte - und für Nutzer, die diese Art aus der SPS-Welt kennen. Wer auf ein einzelnes Ereignis
6
+ reagieren will, ist mit Blockly oder Rules meist einfacher unterwegs.
7
+
8
+ Beim Speichern wird der Plan in JavaScript übersetzt und läuft wie jedes andere Skript dieses Adapters.
9
+
10
+ ## Einen Plan anlegen
11
+
12
+ Ein neues Skript hinzufügen und **Funktionsplan** wählen. Der Editor hat drei Bereiche:
13
+
14
+ - **Palette** (links), mit einer Suche und drei Reitern:
15
+ - **Blöcke**: die Bausteine nach Kategorien - auf die Fläche ziehen oder anklicken. Eine Kategorie klappt mit
16
+ einem Klick auf ihren Namen auf und zu.
17
+ - **Variablen**: die Datenpunkte, die der Plan liest und schreibt; ein Klick zeigt den Baustein.
18
+ - **Favoriten**: die Bausteine, die mit dem Stern markiert sind - er erscheint, wenn die Maus über einem Baustein
19
+ steht.
20
+ - **Fläche**: einen Ausgang (rechts am Baustein) mit einem Eingang (links) verbinden. Nur passende Typen lassen
21
+ sich verbinden - die Farbe eines Anschlusses zeigt seinen Typ; wird eine Verbindung auf einem unpassenden
22
+ Anschluss losgelassen, steht oben, warum. Ein Eingang nimmt genau eine Verbindung. `Entf` löscht das Ausgewählte.
23
+ - **Eigenschaften** (rechts): **Eigenschaften** zeigt die Einstellungen des gewählten Bausteins in Abschnitten, die
24
+ auf- und zuklappen - Allgemein (Instanzname, Typ, ein Kommentar), Parameter, Eingänge und bei Timern, Flipflops,
25
+ Flanken und Regelungsbausteinen eine **Vorschau**: ein Zeitdiagramm des Bausteins mit seinen Werten.
26
+ **Dokumentation** beschreibt den Baustein und seine Anschlüsse. Ist nichts gewählt: die Einstellungen des Plans
27
+ und die Tastenkürzel.
28
+
29
+ Ein Baustein zeigt das Wichtige direkt in sich: den Datenpunkt, den er liest oder schreibt, den Wert eines `CONST`
30
+ und die Werte der Eingänge, die nicht verbunden sind - sie lassen sich gleich dort ändern: Ein Klick schaltet ein
31
+ BOOL um, alles andere wird eingetippt und mit `Enter` übernommen. Im Kopf eines Bausteins zeigt das Zahnrad seine
32
+ Eigenschaften, das Menü `⋮` dupliziert oder löscht ihn (online auch: Haltepunkt; bei einem eigenen Baustein:
33
+ Innenansicht).
34
+
35
+ Probleme stehen unten auf der Fläche; ein Klick wählt den Baustein aus. Ein Plan mit Fehlern lässt sich speichern,
36
+ sein Skript läuft aber nicht, sondern meldet die Fehler im Protokoll.
37
+
38
+ Der Knopf **FBD → JS** zeigt den erzeugten Code.
39
+
40
+ Bearbeiten geht wie gewohnt: `Strg+Z` / `Strg+Y` (oder die Knöpfe der Werkzeugleiste) machen rückgängig und
41
+ wiederholen, `Strg+C`, `Strg+X` und `Strg+V` kopieren, schneiden aus und fügen die ausgewählten Bausteine samt der
42
+ Verbindungen zwischen ihnen ein - auch in einen anderen Plan. Eingefügte Bausteine bekommen neue IDs und, wo der
43
+ alte Name vergeben ist, neue Namen.
44
+
45
+ Die Leiste über der Fläche zeigt den Plan (und den Pfad in eine Instanz hinein) und hat die Werkzeuge:
46
+
47
+ - den Zoom: kleiner, der Zoom (ein Klick: 100 %), größer
48
+ - **Automatisch anordnen** stellt die Bausteine in Spalten entlang des Datenflusses auf: Eingänge links, Ausgänge
49
+ rechts, jeder Baustein auf der Höhe der Bausteine, mit denen er verbunden ist. Kommentare bleiben, wo sie sind.
50
+ `Strg+Z` nimmt es zurück.
51
+ - **Im Plan suchen** (`Strg+F`) findet Bausteine nach Instanzname, Typ, Datenpunkt oder anderem Parameter, Kommentare
52
+ nach ihrem Text. `Enter` geht zum nächsten Treffer, `Umschalt+Enter` zum vorigen, `Esc` schließt die Suche.
53
+ - **Raster** an oder aus (mit Raster rasten die Bausteine ein), und Verbindungen als Kurven oder rechtwinklig wie in
54
+ CFC - beides merkt sich der Browser, nicht der Plan
55
+ - rechts die Onlineansicht, siehe unten
56
+
57
+ **Verbindungsmarken**: Eine Verbindung quer durch den Plan lässt sich statt als Linie als Marke an beiden Enden
58
+ zeigen - Verbindung auswählen und in ihren Eigenschaften **Als Verbindungsmarke zeigen** einschalten. Beide Marken
59
+ zeigen den Namen des Bausteins, von dem die Verbindung kommt, oder einen eigenen. Ein Doppelklick auf eine Marke
60
+ springt zum anderen Ende. Nur die Darstellung ändert sich, die Verbindung wirkt wie zuvor.
61
+
62
+ ## Onlineansicht
63
+
64
+ **Online** (rechts in der Leiste über der Fläche) zeigt die Werte des laufenden Plans: an jedem Ausgang,
65
+ BOOL-Leitungen grün (`TRUE`) oder grau (`FALSE`), andere Leitungen mit ihrem Wert in der Mitte. Neben oder unter dem
66
+ Knopf stehen:
67
+
68
+ - der Zykluszähler - er bleibt stehen, wenn der Plan nicht mehr rechnet
69
+ - eine Warnung, wenn keine Daten kommen (das Skript läuft nicht, oder seine Instanz ist gestoppt)
70
+ - ein Hinweis, wenn der Plan nach dem Speichern geändert wurde: Die Werte gehören zur gespeicherten Fassung
71
+
72
+ Schlägt ein Zyklus fehl, wird der Baustein, dessen Code fehlschlug, rot umrandet und der Fehler unten links
73
+ aufgeführt; auch das Protokoll nennt den Baustein (`Error in the function block diagram in block b7: ...`).
74
+
75
+ Die Werte fließen nur, solange ein Editor den Plan online zeigt: Der Editor fragt alle 10 s beim Adapter an, nach
76
+ 30 s ohne Anfrage hört der Plan auf zu senden. Es kommen höchstens vier Aktualisierungen pro Sekunde, jede nur mit den
77
+ geänderten Werten. Ein Plan, der vor dieser Version gespeichert wurde, zeigt den Zykluszähler, aber keine Werte -
78
+ einmal speichern.
79
+
80
+ ### In eine Instanz hinein
81
+
82
+ Ein Doppelklick auf eine Instanz eines eigenen Bausteins (oder **Innenansicht** in ihren Eigenschaften) zeigt den
83
+ Plan des Bausteins - so, wie dieser Plan ihn mitführt, nur lesbar - und online mit den Werten genau dieser Instanz.
84
+ Eine Instanz darin öffnet sich genauso; der Pfad oben links führt zurück, ebenso `Esc`. Werte im Inneren lassen sich
85
+ erzwingen; Haltepunkte werden im Plan selbst gesetzt. Die Werte im Inneren brauchen einen Plan, der mit dieser
86
+ Version gespeichert wurde.
87
+
88
+ ### Werte erzwingen, Haltepunkte, Einzelschritte
89
+
90
+ Solange der Plan online gezeigt wird, lässt er sich steuern:
91
+
92
+ - **Erzwingen**: einen Baustein (oder eine Verbindung) auswählen - die Eigenschaften zeigen seine Ausgänge mit ihren
93
+ Werten. **TRUE** / **FALSE** oder ein Wert und **Erzwingen** halten den Ausgang auf diesem Wert, gleich was der
94
+ Baustein rechnet; die Bausteine dahinter und die Datenpunkte, die der Plan schreibt, bekommen den erzwungenen Wert.
95
+ Ein erzwungener Wert ist orange umrandet; **Freigeben** lässt ihn los.
96
+ - **Haltepunkte**: der Punkt oben links an einem Baustein, `F9` oder **Haltepunkt** in seinen Eigenschaften. Der
97
+ Plan hält vor diesem Baustein an; der Baustein, der als nächster läuft, ist gelb umrandet, und die Werte zeigen, wie
98
+ weit der Zyklus kam.
99
+ - Die Knöpfe links von **Online**: **Anhalten** / **Fortsetzen** (`F8`), **Ein Zyklus** und **Ein Baustein** (`F10`).
100
+ Solange der Plan wartet, warten auch die Änderungen seiner Eingänge. Ein Zyklus von Hand rechnet mit einer
101
+ Zykluszeit als vergangener Zeit - Timer verhalten sich so, wie sie es täten, egal wie lange der Plan wartete.
102
+
103
+ Das alles endet mit der Onlineansicht: Schaltet der Editor sie aus, wird er geschlossen oder verschwindet er (30 s
104
+ ohne Anfrage), gibt die Laufzeit die erzwungenen Werte frei, entfernt die Haltepunkte und läuft weiter - und
105
+ protokolliert das. Beim Speichern des Plans bleiben erzwungene Werte und Haltepunkte erhalten, solange die
106
+ Onlineansicht offen ist. Haltepunkte und Einzelschritte brauchen einen Plan, der mit dieser Version gespeichert
107
+ wurde; ein älterer lässt sich schon erzwingen und anhalten.
108
+
109
+ **Vorsicht:** Ein erzwungener Wert wirkt auf echte Geräte - der Plan schreibt seine Datenpunkte damit.
110
+
111
+ ## Bausteine
112
+
113
+ | Kategorie | Bausteine |
114
+ |------------|------------------------------------------------------------------|
115
+ | ioBroker | `STATE_IN`, `STATE_OUT`, `CONST` |
116
+ | Logik | `AND`, `OR`, `XOR`, `NOT` |
117
+ | Speicher | `RS`, `SR`, `R_TRIG`, `F_TRIG` |
118
+ | Zeit | `TON`, `TOF`, `TP`, `BLINK` |
119
+ | Zähler | `CTU`, `CTD`, `CTUD` |
120
+ | Vergleich | `GT`, `GE`, `LT`, `LE`, `EQ`, `NE` |
121
+ | Arithmetik | `ADD`, `SUB`, `MUL`, `DIV`, `MIN`, `MAX`, `ROUND` |
122
+ | Umwandlung | `TO_BOOL`, `TO_INT`, `TO_REAL`, `TO_TIME`, `TO_STRING`, `CONCAT` |
123
+ | Regelung | `HYST`, `RAMP`, `PT1`, `PID` |
124
+ | Kalender | `CLOCK`, `TIMEWINDOW`, `SCHEDULE`, `ASTRO` |
125
+ | Meldungen | `LOG`, `NOTIFY`, `SENDTO` |
126
+ | Experte | `JS` |
127
+
128
+ Namen und Verhalten folgen IEC 61131-3. `AND`, `OR`, `XOR`, `ADD`, `MUL`, `MIN`, `MAX` und `CONCAT` haben 2 bis 16
129
+ Eingänge. Zeiten werden wie `500ms`, `2s`, `1m30s` oder `T#2s` eingegeben, Uhrzeiten wie `08:30`.
130
+
131
+ Die Regelungsbausteine:
132
+
133
+ - `HYST` - Zweipunktschalter: `Q` geht an, wenn `IN` über `HIGH` steigt, und aus, wenn `IN` unter `LOW` fällt;
134
+ dazwischen bleibt `Q`, wie es ist. Eine Heizung, die unter `LOW` einschaltet, nimmt `Q` invertiert (`NOT` oder
135
+ ein invertierter Eingang).
136
+ - `RAMP` - `OUT` folgt `IN`, ändert sich aber um höchstens `UP` pro Sekunde aufwärts und `DOWN` pro Sekunde abwärts;
137
+ `0` begrenzt nicht. Sie beginnt bei `IN`.
138
+ - `PT1` - Tiefpass erster Ordnung: `OUT` folgt `IN` mit der Zeitkonstante `T` (nach `T` sind 63 % eines Sprungs
139
+ erreicht). Glättet einen unruhigen Wert; er beginnt bei `IN`.
140
+ - `PID` - PID-Regler: Sollwert `SP`, Istwert `PV`, Stellgröße `Y` zwischen `YMIN` und `YMAX`. `KP` ist die
141
+ Verstärkung, `TN` die Nachstellzeit des I-Anteils, `TV` die Vorhaltzeit; `TN` oder `TV` gleich `0` lässt den Anteil
142
+ weg. Steht `Y` an einer Grenze, wächst der I-Anteil nicht weiter (Anti-Windup); der D-Anteil wird aus `PV` gebildet,
143
+ ein neuer Sollwert gibt also keinen Stoß. `RST` löscht den I-Anteil.
144
+
145
+ `RAMP`, `PT1` und `PID` hängen von der Zeit ab: Ein Plan mit ihnen läuft zyklisch.
146
+
147
+ Blinker und Zähler:
148
+
149
+ - `BLINK` - solange `EN` wahr ist, ist `Q` für `TH` wahr und für `TL` falsch, beginnend mit wahr.
150
+ - `CTU` zählt die steigenden Flanken an `CU`; `R` setzt `CV` auf 0 zurück, `Q` ist wahr, sobald `CV` `PV` erreicht
151
+ hat. `CTD` zählt bei `CD` herunter, `LD` lädt `PV`, `Q` ist bei 0 und darunter wahr. `CTUD` kann beides; `R` geht
152
+ vor `LD`, und Flanken an `CU` und `CD` im selben Zyklus heben sich auf. Ein Eingang, der beim Start des Skripts
153
+ schon wahr ist, ist keine Flanke. Der Zählerstand bleibt über einen Neustart des Skripts nicht erhalten.
154
+
155
+ Umwandlung: `TO_BOOL`, `TO_INT`, `TO_REAL`, `TO_TIME` und `TO_STRING` nehmen jeden Typ. `TO_INT` rundet, ein
156
+ Dezimalkomma gilt als Punkt, und was keine Zahl ist, ergibt 0; `TO_TIME` liest eine Zahl als ms und einen Text wie
157
+ `2s` oder `08:30`. `CONCAT` fügt seine Eingänge zu einem Text zusammen - Zahlen so, wie sie sind, also vorher mit
158
+ `ROUND` runden (`DIGITS` Nachkommastellen, 0 bis 10).
159
+
160
+ Der Kalender:
161
+
162
+ - `CLOCK` - die Ortszeit: `TOD` (Uhrzeit), `HOUR`, `MIN`, `WDAY` (1 Montag ... 7 Sonntag), `DAY`, `MONTH`, `YEAR`.
163
+ - `TIMEWINDOW` - `Q` ist von `START` bis `END` an den gewählten Tagen wahr (jeden Tag, Montag bis Freitag, Samstag
164
+ und Sonntag). Ein Fenster über Mitternacht wie `22:00` bis `06:00` gehört zu dem Tag, an dem es beginnt: Bei
165
+ Montag bis Freitag reicht es von Freitagnacht bis Samstagmorgen, aber nicht von Sonntagnacht in den Montag.
166
+ - `SCHEDULE` - `Q` ist einen Zyklus lang wahr, wenn die Zeit des Cron-Musters kommt, etwa `0 8 * * 1-5` für 8:00 von
167
+ Montag bis Freitag, oder mit Sekunden vorne `*/5 * * * * *` für alle 5 Sekunden. Der Knopf neben dem Feld öffnet den Dialog für das Muster.
168
+ - `ASTRO` - `Q` ist von einem Sonnenereignis bis zu einem anderen wahr, etwa von `sunset` bis `sunrise`, jeweils mit
169
+ einem Versatz in Minuten. `START` und `END` sind die Zeiten der beiden Ereignisse heute. Die Position ist die aus den
170
+ Einstellungen des Adapters; ohne sie gibt es keine Zeiten, und `Q` bleibt falsch.
171
+
172
+ `CLOCK`, `TIMEWINDOW` und `ASTRO` lassen einen Plan zyklisch laufen. `SCHEDULE` nicht: Wenn seine Zeit kommt, läuft
173
+ der Plan sofort, und gleich danach noch einmal, um den Impuls zu beenden.
174
+
175
+ - `STATE_IN` liest einen Datenpunkt und wandelt ihn in den gewählten Typ (`BOOL`, `INT`, `REAL`, `STRING`). Ein
176
+ Wert, der sich nicht wandeln lässt, wird einmal im Protokoll gemeldet und als 0 gelesen. Ändert sich die ID des
177
+ Datenpunkts - im Dialog gewählt oder eingetippt -, wird der Typ aus seinem Objekt übernommen, und ein Baustein,
178
+ der noch seinen ersten Namen hat, bekommt den Namen des Datenpunkts. Den Typ kann man danach anders setzen; neu
179
+ übernommen wird er erst mit der nächsten ID.
180
+ - `STATE_OUT` schreibt einen Datenpunkt nur, wenn sich der Wert ändert. `Mindestzeit zwischen zwei
181
+ Schreibvorgängen` begrenzt, wie oft er schreibt; der letzte Wert wird geschrieben, wenn die Zeit um ist.
182
+ - `CONST` ist ein Wert des gewählten Typs. Mit einem Eingang anderen Typs verbunden, übernimmt er dessen Typ und
183
+ behält seinen Wert, soweit es geht (`"0"` wird für eine `TIME` zu 0 ms) - außer er speist schon andere Eingänge,
184
+ die den neuen Typ nicht nehmen.
185
+
186
+ Die Meldungen:
187
+
188
+ - `LOG` schreibt eine Zeile ins ioBroker-Protokoll, mit der gewählten Stufe (`info`, `warn`, `error`, `debug`):
189
+ bei steigender Flanke an `TRIG` oder wann immer sich `IN` ändert. `%s` im Text ist der Wert von `IN`. Höchstens
190
+ 20 Zeilen pro Minute - ein Plan, der alle 200 ms läuft, würde das Protokoll sonst fluten; die 20. Zeile sagt das.
191
+ - `NOTIFY` sendet den Text als ioBroker-Benachrichtigung - als Meldung oder als Alarm -, `SENDTO` an einen Adapter
192
+ wie `telegram.0`, `pushover.0` oder `email.0`, als `{ text, message, title, subject }` mit dem gewählten Befehl
193
+ (`send`). Beide senden, wenn `LOG` schreiben würde, höchstens 5-mal pro Minute; das Protokoll sagt, wenn mehr
194
+ ausgelassen wurden.
195
+
196
+ Der Expertenbaustein `JS` führt eigenen Code aus. Der Code ist der Rumpf einer Funktion, die die Eingänge `IN1` ...
197
+ `INn` (0 bis 8, beliebiger Typ) bekommt, dazu `dt` (ms seit dem letzten Zyklus), `firstScan` und `state` - ein Objekt,
198
+ das von einem Zyklus zum nächsten erhalten bleibt. Er gibt den Wert von `OUT1` zurück oder ein Feld
199
+ `[OUT1, OUT2, ...]` für mehr Ausgänge (1 bis 8); wo er `undefined` liefert, behält ein Ausgang seinen Wert. Die
200
+ Ausgänge dürfen an Eingänge jedes Typs, der Code muss also liefern, was diese erwarten.
201
+
202
+ ```js
203
+ // zählt, wie oft IN1 über IN2 gestiegen ist
204
+ if (IN1 > IN2 && !state.above) {
205
+ state.count = (state.count || 0) + 1;
206
+ }
207
+ state.above = IN1 > IN2;
208
+ return state.count || 0;
209
+ ```
210
+
211
+ Der Code läuft im Skript des Plans, er kann also Funktionen der Skripte wie `log()` aufrufen - er sollte aber auf
212
+ nichts warten: Der nächste Baustein braucht seine Ausgänge sofort. Ein Syntaxfehler wird schon vor dem Speichern
213
+ angezeigt, ein Fehler beim Ausführen am Baustein.
214
+
215
+ Signaltypen: `BOOL`, `INT`, `REAL`, `TIME`, `STRING`. Ein `INT` darf an einen `REAL`-Eingang; andere Umwandlungen
216
+ geschehen nicht von selbst.
217
+
218
+ ## Eigene Bausteine
219
+
220
+ Ein Plan kann selbst ein Baustein sein, den andere Pläne beliebig oft einsetzen - wie ein Funktionsbaustein in der
221
+ SPS. Dazu in den Einstellungen des Plans **Dieser Plan ist ein Baustein** einschalten und dem Baustein einen Namen
222
+ und eine Beschreibung geben.
223
+
224
+ - Die Eingänge des Bausteins sind `FB_IN`-Bausteine, seine Ausgänge `FB_OUT`-Bausteine (Kategorie **Schnittstelle**,
225
+ nur im Plan eines Bausteins angeboten). Der Anschlussname ist der Name des Ein- oder Ausgangs am Baustein; `FB_IN`
226
+ hat außerdem einen Typ und den Wert, den der Eingang hat, wenn er nicht verbunden ist.
227
+ - Ein Baustein greift nicht auf Datenpunkte zu: `STATE_IN` und `STATE_OUT` sind in ihm nicht erlaubt, `CONST`
228
+ schon. Er darf andere eigene Bausteine verwenden, aber nicht sich selbst.
229
+ - Jede Instanz hat ihren eigenen Zustand - zwei Instanzen eines Bausteins mit einem Timer laufen unabhängig.
230
+ - Das Skript eines Bausteins tut nichts, wenn es läuft; der Baustein arbeitet nur in den Plänen, die ihn einsetzen.
231
+
232
+ Die Bausteine aller Pläne stehen in der Palette unter **Eigene Bausteine**. Der Plan, der einen Baustein einsetzt,
233
+ speichert eine Kopie davon und damit die Version: Jede gespeicherte Änderung eines Bausteins ist eine neue Version.
234
+ Pläne mit einer älteren arbeiten mit ihr weiter und zeigen einen Hinweis - **Aktualisieren** in den Eigenschaften
235
+ einer Instanz übernimmt die neue Version in den Plan, **Baustein öffnen** öffnet den Plan des Bausteins.
236
+ Verbindungen zu Ein- oder Ausgängen, die es nicht mehr gibt, entfernt das Aktualisieren.
237
+
238
+ Weil die Kopie im Plan steht, läuft ein Plan weiter, wenn der Baustein gelöscht wird, und lässt sich allein
239
+ exportieren und importieren. Beim Kopieren von Instanzen in einen anderen Plan kommt der Baustein mit.
240
+
241
+ Ein Fehler in einem Baustein wird an der Instanz gemeldet, die ihn ausgeführt hat, im Editor und im Protokoll.
242
+
243
+ ## Ausführung
244
+
245
+ Die Bausteine laufen in der Reihenfolge des Datenflusses; die Zahl in der Ecke jedes Bausteins ist seine Position.
246
+ Was gleichzeitig laufen könnte, läuft von links nach rechts, dann von oben nach unten.
247
+
248
+ - **Ereignisgesteuert**: Hängt kein Baustein von der Zeit ab, läuft der Plan, sobald sich ein Eingang ändert.
249
+ Änderungen innerhalb von 20 ms laufen gemeinsam in einem Zyklus.
250
+ - **Zyklisch**: Sobald der Plan einen Timer enthält, läuft er alle 200 ms (50 ms bis 10 s, siehe Einstellungen des
251
+ Plans) und zusätzlich direkt nach der Änderung eines Eingangs.
252
+
253
+ Die Betriebsart wird automatisch gewählt oder in den Einstellungen des Plans festgelegt.
254
+
255
+ Eine Rückkopplung ist nur über einen speichernden Baustein erlaubt (Timer, Zähler, Flipflop, Flanke, Regelungsbaustein,
256
+ `JS`, eigener Baustein): Die zurückführende
257
+ Verbindung liest, was dieser Baustein im vorigen Zyklus ausgegeben hat, und wird als Doppelstrich gezeichnet. Eine
258
+ Rückkopplung ohne einen solchen Baustein ist ein Fehler.
259
+
260
+ Ein Timer zählt ab dem Zyklus, in dem er die Änderung seines Eingangs sieht. Er läuft also nie vor seiner Zeit ab,
261
+ höchstens einen Zyklus später.
262
+
263
+ ## Grenzen
264
+
265
+ - Nicht für sicherheitsgerichtete Funktionen. Ein Plan läuft in einem ioBroker-Skript, ohne Echtzeitgarantien.
266
+ - Der Zustand der Bausteine bleibt über einen Neustart des Skripts nicht erhalten.
267
+ - Noch nicht vorhanden: Haltepunkte in einem eigenen Baustein, eine manuelle Ausführungsreihenfolge, Verbindungen,
268
+ die um Bausteine herum geführt werden.
269
+
270
+ ## Ablage
271
+
272
+ Der Plan steht im Skript selbst, als letzte Zeile von `common.source` (`//#fbd:{...}`); darüber steht der erzeugte
273
+ Code. Der Plan enthält die Kopien der eigenen Bausteine, die er einsetzt. Die Bausteine der Bibliothek sind im Modul `@iobroker/fb-runtime` umgesetzt, das mit dem Adapter kommt, und werden nicht in
274
+ jedes Skript kopiert.
package/docs/en/fbd.md ADDED
@@ -0,0 +1,260 @@
1
+ # Function block diagrams (FBD)
2
+
3
+ A function block diagram is logic drawn from blocks, the way a PLC is programmed in CFC: timers, flip-flops,
4
+ comparisons and arithmetic, wired to ioBroker states. It is meant for logic that runs all the time - delays,
5
+ latches, thresholds - and for users who know this style from a PLC. To react to a single event, Blockly or Rules
6
+ are usually the simpler choice.
7
+
8
+ The diagram is turned into JavaScript when it is saved and runs like every other script of this adapter.
9
+
10
+ ## Creating a diagram
11
+
12
+ Add a new script and choose **Function block diagram**. The editor has three parts:
13
+
14
+ - **Palette** (left), with a search and three tabs:
15
+ - **Blocks**: the blocks by category - drag one onto the canvas, or click it to add it. A category opens and
16
+ closes with a click on its name.
17
+ - **Variables**: the states the diagram reads and writes; a click shows the block.
18
+ - **Favorites**: the blocks marked with the star that shows when the mouse is over a block.
19
+ - **Canvas**: connect an output (right side of a block) with an input (left side). Only fitting types can be
20
+ connected - the color of a pin shows its type; a link let go on a pin that does not take it says why. An input
21
+ takes one link. `Delete` removes what is selected.
22
+ - **Properties** (right): **Properties** shows the settings of the selected block in parts that open and close -
23
+ general (instance name, type, a comment), parameters, inputs and, for timers, flip-flops, edges and control blocks,
24
+ a **preview**: a timing diagram of the block with its values. **Documentation** describes the block and its pins.
25
+ With nothing selected: the settings of the diagram, and the keys.
26
+
27
+ A block shows what matters right in it: the state it reads or writes, the value of a `CONST`, and the values of the
28
+ inputs that are not connected - these can be changed right there: a click switches a BOOL, anything else is typed in
29
+ and taken with `Enter`. In the head of a block, the gear shows its properties, the menu `⋮` duplicates or deletes it
30
+ (online also: breakpoint; for an own block: inside view).
31
+
32
+ Problems are listed at the bottom of the canvas; a click selects the block. A diagram with errors can be saved, but
33
+ its script does not run - it logs the errors instead.
34
+
35
+ The button **FBD → JS** shows the generated code.
36
+
37
+ Editing works as usual: `Ctrl+Z` / `Ctrl+Y` (or the buttons of the toolbar) undo and redo, `Ctrl+C`, `Ctrl+X`
38
+ and `Ctrl+V` copy, cut and paste the selected blocks with the links between them - also into another diagram. Pasted
39
+ blocks get new IDs, and new names where the old ones are taken.
40
+
41
+ The bar above the canvas shows the diagram (and the path into an instance) and has the tools:
42
+
43
+ - the zoom: smaller, the zoom (a click: 100 %), larger
44
+ - **Arrange automatically** puts the blocks in columns along the data flow: inputs on the left, outputs on the
45
+ right, each block level with the blocks it is linked to. Comments stay where they are. `Ctrl+Z` takes it back.
46
+ - **Find in the diagram** (`Ctrl+F`) finds blocks by instance name, type, state ID or other parameter, comments by
47
+ their text. `Enter` goes to the next match, `Shift+Enter` to the one before, `Esc` closes the search.
48
+ - **Grid** on or off (with it, blocks snap to it), and links as curves or at right angles as in CFC - both are kept
49
+ by the browser, not in the diagram
50
+ - on the right the online view, see below
51
+
52
+ **Connection marks**: a link across the whole diagram can be shown as a mark at both ends instead of a line - select
53
+ the link and switch on **Show as a connection mark** in its properties. Both marks show the name of the block the
54
+ link comes from, or a name of their own. A double click on a mark jumps to the other end. Only the drawing changes,
55
+ the link works the same.
56
+
57
+ ## Online view
58
+
59
+ **Online** (on the right of the bar above the canvas) shows the values of the running diagram: at every output, BOOL
60
+ links in green (`TRUE`) or grey (`FALSE`), other links with their value in the middle. Next to the button, or under
61
+ it:
62
+
63
+ - the cycle count - it stands still when the diagram stopped running
64
+ - a warning when no data comes (the script does not run, or its instance is stopped)
65
+ - a hint when the diagram was changed after saving: the values belong to the saved version
66
+
67
+ When a cycle fails, the block whose code failed is framed in red and the error is listed at the bottom left; the
68
+ log names the block too (`Error in the function block diagram in block b7: ...`).
69
+
70
+ The values only flow while an editor shows the diagram online: the editor asks the adapter every 10 s, and after 30 s
71
+ without a request the diagram stops sending. At most four updates a second are sent, each with the values that
72
+ changed only. A diagram saved before this version shows the cycle count, but no values - save it once.
73
+
74
+ ### Inside an instance
75
+
76
+ A double click on an instance of an own block (or **Inside view** in its properties) shows the diagram of the
77
+ block - as this diagram carries it, read only - and online with the values of just this instance. An instance inside
78
+ it opens the same way; the path at the top left leads back, and so does `Esc`. Values inside can be forced;
79
+ breakpoints are set in the diagram itself. The values inside need a diagram saved with this version.
80
+
81
+ ### Forcing values, breakpoints, single steps
82
+
83
+ While the diagram is shown online, it can be steered:
84
+
85
+ - **Forcing**: select a block (or a link) - its properties show the outputs with their values. **TRUE** / **FALSE**,
86
+ or a value and **Force**, hold the output at that value, whatever the block computes; the blocks behind it and the
87
+ states the diagram writes get the forced value. A forced value is framed in orange; **Release** lets it go.
88
+ - **Breakpoints**: the dot at the top left of a block, `F9` or **Breakpoint** in its properties. The diagram stops in
89
+ front of that block; the block that runs next is framed in yellow, and the values show how far the cycle got.
90
+ - The buttons left of **Online**: **Pause** / **Run on** (`F8`), **One cycle**, and **One block** (`F10`). While the
91
+ diagram waits, the changes of its inputs wait too. A cycle started by hand counts one cycle time as time passed,
92
+ so timers behave as they would, however long the diagram waited.
93
+
94
+ All of that ends with the online view: when the editor switches it off, is closed or goes away (30 s without a
95
+ request), the runtime releases the forced values, removes the breakpoints and runs on - it logs that. Saving the
96
+ diagram keeps forced values and breakpoints while the online view stays open. Breakpoints and single steps need a
97
+ diagram saved with this version; a diagram saved before can already be forced and paused.
98
+
99
+ **Careful:** a forced value acts on real devices - the diagram writes its states with it.
100
+
101
+ ## Blocks
102
+
103
+ | Category | Blocks |
104
+ |------------|------------------------------------------------------------------|
105
+ | ioBroker | `STATE_IN`, `STATE_OUT`, `CONST` |
106
+ | Logic | `AND`, `OR`, `XOR`, `NOT` |
107
+ | Memory | `RS`, `SR`, `R_TRIG`, `F_TRIG` |
108
+ | Timers | `TON`, `TOF`, `TP`, `BLINK` |
109
+ | Counters | `CTU`, `CTD`, `CTUD` |
110
+ | Comparison | `GT`, `GE`, `LT`, `LE`, `EQ`, `NE` |
111
+ | Arithmetic | `ADD`, `SUB`, `MUL`, `DIV`, `MIN`, `MAX`, `ROUND` |
112
+ | Conversion | `TO_BOOL`, `TO_INT`, `TO_REAL`, `TO_TIME`, `TO_STRING`, `CONCAT` |
113
+ | Control | `HYST`, `RAMP`, `PT1`, `PID` |
114
+ | Calendar | `CLOCK`, `TIMEWINDOW`, `SCHEDULE`, `ASTRO` |
115
+ | Messages | `LOG`, `NOTIFY`, `SENDTO` |
116
+ | Expert | `JS` |
117
+
118
+ The names and the behavior follow IEC 61131-3. `AND`, `OR`, `XOR`, `ADD`, `MUL`, `MIN`, `MAX` and `CONCAT` can
119
+ have 2 to 16 inputs. Times are entered like `500ms`, `2s`, `1m30s` or `T#2s`, times of day like `08:30`.
120
+
121
+ The control blocks:
122
+
123
+ - `HYST` - two-point switch: `Q` goes on when `IN` rises above `HIGH` and off when it falls below `LOW`; in between
124
+ it stays as it is. A heating that switches on below `LOW` takes `Q` inverted (`NOT`, or an inverted input).
125
+ - `RAMP` - `OUT` follows `IN`, but changes by at most `UP` per second upwards and `DOWN` per second downwards; `0`
126
+ does not limit. It starts at `IN`.
127
+ - `PT1` - low pass of the first order: `OUT` follows `IN` with the time constant `T` (after `T`, 63 % of a step are
128
+ reached). Smooths a noisy value; it starts at `IN`.
129
+ - `PID` - PID controller: set point `SP`, process value `PV`, output `Y` between `YMIN` and `YMAX`. `KP` is the gain,
130
+ `TN` the reset time of the integral part, `TV` the derivative time; `TN` or `TV` of `0` leaves that part out.
131
+ While `Y` is at a limit, the integral part does not grow further (anti-windup); the derivative is taken from `PV`,
132
+ so a new set point gives no kick. `RST` clears the integral part.
133
+
134
+ `RAMP`, `PT1` and `PID` depend on time: a diagram with them runs cyclically.
135
+
136
+ Timers and counters:
137
+
138
+ - `BLINK` - while `EN` is true, `Q` is true for `TH` and false for `TL`, beginning with true.
139
+ - `CTU` counts the rising edges of `CU`; `R` sets `CV` back to 0, `Q` is true once `CV` reached `PV`. `CTD`
140
+ counts down on `CD`, `LD` loads `PV`, `Q` is true at 0 and below. `CTUD` does both; `R` goes before `LD`, and
141
+ edges of `CU` and `CD` in the same cycle cancel out. An input that is already true when the script starts is no
142
+ edge. The count is not kept over a restart of the script.
143
+
144
+ Conversion: `TO_BOOL`, `TO_INT`, `TO_REAL`, `TO_TIME` and `TO_STRING` take any type. `TO_INT` rounds, a decimal
145
+ comma counts as a point, and what is no number gives 0; `TO_TIME` reads a number as ms and a text like `2s` or
146
+ `08:30`. `CONCAT` joins its inputs into one text - numbers as they are, so round them with `ROUND` first (`DIGITS`
147
+ decimals, 0 to 10).
148
+
149
+ The calendar:
150
+
151
+ - `CLOCK` - the local time: `TOD` (time of day), `HOUR`, `MIN`, `WDAY` (1 Monday ... 7 Sunday), `DAY`, `MONTH`,
152
+ `YEAR`.
153
+ - `TIMEWINDOW` - `Q` is true from `START` to `END` on the chosen days (every day, Monday to Friday, Saturday and
154
+ Sunday). A window over midnight, like `22:00` to `06:00`, belongs to the day it starts on: on Monday to Friday it
155
+ lasts from Friday night into Saturday morning, but not from Sunday night into Monday.
156
+ - `SCHEDULE` - `Q` is true for one cycle when the time of the cron pattern comes, like `0 8 * * 1-5` for 8:00 on
157
+ Monday to Friday, or with seconds in front `*/5 * * * * *` for every 5 seconds. The button next to the field opens the dialog for the pattern.
158
+ - `ASTRO` - `Q` is true from one event of the sun to another, like from `sunset` to `sunrise`, each with an offset
159
+ in minutes. `START` and `END` are the times of the two events today. The position is the one in the settings of
160
+ the adapter; without it there are no times, and `Q` stays false.
161
+
162
+ `CLOCK`, `TIMEWINDOW` and `ASTRO` make a diagram run cyclically. `SCHEDULE` does not: when its time comes, the
163
+ diagram runs at once, and once more right after it to end the pulse.
164
+
165
+ - `STATE_IN` reads a state and converts it to the chosen type (`BOOL`, `INT`, `REAL`, `STRING`). A value that
166
+ cannot be converted is reported once in the log and read as 0. When the state ID changes - picked in the dialog
167
+ or typed - the type is taken from the object of the state, and a block that still has its first name is named
168
+ after the state. The type can be set differently afterwards; it is taken again only with the next ID.
169
+ - `STATE_OUT` writes a state only when the value changes. `Minimum time between writes` limits how often it
170
+ writes; the last value is written when the time is over.
171
+ - `CONST` is a value of the chosen type. Linked to an input of another type, it takes the type of the input and
172
+ keeps its value as far as it goes (`"0"` becomes 0 ms for a `TIME`) - unless it feeds other inputs already that
173
+ the new type would not fit.
174
+
175
+ The messages:
176
+
177
+ - `LOG` writes a line into the log of ioBroker, with the chosen level (`info`, `warn`, `error`, `debug`): on a
178
+ rising edge of `TRIG`, or whenever `IN` changes. `%s` in the text is the value of `IN`. At most 20 lines a minute -
179
+ a diagram that runs every 200 ms would flood the log otherwise; the 20th line says so.
180
+ - `NOTIFY` sends the text as a notification of ioBroker - a message or an alert - and `SENDTO` to an adapter like
181
+ `telegram.0`, `pushover.0` or `email.0`, as `{ text, message, title, subject }` with the chosen command (`send`).
182
+ Both send when `LOG` would write, at most 5 times a minute; the log says when more were left out.
183
+
184
+ The expert block `JS` runs code of its own. The code is the body of a function that gets the inputs `IN1` ...
185
+ `INn` (0 to 8, of any type), `dt` (ms since the last cycle), `firstScan` and `state` - an object that is kept from
186
+ one cycle to the next. It returns the value of `OUT1`, or an array `[OUT1, OUT2, ...]` for more outputs (1 to 8);
187
+ where it gives `undefined`, an output keeps its value. The outputs may be connected to inputs of any type, so the
188
+ code has to put out what they expect.
189
+
190
+ ```js
191
+ // counts how often IN1 went above IN2
192
+ if (IN1 > IN2 && !state.above) {
193
+ state.count = (state.count || 0) + 1;
194
+ }
195
+ state.above = IN1 > IN2;
196
+ return state.count || 0;
197
+ ```
198
+
199
+ The code runs in the script of the diagram, so it can call the functions of scripts like `log()` - but it should
200
+ not wait for anything: the next block needs its outputs at once. A syntax error is shown before the diagram is
201
+ saved, an error when it runs at the block.
202
+
203
+ Signal types: `BOOL`, `INT`, `REAL`, `TIME`, `STRING`. An `INT` may be connected to a `REAL` input; other
204
+ conversions are not done by themselves.
205
+
206
+ ## Own blocks
207
+
208
+ A diagram can be a block itself, which other diagrams use as often as they like - like a function block in a PLC.
209
+ Switch on **This diagram is a block** in the settings of the diagram and give the block a name and a description.
210
+
211
+ - The inputs of the block are `FB_IN` blocks, its outputs `FB_OUT` blocks (category **Interface**, only offered in
212
+ the diagram of a block). The pin name is what the input or output is called on the block; `FB_IN` also has a type
213
+ and the value the input has when it is not connected.
214
+ - A block has no access to states: `STATE_IN` and `STATE_OUT` are not allowed in it, `CONST` is. It may use other
215
+ own blocks, but not itself.
216
+ - Every instance has its own state - two instances of a block with a timer time independently.
217
+ - The script of a block does nothing when it runs; the block only works in the diagrams that use it.
218
+
219
+ The blocks of all diagrams are offered in the palette under **Own blocks**. The diagram that uses a block stores a
220
+ copy of it, and with it the version: every saved change of a block is a new version. The diagrams that use an older
221
+ one keep working with it and show a notice - **Update** in the properties of an instance takes the new version into
222
+ the diagram, **Open block** opens the diagram of the block. Links to inputs or outputs that no longer exist are
223
+ removed by the update.
224
+
225
+ Because the copy is stored with the diagram, a diagram keeps working when the block is deleted, and it can be
226
+ exported and imported alone. Copying instances into another diagram takes the block along.
227
+
228
+ An error in a block is reported at the instance that ran it, in the editor and in the log.
229
+
230
+ ## Execution
231
+
232
+ The blocks run in the order of the data flow; the number in the corner of each block is its position. Blocks that
233
+ could run at the same time run from left to right, then from top to bottom.
234
+
235
+ - **Event driven**: when no block depends on time, the diagram runs whenever an input changes. Changes within
236
+ 20 ms run together in one cycle.
237
+ - **Cyclic**: as soon as the diagram contains a timer, it runs every 200 ms (50 ms to 10 s, see the settings of
238
+ the diagram), and additionally right after an input changed.
239
+
240
+ The execution mode is chosen automatically, or can be set in the settings of the diagram.
241
+
242
+ A loop is only allowed through a block that stores a value (timer, counter, flip-flop, edge, control block,
243
+ `JS`, own block): the link that leads back
244
+ reads what that block put out in the previous cycle and is drawn as a double line. A loop without such a block
245
+ is an error.
246
+
247
+ A timer counts from the cycle in which it sees its input change, so it never expires before its time - at most
248
+ one cycle later.
249
+
250
+ ## Limits
251
+
252
+ - Not for safety related functions. A diagram runs in a script of ioBroker, without real time guarantees.
253
+ - The state of the blocks is not kept over a restart of the script.
254
+ - Not yet available: breakpoints inside an own block, a manual execution order, links routed around blocks.
255
+
256
+ ## Storage
257
+
258
+ The diagram is stored in the script itself, as the last line of `common.source` (`//#fbd:{...}`); the lines above
259
+ are the generated code. The diagram includes the copies of the own blocks it uses. The blocks of the library are implemented in the module `@iobroker/fb-runtime`, which comes with the
260
+ adapter, and not copied into every script.