iobroker.javascript 10.2.4 → 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 (186) hide show
  1. package/README.md +10 -21
  2. package/admin/assets/AiChatPanel-CpY4Bun-.js +27 -0
  3. package/admin/assets/{AiChatService-Bsp_rhVx.js → AiChatService-QKcpW4jQ.js} +1 -1
  4. package/admin/assets/AiDiffView-DscPfZ38.js +1 -0
  5. package/admin/assets/{AiInlineProvider-BxOW88xU.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-teJTIU-2.js +15 -0
  10. package/admin/assets/Documentation-uz4Ut9pT.js +4339 -0
  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-BCGahS47.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-BnL93BgK.js +1 -0
  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-NI-3Uv4e.js +1217 -0
  22. package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-DVaMIZyC.js +9 -0
  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-CLb0DLyc.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-BxCMg9X4.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-XivsIDE5.js → blocks_trigger-DeAYXpSS.js} +1 -1
  38. package/admin/assets/{cronHoverProvider-BZMOFHO_.js → cronHoverProvider-DoO2_tpG.js} +1 -1
  39. package/admin/assets/{field_cron-CxKi__cX.js → field_cron-D3Ts_s9M.js} +1 -1
  40. package/admin/assets/{field_oid-CJIYiGxY.js → field_oid-BRNXredg.js} +1 -1
  41. package/admin/assets/{field_script-CehplM7L.js → field_script-3X6ousg7.js} +1 -1
  42. package/admin/assets/helpers-BTGaTdnT.js +1 -0
  43. package/admin/assets/{hostInit-Bs-bStPF.js → hostInit-2h2Cbsaw.js} +1 -1
  44. package/admin/assets/iconLibraryData-B5fiyl1C.js +1 -0
  45. package/admin/assets/index-BHhhebRG.css +1 -0
  46. package/admin/assets/index-CbQlIKB_.js +156 -0
  47. package/admin/assets/{inlineChatWidget-NIvdRGmU.js → inlineChatWidget-BwQVCPkx.js} +1 -1
  48. package/admin/assets/{inlineDiffController-Qh402KhK.js → inlineDiffController-BsDDsDHn.js} +1 -1
  49. package/admin/assets/loadBlocks-RpqM7PwO.js +117 -0
  50. package/admin/assets/loadMonaco-BVOEahNw.js +1 -0
  51. package/admin/assets/{mf-entry-bootstrap-0-019228a5.js → mf-entry-bootstrap-0-0deef484.js} +3 -3
  52. package/admin/assets/{pendingShares-B3t6ewri.js → pendingShares-BaAadIDv.js} +1 -1
  53. package/admin/assets/reactour.esm-DX9ZgYlx.js +137 -0
  54. package/admin/assets/stateHoverProvider-BEadnSXp.js +11 -0
  55. package/admin/assets/tileFbd-CWAy7R7m.svg +85 -0
  56. package/admin/custom/assets/Components-FkGDIlId.js +1 -0
  57. package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-Cs88NUCd.js +1 -0
  58. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-P-8ffWXw.js +1 -0
  59. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-ZVuRAEo5.js +1 -0
  60. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DVb0ZZ1Q.js +1217 -0
  61. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-Dna3WF04.js +1 -0
  62. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_mui_mf_1_x_mf_2_date_mf_2_pickers__loadShare__.js-DcjdCGAx.js +1 -0
  63. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare__date_mf_2_fns__loadShare__.js-CnhNjamd.js +1 -0
  64. package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare__leaflet__loadShare__.js-im3edKNs.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare__leaflet__loadShare__.js-Dz7BFJqH.js} +1 -1
  65. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-B0olko2J.js +1 -0
  66. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__prebuild___mf_0_iobroker_mf_1_json_mf_2_config__prebuild__-CzN4reh_.js +122 -0
  67. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__prebuild__leaflet__prebuild__-xPcBaiTQ.js +1 -0
  68. package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-Byvr2uOb.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-CXpyx8Vy.js} +1 -1
  69. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__prebuild__react_mf_2_dom_mf_1_client__prebuild__-DuFBE5fh.js +9 -0
  70. package/admin/custom/assets/{hostInit-IJMNq3h7.js → hostInit-6oh4UY2k.js} +1 -1
  71. package/admin/custom/assets/iconLibraryData-B5fiyl1C.js +1 -0
  72. package/admin/custom/assets/index-BrlyEy6J.js +1 -0
  73. package/admin/custom/assets/lib-BmDlTzq2.js +3 -0
  74. package/admin/custom/assets/{mf-entry-bootstrap-0-f149bc46.js → mf-entry-bootstrap-0-ad1cd7d0.js} +3 -3
  75. package/admin/custom/assets/pendingShares-kV2kwejX.js +1 -0
  76. package/admin/custom/assets/rolldown-runtime-Dqfqb5bO.js +1 -0
  77. package/admin/custom/customComponents.js +3 -2
  78. package/admin/custom/i18n/en.json +39 -39
  79. package/admin/custom/i18n/es.json +1 -1
  80. package/admin/custom/i18n/fr.json +2 -2
  81. package/admin/custom/i18n/it.json +1 -1
  82. package/admin/custom/i18n/nl.json +2 -2
  83. package/admin/custom/i18n/pt.json +2 -2
  84. package/admin/custom/i18n/ru.json +2 -2
  85. package/admin/custom/i18n/uk.json +1 -1
  86. package/admin/custom/i18n/zh-cn.json +1 -1
  87. package/admin/i18n/de.json +1 -1
  88. package/admin/i18n/en.json +115 -115
  89. package/admin/i18n/fr.json +115 -115
  90. package/admin/i18n/it.json +115 -115
  91. package/admin/i18n/nl.json +115 -115
  92. package/admin/i18n/pl.json +1 -1
  93. package/admin/i18n/pt.json +115 -115
  94. package/admin/i18n/ru.json +115 -115
  95. package/admin/i18n/uk.json +115 -115
  96. package/admin/i18n/zh-cn.json +115 -115
  97. package/admin/mf-manifest.json +1 -1
  98. package/admin/mf-stats.json +1 -1
  99. package/admin/remoteEntry.js +2 -2
  100. package/admin/tab.html +3 -7
  101. package/build/lib/fb/analyze.js +288 -0
  102. package/build/lib/fb/analyze.js.map +1 -0
  103. package/build/lib/fb/blocks.js +605 -0
  104. package/build/lib/fb/blocks.js.map +1 -0
  105. package/build/lib/fb/generate.js +326 -0
  106. package/build/lib/fb/generate.js.map +1 -0
  107. package/build/lib/fb/graph.js +240 -0
  108. package/build/lib/fb/graph.js.map +1 -0
  109. package/build/lib/fb/index.js +57 -0
  110. package/build/lib/fb/index.js.map +1 -0
  111. package/build/lib/fb/js.js +33 -0
  112. package/build/lib/fb/js.js.map +1 -0
  113. package/build/lib/fb/layout.js +205 -0
  114. package/build/lib/fb/layout.js.map +1 -0
  115. package/build/lib/fb/library.js +657 -0
  116. package/build/lib/fb/library.js.map +1 -0
  117. package/build/lib/fb/runtime.js +793 -0
  118. package/build/lib/fb/runtime.js.map +1 -0
  119. package/build/lib/fb/time.js +76 -0
  120. package/build/lib/fb/time.js.map +1 -0
  121. package/build/lib/fb/types.js +19 -0
  122. package/build/lib/fb/types.js.map +1 -0
  123. package/build/lib/fb/user.js +78 -0
  124. package/build/lib/fb/user.js.map +1 -0
  125. package/build/lib/javascript.d.ts +17 -17
  126. package/build/lib/mirror.js +4 -0
  127. package/build/lib/mirror.js.map +1 -1
  128. package/build/lib/sandbox.js +44 -0
  129. package/build/lib/sandbox.js.map +1 -1
  130. package/build/main.js +66 -1
  131. package/build/main.js.map +1 -1
  132. package/build/types.d.ts +9 -1
  133. package/docs/de/README.md +1 -1
  134. package/docs/de/fbd.md +274 -0
  135. package/docs/de/javascript.md +2167 -0
  136. package/docs/en/fbd.md +260 -0
  137. package/docs/en/javascript.md +28 -30
  138. package/io-package.json +52 -28
  139. package/package.json +8 -8
  140. package/admin/assets/AiChatPanel-AZko1BsN.js +0 -27
  141. package/admin/assets/AiDiffView-Cri2QFh1.js +0 -1
  142. package/admin/assets/Debugger-CVDh3kgz.js +0 -15
  143. package/admin/assets/Error-Ch2nx5uC.js +0 -1
  144. package/admin/assets/Import-XKVP-nRT.js +0 -1
  145. package/admin/assets/RulesEditor-DsO4cKIk.js +0 -1
  146. package/admin/assets/ScriptEditorVanillaMonaco-BDAw2Bw6.js +0 -3
  147. package/admin/assets/_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-BMAFQFoH.js +0 -1
  148. package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__113183188387379__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-D-gi6Mty.js +0 -1217
  149. package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__113183188387379__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-CDctpiPx.js +0 -9
  150. package/admin/assets/aiPromptBuilder-aJfHa-eU.js +0 -1
  151. package/admin/assets/blocks_action-DS28sNfo.js +0 -1
  152. package/admin/assets/blocks_logic-Dpp2fwlu.js +0 -1
  153. package/admin/assets/blocks_number-N4IfHvYD.js +0 -1
  154. package/admin/assets/blocks_object-uK7FHVhS.js +0 -1
  155. package/admin/assets/blocks_procedures-C_KD0Bm6.js +0 -3
  156. package/admin/assets/blocks_switch-C8Rls5pK.js +0 -2
  157. package/admin/assets/blocks_system-CEQnj5fY.js +0 -1
  158. package/admin/assets/blocks_text-BDEWxu0P.js +0 -1
  159. package/admin/assets/blocks_time-aHQQK1Uz.js +0 -1
  160. package/admin/assets/blocks_timeout-C2L93TLJ.js +0 -1
  161. package/admin/assets/helpers-DiwtLpXM.js +0 -1
  162. package/admin/assets/index-B0FfAYMN.js +0 -871
  163. package/admin/assets/index-CXaeqPRy.css +0 -1
  164. package/admin/assets/stateHoverProvider-BkW15VMN.js +0 -9
  165. package/admin/assets/virtualExposes-DgGB-18P.js +0 -1
  166. package/admin/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__iobroker_javascript__remoteEntry_js-CiidVc0O.js +0 -1
  167. package/admin/assets/virtual_mf-exposes___mfe_internal__iobroker_javascript__remoteEntry_js-ChiJXsfH.js +0 -1
  168. package/admin/custom/assets/Components-SGnA-3W_.js +0 -1
  169. package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-Bx3X6TLB.js +0 -1
  170. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-Cc7MmJgr.js +0 -1
  171. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-CdvEvX5z.js +0 -1
  172. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-D5NaoeJi.js +0 -1217
  173. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-Cbgw_a3f.js +0 -1
  174. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare___mf_0_mui_mf_1_x_mf_2_date_mf_2_pickers__loadShare__.js-CMr75K5w.js +0 -1
  175. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare__date_mf_2_fns__loadShare__.js-DKIvPDPX.js +0 -1
  176. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-D50aYKgD.js +0 -1
  177. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__prebuild___mf_0_iobroker_mf_1_json_mf_2_config__prebuild__-CEzQFX7o.js +0 -122
  178. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__prebuild__leaflet__prebuild__-BUDmnAcx.js +0 -1
  179. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__prebuild__react_mf_2_dom_mf_1_client__prebuild__-D_1oh1WH.js +0 -9
  180. package/admin/custom/assets/index-7r4VklMp.js +0 -1
  181. package/admin/custom/assets/lib-DDU2Oe48.js +0 -3
  182. package/admin/custom/assets/pendingShares-DarGQhyO.js +0 -1
  183. package/admin/custom/assets/rolldown-runtime-BcKkbAw3.js +0 -1
  184. package/admin/custom/assets/virtualExposes-C0IqMANQ.js +0 -1
  185. package/admin/custom/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-CqKvh5Xu.js +0 -1
  186. package/admin/custom/assets/virtual_mf-exposes___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-DrBN_S5o.js +0 -2
@@ -0,0 +1,2167 @@
1
+ ## Inhalt
2
+ - [Globale Funktionen](#globale-funktionen)
3
+ - [Best Practice](#best-practice)
4
+
5
+ - [Funktionen](#die-folgenden-funktionen-können-in-skripten-verwendet-werden)
6
+ - [require - Modul laden](#require---modul-laden)
7
+ - [console - Gibt die Nachricht im Log aus](#console---gibt-die-nachricht-im-log-aus)
8
+ - [exec - Führt ein Betriebssystem-Kommando aus, z. B. "cp file1 file2"](#exec---führt-ein-betriebssystem-kommando-aus-z-b-cp-file1-file2)
9
+ - [on - Änderungen oder Aktualisierungen eines States abonnieren](#on---änderungen-oder-aktualisierungen-eines-states-abonnieren)
10
+ - [once](#once)
11
+ - [subscribe - wie on](#subscribe---wie-on)
12
+ - [unsubscribe](#unsubscribe)
13
+ - [getSubscriptions](#getsubscriptions)
14
+ - [getFileSubscriptions](#getfilesubscriptions)
15
+ - [schedule](#schedule)
16
+ - [Zeitplan](#zeitplan)
17
+ - [Astro-Funktion](#astro-funktion)
18
+ - [scheduleById](#schedulebyid)
19
+ - [getSchedules](#getschedules)
20
+ - [clearSchedule](#clearschedule)
21
+ - [getAttr](#getattr)
22
+ - [getAstroDate](#getastrodate)
23
+ - [isAstroDay](#isastroday)
24
+ - [compareTime](#comparetime)
25
+ - [setState](#setstate)
26
+ - [setStateAsync](#setstateasync)
27
+ - [setStateDelayed](#setstatedelayed)
28
+ - [clearStateDelayed](#clearstatedelayed)
29
+ - [getStateDelayed](#getstatedelayed)
30
+ - [getState](#getstate)
31
+ - [getStateAsync](#getstateasync)
32
+ - [existsState](#existsstate)
33
+ - [getObject](#getobject)
34
+ - [setObject](#setobject)
35
+ - [existsObject](#existsobject)
36
+ - [extendObject](#extendobject)
37
+ - [deleteObject](#deleteobject)
38
+ - [getIdByName](#getidbyname)
39
+ - [getEnums](#getenums)
40
+ - [createState](#createstate)
41
+ - [createStateAsync](#createstateasync)
42
+ - [deleteState](#deletestate)
43
+ - [deleteStateAsync](#deletestateasync)
44
+ - [sendTo](#sendto)
45
+ - [sendToAsync](#sendtoasync)
46
+ - [sendToHost](#sendtohost)
47
+ - [sendToHostAsync](#sendtohostasync)
48
+ - [setInterval](#setinterval)
49
+ - [clearInterval](#clearinterval)
50
+ - [setTimeout](#settimeout)
51
+ - [clearTimeout](#cleartimeout)
52
+ - [setImmediate](#setimmediate)
53
+ - [formatDate](#formatdate)
54
+ - [formatTimeDiff](#formattimediff)
55
+ - [getDateObject](#getdateobject)
56
+ - [formatValue](#formatvalue)
57
+ - [adapterSubscribe](#adaptersubscribe)
58
+ - [adapterUnsubscribe](#adapterunsubscribe)
59
+ - [$ - Selektor](#---selektor)
60
+ - [readFile](#readfile)
61
+ - [writeFile](#writefile)
62
+ - [delFile](#delfile)
63
+ - [renameFile](#renamefile)
64
+ - [onFile](#onfile)
65
+ - [offFile](#offfile)
66
+ - [onStop](#onstop)
67
+ - [getHistory](#gethistory)
68
+ - [runScript](#runscript)
69
+ - [runScriptAsync](#runscriptasync)
70
+ - [startScript](#startscript)
71
+ - [startScriptAsync](#startscriptasync)
72
+ - [stopScript](#stopscript)
73
+ - [stopScriptAsync](#stopscriptasync)
74
+ - [isScriptActive](#isscriptactive)
75
+ - [name](#scriptname)
76
+ - [instance](#instance)
77
+ - [SECRETS](#secrets)
78
+ - [messageTo](#messageto)
79
+ - [messageToAsync](#messagetoasync)
80
+ - [onMessage](#onmessage)
81
+ - [onMessageUnregister](#onmessageunregister)
82
+ - [onLog](#onlog)
83
+ - [onLogUnregister](#onlogunregister)
84
+ - [wait](#wait)
85
+ - [sleep](#sleep)
86
+ - [httpGet](#httpget)
87
+ - [httpPost](#httppost)
88
+ - [createTempFile](#createtempfile)
89
+ - [registerNotification](#registernotification)
90
+
91
+ - [Skriptaktivität](#skriptaktivität)
92
+
93
+ ## Globale Funktionen
94
+ Globale Skripte können im Ordner `global` definiert werden.
95
+ Alle globalen Skripte stehen in allen Instanzen zur Verfügung. Ist ein globales Skript deaktiviert, wird es nicht verwendet.
96
+ Ein globales Skript wird einfach dem normalen Skript vorangestellt und zusammen mit diesem kompiliert. Daher können über globale Skripte keine Daten zwischen Skripten ausgetauscht werden. Dafür sollten States verwendet werden.
97
+
98
+ Um globale Funktionen in TypeScript zu verwenden, müssen sie zuerst mit `declare` deklariert werden, damit der Compiler die globalen Funktionen kennt. Beispiel:
99
+ ```typescript
100
+ // globales Skript:
101
+ // ================
102
+ function globalFn(arg: string): void {
103
+ // eigentliche Implementierung
104
+ }
105
+
106
+ // normales Skript:
107
+ // ================
108
+ declare function globalFn(arg: string): void;
109
+ // wie gewohnt verwenden:
110
+ globalFn('test');
111
+ ```
112
+
113
+ #### Best Practice:
114
+ Es empfiehlt sich, zwei Instanzen des JavaScript-Adapters anzulegen: eine "test"- und eine "production"-Instanz.
115
+ Nachdem das Skript in der "test"-Instanz getestet wurde, kann es nach "production" verschoben werden. So lässt sich die "test"-Instanz beliebig neu starten.
116
+
117
+ ## Die folgenden Funktionen können in Skripten verwendet werden:
118
+
119
+ ### require - Modul laden
120
+ ```js
121
+ const mod = require('module_name');
122
+ ```
123
+ Folgende Module sind bereits vorgeladen: `node:dgram`, `node:crypto`, `node:dns`, `node:events`, `node:fs`, `node:http`, `node:https`, `node:http2`, `node:net`, `node:os`, `node:path`, `node:util`, `node:stream`, `node:zlib`, `suncalc2`, `axios`, `wake_on_lan`, `request` (veraltet)
124
+
125
+ Um andere Module zu verwenden, trägt man den Namen (und die Version) des Moduls in der Instanzkonfiguration ein. ioBroker installiert das Modul dann. Anschließend kann es in den Skripten geladen (require) und verwendet werden.
126
+
127
+ ### console - Gibt die Nachricht im Log aus
128
+ Die Verwendung ist dieselbe wie in `javascript`
129
+
130
+ ### exec - Führt ein Betriebssystem-Kommando aus, z. B. `cp file1 file2`
131
+ ```js
132
+ exec(cmd, [options], callback);
133
+ ```
134
+
135
+ Führt ein Systemkommando aus und liefert dessen Ausgaben.
136
+
137
+ ```js
138
+ // Liste der Dateien und Verzeichnisse in /var/log abrufen
139
+ exec('ls /var/log', (error, stdout, stderr) => {
140
+ log('stdout: ' + stdout);
141
+ });
142
+ ```
143
+
144
+ Node.js verwendet /bin/sh zum Ausführen von Kommandos. Soll eine andere Shell verwendet werden, kann das Optionsobjekt genutzt werden, wie in der [Node.js-Dokumentation](https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback) zu child_process.exec beschrieben.
145
+ Es empfiehlt sich, bei Kommandos immer vollständige Pfadnamen anzugeben, damit sichergestellt ist, dass das richtige Kommando ausgeführt wird.
146
+
147
+ **Hinweis:** Um diese Funktion aufzurufen, muss die Option *Kommando "exec" erlauben* aktiviert sein.
148
+
149
+ ### on - Änderungen oder Aktualisierungen eines States abonnieren
150
+ ```js
151
+ on(pattern, callbackOrId, value);
152
+ ```
153
+
154
+ Die Callback-Funktion erhält als Parameter ein Objekt mit folgendem Inhalt:
155
+ ```js
156
+ {
157
+ id: 'javascript.0.myplayer',
158
+ state: {
159
+ val: 'new state',
160
+ ts: 1416149118,
161
+ ack: true,
162
+ lc: 1416149118,
163
+ from: 'system.adapter.sonos.0'
164
+ },
165
+ oldState: {
166
+ val: 'old state',
167
+ ts: 1416148233,
168
+ ack: true,
169
+ lc: 1416145154,
170
+ from: 'system.adapter.sonos.0'
171
+ }
172
+ }
173
+ ```
174
+
175
+ **Hinweis:** `state` hieß früher `newState`. Diese Bezeichnung funktioniert weiterhin.
176
+
177
+ Beispiel:
178
+ ```js
179
+ let timer;
180
+
181
+ // State "javascript.0.counter" anlegen
182
+ createState('counter', 0);
183
+
184
+ // Bei Änderung
185
+ on('adapter.0.device.channel.sensor', (data) => {
186
+ // Aber nicht öfter als alle 30 Sekunden
187
+ if (!timer) {
188
+ timer = setTimeout(() => {
189
+ timer = null;
190
+ }, 30000);
191
+
192
+ // Bestätigten Wert setzen
193
+ setState('counter', 1 + getState('counter'), true);
194
+
195
+ // Oder ein unbestätigtes Kommando setzen
196
+ setState('adapter.0.device.channel.actor', true);
197
+ }
198
+ });
199
+ ```
200
+
201
+ Folgende Parameter können zur Definition des Triggers verwendet werden:
202
+
203
+ | Parameter | Typ/Wert | Beschreibung |
204
+ |-------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
205
+ | logic | string | Logik "and" oder "or" zur Verknüpfung der Bedingungen \(Standard: "and"\) |
206
+ | | | |
207
+ | id | string | ID ist gleich der angegebenen |
208
+ | | RegExp | ID entspricht dem regulären Ausdruck |
209
+ | | Array | ID ist in einer Liste erlaubter IDs enthalten |
210
+ | | | |
211
+ | name | string | Name ist gleich dem angegebenen |
212
+ | | RegExp | Name entspricht dem regulären Ausdruck |
213
+ | | Array | Name ist in einer Liste erlaubter Namen enthalten |
214
+ | | | |
215
+ | change | string | "eq", "ne", "gt", "ge", "lt", "le", "any" |
216
+ | | "eq" | (gleich) Neuer Wert muss gleich dem alten sein (state.val == oldState.val) |
217
+ | | "ne" | (ungleich) Neuer Wert muss ungleich dem alten sein (state.val != oldState.val) **Ist das Muster ein ID-String, wird dieser Wert standardmäßig verwendet** |
218
+ | | "gt" | (größer) Neuer Wert muss größer als der alte sein (state.val > oldState.val) |
219
+ | | "ge" | (größer oder gleich) Neuer Wert muss größer oder gleich dem alten sein (state.val >= oldState.val) |
220
+ | | "lt" | (kleiner) Neuer Wert muss kleiner als der alte sein (state.val < oldState.val) |
221
+ | | "le" | (kleiner oder gleich) Neuer Wert muss kleiner oder gleich dem alten sein (state.val <= oldState.val) |
222
+ | | "any" | Trigger wird ausgelöst, sobald ein neuer Wert eintrifft |
223
+ | | | |
224
+ | val | mixed | Neuer Wert muss gleich dem angegebenen sein |
225
+ | valNe | mixed | Neuer Wert muss ungleich dem angegebenen sein |
226
+ | valGt | mixed | Neuer Wert muss größer als der angegebene sein |
227
+ | valGe | mixed | Neuer Wert muss größer oder gleich dem angegebenen sein |
228
+ | valLt | mixed | Neuer Wert muss kleiner als der angegebene sein |
229
+ | valLe | mixed | Neuer Wert muss kleiner oder gleich dem angegebenen sein |
230
+ | | | |
231
+ | ack | boolean | Bestätigungsstatus (ack) des neuen Werts ist gleich dem angegebenen |
232
+ | q | number | Qualitätscode des neuen Werts ist gleich dem angegebenen. Mit '*' passt jeder Code. **Ist q nicht angegeben, wird q = 0 als Muster gesetzt!** |
233
+ | | | |
234
+ | oldVal | mixed | Vorheriger Wert muss gleich dem angegebenen sein |
235
+ | oldValNe | mixed | Vorheriger Wert muss ungleich dem angegebenen sein |
236
+ | oldValGt | mixed | Vorheriger Wert muss größer als der angegebene sein |
237
+ | oldValGe | mixed | Vorheriger Wert muss größer oder gleich dem angegebenen sein |
238
+ | oldValLt | mixed | Vorheriger Wert muss kleiner als der angegebene sein |
239
+ | oldValLe | mixed | Vorheriger Wert muss kleiner oder gleich dem angegebenen sein |
240
+ | | | |
241
+ | oldAck | bool | Bestätigungsstatus (ack) des vorherigen Werts ist gleich dem angegebenen |
242
+ | oldQ | number | Qualitätscode des vorherigen Werts ist gleich dem angegebenen. Mit '*' passt jeder Code |
243
+ | | | |
244
+ | ts | number | Zeitstempel des neuen Werts muss gleich dem angegebenen sein (state.ts == ts) |
245
+ | tsGt | number | Zeitstempel des neuen Werts muss größer als der angegebene sein (state.ts > ts) |
246
+ | tsGe | number | Zeitstempel des neuen Werts muss größer oder gleich dem angegebenen sein (state.ts >= ts) |
247
+ | tsLt | number | Zeitstempel des neuen Werts muss kleiner als der angegebene sein (state.ts < ts) |
248
+ | tsLe | number | Zeitstempel des neuen Werts muss kleiner oder gleich dem angegebenen sein (state.ts <= ts) |
249
+ | | | |
250
+ | oldTs | number | Vorheriger Zeitstempel muss gleich dem angegebenen sein (oldState.ts == ts) |
251
+ | oldTsGt | number | Vorheriger Zeitstempel muss größer als der angegebene sein (oldState.ts > ts) |
252
+ | oldTsGe | number | Vorheriger Zeitstempel muss größer oder gleich dem angegebenen sein (oldState.ts >= ts) |
253
+ | oldTsLt | number | Vorheriger Zeitstempel muss kleiner als der angegebene sein (oldState.ts < ts) |
254
+ | oldTsLe | number | Vorheriger Zeitstempel muss kleiner oder gleich dem angegebenen sein (oldState.ts <= ts) |
255
+ | | | |
256
+ | lc | number | Zeitstempel der letzten Änderung muss gleich dem angegebenen sein (state.lc == lc) |
257
+ | lcGt | number | Zeitstempel der letzten Änderung muss größer als der angegebene sein (state.lc > lc) |
258
+ | lcGe | number | Zeitstempel der letzten Änderung muss größer oder gleich dem angegebenen sein (state.lc >= lc) |
259
+ | lcLt | number | Zeitstempel der letzten Änderung muss kleiner als der angegebene sein (state.lc < lc) |
260
+ | lcLe | number | Zeitstempel der letzten Änderung muss kleiner oder gleich dem angegebenen sein (state.lc <= lc) |
261
+ | | | |
262
+ | oldLc | number | Vorheriger Zeitstempel der letzten Änderung muss gleich dem angegebenen sein (oldState.lc == lc) |
263
+ | oldLcGt | number | Vorheriger Zeitstempel der letzten Änderung muss größer als der angegebene sein (oldState.lc > lc) |
264
+ | oldLcGe | number | Vorheriger Zeitstempel der letzten Änderung muss größer oder gleich dem angegebenen sein (oldState.lc >= lc) |
265
+ | oldLcLt | number | Vorheriger Zeitstempel der letzten Änderung muss kleiner als der angegebene sein (oldState.lc < lc) |
266
+ | oldLcLe | number | Vorheriger Zeitstempel der letzten Änderung muss kleiner oder gleich dem angegebenen sein (oldState.lc <= lc) |
267
+ | | | |
268
+ | channelId | string | Kanal-ID muss gleich der angegebenen sein |
269
+ | | RegExp | Kanal-ID entspricht dem regulären Ausdruck |
270
+ | | Array | Kanal-ID ist in einer Liste erlaubter Kanal-IDs enthalten |
271
+ | | | |
272
+ | channelName | string | Kanalname muss gleich dem angegebenen sein |
273
+ | | RegExp | Kanalname entspricht dem regulären Ausdruck |
274
+ | | Array | Kanalname ist in einer Liste erlaubter Kanalnamen enthalten |
275
+ | | | |
276
+ | deviceId | string | Geräte-ID muss gleich der angegebenen sein |
277
+ | | RegExp | Geräte-ID entspricht dem regulären Ausdruck |
278
+ | | Array | Geräte-ID ist in einer Liste erlaubter Geräte-IDs enthalten |
279
+ | | | |
280
+ | deviceName | string | Gerätename muss gleich dem angegebenen sein |
281
+ | | RegExp | Gerätename entspricht dem regulären Ausdruck |
282
+ | | Array | Gerätename ist in einer Liste erlaubter Gerätenamen enthalten |
283
+ | | | |
284
+ | enumId | string | State gehört zum angegebenen Enum |
285
+ | | RegExp | Eine Enum-ID des States entspricht dem angegebenen regulären Ausdruck |
286
+ | | Array | Eine Enum-ID des States ist in der angegebenen Liste von Enum-IDs enthalten |
287
+ | | | |
288
+ | enumName | string | State gehört zum angegebenen Enum |
289
+ | | RegExp | Ein Enum-Name des States entspricht dem angegebenen regulären Ausdruck |
290
+ | | Array | Ein Enum-Name des States ist in der angegebenen Liste von Enum-Namen enthalten |
291
+ | | | |
292
+ | from | string | Neuer Wert stammt vom angegebenen Adapter |
293
+ | | RegExp | Neuer Wert stammt von einem Adapter, der dem regulären Ausdruck entspricht |
294
+ | | Array | Neuer Wert stammt von einem Adapter aus der angegebenen Liste erlaubter Adapter |
295
+ | | | |
296
+ | fromNe | string | Neuer Wert stammt nicht vom angegebenen Adapter |
297
+ | | RegExp | Neuer Wert stammt nicht von einem Adapter, der dem regulären Ausdruck entspricht |
298
+ | | Array | Neuer Wert stammt nicht von einem Adapter aus der angegebenen Liste verbotener Adapter |
299
+ | | | |
300
+ | oldFrom | string | Alter Wert stammt vom angegebenen Adapter |
301
+ | | RegExp | Alter Wert stammt von einem Adapter, der dem regulären Ausdruck entspricht |
302
+ | | Array | Alter Wert stammt von einem Adapter aus der angegebenen Liste erlaubter Adapter |
303
+ | | | |
304
+ | oldFromNe | string | Alter Wert stammt nicht vom angegebenen Adapter |
305
+ | | RegExp | Alter Wert stammt nicht von einem Adapter, der dem regulären Ausdruck entspricht |
306
+ | | Array | Alter Wert stammt nicht von einem Adapter aus der angegebenen Liste verbotener Adapter |
307
+
308
+ Beispiele:
309
+ Trigger auf alle States mit der ID `'*.STATE'`, wenn sie bestätigt (ack) sind und den neuen Wert `true` haben.
310
+
311
+ ```js
312
+ {
313
+ "id": /\.STATE$/,
314
+ "val": true,
315
+ "ack": true,
316
+ "logic": "and"
317
+ }
318
+ ```
319
+
320
+ **Hinweis:** RegExp kann direkt verwendet werden:
321
+
322
+ ```js
323
+ on(/^system\.adapter\..*\.\d+\.memRss$/, function (obj) {
324
+ });
325
+
326
+ // entspricht
327
+ on({id: /^system\.adapter\..*\.\d+\.memRss$/, change: "ne"}, function (obj) {
328
+ });
329
+ ```
330
+
331
+ Um zwei States einfach miteinander zu verbinden, schreibt man:
332
+ ```js
333
+ on('stateId1', 'stateId2');
334
+ ```
335
+
336
+ Alle Änderungen von *stateId1* werden in *stateId2* geschrieben.
337
+
338
+ Ist der Parameter `value` in Kombination mit einer State-ID als zweitem Parameter gesetzt, wird der State bei jeder Änderung mit `value` befüllt.
339
+ ```js
340
+ on('stateId1', 'stateId2', 'triggered');
341
+ setState('stateId1', 'new value');
342
+
343
+ // stateId2 wird auf 'triggered' gesetzt.
344
+ ```
345
+
346
+ Die Funktion `on` gibt einen Handler zurück. Dieser Handler kann zum Beenden des Abonnements verwendet werden.
347
+
348
+ *Hinweis:* Standardmäßig werden nur States mit der Qualität 0x00 an die Callback-Funktion übergeben. Um alle Ereignisse zu erhalten, muss `{q: '*'}` zur Muster-Struktur hinzugefügt werden.
349
+
350
+ *Hinweis:* Standardmäßig ist "change" gleich "any", außer wenn nur eine ID als String angegeben wird (wie `on('id', () => {});`). Im letzteren Fall wird change auf "ne" gesetzt.
351
+
352
+ *Hinweis:* Sollen auch das Löschen oder Ablaufen von States als Trigger erkannt werden, muss change mit `ne` oder `any` UND q mit `*` als Filter verwendet werden!
353
+
354
+ *Hinweis:* Ab Version 4.3.2 kann der Trigger-Typ als zweiter Parameter angegeben werden: `on('my.id.0', 'any', obj => log(obj.state.val));`
355
+
356
+ ### once
357
+ Registriert ein einmaliges Abonnement, das nach dem ersten Aufruf automatisch beendet wird. Wie [on](#on---änderungen-oder-aktualisierungen-eines-states-abonnieren), wird aber nur einmal ausgeführt.
358
+
359
+ ```js
360
+ once(pattern, callback);
361
+ ```
362
+
363
+ ### subscribe - wie **[on](#on---änderungen-oder-aktualisierungen-eines-states-abonnieren)**
364
+
365
+ ### unsubscribe
366
+ ```js
367
+ unsubscribe(id);
368
+ // oder
369
+ unsubscribe(handler);
370
+ ```
371
+
372
+ Entfernt alle Abonnements für die angegebene Objekt-ID oder den angegebenen Handler.
373
+
374
+ ```js
375
+ // Per Handler
376
+ let mySubscription = on({ id: 'javascript.0.myState', change: 'any' }, (data) => {
377
+ // Abonnement nach dem ersten Trigger beenden
378
+ if (unsubscribe(mySubscription)) {
379
+ log('Subscription deleted');
380
+ }
381
+ });
382
+
383
+ // Per Objekt-ID
384
+ on({ id: 'javascript.0.myState1', change: 'ne' }, (data) => {
385
+ log('Some event');
386
+ });
387
+
388
+ on({ id: 'javascript.0.myState1', change: 'any' }, (data) => {
389
+ // Abonnement beenden
390
+ if (unsubscribe('javascript.0.myState1')) {
391
+ log('All subscriptions deleted');
392
+ }
393
+ });
394
+ ```
395
+
396
+ ### getSubscriptions
397
+ Liefert die Liste der Abonnements.
398
+
399
+ Beispiel für ein Ergebnis:
400
+ ```js
401
+ {
402
+ 'megad.0.dataPointName': [
403
+ {
404
+ name : 'script.js.NameOfScript',
405
+ pattern : {
406
+ id : 'megad.0.dataPointName',
407
+ change : 'ne'
408
+ }
409
+ }
410
+ ]
411
+ }
412
+ ```
413
+
414
+ ### getFileSubscriptions
415
+ Liefert die Liste der Datei-Abonnements.
416
+
417
+ Beispiel für ein Ergebnis:
418
+ ```js
419
+ {
420
+ 'vis.0$%$main/*': [
421
+ {
422
+ name : 'script.js.NameOfScript',
423
+ id : 'vis.0',
424
+ fileNamePattern: 'main/*'
425
+ }
426
+ ]
427
+ }
428
+ ```
429
+
430
+ ### schedule
431
+ ```js
432
+ schedule(pattern, callback);
433
+ ```
434
+
435
+ Zeitplaner mit Astro-Funktion.
436
+
437
+ #### Zeitplan
438
+ Das Muster kann ein String mit [Cron-Syntax](http://en.wikipedia.org/wiki/Cron) sein, der aus 5 (ohne Sekunden) oder 6 (mit Sekunden) Stellen besteht:
439
+ ```
440
+ * * * * * *
441
+ │ │ │ │ │ │
442
+ │ │ │ │ │ │
443
+ │ │ │ │ │ └───── Wochentag (0 - 6) (0 bis 6 entspricht Sonntag bis Samstag, alternativ Namen verwenden; 7 ist Sonntag, wie 0)
444
+ │ │ │ │ └────────── Monat (1 - 12)
445
+ │ │ │ └─────────────── Tag des Monats (1 - 31)
446
+ │ │ └──────────────────── Stunde (0 - 23)
447
+ │ └───────────────────────── Minute (0 - 59)
448
+ └───────────────────────────── [optional] Sekunde (0 - 59)
449
+ ```
450
+
451
+ ```js
452
+ // Beispiel mit 5 Stellen:
453
+ schedule('*/2 * * * *', () => {
454
+ log('Will be triggered every 2 minutes!');
455
+ });
456
+
457
+ // Beispiel mit 6 Stellen:
458
+ schedule('*/3 * * * * *', () => {
459
+ log('Will be triggered every 3 seconds!');
460
+ });
461
+ ```
462
+
463
+ Das Muster kann auch ein Objekt sein. Das wird vor allem verwendet, wenn Sekunden benötigt werden:
464
+
465
+ Das Objekt kann folgende Eigenschaften haben:
466
+ - `second`
467
+ - `minute`
468
+ - `hour`
469
+ - `date`
470
+ - `month`
471
+ - `year`
472
+ - `dayOfWeek`
473
+
474
+ ```js
475
+ schedule({ second: [20, 25] }, () => {
476
+ log('Will be triggered at xx:xx:20 and xx:xx:25 of every minute!');
477
+ });
478
+
479
+ schedule({ hour: 12, minute: 30 }, () => {
480
+ log('Will be triggered at 12:30!');
481
+ });
482
+ ```
483
+ Das Muster kann auch ein JavaScript-Date-Objekt (ein bestimmter Zeitpunkt) sein - in diesem Fall wird der Zeitplan nur ein einziges Mal ausgelöst.
484
+
485
+ Werden Start- oder Endzeiten für einen Zeitplan benötigt, lässt sich das ebenfalls mit einem Objekt umsetzen. In diesem Fall hat das Objekt folgende Eigenschaften:
486
+ - `start`
487
+ - `end`
488
+ - `rule`
489
+
490
+ start und end legen jeweils ein Date-Objekt, einen Datums-String oder eine Anzahl von Millisekunden seit dem 01. Januar 1970 00:00:00 UTC fest.
491
+ Die Regel (rule) ist ein Zeitplan-String mit [Cron-Syntax](http://en.wikipedia.org/wiki/Cron) oder ein Objekt:
492
+ ```js
493
+ let startTime = new Date(Date.now() + 5000);
494
+ let endTime = new Date(startTime.getTime() + 5000);
495
+ schedule({ start: startTime, end: endTime, rule: '*/1 * * * * *' }, () => {
496
+ log('It will run after 5 seconds and stop after 10 seconds');
497
+ });
498
+ ```
499
+
500
+ Die Regel selbst kann auch ein Objekt sein:
501
+
502
+ ```js
503
+ let today = new Date();
504
+ let startTime = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1);
505
+ let endTime = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 7);
506
+ let ruleData = { hour: 12, minute: 30 };
507
+ schedule({ start: startTime, end: endTime, rule: ruleData }, () => {
508
+ log('Will be triggered at 12:30, starting tomorow, ending in 7 days');
509
+ });
510
+ ```
511
+
512
+ #### Astro-Funktion
513
+
514
+ Die Astro-Funktion kann über das Attribut "astro" verwendet werden:
515
+
516
+ ```js
517
+ schedule({ astro: 'sunrise' }, () => {
518
+ log("Sunrise!");
519
+ });
520
+
521
+ schedule({ astro: 'sunset', shift: 10 }, () => {
522
+ log("10 minutes after sunset!");
523
+ });
524
+ ```
525
+
526
+ Das Attribut "shift" ist der Versatz in Minuten. Er kann auch negativ sein, um einen Zeitpunkt vor dem Astro-Ereignis festzulegen.
527
+
528
+ Folgende Werte können als Attribut in der Astro-Funktion verwendet werden:
529
+
530
+ - `"sunrise"`: Sonnenaufgang (die Oberkante der Sonne erscheint am Horizont)
531
+ - `"sunriseEnd"`: Ende des Sonnenaufgangs (die Unterkante der Sonne berührt den Horizont)
532
+ - `"goldenHourEnd"`: Ende der morgendlichen goldenen Stunde (weiches Licht, die beste Zeit zum Fotografieren)
533
+ - `"solarNoon"`: Sonnenmittag (die Sonne steht am höchsten)
534
+ - `"goldenHour"`: Beginn der abendlichen goldenen Stunde
535
+ - `"sunsetStart"`: Beginn des Sonnenuntergangs (die Unterkante der Sonne berührt den Horizont)
536
+ - `"sunset"`: Sonnenuntergang (die Sonne verschwindet unter dem Horizont, die abendliche bürgerliche Dämmerung beginnt)
537
+ - `"dusk"`: Abenddämmerung (die abendliche nautische Dämmerung beginnt)
538
+ - `"nauticalDusk"`: nautische Abenddämmerung (die abendliche astronomische Dämmerung beginnt)
539
+ - `"night"`: Beginn der Nacht (dunkel genug für astronomische Beobachtungen)
540
+ - `"nightEnd"`: Ende der Nacht (die morgendliche astronomische Dämmerung beginnt)
541
+ - `"nauticalDawn"`: nautische Morgendämmerung (die morgendliche nautische Dämmerung beginnt)
542
+ - `"dawn"`: Morgendämmerung (die morgendliche nautische Dämmerung endet, die morgendliche bürgerliche Dämmerung beginnt)
543
+ - `"nadir"`: Nadir (der dunkelste Moment der Nacht, die Sonne steht am tiefsten)
544
+
545
+ **Hinweis:** Um die "astro"-Funktion zu verwenden, müssen "latitude" und "longitude" (Breiten- und Längengrad) in den Einstellungen des JavaScript-Adapters definiert sein.
546
+
547
+ **Hinweis:** An manchen Orten kann es vorkommen, dass kein night/nightEnd existiert. Mehr dazu [hier](https://github.com/mourner/suncalc/issues/70).
548
+
549
+ **Hinweis:** Die Funktion "on" kann mit einer kleinen Anpassung auch für Zeitpläne verwendet werden:
550
+ ```js
551
+ on({ time: '*/2 * * * *' }, () => {
552
+ log((new Date()).toString() + " - Will be triggered every 2 minutes!");
553
+ });
554
+
555
+ on({ time: { hour: 12, minute: 30 }}, () => {
556
+ log((new Date()).toString() + " - Will be triggered at 12:30!");
557
+ });
558
+
559
+ on({ astro: 'sunset', shift: 10 }, () => {
560
+ log((new Date()).toString() + " - 10 minutes after sunset!");
561
+ });
562
+ ```
563
+ ### scheduleById
564
+ ```js
565
+ scheduleById(id, callback);
566
+ scheduleById(id, ack, callback);
567
+ ```
568
+
569
+ Ermöglicht das Anlegen eines Zeitplans auf Basis eines State-Werts. Ändert sich der State-Wert, wird der alte Zeitplan gelöscht und automatisch ein neuer Zeitplan angelegt.
570
+
571
+ Unterstützte Formate:
572
+
573
+ - `[h]h:[m]m:ss` (z. B. `12:42:15`, `15:3:12`, `3:10:25`)
574
+ - `[h]h:[m]m` (z. B. `13:37`, `9:40`)
575
+
576
+ ```js
577
+ scheduleById('0_userdata.0.configurableTimeFormat', () => {
578
+ log('Executed!');
579
+ });
580
+ ```
581
+
582
+ Beispiel: State anlegen und bei Änderungen einen Zeitplan registrieren:
583
+
584
+ ```js
585
+ createState(
586
+ '0_userdata.0.myTime',
587
+ '00:00:00', // Standardwert
588
+ {
589
+ type: 'string',
590
+ read: true,
591
+ write: true
592
+ },
593
+ () => {
594
+ scheduleById('0_userdata.0.myTime', () => {
595
+ log('Executed!');
596
+ });
597
+ }
598
+ );
599
+ ```
600
+
601
+ ### getSchedules
602
+ ```js
603
+ const list = getSchedules(true);
604
+ ```
605
+ Liefert die Liste aller CRON-Jobs und Zeitpläne (außer Astro).
606
+ Das Argument muss `true` sein, wenn man die Liste für **jedes laufende Skript** erhalten möchte. Andernfalls werden nur die Zeitpläne des aktuellen Skripts zurückgegeben.
607
+
608
+ ```js
609
+ const list = getSchedules(true);
610
+ list.forEach(schedule => log(JSON.stringify(schedule)));
611
+
612
+ // Alle Zeitpläne in allen Skripten löschen!
613
+ list.forEach(schedule => clearSchedule(schedule));
614
+ ```
615
+
616
+ Beispielausgabe:
617
+ ```
618
+ 2020-11-01 20:15:19.929 - {"type":"cron","pattern":"0 * * * *","scriptName":"script.js.Heizung","id":"cron_1604258108384_74924"}
619
+ 2020-11-01 20:15:19.931 - {"type":"schedule","schedule":"{"period":{}}","scriptName":"script.js.Heizung","id":"schedule_19576"}
620
+ ```
621
+
622
+ ### clearSchedule
623
+ Wenn **keine** "astro"-Funktion verwendet wird, kann man den Zeitplan später abbrechen. Dazu muss das Zeitplan-Objekt gespeichert werden:
624
+
625
+ ```js
626
+ let sch = schedule('*/2 * * * *', () => { /* ... */ });
627
+
628
+ // später:
629
+ clearSchedule(sch);
630
+ ```
631
+
632
+ `clearSchedule` akzeptiert alles, was `schedule` zurückgibt (ein CRON-Job-Objekt oder die ID eines Zeitplans aus dem Zeit-Assistenten)
633
+ und außerdem die Einträge von [getSchedules](#getschedules):
634
+
635
+ ```js
636
+ // Alle Zeitpläne dieses Skripts löschen
637
+ getSchedules().forEach(sch => clearSchedule(sch));
638
+ ```
639
+
640
+ Die Funktion gibt `true` zurück, wenn der Zeitplan gefunden und gelöscht wurde, andernfalls `false`.
641
+ Zeitpläne, die mit der Astro-Option angelegt wurden, können auf diese Weise nicht gelöscht werden.
642
+
643
+ ### getAttr
644
+ ```js
645
+ getAttr({ attr1: { attr2: 5 } }, 'attr1.attr2');
646
+ ```
647
+ Liefert ein Attribut des Objekts. Der Pfad zum Attribut kann verschachtelt sein, wie im Beispiel.
648
+
649
+ Ist das erste Attribut ein String, versucht die Funktion, den String als JSON zu parsen.
650
+
651
+ ### getAstroDate
652
+ ```js
653
+ getAstroDate(pattern, date, offsetMinutes);
654
+ ```
655
+ Liefert ein JavaScript-Date-Objekt für den angegebenen Astro-Namen (z. B. `"sunrise"` oder `"sunriseEnd"`). Die gültigen Werte sind in der Liste der erlaubten Werte im Abschnitt [Astro](#astro-funktion) der Funktion *schedule* aufgeführt.
656
+
657
+ Das zurückgegebene Date-Objekt wird für das übergebene *date* berechnet. Wird kein Datum angegeben, wird der aktuelle Tag verwendet.
658
+
659
+ ```js
660
+ let sunriseEnd = getAstroDate('sunriseEnd');
661
+ log(`Sunrise ends today at ${sunriseEnd.toLocaleTimeString()}`);
662
+
663
+ let today = new Date();
664
+ let tomorrow = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1);
665
+ let tomorrowNight = getAstroDate('night', tomorrow);
666
+ ```
667
+
668
+ **Hinweis: Abhängig vom geografischen Standort kann es vorkommen, dass z. B. 'night'/'nightEnd' zu bestimmten Zeitpunkten nicht existieren (z. B. an nördlichen Standorten jedes Jahr im Mai/Juni)!**
669
+
670
+ Mit Webseiten wie [suncalc.net](http://suncalc.net) kann man prüfen, ob die Zeitpunkte korrekt sind.
671
+
672
+ ### isAstroDay
673
+ ```js
674
+ isAstroDay();
675
+ ```
676
+ Gibt `true` zurück, wenn die aktuelle Zeit zwischen dem astronomischen Sonnenaufgang und Sonnenuntergang liegt.
677
+
678
+ ### compareTime
679
+ ```js
680
+ compareTime(startTime, endTime, operation, timeToCompare);
681
+ ```
682
+ Vergleicht die angegebene Zeit mit Grenzwerten.
683
+
684
+ Ist `timeToCompare` nicht angegeben, wird die aktuelle Zeit verwendet.
685
+
686
+ Folgende Operationen sind möglich:
687
+
688
+ - `">"` - wenn die angegebene Zeit größer als `startTime` ist
689
+ - `">="` - wenn die angegebene Zeit größer oder gleich `startTime` ist
690
+ - `"<"` - wenn die angegebene Zeit kleiner als `startTime` ist
691
+ - `"<="` - wenn die angegebene Zeit kleiner oder gleich `startTime` ist
692
+ - `"=="` - wenn die angegebene Zeit gleich `startTime` ist
693
+ - `"<>"` - wenn die angegebene Zeit ungleich `startTime` ist
694
+ - `"between"` - wenn die angegebene Zeit zwischen `startTime` und `endTime` liegt
695
+ - `"not between"` - wenn die angegebene Zeit nicht zwischen `startTime` und `endTime` liegt
696
+
697
+ Die Zeit kann ein Date-Objekt, ein Datum mit Uhrzeit oder nur eine Uhrzeit sein.
698
+
699
+ Für die Zeitangabe kann man Astro-Namen verwenden. Alle 3 Parameter können als Astro-Zeit angegeben werden.
700
+ Folgende Werte sind möglich: `sunrise`, `sunset`, `sunriseEnd`, `sunsetStart`, `dawn`, `dusk`, `nauticalDawn`, `nauticalDusk`, `nightEnd`, `night`, `goldenHourEnd`, `goldenHour`.
701
+ Details siehe [Astro](#astro-funktion).
702
+
703
+ ```js
704
+ log(compareTime('sunsetStart', 'sunsetEnd', 'between') ? 'Now is sunrise' : 'Now is no sunrise');
705
+ ```
706
+
707
+ Die Zeit kann auch mit einem Offset angegeben werden:
708
+
709
+ ```js
710
+ log(compareTime({ astro: 'sunsetStart', offset: 30 }, { astro: 'sunrise', offset: -30 }, '>') ? 'Now is at least 30 minutes after sunset' : 'No idea');
711
+ ```
712
+
713
+ Struktur eines Astro-Objekts.
714
+
715
+ ```js
716
+ {
717
+ astro: 'sunsetStart',// Pflichtangabe, kann als String statt als Objekt angegeben werden, wenn offset und date Standardwerte haben
718
+ offset: 30, // optional
719
+ date: new Date() // optional
720
+ }
721
+ ```
722
+
723
+ ### setState
724
+ ```js
725
+ setState(id, state, ack, callback);
726
+ ```
727
+
728
+ *Hinweis*: Die folgenden Befehle sind identisch
729
+
730
+ ```js
731
+ setState('myState', 1, false);
732
+ setState('myState', { val: 1, ack: false });
733
+ setState('myState', 1);
734
+ ```
735
+
736
+ Zur Verwendung von `ack` siehe https://github.com/ioBroker/ioBroker/wiki/Adapter-Development-Documentation#commands-and-statuses
737
+ Kurz:
738
+ - `ack` = `false` : Das Skript möchte ein Kommando senden, das vom Zielgerät/Adapter ausgeführt werden soll
739
+ - `ack` = `true` : Das Kommando wurde erfolgreich ausgeführt, und der State wird als positives Ergebnis aktualisiert
740
+
741
+ ### setStateAsync
742
+ ```js
743
+ await setStateAsync(id, state, ack);
744
+ ```
745
+ Wie setState, aber mit `promise`.
746
+
747
+ ### setStateDelayed
748
+ ```js
749
+ setStateDelayed(id, state, isAck, delay, clearRunning, callback);
750
+ ```
751
+
752
+ Wie setState, aber mit einer Verzögerung in Millisekunden. Dabei kann man (standardmäßig) alle laufenden Verzögerungen für diese ID löschen. Z. B.
753
+
754
+ ```js
755
+ // Das Licht in der Küche in einer Sekunde EINschalten
756
+ setStateDelayed('Kitchen.Light.Lamp', true, 1000);
757
+
758
+ // Das Licht in der Küche in 5 Sekunden AUSschalten und den ersten Timeout weiterlaufen lassen.
759
+ setStateDelayed('Kitchen.Light.Lamp', false, 5000, false, () => {
760
+ log('Lamp is OFF');
761
+ });
762
+ ```
763
+ Die Funktion gibt den Handler des Timers zurück, und dieser Timer kann mit clearStateDelayed einzeln gestoppt werden.
764
+
765
+ ### setStateChanged
766
+ ```js
767
+ await setStateChanged(id, state, ack);
768
+ ```
769
+ Wie setState, setzt den Wert aber nur, wenn er sich tatsächlich geändert hat.
770
+
771
+ ### setStateChangedAsync
772
+ ```js
773
+ await setStateChangedAsync(id, state, ack);
774
+ ```
775
+ Wie setStateChanged, aber mit `promise`.
776
+
777
+ ### clearStateDelayed
778
+ ```js
779
+ clearStateDelayed(id);
780
+ ```
781
+
782
+ Löscht alle verzögerten Aufgaben für die angegebene State-ID oder eine bestimmte verzögerte Aufgabe.
783
+
784
+ ```js
785
+ setStateDelayed('Kitchen.Light.Lamp', false, 10000); // Das Licht in der Küche in zehn Sekunden AUSschalten
786
+ let timer = setStateDelayed('Kitchen.Light.Lamp', true, 5000, false); // Das Licht in der Küche in fünf Sekunden EINschalten
787
+ clearStateDelayed('Kitchen.Light.Lamp', timer); // Es wird nichts eingeschaltet
788
+ clearStateDelayed('Kitchen.Light.Lamp'); // Alle laufenden verzögerten Aufgaben für diese ID löschen
789
+ ```
790
+
791
+ ### getStateDelayed
792
+ ```js
793
+ getStateDelayed(id);
794
+ ```
795
+
796
+ Dies ist ein synchroner Aufruf, der die Liste aller laufenden Timer (setStateDelayed) für diese ID liefert.
797
+ Man kann die Funktion auch ohne ID aufrufen und erhält dann die Timer für alle IDs.
798
+ Ruft man die Funktion für eine bestimmte Objekt-ID auf, erhält man folgende Antwort:
799
+
800
+ ```js
801
+ getStateDelayed('hm-rpc.0.LQE91119.1.STATE');
802
+
803
+ // liefert ein Array wie
804
+ [
805
+ { timerId: 1, left: 1123, delay: 5000, val: true, ack: false },
806
+ { timerId: 2, left: 12555, delay: 15000, val: false, ack: false },
807
+ ]
808
+ ```
809
+
810
+ Fragt man alle IDs ab, sieht die Antwort so aus:
811
+
812
+ ```js
813
+ getStateDelayed();
814
+
815
+ // liefert ein Objekt wie
816
+ {
817
+ 'hm-rpc.0.LQE91119.1.STATE': [
818
+ { timerId: 1, left: 1123, delay: 5000, val: true, ack: false },
819
+ { timerId: 2, left: 12555, delay: 15000, val: false, ack: false },
820
+ ],
821
+ 'hm-rpc.0.LQE91119.2.LEVEL': [
822
+ { timerId: 3, left: 5679, delay: 10000, val: 100, ack: false },
823
+ ],
824
+ }
825
+ ```
826
+
827
+ - `left` ist die verbleibende Zeit in Millisekunden
828
+ - `delay` ist der ursprüngliche Verzögerungswert in Millisekunden
829
+
830
+ Man kann auch direkt anhand der timerId abfragen. In diesem Fall lautet die Antwort:
831
+
832
+ ```js
833
+ getStateDelayed(3);
834
+
835
+ // liefert ein Objekt wie
836
+ { id: 'hm-rpc.0.LQE91119.2.LEVEL', left: 5679, delay: 10000, val: 100, ack: false }
837
+ ```
838
+
839
+ ### getState
840
+ ```js
841
+ getState(id);
842
+ ```
843
+
844
+ Liefert den State mit der angegebenen ID in folgender Form:
845
+
846
+ ```js
847
+ {
848
+ val: value,
849
+ ack: true/false,
850
+ ts: timestamp,
851
+ lc: lastchanged,
852
+ from: origin
853
+ }
854
+ ```
855
+
856
+ Existiert der State nicht, wird eine Warnung ins Log geschrieben und das Objekt `{ val: null, notExist: true }` zurückgegeben.
857
+ Um die Warnung zu vermeiden, sollte man vor dem Aufruf von getState prüfen, ob der State existiert (siehe [existsState](#existsstate)).
858
+
859
+ ### getStateAsync
860
+ ```js
861
+ const stateObject = await getStateAsync(id);
862
+ ```
863
+ Wie getState, aber mit `promise`.
864
+
865
+ ### existsState
866
+ ```js
867
+ existsState(id, (err, isExists) => {});
868
+ ```
869
+
870
+ Ist die Option "Nicht alle Zustände beim Start abonnieren" deaktiviert, kann man einen einfacheren Aufruf verwenden:
871
+
872
+ ```js
873
+ existsState(id)
874
+ ```
875
+ In diesem Fall gibt die Funktion true oder false zurück.
876
+
877
+ Prüft, ob ein State existiert.
878
+
879
+ ### getObject
880
+ ```js
881
+ getObject(id, enumName);
882
+ ```
883
+ Liefert die Beschreibung der Objekt-ID, wie sie im System gespeichert ist.
884
+ Man kann den Namen eines Enums angeben. Ist dieser angegeben, werden dem Ergebnis zwei zusätzliche Attribute hinzugefügt: enumIds und enumNames.
885
+ Diese Arrays enthalten alle Enums, in denen die ID Mitglied ist. Z. B.:
886
+
887
+ ```js
888
+ getObject('adapter.N.objectName', 'rooms');
889
+ ```
890
+
891
+ liefert in enumIds alle Räume, in denen das angefragte Objekt Mitglied ist. Gibt man "true" als enumName an, erhält man *alle* Enums zurück.
892
+
893
+ ### setObject
894
+ ```js
895
+ setObject(id, obj, callback);
896
+ ```
897
+ Schreibt ein Objekt in die DB. Dieses Kommando kann in den Einstellungen des Adapters deaktiviert werden. Die Funktion sollte vorsichtig verwendet werden, da sonst die globalen Einstellungen beschädigt werden können.
898
+
899
+ Man sollte sie verwenden, um ein vorhandenes, zuvor gelesenes Objekt zu **ändern**, z. B.:
900
+ ```js
901
+ const obj = getObject('adapter.N.objectName');
902
+ obj.native.settings = 1;
903
+ setObject('adapter.N.objectName', obj, (err) => {
904
+ if (err) log('Cannot write object: ' + err);
905
+ });
906
+ ```
907
+
908
+ ### existsObject
909
+ ```js
910
+ existsObject(id, function (err, isExists) {});
911
+ ```
912
+
913
+ Ist die Option "Nicht alle Zustände beim Start abonnieren" deaktiviert, kann man einen einfacheren Aufruf verwenden:
914
+
915
+ ```js
916
+ existsObject(id)
917
+ ```
918
+ In diesem Fall gibt die Funktion true oder false zurück.
919
+
920
+ Prüft, ob ein Objekt existiert.
921
+
922
+
923
+ ### extendObject
924
+ ```js
925
+ extendObject(id, obj, callback);
926
+ ```
927
+
928
+ Fast dasselbe wie `setObject`, allerdings wird das Objekt zuerst gelesen und dann versucht, alle Einstellungen zusammenzuführen.
929
+
930
+ Verwendung z. B. so:
931
+ ```js
932
+ // Instanz stoppen
933
+ extendObject('system.adapter.sayit.0', {common: {enabled: false}});
934
+ ```
935
+
936
+ ### deleteObject
937
+ ```js
938
+ deleteObject(id, isRecursive, callback);
939
+ ```
940
+
941
+ Löscht ein Objekt anhand der ID aus der DB. Hat das Objekt den Typ `state`, wird auch der State-Wert gelöscht.
942
+
943
+ Zusätzlich kann der Parameter `isRecursive` angegeben werden, dann werden auch alle Kindobjekte der angegebenen ID gelöscht. Sehr gefährlich!
944
+
945
+ Verwendung z. B. so:
946
+ ```js
947
+ // State löschen
948
+ deleteObject('javascript.0.createdState');
949
+ ```
950
+
951
+ *Hinweis: Die Option `isRecursive` ist nur mit js-controller >= 2.2.x verfügbar*
952
+
953
+ ### getIdByName
954
+ ```js
955
+ getIdByName(name, alwaysArray);
956
+ ```
957
+
958
+ Liefert die ID des Objekts mit dem angegebenen Namen.
959
+ Gibt es mehr als ein Objekt mit diesem Namen, ist das Ergebnis ein Array.
960
+ Ist das Flag `alwaysArray` gesetzt, ist das Ergebnis immer ein Array, sofern eine ID gefunden wurde.
961
+ ### getEnums
962
+ ```js
963
+ getEnums(enumName);
964
+ ```
965
+
966
+ Liefert die Liste der vorhandenen Enums mit ihren Mitgliedern, z. B.:
967
+
968
+ ```js
969
+ getEnums('rooms');
970
+
971
+ // liefert alle Räume, z. B.:
972
+ [
973
+ {
974
+ id: 'enum.rooms.LivingRoom',
975
+ members: [ 'hm-rpc.0.JEQ0024123.1', 'hm-rpc.0.BidCoS-RF.4' ],
976
+ name: 'Living room'
977
+ },
978
+ {
979
+ id: 'enum.rooms.Bath',
980
+ members: [ 'hm-rpc.0.JEQ0024124.1', 'hm-rpc.0.BidCoS-RF.5' ],
981
+ name: 'Bath'
982
+ }
983
+ ]
984
+
985
+ getEnums('functions');
986
+
987
+ // liefert alle Funktionen, z. B.:
988
+ [
989
+ {
990
+ id: 'enum.functions.light',
991
+ members: [
992
+ '0_userdata.0.AnotherOne',
993
+ '0_userdata.0.MyLigh'
994
+ ],
995
+ name: {
996
+ en: 'Light',
997
+ ru: 'Свет',
998
+ de: 'Licht',
999
+ fr: 'Lumière',
1000
+ it: 'Leggero',
1001
+ nl: 'Licht',
1002
+ pl: 'Lekki',
1003
+ pt: 'Luz',
1004
+ es: 'Luz',
1005
+ 'zh-cn': '光'
1006
+ }
1007
+ }
1008
+ ]
1009
+ ```
1010
+
1011
+ ### createState
1012
+ ```js
1013
+ createState(name, initialValue, forceCreation, common, native, callback);
1014
+ ```
1015
+ Legt State und Objekt im javascript-Namensraum an, falls sie nicht existieren, z. B. `javascript.0.mystate`.
1016
+
1017
+ !! Eigene States sollten bevorzugt mit der vollständigen ID `0_userdata.0.mystate` angelegt werden !!!
1018
+
1019
+ #### Parameter:
1020
+
1021
+ - `name`: Name des States ohne Namensraum, z. B. `mystate`
1022
+ - `initialValue`: Die Variable kann nach dem Anlegen initialisiert werden. Der Wert "undefined" bedeutet, dass der Wert nicht initialisiert wird.
1023
+ - `forceCreation`: State anlegen/überschreiben, unabhängig davon, ob der State bereits existiert oder nicht.
1024
+ - `common`: common-Beschreibung des Objekts, siehe Beschreibung [hier](https://github.com/ioBroker/ioBroker/blob/master/doc/SCHEMA.md#state)
1025
+ - `native`: native-Beschreibung eines Objekts. Beliebige spezifische Informationen.
1026
+ - `callback`: wird aufgerufen, nachdem der State angelegt und initialisiert wurde.
1027
+
1028
+ Setzt man in `common` das Flag `alias` auf `true`, wird ein Alias mit demselben Namen wie der State (aber im Namensraum `alias.0`) angelegt.
1029
+ Der Alias wird nur angelegt, wenn er noch nicht existiert.
1030
+
1031
+ Folgende Einstellungen für Aliase sind ebenfalls gültig:
1032
+ ```js
1033
+ common => {
1034
+ alias: {
1035
+ id: 'alias.0.myOtherState', // wird automatisch angelegt, falls noch nicht vorhanden
1036
+ write: 'val * 1000', // Umrechnungsfunktion für das Schreiben in den angelegten State
1037
+ read: 'val / 1000' // Umrechnungsfunktion für das Lesen aus dem angelegten State
1038
+ }
1039
+ }
1040
+ ```
1041
+
1042
+ oder
1043
+
1044
+ ```js
1045
+ common => {
1046
+ alias: {
1047
+ id: 'alias.0.myOtherState', // wird automatisch angelegt, falls noch nicht vorhanden
1048
+ }
1049
+ }
1050
+ ```
1051
+
1052
+ Es gibt auch Kurzformen von createState:
1053
+
1054
+ - `createState('myDatapoint')` - legt den State einfach an, falls er nicht existiert
1055
+ - `createState('myDatapoint', 1)` - legt den State an, falls er nicht existiert, und initialisiert ihn mit dem Wert 1
1056
+ - `createState('myDatapoint', { type: 'string', role: 'json', read: true, write: false }, () => { log('created'); });` - mit common-Definitionen wie type, read, write und role
1057
+ - `createState('myDatapoint', { name: 'My own datapoint', unit: '°C' }, () => { log('created'); });`
1058
+ - `createState('myDatapoint', 1, { name: 'My own datapoint', unit: '°C' })` - legt den State mit bestimmtem Namen und bestimmter Einheit an, falls er nicht existiert
1059
+
1060
+ #### Ein Objekt an zweiter Position ist immer das `common`
1061
+
1062
+ Diese Kurzformen sind der Grund, warum ein Objekt an zweiter Position **nie** als Initialwert
1063
+ gelesen wird. `createState('myDatapoint', {}, { type: 'object' })` macht daher nicht das, wonach es aussieht:
1064
+ Das `{}` wird zu `common`, und `{ type: 'object' }` rückt an die Stelle von `native`.
1065
+
1066
+ Um einem State einen Initialwert zu geben, der kein primitiver Wert ist, gibt man ihn in `common.def` an:
1067
+
1068
+ ```js
1069
+ createState('0_userdata.0.myObject', { name: 'My object', type: 'object', read: true, write: true, def: {} });
1070
+ ```
1071
+
1072
+ Ein State vom Typ `object`, `json` oder `array` speichert seinen Wert als JSON, daher beginnt der obige State
1073
+ mit dem String `'{}'` - genau so, wie `setState('0_userdata.0.myObject', {})` ihn speichern würde. Der Standardwert
1074
+ wird automatisch in einen String umgewandelt; `def: '{}'` selbst anzugeben funktioniert ebenso.
1075
+
1076
+ ### createStateAsync
1077
+ ```js
1078
+ await createStateAsync(name, initialValue, forceCreation, common, native);
1079
+ ```
1080
+
1081
+ Wie `createState`, aber es wird ein Promise zurückgegeben.
1082
+
1083
+ ### deleteState
1084
+ ```js
1085
+ deleteState(name, callback);
1086
+ ```
1087
+ Löscht State und Objekt im javascript-Namensraum, z. B. `javascript.0.mystate`. States anderer Adapter können nicht gelöscht werden.
1088
+
1089
+ ```js
1090
+ deleteState('myDatapoint')
1091
+ ```
1092
+ löscht den State einfach, falls er existiert.
1093
+
1094
+ ### deleteStateAsync
1095
+ ```js
1096
+ await deleteStateAsync(name);
1097
+ ```
1098
+
1099
+ Wie `deleteState`, aber es wird ein Promise zurückgegeben.
1100
+
1101
+ ### createAlias
1102
+ ```js
1103
+ createAlias(name, alias, forceCreation, common, native, callback);
1104
+ ```
1105
+
1106
+ Legt einen Alias im Namensraum `alias.0` an, falls er nicht existiert, z. B. `javascript.0.myalias`, der auf einen State oder auf States zum Lesen/Schreiben verweist.
1107
+ Die common-Definition wird aus dem Objekt der Lese-Alias-ID übernommen, ein übergebenes common hat jedoch Vorrang.
1108
+
1109
+ #### Parameter:
1110
+
1111
+ - `name`: ID des neuen Alias-States (auch ohne Alias-Namensraum möglich), z. B. `test.mystate` (der Namensraum `alias.0.` wird ergänzt = `alias.0.test.mystate`)
1112
+ - `alias`: kann entweder eine vorhandene State-ID als String sein oder ein Objekt mit vollständiger Alias-Definition inklusive Lese-/Schreib-IDs und Lese-/Schreibfunktionen. Hinweis: Alias-Definitionen können nicht als Teil des Parameters common gesetzt werden!
1113
+ - `forceCreation`: Alias anlegen/überschreiben, unabhängig davon, ob der State bereits existiert oder nicht.
1114
+ - `common`: common-Beschreibung des Alias-Objekts, siehe Beschreibung [hier](https://github.com/ioBroker/ioBroker/blob/master/doc/SCHEMA.md#state). Hier angegebene Werte haben Vorrang vor der common-Definition des Objekts der Lese-Alias-ID. Hinweis: Alias-Definitionen können nicht als Teil dieses common-Parameters gesetzt werden, siehe Parameter alias!
1115
+ - `native`: native-Beschreibung eines Objekts. Beliebige spezifische Informationen.
1116
+ - `callback`: wird aufgerufen, nachdem der State angelegt und initialisiert wurde.
1117
+
1118
+ Es gibt auch Kurzformen von createAlias:
1119
+
1120
+ - `createAlias('myAlias', 'myDatapoint')` - legt einfach alias.0.myAlias an, das auf javascript.X.myDatapoint verweist, falls es nicht existiert
1121
+ - `createAlias('myAlias', { id: { read: 'myReadDatapoint', write: 'myWriteDatapoint' }})` - legt einen Alias an, der auf unterschiedliche States zum Lesen/Schreiben verweist
1122
+
1123
+ Weitere Details siehe createState, die Funktion arbeitet ähnlich.
1124
+
1125
+ ### createAliasAsync
1126
+ ```js
1127
+ await createAliasAsync(name, alias, forceCreation, common, native);
1128
+ ```
1129
+
1130
+ Wie `createAlias`, aber es wird ein Promise zurückgegeben.
1131
+ ### sendTo
1132
+ ```js
1133
+ sendTo(adapter, command, message, callback);
1134
+ sendTo(adapter, command, message, options, callback);
1135
+ ```
1136
+
1137
+ Sendet eine Nachricht an eine bestimmte oder an alle Instanzen eines Adapters. Wird nur der Adaptername angegeben, wird die Nachricht an alle Instanzen gesendet.
1138
+
1139
+ Welche Nachrichten konkret unterstützt werden, ist in der Dokumentation des jeweiligen Adapters beschrieben.
1140
+
1141
+ Beispiel (mit benutzerdefiniertem Timeout):
1142
+
1143
+ ```js
1144
+ sendTo('telegram', { user: 'UserName', text: 'Test message' }, { timeout: 2000 });
1145
+ ```
1146
+
1147
+ Einige Adapter unterstützen auch Antworten auf die gesendeten Nachrichten (z. B. history, sql, telegram).
1148
+ Die Antwort wird nur dann an den Callback zurückgegeben, wenn die Nachricht an eine bestimmte Instanz gesendet wird!
1149
+
1150
+ Beispiel (mit Callback):
1151
+
1152
+ ```js
1153
+ sendTo('telegram.0', { user: 'UserName', text: 'Test message' }, (res) => {
1154
+ log(`Sent to ${res} users`);
1155
+ });
1156
+ ```
1157
+
1158
+ *Der Standard-Timeout beträgt 20000 Millisekunden (sofern eine Callback-Funktion angegeben wurde)*
1159
+
1160
+ ```js
1161
+ sendTo('telegram.0', { user: 'UserName', text: 'Test message' }, { timeout: 2000 }, (res) => {
1162
+ log(`Sent to ${res} users`);
1163
+ });
1164
+ ```
1165
+
1166
+ ### sendToAsync
1167
+ ```js
1168
+ await sendToAsync(adapter, command, message);
1169
+ await sendToAsync(adapter, command, message, options);
1170
+ ```
1171
+ Wie sendTo, jedoch mit `promise`.
1172
+
1173
+ Beispiel:
1174
+
1175
+ ```js
1176
+ const res = await sendToAsync('sql.0', 'getEnabledDPs', {});
1177
+ log(JSON.stringify(res));
1178
+ ```
1179
+
1180
+ ### sendToHost
1181
+ ```js
1182
+ sendToHost(hostName, command, message, callback);
1183
+ ```
1184
+
1185
+ Sendet eine Nachricht an die Controller-Instanz.
1186
+
1187
+ Die folgenden Kommandos werden unterstützt:
1188
+ - `'cmdExec'`
1189
+ - `'getRepository'`
1190
+ - `'getInstalled'`
1191
+ - `'getVersion'`
1192
+ - `'getDiagData'`
1193
+ - `'getLocationOnDisk'`
1194
+ - `'getDevList'`
1195
+ - `'getLogs'`
1196
+ - `'getLogFile'`
1197
+ - `'getLogFiles'`
1198
+ - `'delLogs'`
1199
+ - `'getHostInfo'`
1200
+ - `'getHostInfoShort'`
1201
+ - `'updateMultihost'`
1202
+ - `'upgradeController'` - Aktualisiert den js-controller auf die neueste Version
1203
+ - `'getInterfaces'` - Liefert alle verfügbaren Netzwerkschnittstellen des Systems
1204
+ - `'upload'` - Startet einen Adapter-Upload
1205
+ - `'rebuildAdapter'`
1206
+ - `'readBaseSettings'`
1207
+ - `'writeBaseSettings'`
1208
+ - `'addNotification'`
1209
+ - `'clearNotifications'`
1210
+ - `'getNotifications'`
1211
+ - `'updateLicenses'` - Liest die Lizenzen von iobroker.net
1212
+ - `'upgradeOsPackages'`
1213
+ - `'restartController'`
1214
+
1215
+ Dabei handelt es sich um recht spezielle Kommandos, die nur selten benötigt werden.
1216
+
1217
+ Beispiel:
1218
+
1219
+ ```js
1220
+ sendToHost('myComputer', 'cmdExec', { data: 'ls /' }, (res) => {
1221
+ log('List of files: ' + res.data);
1222
+ });
1223
+ ```
1224
+
1225
+ **Hinweis:** Um diese Funktion aufzurufen, muss die Option *Kommando "sendToHost" erlauben* aktiviert sein.
1226
+
1227
+ ### sendToHostAsync
1228
+ ```js
1229
+ await sendToHostAsync(hostName, command, message);
1230
+ ```
1231
+ Wie sendToHost, jedoch mit `promise`.
1232
+
1233
+ ### setInterval
1234
+ ```js
1235
+ setInterval(callback, ms, arg1, arg2, arg3, arg4);
1236
+ ```
1237
+
1238
+ Wie `setInterval` in JavaScript.
1239
+
1240
+ ### clearInterval
1241
+ ```js
1242
+ clearInterval(id);
1243
+ ```
1244
+
1245
+ Wie `clearInterval` in JavaScript.
1246
+
1247
+ ### setTimeout
1248
+ ```js
1249
+ setTimeout(callback, ms, arg1, arg2, arg3, arg4);
1250
+ ```
1251
+ Wie `setTimeout` in JavaScript.
1252
+
1253
+ ### clearTimeout
1254
+ ```js
1255
+ clearTimeout(id);
1256
+ ```
1257
+
1258
+ Wie `clearTimeout` in JavaScript.
1259
+
1260
+ ### setImmediate
1261
+ ```js
1262
+ setImmediate(callback, arg1, arg2, arg3, arg4);
1263
+ ```
1264
+
1265
+ Wie `setImmediate` in JavaScript und nahezu identisch mit `setTimeout(callback, 0, arg1, arg2, arg3, arg4)`, jedoch mit höherer Priorität.
1266
+
1267
+ ### formatDate
1268
+ ```js
1269
+ formatDate(millisecondsOrDate, format);
1270
+ ```
1271
+
1272
+ #### Parameter:
1273
+
1274
+ - `millisecondsOrDate`: Anzahl der Millisekunden aus state.ts oder state.lc (Millisekunden seit 1970.01.01 00:00:00), ein JavaScript-Objekt *new Date()* oder die Anzahl der Millisekunden aus *(new Date().getTime())*
1275
+ - `format`: Kann `null` sein, dann wird das Zeitformat des Systems verwendet, andernfalls
1276
+
1277
+ * YYYY, JJJJ, ГГГГ - Jahr vierstellig, z. B. 2015
1278
+ * YY, JJ, ГГ - Jahr zweistellig, z. B. 15
1279
+ * MM, ММ(kyrillisch) - Monat zweistellig, z. B. 01
1280
+ * M, М(kyrillisch) - Monat ohne führende Null, z. B. 1
1281
+ * DD, TT, ДД - Tag zweistellig, z. B. 02
1282
+ * D, T, Д - Tag ohne führende Null, z. B. 2
1283
+ * hh, SS, чч - Stunden zweistellig, z. B. 03
1284
+ * h, S, ч - Stunden ohne führende Null, z. B. 3
1285
+ * mm, мм(kyrillisch) - Minuten zweistellig, z. B. 04
1286
+ * m, м(kyrillisch) - Minuten ohne führende Null, z. B. 4
1287
+ * ss, сс(kyrillisch) - Sekunden zweistellig, z. B. 05
1288
+ * s, с(kyrillisch) - Sekunden ohne führende Null, z. B. 5
1289
+ * sss, ссс(kyrillisch) - Millisekunden
1290
+ * WW, НН(kyrillisch) - Wochentag ausgeschrieben als Text
1291
+ * W, Н(kyrillisch) - Wochentag abgekürzt als Text
1292
+ * OO, ОО(kyrillisch) - Monatsname ausgeschrieben
1293
+ * OOO, ООО(kyrillisch) - Monatsname ausgeschrieben im Genitiv
1294
+ * O, О(kyrillisch) - Monatsname abgekürzt
1295
+
1296
+ #### Beispiel
1297
+
1298
+ ```js
1299
+ formatDate(new Date(), "YYYY-MM-DD") // => Datum "2015-02-24"
1300
+ formatDate(new Date(), "hh:mm") // => Stunden und Minuten "17:41"
1301
+ formatDate(state.ts) // => "24.02.2015"
1302
+ formatDate(state.ts, "JJJJ.MM.TT SS:mm:ss.sss") // => "2015.02.15 17:41:98.123"
1303
+ formatDate(new Date(), "WW") // => Wochentag "Tuesday"
1304
+ formatDate(new Date(), "W") // => Wochentag "Tu"
1305
+ ```
1306
+
1307
+ ### formatTimeDiff
1308
+ ```js
1309
+ formatTimeDiff(milliseconds, format);
1310
+ ```
1311
+
1312
+ #### Parameter:
1313
+
1314
+ - `milliseconds`: Differenz in Millisekunden*
1315
+ - `format`: Kann `null` sein, dann wird das Format `hh:mm:ss` verwendet, andernfalls
1316
+
1317
+ * DD, TT, ДД - Tage zweistellig, z. B. "02"
1318
+ * D, T, Д - Tage ohne führende Null, z. B. "2"
1319
+ * hh, SS, чч - Stunden zweistellig, z. B. "03"
1320
+ * h, S, ч - Stunden ohne führende Null, z. B. "3"
1321
+ * mm, мм(kyrillisch) - Minuten zweistellig, z. B. "04"
1322
+ * m, м(kyrillisch) - Minuten ohne führende Null, z. B. "4"
1323
+ * ss, сс(kyrillisch) - Sekunden zweistellig, z. B. "05"
1324
+ * s, с(kyrillisch) - Sekunden ohne führende Null, z. B. "5"
1325
+
1326
+ Mit dem Escape-Zeichen `\` lässt sich die Ersetzung verhindern, z. B. `DD \Day\s, h \hour\s, m \minute, ss \second\s`
1327
+
1328
+ #### Beispiel
1329
+
1330
+ ```js
1331
+ formatTimeDiff(60000, "mm:ss") // => "01:00"
1332
+
1333
+ const diff = 172800000 + 10800000 + 540000 + 15000; // 2 Tage, 3 Stunden, 9 Minuten + 15 Sekunden
1334
+ formatTimeDiff(diff); // "51:09:15"
1335
+ formatTimeDiff(diff, 'DD hh:mm'); // "02 03:09"
1336
+ formatTimeDiff(diff, 'D hh:mm'); // "2 03:09"
1337
+ formatTimeDiff(diff, 'hh:mm:ss'); // "51:09:15"
1338
+ formatTimeDiff(diff, 'h:m:s'); // "51:9:15"
1339
+ formatTimeDiff(diff, 'hh:mm'); // "51:09"
1340
+ formatTimeDiff(diff, 'mm:ss'); // "3069:15"
1341
+ formatTimeDiff(diff, 'hh'); // "51"
1342
+ formatTimeDiff(diff, 'mm'); // "3069"
1343
+ ```
1344
+
1345
+ ### getDateObject
1346
+ ```js
1347
+ getDateObject(stringOrNumber);
1348
+ ```
1349
+
1350
+ Wandelt einen String oder eine Zahl in ein Date-Objekt um.
1351
+ Wird nur die Uhrzeit angegeben, wird das aktuelle Datum ergänzt und anschließend die Umwandlung versucht.
1352
+
1353
+ ```js
1354
+ getDateObject('20:00'); // 2024-05-18T18:00:00.000Z
1355
+ getDateObject('2024-01-01'); // 2024-01-01T00:00:00.000Z
1356
+ ```
1357
+
1358
+ ### formatValue
1359
+ ```js
1360
+ formatValue(value, decimals, format);
1361
+ ```
1362
+
1363
+ Formatiert einen beliebigen Wert (auch Strings) als Zahl. Ersetzt den Punkt durch ein Komma, wenn dies im System so konfiguriert ist.
1364
+ Decimals gibt die Anzahl der Nachkommastellen an. Der Standardwert ist 2.
1365
+ Format ist optional:
1366
+ - '.,': 1234.567 => 1.234,56
1367
+ - ',.': 1234.567 => 1,234.56
1368
+ - ' .': 1234.567 => 1 234.56
1369
+
1370
+
1371
+ ### adapterSubscribe
1372
+ ```js
1373
+ adapterSubscribe(id);
1374
+ ```
1375
+
1376
+ Sendet an einen Adapter die Nachricht "subscribe", um den Adapter zu informieren. Hat der Adapter in common das Flag "subscribable", wird diese Funktion bei "subscribe" automatisch aufgerufen.
1377
+
1378
+ ### adapterUnsubscribe
1379
+ ```js
1380
+ adapterUnsubscribe(id);
1381
+ ```
1382
+
1383
+ Sendet an einen Adapter die Nachricht `unsubscribe`, um den Adapter zu informieren, dass er die Werte nicht mehr abfragen soll.
1384
+
1385
+ ### $ - Selektor
1386
+ ```js
1387
+ $(selector).on((obj) => {}); // Registriert ein Abonnement für jeden passenden State
1388
+ $(selector).toArray(); // Liefert alle zum Selektor-Ausdruck passenden Objekt-IDs (erfordert Version >= 8.2.0)
1389
+ $(selector).each((id, i) => {}); // Iteriert über alle passenden States
1390
+ $(selector).setState(value, ack, callback); // Setzt den State-Wert aller passenden Objekt-IDs (Callback ist optional)
1391
+ $(selector).setStateAsync(value, ack); // Setzt den State-Wert aller passenden Objekt-IDs - gibt ein Promise zurück
1392
+ $(selector).setStateChanged(value, ack, callback); // Setzt den State-Wert aller passenden Objekt-IDs, falls sich der Wert geändert hat (Callback ist optional)
1393
+ $(selector).setStateChangedAsync(value, ack, callback); // Setzt den State-Wert aller passenden Objekt-IDs, falls sich der Wert geändert hat - gibt ein Promise zurück
1394
+ $(selector).setStateDelayed(state, isAck, delay, clearRunning, callback); // Setzt den State-Wert aller passenden Objekt-IDs mit der angegebenen Verzögerung
1395
+ $(selector).getState(); // Liefert alle States
1396
+ $(selector).getStateAsync(); // Liefert alle States - gibt ein Promise zurück
1397
+ ```
1398
+
1399
+ Format des Selektors:
1400
+ ```js
1401
+ "name[commonAttr=something1](enumName=something2){nativeName=something3}[id=idfilter][state.id=idfilter]"
1402
+ ```
1403
+
1404
+ name kann sein: state, channel, device oder schedule
1405
+ `idfilter` kann Platzhalter '*' enthalten
1406
+
1407
+ Präfixe ***(nicht implementiert - sollte diskutiert werden)*** :
1408
+
1409
+ * \# - nach Name statt nach ID auswählen
1410
+ * . - nach Rolle filtern
1411
+ * § - nach Raum filtern
1412
+
1413
+ ***Beispiel***:
1414
+
1415
+ - `$('state[id=*.STATE]')` oder `$('state[state.id=*.STATE]')` oder `$('*.STATE')` - wählt alle States aus, deren ID auf ".STATE" endet.
1416
+ - `$('state[id='hm-rpc.0.*]')` oder `$('hm-rpc.0.*')` - liefert alle States der Adapterinstanz hm-rpc.0
1417
+ - `$('channel(rooms=Living room)')` - alle States im Raum "Living room"
1418
+ - `$('channel{TYPE=BLIND}[state.id=*.LEVEL]')` - liefert alle Rollläden von Homematic
1419
+ - `$('channel[role=switch](rooms=Living room)[state.id=*.STATE]').setState(false)` - schaltet alle States mit .STATE von Kanälen mit der Rolle "switch" im Raum "Living room" auf false
1420
+ - `$('channel[state.id=*.STATE](functions=Windows)').each(function (id, i) {log(id);});` - gibt alle States des Enums "windows" im Log aus
1421
+ - `$('schedule[id=*65]').each(function (id, i) {log(id);});` - gibt alle Zeitpläne aus, deren ID auf 65 endet
1422
+ - `$('.switch §"Living room")` - nimmt die States aller Schalter im Raum 'Living room' ***(nicht implementiert - sollte diskutiert werden)***
1423
+ - `$('channel .switch §"Living room")` - nimmt die States aller Schalter im Raum 'Living room' ***(nicht implementiert - sollte diskutiert werden)***
1424
+
1425
+ ***Erklärung***
1426
+ Als Beispiel dient folgender Code:
1427
+ ```js
1428
+ $('channel[role=switch][state.id=*.STATE](rooms=Wohnzimmer)').on(obj => {
1429
+ log('New state ' + obj.id + ' = ' + obj.state.val);
1430
+ });
1431
+ ```
1432
+
1433
+ Dieser Code sucht in Kanälen.
1434
+ Er findet alle Kanäle mit `common.role="switch"`, die zu `enum.rooms.Wohnzimmer` gehören.
1435
+ Von diesen Kanälen werden alle States genommen, deren ID auf `".STATE"` endet, und alle diese States werden abonniert.
1436
+ Ändert sich einer dieser States, wird der Callback wie bei der Funktion "on" aufgerufen.
1437
+
1438
+ Folgende Funktionen sind möglich: setState, getState (nur vom ersten), on, each, toArray
1439
+
1440
+ ```js
1441
+ // Alle Schalter im "Wohnzimmer" einschalten
1442
+ $('channel[role=switch][state.id=*.STATE](rooms=Wohnzimmer)').setState(true);
1443
+ ```
1444
+
1445
+ Die "each"-Schleife lässt sich abbrechen, indem man false zurückgibt, z. B.:
1446
+ ```js
1447
+ // Die ersten zwei IDs aller Schalter im "Wohnzimmer" ausgeben
1448
+ $('channel[role=switch][state.id=*.STATE](rooms=Wohnzimmer)').each((id, i) => {
1449
+ log(id);
1450
+ if (i == 1) {
1451
+ return false;
1452
+ }
1453
+ });
1454
+ ```
1455
+ Alternativ kann man ein gewöhnliches Array der IDs abrufen und es beliebig weiterverarbeiten:
1456
+ ```js
1457
+ // States holen und nur diejenigen mit dem Wert `true` herausfiltern
1458
+ const enabled = $('channel[role=switch][state.id=*.STATE](rooms=Wohnzimmer)').toArray().filter((id) => getState(id)?.val === true);
1459
+ ```
1460
+
1461
+ ### readFile
1462
+ ```js
1463
+ readFile(adapter, fileName, (error, bytes) => {});
1464
+ ```
1465
+
1466
+ Das Ergebnis wird im Callback übergeben.
1467
+ Liest eine Datei aus der DB aus dem Ordner `javascript.0`.
1468
+
1469
+ Das Argument *adapter* kann weggelassen werden.
1470
+
1471
+ ```js
1472
+ // vis-Views lesen
1473
+ readFile('vis.0', '/main/vis-views.json', (error, data) => {
1474
+ log(data.substring(0, 50));
1475
+ });
1476
+
1477
+ // Dasselbe wie
1478
+ //readFile('/../vis.0/main/vis-views.json', (error, data) => {
1479
+ // log(data.substring(0, 50));
1480
+ //});
1481
+ ```
1482
+
1483
+ Standardmäßig ist das Arbeitsverzeichnis/der Adapter `javascript.0`.
1484
+
1485
+ ### writeFile
1486
+ ```js
1487
+ writeFile(adapter, fileName, bytes, (error) => {});
1488
+ ```
1489
+
1490
+ Der optionale Fehlercode wird im Callback übergeben. Das Argument *adapter* kann weggelassen werden.
1491
+ fileName ist der Name der Datei in der DB. Alle Dateien werden im Ordner "javascript" gespeichert.
1492
+ Um in andere Ordner zu schreiben, z. B. nach "/vis.0/", verwendet man setFile.
1493
+
1494
+ Eine Datei wie `'/subfolder/file.txt'` wird unter `"/javascript/subfolder/file.txt"` gespeichert und ist über den Webserver unter `"http://ip:8082/javascript/subfolder/file.txt"` erreichbar.
1495
+
1496
+ ```js
1497
+ // Screenshot in der DB speichern
1498
+ const fs = require('node:fs');
1499
+ let data = fs.readFileSync('/tmp/screenshot.png');
1500
+ writeFile(null, '/screenshots/1.png', data, (error) => {
1501
+ log('file written');
1502
+ });
1503
+
1504
+ // Dasselbe wie
1505
+ //writeFile('/screenshots/1.png', data, function (error) {
1506
+ // log('file written');
1507
+ //});
1508
+ ```
1509
+
1510
+ ```js
1511
+ // Datei in '/vis.0' in der DB speichern
1512
+ const fs = require('node:fs');
1513
+ let data = fs.readFileSync('/tmp/screenshot.png');
1514
+ writeFile('vis.0', '/screenshots/1.png', data, (error) => {
1515
+ log('file written');
1516
+ });
1517
+ ```
1518
+
1519
+ ### delFile
1520
+ ```js
1521
+ delFile(adapter, fileName, (error) => {});
1522
+ ```
1523
+
1524
+ Löscht eine Datei oder ein Verzeichnis. fileName ist der Name der Datei oder des Verzeichnisses in der DB.
1525
+
1526
+ Der alternative Name dieser Methode ist `unlink`
1527
+
1528
+ ### renameFile
1529
+ ```js
1530
+ renameFile(adapter, oldName, newName, (error) => {});
1531
+ ```
1532
+
1533
+ Benennt eine Datei oder ein Verzeichnis um. oldName ist der Name der Datei oder des Verzeichnisses in der DB, der in newName umbenannt wird.
1534
+
1535
+ Der alternative Name dieser Methode ist `rename`
1536
+
1537
+ ### onFile
1538
+ ```js
1539
+ onFile(id, fileName, withFile, (id, fileName, size, fileData, mimeType) => {});
1540
+ // oder
1541
+ onFile(id, fileName, (id, fileName, size) => {});
1542
+ ```
1543
+
1544
+ Abonniert Dateiänderungen:
1545
+ - `id` ist die ID eines Objekts vom Typ `meta`, z. B. `vis.0`
1546
+ - `fileName` ist ein Dateiname oder ein Muster, z. B. `main/*` oder `main/vis-view.json`
1547
+ - `withFile` gibt an, ob der Dateiinhalt im Callback übergeben werden soll oder nicht. Die Übergabe des Dateiinhalts kostet Speicher und Zeit; möchte man nur über Änderungen informiert werden, setzt man `withFile` auf false.
1548
+
1549
+ Argumente im Callback:
1550
+ - `id` - ID des `meta`-Objekts;
1551
+ - `fileName` - Dateiname (kein Muster);
1552
+ - `size` - neue Dateigröße;
1553
+ - `fileData` - Dateiinhalt vom Typ `Buffer`, wenn die Datei binär ist (anhand der Dateiendung erkannt), sonst `string`. Wird nur bei `withFile` übergeben;
1554
+ - `mimeType` - MIME-Typ der Datei, z. B. `image/jpeg`. Wird nur bei `withFile` übergeben;
1555
+
1556
+ **Wichtig**: Diese Funktionalität ist nur mit js-controller@4.1.x oder neuer verfügbar.
1557
+
1558
+ ### offFile
1559
+ ```js
1560
+ offFile(id, fileName);
1561
+ // oder
1562
+ onFile(id, fileName);
1563
+ ```
1564
+ Beendet das Abonnement von Dateiänderungen:
1565
+ - `id` ist die ID eines Objekts vom Typ `meta`, z. B. `vis.0`
1566
+ - `fileName` ist ein Dateiname oder ein Muster, z. B. `main/*` oder `main/vis-view.json`
1567
+
1568
+ **Wichtig**: Diese Funktionalität ist nur mit js-controller@4.1.x oder neuer verfügbar.
1569
+
1570
+ ### onStop
1571
+ ```js
1572
+ onStop (() => { /* etwas tun, wenn das Skript gestoppt wird */ }, timeout);
1573
+ ```
1574
+ Registriert einen Callback, der aufgerufen wird, wenn das Skript gestoppt wird. Wird z. B. verwendet, um die Kommunikation zu beenden oder Verbindungen zu schließen.
1575
+
1576
+ ```js
1577
+ // Verbindung aufbauen
1578
+ const conn = require('net');
1579
+ // ...
1580
+
1581
+ // Verbindung schließen, wenn das Skript gestoppt wird
1582
+ onStop((callback) => {
1583
+ if (conn) {
1584
+ // Verbindung schließen
1585
+ conn.destroy();
1586
+ }
1587
+ callback();
1588
+ }, 2000 /*ms*/);
1589
+ ```
1590
+ `timeout` beträgt standardmäßig 1000 ms.
1591
+
1592
+ ### getHistory
1593
+ ```js
1594
+ getHistory(instance, options, (error, result, options, instance) => {});
1595
+ ```
1596
+
1597
+ Liest die Historie aus der angegebenen Instanz. Ist keine Instanz angegeben, wird die im System eingestellte Standard-Historieninstanz verwendet.
1598
+ ```js
1599
+ // Historie von 'system.adapter.admin.0.memRss' aus dem SQL-Treiber lesen
1600
+ const end = new Date().getTime();
1601
+ getHistory(
1602
+ 'sql.0',
1603
+ {
1604
+ id: 'system.adapter.admin.0.memRss',
1605
+ start: end - 3600000,
1606
+ end: end,
1607
+ aggregate: 'm4',
1608
+ timeout: 2000
1609
+ },
1610
+ (err, result) => {
1611
+ if (err) console.error(err);
1612
+ if (result) {
1613
+ for (let i = 0; i < result.length; i++) {
1614
+ log(result[i].id + ' ' + new Date(result[i].ts).toISOString());
1615
+ }
1616
+ }
1617
+ }
1618
+ );
1619
+ ```
1620
+
1621
+ Die möglichen Optionen sind [hier](https://github.com/ioBroker/ioBroker.history#access-values-from-javascript-adapter) beschrieben.
1622
+
1623
+ Zusätzlich zu diesen Parametern muss "id" angegeben werden, optional kann auch timeout angegeben werden (Standard: 20000 ms).
1624
+
1625
+ Ein weiteres Beispiel:
1626
+ ```js
1627
+ // Die letzten 50 Einträge aus der Standard-Historieninstanz ohne Aggregation abrufen:
1628
+ getHistory({
1629
+ id: 'system.adapter.admin.0.alive',
1630
+ aggregate: 'none',
1631
+ count: 50
1632
+ }, (err, result) => {
1633
+ if (err) console.error(err);
1634
+ if (result) {
1635
+ for (let i = 0; i < result.length; i++) {
1636
+ log(result[i].id + ' ' + new Date(result[i].ts).toISOString());
1637
+ }
1638
+ }
1639
+ });
1640
+ ```
1641
+
1642
+ **Hinweis: ** Selbstverständlich muss die Historie für die gewählte ID zuerst im Admin aktiviert werden.
1643
+ ### runScript
1644
+ ```js
1645
+ runScript('scriptName', () => {
1646
+ // Callback ist optional
1647
+ log('Srcipt started, but not yet executed');
1648
+ });
1649
+ ```
1650
+
1651
+ Startet andere Skripte (und auch sich selbst) anhand des Namens bzw. startet sie neu.
1652
+
1653
+ ```js
1654
+ // Skript neu starten
1655
+ runScript('groupName.scriptName1');
1656
+ ```
1657
+
1658
+ ### runScriptAsync
1659
+ Wie runScript, aber mit `promise`.
1660
+ ```js
1661
+ runScriptAsync('scriptName')
1662
+ .then(() => log('Script started, but not yet executed'));
1663
+
1664
+ // oder
1665
+
1666
+ await runScriptAsync('scriptName');
1667
+ log(`Script was restarted`);
1668
+ ```
1669
+
1670
+ ### startScript
1671
+ ```js
1672
+ startScript('scriptName', ignoreIfStarted, callback);
1673
+ ```
1674
+
1675
+ Startet das Skript. Wenn ignoreIfStarted auf true gesetzt ist, passiert nichts, falls das Skript bereits läuft, andernfalls wird das Skript neu gestartet.
1676
+
1677
+ ```js
1678
+ startScript('scriptName', true); // Skript starten, falls es nicht gestartet ist
1679
+ ```
1680
+
1681
+ ### startScriptAsync
1682
+ Wie startScript, aber mit `promise`.
1683
+
1684
+ ```js
1685
+ startScriptAsync('scriptName', ignoreIfStarted)
1686
+ .then(started => log(`Script was ${started ? 'started' : 'already started'}`));
1687
+
1688
+ // oder
1689
+
1690
+ const started = await startScriptAsync('scriptName', ignoreIfStarted);
1691
+ log(`Script was ${started ? 'started' : 'already started'}`);
1692
+ ```
1693
+
1694
+ Startet das Skript. Wenn ignoreIfStarted auf true gesetzt ist, passiert nichts, falls das Skript bereits läuft, andernfalls wird das Skript neu gestartet.
1695
+
1696
+ ```js
1697
+ startScript('scriptName', true); // Skript starten, falls es nicht gestartet ist
1698
+ ```
1699
+
1700
+ ### stopScript
1701
+ ```js
1702
+ stopScript('scriptName', callback);
1703
+ ```
1704
+
1705
+ Wenn stopScript ohne Argumente aufgerufen wird, stoppt sich das Skript selbst:
1706
+
1707
+ ```js
1708
+ stopScript();
1709
+ ```
1710
+
1711
+ ### stopScriptAsync
1712
+ Wie stopScript, aber mit `promise`:
1713
+ ```js
1714
+ stopScriptAsync('scriptName')
1715
+ .then(stopped => log(`Script was ${stopped ? 'stopped' : 'already stopped'}`));
1716
+
1717
+ // oder
1718
+ const stopped = await stopScriptAsync('scriptName');
1719
+ log(`Script was ${stopped ? 'stopped' : 'already stopped'}`);
1720
+ ```
1721
+
1722
+ Wenn stopScript ohne Argumente aufgerufen wird, stoppt sich das Skript selbst:
1723
+
1724
+ ```js
1725
+ stopScript();
1726
+ ```
1727
+
1728
+ ### isScriptActive
1729
+ ```js
1730
+ isScriptActive('scriptName');
1731
+ ```
1732
+
1733
+ Gibt zurück, ob ein Skript aktiviert oder deaktiviert ist. Dabei ist zu beachten, dass damit nicht angegeben wird, ob das Skript gerade läuft oder nicht.
1734
+ Das Skript kann beendet, aber dennoch aktiviert sein.
1735
+
1736
+ Es ist keine Funktion. Es ist eine Variable mit der JavaScript-Instanz, die im Gültigkeitsbereich des Skripts sichtbar ist.
1737
+
1738
+ ### toInt
1739
+ ### toFloat
1740
+ ### toBoolean
1741
+ ### jsonataExpression
1742
+
1743
+ ### wait
1744
+ Pausiert einfach die Ausführung des Skripts.
1745
+ Achtung: Diese Funktion ist ein `promise` und muss wie folgt aufgerufen werden:
1746
+ ```js
1747
+ await wait(1000);
1748
+ ```
1749
+
1750
+ ### sleep
1751
+ Wie [wait](#wait)
1752
+
1753
+ ### messageTo
1754
+ ```js
1755
+ messageTo({ instance: 'instance', script: 'script.js.common.scriptName', message: 'messageName' }, data, { timeout: 1000 }, result =>
1756
+ log(JSON.stringify(result)));
1757
+ ```
1758
+
1759
+ Sendet die Nachricht über den "Nachrichtenbus" an ein anderes Skript. Oder sogar an einen Handler im selben Skript.
1760
+
1761
+ Das Timeout für den Callback beträgt standardmäßig 5 Sekunden.
1762
+
1763
+ Das Ziel kann verkürzt werden zu:
1764
+
1765
+ ```js
1766
+ messageTo('messageName', data, (result) => {
1767
+ log(JSON.stringify(result));
1768
+ });
1769
+ ```
1770
+
1771
+ Callback und Optionen sind optional, das Timeout beträgt standardmäßig 5000 Millisekunden (falls ein Callback angegeben ist).
1772
+
1773
+ ```js
1774
+ messageTo('messageName', dataWithNoResponse);
1775
+ ```
1776
+
1777
+ ### messageToAsync
1778
+ ```js
1779
+ onMessage('myTopic', async (data, callback) => {
1780
+ log(data);
1781
+
1782
+ if (!data.myPayload) {
1783
+ // Fehler zurückgeben (Promise reject)
1784
+ callback({ error: 'something went wrong!!' });
1785
+ } else {
1786
+ // Ergebnis zurückgeben (Promise resolve)
1787
+ callback({ result: 'ok' });
1788
+ }
1789
+ });
1790
+
1791
+ (async () => {
1792
+ try {
1793
+ const msg = await messageToAsync({ instance: 0, script: 'script.js.test2', message: 'myTopic' }, { myPayload: true }, { timeout: 1000 });
1794
+ log(`Done with: ${JSON.stringify(msg)}`);
1795
+ } catch (error) {
1796
+ // Inhalt von result.error
1797
+ console.error(error);
1798
+ }
1799
+ })();
1800
+ ```
1801
+
1802
+ ### onMessage
1803
+ ```js
1804
+ onMessage('messageName', (data, callback) => {
1805
+ log(`Received data: ${data}`);
1806
+
1807
+ callback({ result: Date.now() });
1808
+ });
1809
+ ```
1810
+
1811
+ Abonniert den Nachrichtenbus des `javascript`-Adapters und liefert die Antwort über den Callback.
1812
+ Die Antwort des Skripts, das als erstes antwortet, wird als Antwort akzeptiert, alle anderen Antworten werden ignoriert.
1813
+
1814
+ Um eine Nachricht an ein JavaScript-Skript zu senden, die dann von diesem Handler empfangen wird, verwendet man [messageTo](#messageto).
1815
+
1816
+ Um eine Nachricht von einem beliebigen anderen Adapter zu senden, verwendet man
1817
+
1818
+ ```js
1819
+ adapter.sendTo('javascript.0', 'toScript', {
1820
+ script: 'script.js.messagetest',
1821
+ message: 'messageName',
1822
+ data: {
1823
+ flag: true
1824
+ }
1825
+ });
1826
+ ```
1827
+
1828
+ Um eine Nachricht über die CLI zu senden, verwendet man
1829
+
1830
+ ```bash
1831
+ iob message javascript.0 toScript '{"script": "script.js.messagetest", "message": "messageName", "data": { "flag": true }}'
1832
+ ```
1833
+
1834
+ ### onMessageUnregister
1835
+ ```js
1836
+ const id = onMessage('messageName', (data, callback) => {
1837
+ log(data);
1838
+ callback({ result: Date.now() });
1839
+ });
1840
+
1841
+ // Abonnement eines bestimmten Handlers beenden
1842
+ onMessageUnregister(id);
1843
+ // oder Abonnement über den Namen beenden
1844
+ onMessageUnregister('messageName');
1845
+ ```
1846
+
1847
+ Beendet das Abonnement dieser Nachricht.
1848
+
1849
+ ### onLog
1850
+ ```js
1851
+ onLog('error', data => {
1852
+ sendTo('telegram.0', { user: 'UserName', text: data.message });
1853
+ log('Following was sent to telegram: ' + data.message);
1854
+ });
1855
+ ```
1856
+
1857
+ Abonniert Logs mit dem angegebenen Schweregrad.
1858
+
1859
+ *Wichtig:* Im Handler können keine Logs mit demselben Schweregrad ausgegeben werden, um Endlosschleifen zu vermeiden.
1860
+
1861
+ Beispielsweise erzeugt dies keine Logs:
1862
+ ```js
1863
+ onLog('error', data => {
1864
+ console.error('Error: ' + data.message);
1865
+ });
1866
+ ```
1867
+
1868
+ Um alle Logs zu empfangen, kann `*` verwendet werden. In diesem Fall wird die Log-Ausgabe im Handler vollständig deaktiviert.
1869
+
1870
+ ```js
1871
+ onLog('*', data => {
1872
+ console.error('Error: ' + data.message); // erzeugt keine Logs
1873
+ });
1874
+ ```
1875
+
1876
+ ### onLogUnregister
1877
+ ```js
1878
+ function logHandler(data) {
1879
+ console.error('Error: ' + data.message);
1880
+ }
1881
+ const id = onLog('warn', logHandler);
1882
+
1883
+ // Abonnement über die ID beenden
1884
+ onLogUnregister(id);
1885
+ // oder Abonnement über die Handler-Funktion beenden
1886
+ onLogUnregister(logHandler);
1887
+ // oder Abonnement aller Handler mit einem bestimmten Schweregrad beenden
1888
+ onLogUnregister('warn');
1889
+ ```
1890
+
1891
+ Beendet das Abonnement dieser Logs.
1892
+
1893
+ ### httpGet
1894
+
1895
+ *Erfordert Version >= 7.9.0*
1896
+
1897
+ ```js
1898
+ httpGet('http://jsonplaceholder.typicode.com/posts', (err, response) => {
1899
+ if (!err) {
1900
+ console.log(response.statusCode);
1901
+ console.log(response.data);
1902
+ } else {
1903
+ console.error(err);
1904
+ }
1905
+ });
1906
+ ```
1907
+
1908
+ Der zweite Parameter kann ein Objekt mit weiteren Optionen sein (optional). Alle Optionen sind optional. Unterstützte Flags:
1909
+
1910
+ - `timeout` (number) - Timeout in Millisekunden
1911
+ - `responseType` (string) - Unterstützte Werte sind `text` (Standard) oder `arraybuffer` für Binärdaten in der Antwort
1912
+ - `basicAuth` (object) - Zugangsdaten für die HTTP-Basic-Authentifizierung, z. B. `{ user: 'admin', password: 'iobroker' }`
1913
+ - `bearerAuth` (string) - Token für die Bearer-Authentifizierung
1914
+ - `headers` (object) - Zusätzliche benutzerdefinierte HTTP-Header, z. B. `{ 'Accept-Language': 'en-GB,en;q=0.9' }`
1915
+ - `validateCertificate` (boolean) - Erlaubt selbstsignierte Zertifikate, wenn `false`
1916
+
1917
+ ```js
1918
+ httpGet('http://jsonplaceholder.typicode.com/posts', { timeout: 1000 }, (err, response) => {
1919
+ if (!err) {
1920
+ console.log(response.statusCode);
1921
+ console.log(response.data);
1922
+ } else {
1923
+ console.error(err);
1924
+ }
1925
+ });
1926
+ ```
1927
+
1928
+ Datei in das ioBroker-Dateisystem herunterladen:
1929
+
1930
+ ```js
1931
+ httpGet('http://1.2.3.4/image.jpg', { responseType: 'arraybuffer' }, async (err, response) => {
1932
+ if (!err) {
1933
+ writeFile('0_userdata.0', 'test.jpg', response.data, (err) => {
1934
+ if (err) {
1935
+ console.error(err);
1936
+ }
1937
+ });
1938
+ } else {
1939
+ console.error(err);
1940
+ }
1941
+ });
1942
+ ```
1943
+
1944
+ Zertifikatsprüfung deaktivieren - *Erfordert Version >= 8.4.0*
1945
+
1946
+ ```js
1947
+ httpGet('http://jsonplaceholder.typicode.com/posts', { validateCertificate: false }, (err, response) => {
1948
+ if (!err) {
1949
+ console.log(response.statusCode);
1950
+ console.log(response.data);
1951
+ } else {
1952
+ console.error(err);
1953
+ }
1954
+ });
1955
+ ```
1956
+
1957
+ ### httpPost
1958
+
1959
+ *Erfordert Version >= 7.9.0*
1960
+
1961
+ ```js
1962
+ httpPost('http://jsonplaceholder.typicode.com/posts', { title: 'foo', body: 'bar', userId: 1 }, (error, response) => {
1963
+ if (!error) {
1964
+ console.log(response.statusCode);
1965
+ console.log(response.data);
1966
+ console.log(response.headers);
1967
+ } else {
1968
+ console.error(error);
1969
+ }
1970
+ });
1971
+ ```
1972
+
1973
+ Mit benutzerdefinierten Headern und Authentifizierung
1974
+
1975
+ ```js
1976
+ httpPost(
1977
+ 'http://jsonplaceholder.typicode.com/posts',
1978
+ {
1979
+ title: 'foo',
1980
+ body: 'bar',
1981
+ userId: 1
1982
+ },
1983
+ {
1984
+ timeout: 2000,
1985
+ basicAuth: {
1986
+ user: 'admin',
1987
+ password: 'dg2LdALNznHFNo'
1988
+ },
1989
+ headers: {
1990
+ 'Cookie': 'PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1'
1991
+ }
1992
+ },
1993
+ (error, response) => {
1994
+ if (!error) {
1995
+ console.log(response.statusCode);
1996
+ console.log(response.data);
1997
+ console.log(response.headers);
1998
+ } else {
1999
+ console.error(error);
2000
+ }
2001
+ }
2002
+ );
2003
+ ```
2004
+
2005
+ ### createTempFile
2006
+
2007
+ *Erfordert Version >= 8.3.0*
2008
+
2009
+ ```js
2010
+ httpGet('https://raw.githubusercontent.com/ioBroker/ioBroker.javascript/master/admin/javascript.svg', { responseType: 'arraybuffer' }, async (err, response) => {
2011
+ if (err) {
2012
+ console.error(err);
2013
+ } else {
2014
+ const tempFilePath = createTempFile('javascript.svg', response.data);
2015
+ console.log(`Saved to ${tempFilePath}`);
2016
+
2017
+ // Den neuen Pfad in anderen Skripten verwenden (z. B. sendTo)
2018
+ }
2019
+ });
2020
+ ```
2021
+
2022
+ ```js
2023
+ onFile('0_userdata.0', '*.jpg', true, async (id, fileName, size, data, mimeType) => {
2024
+ const tempFilePath = createTempFile(fileName, response.data);
2025
+
2026
+ // Den neuen Pfad in anderen Skripten verwenden (z. B. sendTo)
2027
+ });
2028
+ ```
2029
+
2030
+ ```js
2031
+ readFile('0_userdata.0', 'test.jpg', (err, data, mimeType) => {
2032
+ if (err) {
2033
+ console.error(err);
2034
+ } else {
2035
+ const tempFilePath = createTempFile('test.jpg', data);
2036
+
2037
+ // Den neuen Pfad in anderen Skripten verwenden (z. B. sendTo)
2038
+ sendTo('telegram.0', 'send', {
2039
+ text: tempFilePath,
2040
+ caption: 'Just a test image',
2041
+ user: 'yourUsername',
2042
+ });
2043
+ }
2044
+ });
2045
+ ```
2046
+
2047
+ ### registerNotification
2048
+
2049
+ *Erfordert Version >= 8.8.0*
2050
+
2051
+ ```js
2052
+ registerNotification('This is just an information'); // Benachrichtigung
2053
+ registerNotification('This is an important message!', true); // Alarm
2054
+ ```
2055
+
2056
+ ## Globale Skriptvariablen
2057
+ ### scriptName
2058
+ `scriptName` - Der Name des Skripts.
2059
+
2060
+ ```js
2061
+ log(`Script ${scriptName} started!`);
2062
+ ```
2063
+
2064
+ ### instance
2065
+ `instance` - Die JavaScript-Instanz, in der ein Skript ausgeführt wird (z. B. `0`).
2066
+
2067
+ ```js
2068
+ log(`Script ${scriptName} started started by ${instance}`);
2069
+ ```
2070
+
2071
+ ### defaultDataDir
2072
+ `defaultDataDir` - Absoluter Pfad zu iobroker-data.
2073
+
2074
+ ```js
2075
+ log(`Data dir: ${defaultDataDir}`);
2076
+ ```
2077
+
2078
+ ### verbose
2079
+ `verbose` - Ist der ausführliche Modus (Verbose) aktiviert?
2080
+
2081
+ ```js
2082
+ log(`Verbose mode: ${verbose ? 'enabled' : 'disabled'}`);
2083
+
2084
+ // Beispiel
2085
+ if (verbose) {
2086
+ log('...');
2087
+ }
2088
+ ```
2089
+
2090
+ ### SECRETS
2091
+ `SECRETS` - Die Zugangsdaten aus dem zentralen Zugangsdaten-Speicher von ioBroker.
2092
+
2093
+ Die Zugangsdaten werden in der Admin-Oberfläche unter **Allgemeine Einstellungen** -> **Zugangsdaten** verwaltet. Jeder Zugangsdaten-Eintrag
2094
+ hat eine ID (wie `CameraPassword`) und enthält entweder einen einzelnen Schlüssel **key** (z. B. einen API-Schlüssel oder ein Passwort) oder ein
2095
+ Paar aus **login**/**password**. Die geheimen Felder werden mit dem System-Secret verschlüsselt gespeichert und
2096
+ den Skripten bereits entschlüsselt übergeben:
2097
+
2098
+ ```js
2099
+ // Zugangsdaten-Eintrag vom Typ "key"
2100
+ httpGet(`http://camera.local/snapshot?password=${SECRETS.CameraPassword.key}`, (err, result) => {
2101
+ // ...
2102
+ });
2103
+
2104
+ // Zugangsdaten-Eintrag vom Typ "login"
2105
+ log(`Mail account: ${SECRETS.MyMailAccount.login} / ${SECRETS.MyMailAccount.password}`);
2106
+
2107
+ // IDs von Zugangsdaten, die keine gültigen Variablennamen sind
2108
+ log(SECRETS['My camera'].key);
2109
+ ```
2110
+
2111
+ `SECRETS` ist schreibgeschützt und immer aktuell: Wenn ein Zugangsdaten-Eintrag in der Admin-Oberfläche hinzugefügt, geändert oder gelöscht wird,
2112
+ wird der neue Wert sofort verwendet - weder der Adapter noch das Skript müssen neu gestartet werden.
2113
+
2114
+ Wenn ein Zugangsdaten-Eintrag nicht existiert, wird `undefined` zurückgegeben:
2115
+
2116
+ ```js
2117
+ if (SECRETS.CameraPassword) {
2118
+ log('The camera password is defined');
2119
+ }
2120
+ ```
2121
+
2122
+ #### Welche Felder hat ein Zugangsdaten-Eintrag?
2123
+
2124
+ Jeder Zugangsdaten-Eintrag hat entweder einen einzelnen `key` oder ein Paar `login`/`password`. Es gibt drei Möglichkeiten, das herauszufinden:
2125
+
2126
+ - In den Instanzeinstellungen des JavaScript-Adapters listet der Abschnitt **Verfügbare Zugangsdaten** jeden
2127
+ Zugangsdaten-Eintrag mit seinen Feldern und dem kopierfertigen Ausdruck auf.
2128
+ - Im Editor bietet die Autovervollständigung nach `SECRETS.` die vorhandenen Zugangsdaten an und nach dem
2129
+ nächsten Punkt genau die Felder, die dieser Zugangsdaten-Eintrag hat.
2130
+ - In einem Skript:
2131
+
2132
+ ```js
2133
+ log(JSON.stringify(Object.keys(SECRETS.CameraPassword))); // ["key"]
2134
+ log(JSON.stringify(Object.keys(SECRETS.MyMailAccount))); // ["login","password"]
2135
+ ```
2136
+
2137
+ Blockly hat für denselben Zweck einen **Zugangsdaten**-Baustein - siehe die
2138
+ [Blockly-Dokumentation](../en/blockly.md#credential) (englisch).
2139
+
2140
+ Der Zugriff kann mit der Instanzoption **Skripten den Zugriff auf die Zugangsdaten erlauben** abgeschaltet werden.
2141
+ `SECRETS` ist dann leer, und es wird eine Warnung ins Log geschrieben.
2142
+
2143
+ **Hinweis:** Dies erfordert js-controller 7.2 oder neuer.
2144
+
2145
+ ## Option - "Nicht alle Zustände beim Start abonnieren"
2146
+ Es gibt zwei Modi, States zu abonnieren:
2147
+
2148
+ 1. Der Adapter abonniert beim Start alle States und empfängt alle Änderungen aller States (getState(id) ist einfach zu verwenden, benötigt aber mehr CPU und RAM):
2149
+
2150
+ ```js
2151
+ log(getState('someID').val);
2152
+ ```
2153
+
2154
+ 2. Der Adapter abonniert die angegebene ID jedes Mal, wenn `on/subscribe` aufgerufen wird. In diesem Modus empfängt der Adapter nur Aktualisierungen für die gewünschten States. Diese Option benötigt weniger RAM und ist effizienter, allerdings kann man nicht synchron über getState auf States zugreifen. **Man muss Callbacks oder Promises verwenden, um auf die States zuzugreifen**:
2155
+
2156
+ ```js
2157
+ getState('someID', (error, state) => {
2158
+ log(state.val);
2159
+ });
2160
+ ```
2161
+
2162
+ Grund: Der Adapter hat den Wert des States nicht im RAM und muss ihn aus der zentralen State-Datenbank anfordern.
2163
+
2164
+ ## Skriptaktivität
2165
+
2166
+ Skripte können über States aktiviert und deaktiviert werden. Für jedes Skript wird ein State mit dem Namen `javascript.INSTANCE.scriptEnabled.SCRIPT_NAME` angelegt.
2167
+ Skripte können aktiviert und deaktiviert werden, indem dieser State mit `ack=false` gesteuert wird.