iobroker.jetframe 1.0.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 (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +357 -0
  3. package/admin/SF-Pro.ttf +0 -0
  4. package/admin/admin.d.ts +65 -0
  5. package/admin/frame.html +982 -0
  6. package/admin/frame.html.bak-aircraft-card-real-row-20260518-1608 +1236 -0
  7. package/admin/frame.html.bak-aircraft-card-structure-20260518-1517 +1236 -0
  8. package/admin/frame.html.bak-aircraft-logo-id-fix-20260518-1639 +1239 -0
  9. package/admin/frame.html.bak-shortcut-test +1236 -0
  10. package/admin/frame.html.bak-tablet-class-20260518-1729 +1239 -0
  11. package/admin/heatmap.html +216 -0
  12. package/admin/index.html +268 -0
  13. package/admin/index_m.html +1749 -0
  14. package/admin/jetframe.css +1260 -0
  15. package/admin/jetframe.css.bak-airbus-landscape-fix +4630 -0
  16. package/admin/jetframe.css.bak-aircraft-card-clean-equal-20260518-1438 +4899 -0
  17. package/admin/jetframe.css.bak-aircraft-card-real-row-20260518-1608 +4814 -0
  18. package/admin/jetframe.css.bak-aircraft-card-row-left-20260518-1525 +4604 -0
  19. package/admin/jetframe.css.bak-aircraft-card-slim-equal-20260518-1446 +4647 -0
  20. package/admin/jetframe.css.bak-aircraft-card-structure-20260518-1517 +4646 -0
  21. package/admin/jetframe.css.bak-aircraft-inline-final-20260518-1527 +4654 -0
  22. package/admin/jetframe.css.bak-aircraft-row-compact-fix-20260518-1639 +4763 -0
  23. package/admin/jetframe.css.bak-before-aircrafttype-purge +4818 -0
  24. package/admin/jetframe.css.bak-before-cleanup +4670 -0
  25. package/admin/jetframe.css.bak-before-remove-tablet-only-20260518-1711 +4896 -0
  26. package/admin/jetframe.css.bak-before-tablet-layout-rework-20260518-1650 +4914 -0
  27. package/admin/jetframe.css.bak-clean-duplicate-fonts-20260518-1340 +4975 -0
  28. package/admin/jetframe.css.bak-clean-old-index-fix-20260518-1937 +5167 -0
  29. package/admin/jetframe.css.bak-hardleft-airbus +4751 -0
  30. package/admin/jetframe.css.bak-index-iphone-landscape-20260518-1931 +5030 -0
  31. package/admin/jetframe.css.bak-index-landscape-final-20260518-1941 +5167 -0
  32. package/admin/jetframe.css.bak-index-landscape-real-20260518-1936 +5186 -0
  33. package/admin/jetframe.css.bak-landscape-compact-jumbo-bold-20260518-1343 +4802 -0
  34. package/admin/jetframe.css.bak-logo-align-final +4551 -0
  35. package/admin/jetframe.css.bak-logo-final2 +4551 -0
  36. package/admin/jetframe.css.bak-narrowbody-font-fix +4992 -0
  37. package/admin/jetframe.css.bak-nuke-airbus-align +4790 -0
  38. package/admin/jetframe.css.bak-pill-balance-20260518-1603 +4773 -0
  39. package/admin/jetframe.css.bak-pill-balance-fix +4910 -0
  40. package/admin/jetframe.css.bak-radar-fix-fonts +4710 -0
  41. package/admin/jetframe.css.bak-shortcut-test +4899 -0
  42. package/admin/jetframe.css.bak-smaller-aircraft-card-fonts-20260518-1345 +4897 -0
  43. package/admin/jetframe.css.bak-tablet-fix-real-20260518-1748 +4945 -0
  44. package/admin/jetframe.css.bak-tablet-fullscreen-fix-20260518-1804 +4972 -0
  45. package/admin/jetframe.css.bak-tablet-landscape-layout-20260518-1645 +4802 -0
  46. package/admin/jetframe.css.bak-tablet-layout-final-20260518-1839 +4802 -0
  47. package/admin/jetframe.css.bak-tablet-layout-v3-20260518-1729 +4802 -0
  48. package/admin/jetframe.css.bak-tablet-layout-v4-20260518-1801 +4957 -0
  49. package/admin/jetframe.css.bak-tablet-layout-v5-20260518-1843 +4970 -0
  50. package/admin/jetframe.css.bak-tablet-layout-v6-20260518-1848 +4958 -0
  51. package/admin/jetframe.css.bak-tablet-layout-v7-20260518-1909 +4985 -0
  52. package/admin/jetframe.css.bak-tablet-only-landscape-v2-20260518-1707 +4802 -0
  53. package/admin/jetframe.css.bak-tablet-pages-final-20260519-1857 +5188 -0
  54. package/admin/jetframe.css.bak-tablet-pages-final-20260519-1859 +5347 -0
  55. package/admin/jetframe.css.bak-tablet-pages-v2-20260519-190807 +5349 -0
  56. package/admin/jetframe.css.bak-typography-align-final +4818 -0
  57. package/admin/jetframe.png +0 -0
  58. package/admin/manifest.webmanifest +15 -0
  59. package/admin/src/app.tsx +58 -0
  60. package/admin/src/components/settings.tsx +97 -0
  61. package/admin/src/i18n/de.json +11 -0
  62. package/admin/src/i18n/en.json +11 -0
  63. package/admin/src/i18n/es.json +11 -0
  64. package/admin/src/i18n/fr.json +11 -0
  65. package/admin/src/i18n/i18n.d.ts +28 -0
  66. package/admin/src/i18n/it.json +11 -0
  67. package/admin/src/i18n/nl.json +11 -0
  68. package/admin/src/i18n/pl.json +11 -0
  69. package/admin/src/i18n/pt.json +11 -0
  70. package/admin/src/i18n/ru.json +11 -0
  71. package/admin/src/i18n/uk.json +11 -0
  72. package/admin/src/i18n/zh-cn.json +11 -0
  73. package/admin/src/index.tsx +25 -0
  74. package/admin/stats.html +228 -0
  75. package/admin/style.css +32 -0
  76. package/admin/tsconfig.json +11 -0
  77. package/admin/words.js +46 -0
  78. package/build/lib/adsb.js +218 -0
  79. package/build/lib/adsb.js.map +7 -0
  80. package/build/lib/airportNamesDe.js +131 -0
  81. package/build/lib/airportNamesDe.js.map +7 -0
  82. package/build/lib/airports.js +281 -0
  83. package/build/lib/airports.js.map +7 -0
  84. package/build/lib/classify.js +339 -0
  85. package/build/lib/classify.js.map +7 -0
  86. package/build/lib/config.js +103 -0
  87. package/build/lib/config.js.map +7 -0
  88. package/build/lib/flightInfo.js +1409 -0
  89. package/build/lib/flightInfo.js.map +7 -0
  90. package/build/lib/geo.js +84 -0
  91. package/build/lib/geo.js.map +7 -0
  92. package/build/lib/images.js +422 -0
  93. package/build/lib/images.js.map +7 -0
  94. package/build/lib/specialLiveries.js +342 -0
  95. package/build/lib/specialLiveries.js.map +7 -0
  96. package/build/lib/states.js +971 -0
  97. package/build/lib/states.js.map +7 -0
  98. package/build/lib/staticFiles.js +73 -0
  99. package/build/lib/staticFiles.js.map +7 -0
  100. package/build/lib/types.js +17 -0
  101. package/build/lib/types.js.map +7 -0
  102. package/build/lib/visConfig.js +52 -0
  103. package/build/lib/visConfig.js.map +7 -0
  104. package/build/main.js +1454 -0
  105. package/build/main.js.map +7 -0
  106. package/io-package.json +169 -0
  107. package/package.json +82 -0
@@ -0,0 +1,971 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var states_exports = {};
20
+ __export(states_exports, {
21
+ clearFlight: () => clearFlight,
22
+ ensureBaseStates: () => ensureBaseStates,
23
+ ensureFlightStates: () => ensureFlightStates,
24
+ ensureState: () => ensureState,
25
+ ensureStates: () => ensureStates,
26
+ trackDirectionText: () => trackDirectionText,
27
+ writeFlight: () => writeFlight
28
+ });
29
+ module.exports = __toCommonJS(states_exports);
30
+ var import_geo = require("./geo");
31
+ var import_images = require("./images");
32
+ const LAST_SPEECH_TRIGGER = {};
33
+ async function ensureState(adapter, id, def, type, role) {
34
+ const obj = await adapter.getForeignObjectAsync(id);
35
+ if (!obj) {
36
+ await adapter.setForeignObjectAsync(id, {
37
+ type: "state",
38
+ common: {
39
+ name: id.split(".").pop() || id,
40
+ type,
41
+ role,
42
+ read: true,
43
+ write: true
44
+ },
45
+ native: {}
46
+ });
47
+ await adapter.setForeignStateAsync(id, def, true);
48
+ }
49
+ }
50
+ async function ensureBaseStates(adapter, config) {
51
+ await ensureState(adapter, `${config.dpRoot}.enabled`, config.enabled !== false, "boolean", "switch");
52
+ await adapter.setForeignStateAsync(`${config.dpRoot}.enabled`, config.enabled !== false, true);
53
+ await ensureState(adapter, `${config.dpRoot}.status`, "init", "string", "text");
54
+ await ensureState(adapter, `${config.dpRoot}.lastUpdate`, "", "string", "text");
55
+ await ensureState(adapter, `${config.dpRoot}.allCount`, 0, "number", "value");
56
+ await ensureState(adapter, `${config.dpRoot}.matchCount`, 0, "number", "value");
57
+ await ensureState(adapter, `${config.dpRoot}.clearImageCache`, false, "boolean", "button");
58
+ await ensureState(adapter, config.airportJsonDp, "[]", "string", "json");
59
+ await ensureState(adapter, `${config.dpRoot}.airportjsonLastUpdate`, "", "string", "text");
60
+ await ensureState(adapter, `${config.dpRoot}.specialLiveries`, "[]", "string", "json");
61
+ await ensureState(adapter, `${config.dpRoot}.specialLiveriesLastUpdate`, "", "string", "text");
62
+ await ensureState(adapter, `${config.dpRoot}.speechMode`, "browser", "string", "text");
63
+ await ensureState(
64
+ adapter,
65
+ `${config.dpRoot}.speechTemplate`,
66
+ "{modeSpeechText}: {airlineName} {bestCallsign} {routeDirectionText} {routeOtherAirport} in {altitudeFt} Fu\xDF. {windowPositionSpeechText}.",
67
+ "string",
68
+ "text"
69
+ );
70
+ await adapter.setForeignStateAsync(`${config.dpRoot}.speechMode`, config.speechMode || "browser", true);
71
+ try {
72
+ const speechEnabledObj = await adapter.getForeignObjectAsync(`${config.dpRoot}.speechEnabled`);
73
+ if (!speechEnabledObj) {
74
+ await adapter.setForeignObjectAsync(`${config.dpRoot}.speechEnabled`, {
75
+ type: "state",
76
+ common: {
77
+ name: "Sprachausgabe aktiv",
78
+ type: "boolean",
79
+ role: "switch",
80
+ read: true,
81
+ write: true,
82
+ def: true
83
+ },
84
+ native: {}
85
+ });
86
+ }
87
+ const speechEnabledState = await adapter.getForeignStateAsync(`${config.dpRoot}.speechEnabled`);
88
+ if ((speechEnabledState == null ? void 0 : speechEnabledState.val) === null || (speechEnabledState == null ? void 0 : speechEnabledState.val) === void 0) {
89
+ await adapter.setForeignStateAsync(`${config.dpRoot}.speechEnabled`, true, true);
90
+ }
91
+ } catch {
92
+ }
93
+ await adapter.setForeignStateAsync(
94
+ `${config.dpRoot}.speechTemplate`,
95
+ config.speechTemplate || "{modeSpeechText}: {airlineName} {bestCallsign} {routeDirectionText} {routeOtherAirport} in {altitudeFt} Fuss. {windowPositionSpeechText}.",
96
+ true
97
+ );
98
+ await ensureFlightStates(adapter, `${config.dpRoot}.current`);
99
+ await ensureFlightStates(adapter, `${config.dpRoot}.airport`);
100
+ await ensureFlightStates(adapter, `${config.dpRoot}.overflight`);
101
+ }
102
+ async function ensureFlightStates(adapter, base) {
103
+ const strings = [
104
+ ".text",
105
+ ".callsign",
106
+ ".rawCallsign",
107
+ ".cleanedCallsign",
108
+ ".operationalCallsign",
109
+ ".routeCallsign",
110
+ ".hex",
111
+ ".mode",
112
+ ".flightPhase",
113
+ ".directionText",
114
+ ".trackDirectionText",
115
+ ".modeVisText",
116
+ ".windowPositionText",
117
+ ".windowPositionClass",
118
+ ".windowPositionSpeechText",
119
+ ".probableRunway",
120
+ ".probableRunwayText",
121
+ ".probableRunway",
122
+ ".probableRunwayText",
123
+ ".airlineName",
124
+ ".airlineIata",
125
+ ".airlineIcao",
126
+ ".originIata",
127
+ ".destIata",
128
+ ".originName",
129
+ ".destName",
130
+ ".originDisplayName",
131
+ ".destDisplayName",
132
+ ".departureAirport",
133
+ ".approachAirport",
134
+ ".routeText",
135
+ ".routeTextLong",
136
+ ".routeWarning",
137
+ ".routeSource",
138
+ ".routeDisplayText",
139
+ ".routeCodesText",
140
+ ".aircraftModel",
141
+ ".aircraftType",
142
+ ".registration",
143
+ ".manufacturer",
144
+ ".manufacturerLogoText",
145
+ ".manufacturerLogoUrl",
146
+ ".aircraftTypeText",
147
+ ".aircraftSize",
148
+ ".squawk",
149
+ ".emergency",
150
+ ".emergencyType",
151
+ ".emergencyText",
152
+ ".squawk",
153
+ ".emergency",
154
+ ".emergencyType",
155
+ ".emergencyText",
156
+ ".logoUrl",
157
+ ".jetphotosUrl",
158
+ ".jetphotosImageUrl",
159
+ ".localLogoUrl",
160
+ ".localImageUrl",
161
+ ".finalImageUrl",
162
+ ".specialText",
163
+ ".specialLiveryTitle",
164
+ ".specialLiveryDescription",
165
+ ".specialLiveryFull",
166
+ ".specialLiveryVisText",
167
+ ".specialDisplayText",
168
+ ".speechText"
169
+ ];
170
+ for (const s of strings) {
171
+ await ensureState(adapter, base + s, "", "string", "text");
172
+ }
173
+ const bools = [".statistics.today.rushHourNow"];
174
+ const nums = [
175
+ ".altitudeFt",
176
+ ".speedKt",
177
+ ".verticalRate",
178
+ ".trackDeg",
179
+ ".distHomeNm",
180
+ ".distanceKm",
181
+ ".distAirportNm",
182
+ ".bearingHomeDeg",
183
+ ".windowDiffDeg",
184
+ ".probableRunwayHeading",
185
+ ".probableRunwayDiffDeg",
186
+ ".runwayConfidence",
187
+ ".bearingAircraftToAirportDeg",
188
+ ".bearingAirportToAircraftDeg",
189
+ ".landingTrackDiffDeg",
190
+ ".takeoffTrackDiffDeg",
191
+ ".airportTrackDiffDeg"
192
+ ];
193
+ for (const n of nums) {
194
+ await ensureState(adapter, base + n, 0, "number", "value");
195
+ }
196
+ await ensureState(adapter, `${base}.routeReliable`, false, "boolean", "indicator");
197
+ await ensureState(adapter, `${base}.isSpecial`, false, "boolean", "indicator");
198
+ await ensureState(adapter, `${base}.isEmergency`, false, "boolean", "indicator");
199
+ await ensureState(adapter, `${base}.speechTrigger`, false, "boolean", "button");
200
+ }
201
+ function cleanRouteCallsign(a) {
202
+ const v = String(a.routeCallsign || "").trim().toUpperCase();
203
+ const own = String(a.callsign || "").trim().toUpperCase();
204
+ if (!v) {
205
+ return "";
206
+ }
207
+ if (v === own) {
208
+ return "";
209
+ }
210
+ if (/^\d+$/.test(v)) {
211
+ return "";
212
+ }
213
+ if (!/[A-Z]/.test(v)) {
214
+ return "";
215
+ }
216
+ if (v.length < 4 || v.length > 8) {
217
+ return "";
218
+ }
219
+ return v;
220
+ }
221
+ function trackDirectionText(degRaw) {
222
+ const deg = Number(degRaw);
223
+ if (!Number.isFinite(deg)) {
224
+ return "";
225
+ }
226
+ const normalized = (deg % 360 + 360) % 360;
227
+ const dirs = ["\u2191 Norden", "\u2197 Nordost", "\u2192 Osten", "\u2198 S\xFCdost", "\u2193 S\xFCden", "\u2199 S\xFCdwest", "\u2190 Westen", "\u2196 Nordwest"];
228
+ const index = Math.round(normalized / 45) % 8;
229
+ return dirs[index];
230
+ }
231
+ function getFlightPhase(a) {
232
+ const mode = String(a.mode || "").toUpperCase();
233
+ const altFt = Number(a.altFt || a.altitudeFt || 0);
234
+ const vr = Number(a.verticalRate || 0);
235
+ const distAirportNm = Number(a.distAirportNm || 0);
236
+ if (mode === "LANDING") {
237
+ if (altFt > 0 && altFt <= 1800) {
238
+ return "landing";
239
+ }
240
+ if (distAirportNm > 0 && distAirportNm <= 12) {
241
+ return "approach";
242
+ }
243
+ if (vr < -300) {
244
+ return "descent";
245
+ }
246
+ return "approach";
247
+ }
248
+ if (mode === "TAKEOFF") {
249
+ if (altFt > 0 && altFt <= 1800) {
250
+ return "departure";
251
+ }
252
+ if (vr > 300) {
253
+ return "climb";
254
+ }
255
+ return "departure";
256
+ }
257
+ if (mode === "OVERFLIGHT") {
258
+ if (vr < -500) {
259
+ return "descent";
260
+ }
261
+ if (vr > 500) {
262
+ return "climb";
263
+ }
264
+ return "cruise";
265
+ }
266
+ if (vr < -500) {
267
+ return "descent";
268
+ }
269
+ if (vr > 500) {
270
+ return "climb";
271
+ }
272
+ if (altFt > 8e3) {
273
+ return "cruise";
274
+ }
275
+ return "unknown";
276
+ }
277
+ async function setForeignStateChanged(adapter, id, value, ack = true) {
278
+ try {
279
+ const oldState = await adapter.getForeignStateAsync(id);
280
+ if (oldState && oldState.val === value && oldState.ack === ack) {
281
+ return;
282
+ }
283
+ } catch {
284
+ }
285
+ await adapter.setForeignStateAsync(id, value, ack);
286
+ }
287
+ async function writeFlight(adapter, base, a) {
288
+ const routeCallsign = String(a.routeCallsign || a.callsign || "").trim().toUpperCase();
289
+ const display = await buildDisplayInfo(adapter, adapter.config, a);
290
+ display.speechText = await buildSpeechTextForWrite(adapter, base, a, display);
291
+ await setForeignStateChanged(adapter, `${base}.text`, buildMessage(a), true);
292
+ const rawCallsign = String(a.rawCallsign || a.callsign || "").trim();
293
+ const cleanedCallsign = String(a.cleanedCallsign || a.callsign || "").trim().replace(/\s+/g, "").toUpperCase();
294
+ await setForeignStateChanged(adapter, `${base}.callsign`, a.callsign || "", true);
295
+ await setForeignStateChanged(adapter, `${base}.rawCallsign`, rawCallsign, true);
296
+ await setForeignStateChanged(adapter, `${base}.cleanedCallsign`, cleanedCallsign, true);
297
+ await setForeignStateChanged(
298
+ adapter,
299
+ `${base}.operationalCallsign`,
300
+ a.operationalCallsign || a.callsign || "",
301
+ true
302
+ );
303
+ await setForeignStateChanged(adapter, `${base}.routeCallsign`, routeCallsign, true);
304
+ await setForeignStateChanged(adapter, `${base}.hex`, a.hex || "", true);
305
+ await setForeignStateChanged(adapter, `${base}.mode`, a.mode || "", true);
306
+ await setForeignStateChanged(adapter, `${base}.flightPhase`, getFlightPhase(a), true);
307
+ await setForeignStateChanged(adapter, `${base}.directionText`, a.directionText || "", true);
308
+ await setForeignStateChanged(adapter, `${base}.modeVisText`, display.modeVisText, true);
309
+ await setForeignStateChanged(adapter, `${base}.windowPositionText`, display.windowPositionText, true);
310
+ await setForeignStateChanged(adapter, `${base}.windowPositionClass`, display.windowPositionClass, true);
311
+ await setForeignStateChanged(adapter, `${base}.windowPositionSpeechText`, display.windowPositionSpeechText, true);
312
+ await setForeignStateChanged(adapter, `${base}.probableRunway`, a.probableRunway || "", true);
313
+ await setForeignStateChanged(adapter, `${base}.probableRunwayText`, a.probableRunwayText || "", true);
314
+ await setForeignStateChanged(adapter, `${base}.probableRunwayHeading`, a.probableRunwayHeading || 0, true);
315
+ await setForeignStateChanged(adapter, `${base}.probableRunwayDiffDeg`, a.probableRunwayDiffDeg || 0, true);
316
+ await setForeignStateChanged(adapter, `${base}.runwayConfidence`, a.runwayConfidence || 0, true);
317
+ await setForeignStateChanged(adapter, `${base}.airlineName`, a.airlineName || "", true);
318
+ await setForeignStateChanged(adapter, `${base}.airlineIata`, a.airlineIata || "", true);
319
+ await setForeignStateChanged(adapter, `${base}.airlineIcao`, a.airlineIcao || "", true);
320
+ await setForeignStateChanged(adapter, `${base}.originIata`, a.originIata || "", true);
321
+ await setForeignStateChanged(adapter, `${base}.destIata`, a.destIata || "", true);
322
+ await setForeignStateChanged(adapter, `${base}.originName`, a.originName || "", true);
323
+ await setForeignStateChanged(adapter, `${base}.destName`, a.destName || "", true);
324
+ await setForeignStateChanged(adapter, `${base}.originDisplayName`, display.originDisplayName, true);
325
+ await setForeignStateChanged(adapter, `${base}.destDisplayName`, display.destDisplayName, true);
326
+ await setForeignStateChanged(adapter, `${base}.departureAirport`, display.departureAirport, true);
327
+ await setForeignStateChanged(adapter, `${base}.approachAirport`, display.approachAirport, true);
328
+ await setForeignStateChanged(adapter, `${base}.routeText`, a.routeText || "", true);
329
+ await setForeignStateChanged(adapter, `${base}.routeTextLong`, a.routeTextLong || "", true);
330
+ await setForeignStateChanged(adapter, `${base}.routeReliable`, !!a.routeReliable, true);
331
+ await setForeignStateChanged(adapter, `${base}.routeWarning`, a.routeWarning || "", true);
332
+ await setForeignStateChanged(adapter, `${base}.routeSource`, a.routeSource || "", true);
333
+ await setForeignStateChanged(adapter, `${base}.routeDisplayText`, display.routeDisplayText, true);
334
+ await setForeignStateChanged(adapter, `${base}.routeCodesText`, display.routeCodesText, true);
335
+ await setForeignStateChanged(adapter, `${base}.aircraftModel`, a.aircraftModel || "", true);
336
+ await setForeignStateChanged(adapter, `${base}.aircraftType`, a.aircraftType || a.type || "", true);
337
+ await setForeignStateChanged(adapter, `${base}.registration`, a.registration || "", true);
338
+ await setForeignStateChanged(adapter, `${base}.manufacturer`, display.manufacturer, true);
339
+ await setForeignStateChanged(adapter, `${base}.manufacturerLogoText`, display.manufacturerLogoText, true);
340
+ await setForeignStateChanged(adapter, `${base}.manufacturerLogoUrl`, display.manufacturerLogoUrl, true);
341
+ await setForeignStateChanged(adapter, `${base}.aircraftTypeText`, display.aircraftTypeText, true);
342
+ await setForeignStateChanged(adapter, `${base}.aircraftSize`, display.aircraftSize, true);
343
+ await setForeignStateChanged(adapter, `${base}.squawk`, a.squawk || "", true);
344
+ await setForeignStateChanged(adapter, `${base}.emergency`, a.emergency || "", true);
345
+ await setForeignStateChanged(adapter, `${base}.emergencyType`, a.emergencyType || "", true);
346
+ await setForeignStateChanged(adapter, `${base}.emergencyText`, a.emergencyText || "", true);
347
+ await setForeignStateChanged(adapter, `${base}.logoUrl`, a.logoUrl || "", true);
348
+ await setForeignStateChanged(adapter, `${base}.jetphotosUrl`, a.jetphotosUrl || "", true);
349
+ await setForeignStateChanged(adapter, `${base}.jetphotosImageUrl`, a.jetphotosImageUrl || "", true);
350
+ const localLogoUrl = await keepExistingStringState(adapter, `${base}.localLogoUrl`, a.localLogoUrl);
351
+ const localImageUrl = await keepExistingStringState(adapter, `${base}.localImageUrl`, a.localImageUrl);
352
+ const preferredImage = a.jetphotosImageUrl || a.finalImageUrl || localImageUrl || "";
353
+ const finalImageUrl = await keepExistingStringState(adapter, `${base}.finalImageUrl`, preferredImage);
354
+ await setForeignStateChanged(adapter, `${base}.localLogoUrl`, localLogoUrl, true);
355
+ await setForeignStateChanged(adapter, `${base}.localImageUrl`, localImageUrl, true);
356
+ await setForeignStateChanged(adapter, `${base}.finalImageUrl`, finalImageUrl, true);
357
+ await setForeignStateChanged(adapter, `${base}.altitudeFt`, Math.round(a.altFt || 0), true);
358
+ await setForeignStateChanged(adapter, `${base}.speedKt`, Math.round(a.speedKt || 0), true);
359
+ await setForeignStateChanged(adapter, `${base}.verticalRate`, Math.round(a.verticalRate || 0), true);
360
+ await setForeignStateChanged(adapter, `${base}.trackDeg`, Math.round(a.trackDeg || 0), true);
361
+ await setForeignStateChanged(adapter, `${base}.trackDirectionText`, trackDirectionText(a.trackDeg), true);
362
+ await setForeignStateChanged(adapter, `${base}.distHomeNm`, a.distHomeNm || 0, true);
363
+ await setForeignStateChanged(
364
+ adapter,
365
+ `${base}.distanceKm`,
366
+ Math.round(Number(a.distHomeNm || 0) * 1.852 * 10) / 10,
367
+ true
368
+ );
369
+ await setForeignStateChanged(adapter, `${base}.distAirportNm`, (0, import_geo.round)(a.distAirportNm || 0, 1), true);
370
+ await setForeignStateChanged(adapter, `${base}.bearingHomeDeg`, (0, import_geo.round)(a.bearingHomeDeg || 0, 1), true);
371
+ await setForeignStateChanged(adapter, `${base}.windowDiffDeg`, (0, import_geo.round)(a.windowDiffDeg || 0, 1), true);
372
+ await setForeignStateChanged(
373
+ adapter,
374
+ `${base}.bearingAircraftToAirportDeg`,
375
+ (0, import_geo.round)(a.bearingAircraftToAirportDeg || 0, 1),
376
+ true
377
+ );
378
+ await setForeignStateChanged(
379
+ adapter,
380
+ `${base}.bearingAirportToAircraftDeg`,
381
+ (0, import_geo.round)(a.bearingAirportToAircraftDeg || 0, 1),
382
+ true
383
+ );
384
+ await setForeignStateChanged(adapter, `${base}.landingTrackDiffDeg`, (0, import_geo.round)(a.landingTrackDiffDeg || 0, 1), true);
385
+ await setForeignStateChanged(adapter, `${base}.takeoffTrackDiffDeg`, (0, import_geo.round)(a.takeoffTrackDiffDeg || 0, 1), true);
386
+ await setForeignStateChanged(adapter, `${base}.airportTrackDiffDeg`, (0, import_geo.round)(a.airportTrackDiffDeg || 0, 1), true);
387
+ await setForeignStateChanged(adapter, `${base}.specialText`, a.specialText || "", true);
388
+ await setForeignStateChanged(adapter, `${base}.specialLiveryTitle`, a.specialLiveryTitle || "", true);
389
+ await setForeignStateChanged(adapter, `${base}.specialLiveryDescription`, a.specialLiveryDescription || "", true);
390
+ await setForeignStateChanged(adapter, `${base}.specialLiveryFull`, a.specialLiveryFull || "", true);
391
+ await setForeignStateChanged(adapter, `${base}.specialLiveryVisText`, a.specialLiveryVisText || "", true);
392
+ await setForeignStateChanged(adapter, `${base}.specialDisplayText`, display.specialDisplayText, true);
393
+ await setForeignStateChanged(adapter, `${base}.speechText`, display.speechText, true);
394
+ await setForeignStateChanged(adapter, `${base}.isSpecial`, !!a.isSpecial, true);
395
+ await setForeignStateChanged(adapter, `${base}.isEmergency`, !!a.isEmergency, true);
396
+ await maybeTriggerSpeech(adapter, base, a, display.speechText);
397
+ }
398
+ async function clearFlight(adapter, base) {
399
+ const strings = [
400
+ ".text",
401
+ ".callsign",
402
+ ".operationalCallsign",
403
+ ".routeCallsign",
404
+ ".hex",
405
+ ".mode",
406
+ ".directionText",
407
+ ".modeVisText",
408
+ ".windowPositionText",
409
+ ".windowPositionClass",
410
+ ".windowPositionSpeechText",
411
+ ".airlineName",
412
+ ".airlineIata",
413
+ ".airlineIcao",
414
+ ".originIata",
415
+ ".destIata",
416
+ ".originName",
417
+ ".destName",
418
+ ".originDisplayName",
419
+ ".destDisplayName",
420
+ ".departureAirport",
421
+ ".approachAirport",
422
+ ".routeText",
423
+ ".routeTextLong",
424
+ ".routeWarning",
425
+ ".routeSource",
426
+ ".routeDisplayText",
427
+ ".routeCodesText",
428
+ ".aircraftModel",
429
+ ".aircraftType",
430
+ ".registration",
431
+ ".manufacturer",
432
+ ".manufacturerLogoText",
433
+ ".manufacturerLogoUrl",
434
+ ".aircraftTypeText",
435
+ ".aircraftSize",
436
+ ".logoUrl",
437
+ ".jetphotosUrl",
438
+ ".jetphotosImageUrl",
439
+ ".localLogoUrl",
440
+ ".localImageUrl",
441
+ ".finalImageUrl",
442
+ ".specialText",
443
+ ".specialLiveryTitle",
444
+ ".specialLiveryDescription",
445
+ ".specialLiveryFull",
446
+ ".specialLiveryVisText",
447
+ ".specialDisplayText",
448
+ ".speechText"
449
+ ];
450
+ for (const s of strings) {
451
+ await setForeignStateChanged(adapter, base + s, "", true);
452
+ }
453
+ const nums = [
454
+ ".altitudeFt",
455
+ ".speedKt",
456
+ ".verticalRate",
457
+ ".trackDeg",
458
+ ".distHomeNm",
459
+ ".distAirportNm",
460
+ ".bearingHomeDeg",
461
+ ".windowDiffDeg",
462
+ ".probableRunwayHeading",
463
+ ".probableRunwayDiffDeg",
464
+ ".runwayConfidence",
465
+ ".bearingAircraftToAirportDeg",
466
+ ".bearingAirportToAircraftDeg",
467
+ ".landingTrackDiffDeg",
468
+ ".takeoffTrackDiffDeg",
469
+ ".airportTrackDiffDeg"
470
+ ];
471
+ for (const n of nums) {
472
+ await setForeignStateChanged(adapter, base + n, 0, true);
473
+ }
474
+ await setForeignStateChanged(adapter, `${base}.routeReliable`, false, true);
475
+ await setForeignStateChanged(adapter, `${base}.isSpecial`, false, true);
476
+ await setForeignStateChanged(adapter, `${base}.isEmergency`, false, true);
477
+ await setForeignStateChanged(adapter, `${base}.speechTrigger`, false, true);
478
+ }
479
+ async function buildDisplayInfo(adapter, config, a) {
480
+ var _a, _b, _c;
481
+ const originDisplayName = cityOnly(a.originName) || String(a.originIata || "").trim() || "\u2014";
482
+ const destDisplayName = cityOnly(a.destName) || String(a.destIata || "").trim() || "\u2014";
483
+ const routeDisplayText = `${originDisplayName} \u2192 ${destDisplayName}`;
484
+ const routeCodesText = `${a.originIata || "\u2014"} \u2192 ${a.destIata || "\u2014"}`;
485
+ const configuredAirportLabel = airportLabel(
486
+ ((_a = config.airport) == null ? void 0 : _a.name) || ((_b = config.airport) == null ? void 0 : _b.iata) || "",
487
+ ((_c = config.airport) == null ? void 0 : _c.iata) || ""
488
+ );
489
+ const mode = String(a.mode || "").toUpperCase();
490
+ const departureAirport = airportLabel(originDisplayName, a.originIata) || (mode === "TAKEOFF" ? configuredAirportLabel : "");
491
+ const approachAirport = airportLabel(destDisplayName, a.destIata) || (mode === "LANDING" ? configuredAirportLabel : "");
492
+ const modeVisText = modeVisTextFromFlight(a, originDisplayName, destDisplayName);
493
+ const window = windowPositionInfo(a);
494
+ const aircraft = await aircraftDisplayInfo(adapter, config, a);
495
+ const specialDisplayText = String(a.specialLiveryVisText || a.specialLiveryFull || a.specialText || "").trim();
496
+ const speechText = buildSpeechText(a, {
497
+ originDisplayName,
498
+ destDisplayName,
499
+ departureAirport,
500
+ approachAirport,
501
+ routeDisplayText,
502
+ routeCodesText,
503
+ specialDisplayText,
504
+ windowPositionSpeechText: window.speechText,
505
+ aircraftTypeText: aircraft.aircraftTypeText,
506
+ aircraftSize: aircraft.aircraftSize
507
+ });
508
+ return {
509
+ modeVisText,
510
+ windowPositionText: window.text,
511
+ windowPositionClass: window.className,
512
+ windowPositionSpeechText: window.speechText,
513
+ originDisplayName,
514
+ destDisplayName,
515
+ departureAirport,
516
+ approachAirport,
517
+ routeDisplayText,
518
+ routeCodesText,
519
+ specialDisplayText,
520
+ manufacturer: aircraft.manufacturer,
521
+ manufacturerLogoText: aircraft.manufacturerLogoText,
522
+ manufacturerLogoUrl: aircraft.manufacturerLogoUrl,
523
+ aircraftTypeText: aircraft.aircraftTypeText,
524
+ aircraftSize: aircraft.aircraftSize
525
+ };
526
+ }
527
+ function airportLabel(name, iata) {
528
+ const n = String(name || "").trim();
529
+ const c = String(iata || "").trim().toUpperCase();
530
+ if (n && c && n !== "\u2014") {
531
+ return `${n} (${c})`;
532
+ }
533
+ if (c) {
534
+ return c;
535
+ }
536
+ if (n && n !== "\u2014") {
537
+ return n;
538
+ }
539
+ return "";
540
+ }
541
+ function modeVisTextFromFlight(a, originDisplayName, destDisplayName) {
542
+ const mode = String(a.mode || "").toUpperCase();
543
+ if (mode === "TAKEOFF") {
544
+ return `\u{1F6EB} Start ${originDisplayName !== "\u2014" ? originDisplayName : ""}`.trim();
545
+ }
546
+ if (mode === "LANDING") {
547
+ return `\u{1F6EC} Landung ${destDisplayName !== "\u2014" ? destDisplayName : ""}`.trim();
548
+ }
549
+ if (mode === "OVERFLIGHT") {
550
+ return "\u{1F6E9}\uFE0F \xDCberflug";
551
+ }
552
+ return "\u2708\uFE0F Flight";
553
+ }
554
+ function windowPositionInfo(a) {
555
+ const bearing = Number(a.bearingHomeDeg || 0);
556
+ const diff = Number(a.windowDiffDeg || 0);
557
+ if (!bearing && !diff) {
558
+ return {
559
+ text: "\u2197\uFE0F Position unbekannt",
560
+ className: "side",
561
+ speechText: "am Fenster"
562
+ };
563
+ }
564
+ const abs = Math.abs(diff);
565
+ if (abs <= 8) {
566
+ return {
567
+ text: "\u2B06\uFE0F direkt vor dem Fenster",
568
+ className: "center",
569
+ speechText: "direkt vor dem Fenster"
570
+ };
571
+ }
572
+ if (diff < 0) {
573
+ return {
574
+ text: `\u2B05\uFE0F links vom Fenster \xB7 ${Math.round(abs)}\xB0`,
575
+ className: "side",
576
+ speechText: "links vom Fenster"
577
+ };
578
+ }
579
+ return {
580
+ text: `\u27A1\uFE0F rechts vom Fenster \xB7 ${Math.round(abs)}\xB0`,
581
+ className: "side",
582
+ speechText: "rechts vom Fenster"
583
+ };
584
+ }
585
+ async function aircraftDisplayInfo(adapter, config, a) {
586
+ const raw = String(a.aircraftModel || a.aircraftType || a.type || "").trim();
587
+ const type = String(a.aircraftType || a.type || "").trim().toUpperCase();
588
+ const model = String(a.aircraftModel || "").trim().toUpperCase();
589
+ const all = `${type} ${model} ${raw}`.toUpperCase();
590
+ let manufacturer = "Flugzeug";
591
+ let manufacturerLogoText = "\u2708";
592
+ let aircraftTypeText = raw || type || "\u2014";
593
+ if (all.includes("AIRBUS") || /^A\d/.test(type)) {
594
+ manufacturer = "Airbus";
595
+ manufacturerLogoText = "A";
596
+ if (type && /^A\d/.test(type)) {
597
+ aircraftTypeText = `Airbus ${type}`;
598
+ }
599
+ } else if (all.includes("BOEING") || /^B\d/.test(type)) {
600
+ manufacturer = "Boeing";
601
+ manufacturerLogoText = "B";
602
+ if (type && /^B\d/.test(type)) {
603
+ aircraftTypeText = `Boeing ${type}`;
604
+ }
605
+ } else if (all.includes("EMBRAER") || /^E\d/.test(type) || all.includes("E-JET")) {
606
+ manufacturer = "Embraer";
607
+ manufacturerLogoText = "E";
608
+ if (type) {
609
+ aircraftTypeText = `Embraer ${type}`;
610
+ }
611
+ } else if (all.includes("ATR") || /^AT\d/.test(type)) {
612
+ manufacturer = "ATR";
613
+ manufacturerLogoText = "ATR";
614
+ if (type) {
615
+ aircraftTypeText = `ATR ${type}`;
616
+ }
617
+ } else if (all.includes("DASSAULT") || all.includes("FALCON")) {
618
+ manufacturer = "Dassault";
619
+ manufacturerLogoText = "D";
620
+ if (type) {
621
+ aircraftTypeText = `Dassault ${type}`;
622
+ }
623
+ } else if (all.includes("LOCKHEED") || all.includes("HERCULES") || all.includes("C130")) {
624
+ manufacturer = "Lockheed";
625
+ manufacturerLogoText = "L";
626
+ if (type) {
627
+ aircraftTypeText = `Lockheed ${type}`;
628
+ }
629
+ } else if (all.includes("HONDA") || all.includes("HONDAJET")) {
630
+ manufacturer = "Honda";
631
+ manufacturerLogoText = "H";
632
+ if (type) {
633
+ aircraftTypeText = `HondaJet ${type}`;
634
+ }
635
+ } else if (all.includes("BOMBARDIER") || all.includes("CRJ") || all.includes("CSERIES") || all.includes("A220")) {
636
+ manufacturer = all.includes("A220") ? "Airbus" : "Bombardier";
637
+ manufacturerLogoText = manufacturer === "Airbus" ? "A" : "B";
638
+ if (type) {
639
+ aircraftTypeText = `${manufacturer} ${type}`;
640
+ }
641
+ }
642
+ const aircraftSize = aircraftSizeLabel(all);
643
+ let manufacturerLogoUrl = findConfiguredManufacturerLogo(config, manufacturer, all);
644
+ if (manufacturerLogoUrl && config.cacheExternalImages) {
645
+ manufacturerLogoUrl = await (0, import_images.cacheExternalLogoUrl)(
646
+ adapter,
647
+ manufacturerLogoUrl,
648
+ manufacturer,
649
+ import_images.MANUFACTURER_LOGO_CACHE_DIR,
650
+ adapter.log.debug.bind(adapter.log),
651
+ adapter.log.warn.bind(adapter.log)
652
+ );
653
+ }
654
+ return {
655
+ manufacturer,
656
+ manufacturerLogoText,
657
+ manufacturerLogoUrl,
658
+ aircraftTypeText,
659
+ aircraftSize
660
+ };
661
+ }
662
+ function findConfiguredManufacturerLogo(config, manufacturer, allText) {
663
+ if (!config.externalManufacturerLogos) {
664
+ return "";
665
+ }
666
+ const entries = parseManufacturerLogoConfig(config.manufacturerLogoUrls);
667
+ if (!entries.length) {
668
+ return "";
669
+ }
670
+ const haystack = `${manufacturer} ${allText}`.toUpperCase();
671
+ for (const entry of entries) {
672
+ if (haystack.includes(entry.key)) {
673
+ return entry.url;
674
+ }
675
+ }
676
+ return "";
677
+ }
678
+ function parseManufacturerLogoConfig(raw) {
679
+ const text = String(raw || "").trim();
680
+ if (!text) {
681
+ return [];
682
+ }
683
+ try {
684
+ const obj = JSON.parse(text);
685
+ if (obj && typeof obj === "object" && !Array.isArray(obj)) {
686
+ return Object.entries(obj).map(([key, url]) => ({
687
+ key: String(key || "").trim().toUpperCase(),
688
+ url: String(url || "").trim()
689
+ })).filter((entry) => !!entry.key && /^https?:\/\//i.test(entry.url));
690
+ }
691
+ } catch {
692
+ }
693
+ return text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => {
694
+ const idx = line.indexOf("=");
695
+ if (idx < 1) {
696
+ return null;
697
+ }
698
+ return {
699
+ key: line.slice(0, idx).trim().toUpperCase(),
700
+ url: line.slice(idx + 1).trim()
701
+ };
702
+ }).filter((entry) => !!(entry == null ? void 0 : entry.key) && /^https?:\/\//i.test(entry.url));
703
+ }
704
+ function aircraftSizeLabel(allText) {
705
+ const all = String(allText || "").toUpperCase().replace(/[\s_-]/g, "");
706
+ if (/A38|A380|A388/.test(all)) {
707
+ return "Superjumbo";
708
+ }
709
+ if (/B74|B747|B741|B742|B743|B744|B748/.test(all)) {
710
+ return "Jumbo";
711
+ }
712
+ if (/AN124|AN225|C5M|GALAXY|C17|C17A|GLOBEMASTER/.test(all)) {
713
+ return "Heavy Cargo";
714
+ }
715
+ if (/A400|A400M|C130|HERCULES|KC135|KC46|E3|E7/.test(all)) {
716
+ return "Military";
717
+ }
718
+ if (/A300|A310|A330|A332|A333|A338|A339/.test(all) || /A340|A342|A343|A345|A346/.test(all) || /A350|A359|A35K|A351/.test(all) || /B757|B752|B753/.test(all) || /B767|B762|B763|B764/.test(all) || /B777|B772|B773|B77W|B778|B779|B77L|B77F/.test(all) || /B787|B788|B789|B78X/.test(all) || /DC10|MD11|IL86|IL96|L1011/.test(all)) {
719
+ return "Widebody";
720
+ }
721
+ if (/A300F|A330F|B763F|B752F|B733F|B734F|B738F|AN12|AN26/.test(all)) {
722
+ return "Cargo";
723
+ }
724
+ if (/A220|A221|A223|BCS1|BCS3|CS100|CS300/.test(all) || /A318|A319|A320|A321|A20N|A21N/.test(all) || /B707|B717|B727|B737|B731|B732|B733|B734|B735|B736|B738|B739|B38M|B39M/.test(all) || /DC8|DC9|MD80|MD81|MD82|MD83|MD87|MD88|MD90/.test(all) || /TU134|TU154|TU204|TU214|C919|ARJ21|MC21/.test(all)) {
725
+ return "Narrowbody";
726
+ }
727
+ if (/CRJ|CRJ1|CRJ2|CRJ7|CRJ9|CRJX|CRJ100|CRJ200|CRJ700|CRJ900|CRJ1000/.test(all) || /ERJ|E135|E140|E145|E170|E175|E190|E195|E290|E295/.test(all) || /AT42|AT43|AT45|AT46|AT72|AT75|AT76|ATR/.test(all) || /DH8|DHC8|Q200|Q300|Q400/.test(all) || /SF34|SF340|SB20|F50|F70|F100|DO228|DO328|RJ70|RJ85|RJ100/.test(all)) {
728
+ return "Regional";
729
+ }
730
+ if (/GLEX|GLF|G280|G450|G500|G550|G650|G700/.test(all) || /CL30|CL35|CL60|GLOBAL|CHALLENGER/.test(all) || /FALCON|FA7X|FA8X|FA50|FA90|F2TH|F900|F2000/.test(all) || /CITATION|C25A|C25B|C25C|C56X|C68A|C700|LJ35|LJ45|LJ60|LJ75/.test(all) || /LEGACY|PRAETOR|PHENOM|E50P|E55P|HA420|PC24/.test(all)) {
731
+ return "Business Jet";
732
+ }
733
+ if (/C172|C182|C206|C208|PA28|PA34|BE20|BE9L|PC12|DA40|DA42/.test(all)) {
734
+ return "General Aviation";
735
+ }
736
+ if (/EC135|EC145|H135|H145|H160|AW109|AW139|AW169|AW189|S76|S92|UH60|CH47|MI8|KA32/.test(all)) {
737
+ return "Helicopter";
738
+ }
739
+ if (/F14|F15|F16|F18|F22|F35|EUROFIGHTER|TYPHOON|RAFALE|GRIPEN|MIRAGE|SU27|SU30|SU35|MIG29|B1|B2|B52|TU95|TU160/.test(
740
+ all
741
+ )) {
742
+ return "Military";
743
+ }
744
+ return "Unknown";
745
+ }
746
+ function buildSpeechText(a, display) {
747
+ const mode = String(a.mode || "").toUpperCase();
748
+ let modeSpeechText = "Flug";
749
+ let routeDirectionText = "von";
750
+ let routeOtherAirport = display.originDisplayName || display.destDisplayName || "";
751
+ if (mode === "LANDING") {
752
+ modeSpeechText = "Landung";
753
+ routeDirectionText = "aus";
754
+ routeOtherAirport = display.originDisplayName || "";
755
+ }
756
+ if (mode === "TAKEOFF") {
757
+ modeSpeechText = "Start";
758
+ routeDirectionText = "nach";
759
+ routeOtherAirport = display.destDisplayName || "";
760
+ }
761
+ if (mode === "OVERFLIGHT") {
762
+ modeSpeechText = "\xDCberflug";
763
+ routeDirectionText = "von";
764
+ routeOtherAirport = display.routeDisplayText || "";
765
+ }
766
+ const bestCallsign = String(a.routeCallsign || a.callsign || "").trim();
767
+ const template = "{modeSpeechText}: {airlineName} {bestCallsign} {routeDirectionText} {routeOtherAirport} in {altitudeFt} Fu\xDF. {windowPositionSpeechText}.";
768
+ const values = {
769
+ modeSpeechText,
770
+ routeDirectionText,
771
+ routeOtherAirport,
772
+ bestCallsign,
773
+ airlineName: String(a.airlineName || "Unbekannte Airline"),
774
+ callsign: String(a.callsign || ""),
775
+ operationalCallsign: String(a.operationalCallsign || a.callsign || ""),
776
+ routeCallsign: String(a.routeCallsign || a.callsign || ""),
777
+ originDisplayName: display.originDisplayName || "",
778
+ destDisplayName: display.destDisplayName || "",
779
+ routeDisplayText: display.routeDisplayText || "",
780
+ routeCodesText: display.routeCodesText || "",
781
+ aircraftTypeText: display.aircraftTypeText || "",
782
+ aircraftSize: display.aircraftSize || "",
783
+ registration: String(a.registration || ""),
784
+ altitudeFt: String(Math.round(a.altFt || 0)),
785
+ speedKt: String(Math.round(a.speedKt || 0)),
786
+ verticalRate: String(Math.round(a.verticalRate || 0)),
787
+ trackDeg: String(Math.round(a.trackDeg || 0)),
788
+ windowPositionSpeechText: display.windowPositionSpeechText || "",
789
+ specialDisplayText: display.specialDisplayText || ""
790
+ };
791
+ return template.replace(/\{([a-zA-Z0-9_]+)\}/g, (_match, key) => values[key] || "").replace(/\s+/g, " ").replace(/\s+\./g, ".").trim();
792
+ }
793
+ async function maybeTriggerSpeech(adapter, base, a, speechText) {
794
+ if (!base.endsWith(".current")) {
795
+ return;
796
+ }
797
+ const root = base.split(".").slice(0, -1).join(".");
798
+ let speechMode = "browser";
799
+ try {
800
+ const st = await adapter.getForeignStateAsync(`${root}.speechMode`);
801
+ speechMode = String((st == null ? void 0 : st.val) || "browser");
802
+ } catch {
803
+ speechMode = "browser";
804
+ }
805
+ if (speechMode !== "external" && speechMode !== "both") {
806
+ return;
807
+ }
808
+ const key = [
809
+ String(a.callsign || ""),
810
+ String(a.routeCallsign || ""),
811
+ String(a.registration || ""),
812
+ String(speechText || "")
813
+ ].join("|");
814
+ if (!key || LAST_SPEECH_TRIGGER[base] === key) {
815
+ return;
816
+ }
817
+ LAST_SPEECH_TRIGGER[base] = key;
818
+ await adapter.setForeignStateAsync(`${base}.speechTrigger`, true, true);
819
+ setTimeout(() => {
820
+ adapter.setForeignStateAsync(`${base}.speechTrigger`, false, true).catch(() => {
821
+ });
822
+ }, 500);
823
+ }
824
+ async function buildSpeechTextForWrite(adapter, base, a, display) {
825
+ const root = base.split(".").slice(0, -1).join(".");
826
+ let template = "{modeSpeechText}: {airlineName} {bestCallsign} {routeDirectionText} {routeOtherAirport} in {altitudeFt} Fuss. {windowPositionSpeechText}.";
827
+ try {
828
+ const st = await adapter.getForeignStateAsync(`${root}.speechTemplate`);
829
+ if (st == null ? void 0 : st.val) {
830
+ template = String(st.val);
831
+ }
832
+ } catch {
833
+ }
834
+ return buildSpeechTextFromTemplate(a, display, template);
835
+ }
836
+ function buildSpeechTextFromTemplate(a, display, template) {
837
+ const mode = String(a.mode || "").toUpperCase();
838
+ let modeSpeechText = "Flug";
839
+ let routeDirectionText = "von";
840
+ let routeOtherAirport = display.originDisplayName || display.destDisplayName || "";
841
+ if (mode === "LANDING") {
842
+ modeSpeechText = "Landung";
843
+ routeDirectionText = "aus";
844
+ routeOtherAirport = display.originDisplayName || "";
845
+ }
846
+ if (mode === "TAKEOFF") {
847
+ modeSpeechText = "Start";
848
+ routeDirectionText = "nach";
849
+ routeOtherAirport = display.destDisplayName || "";
850
+ }
851
+ if (mode === "OVERFLIGHT") {
852
+ modeSpeechText = "\xDCberflug";
853
+ routeDirectionText = "von";
854
+ routeOtherAirport = display.routeDisplayText || "";
855
+ }
856
+ const bestCallsign = String(a.routeCallsign || a.callsign || "").trim();
857
+ const values = {
858
+ modeSpeechText,
859
+ routeDirectionText,
860
+ routeOtherAirport,
861
+ bestCallsign,
862
+ airlineName: String(a.airlineName || "Unbekannte Airline"),
863
+ callsign: String(a.callsign || ""),
864
+ operationalCallsign: String(a.operationalCallsign || a.callsign || ""),
865
+ routeCallsign: String(a.routeCallsign || a.callsign || ""),
866
+ originDisplayName: display.originDisplayName || "",
867
+ destDisplayName: display.destDisplayName || "",
868
+ routeDisplayText: display.routeDisplayText || "",
869
+ routeCodesText: display.routeCodesText || "",
870
+ aircraftTypeText: display.aircraftTypeText || "",
871
+ aircraftSize: display.aircraftSize || "",
872
+ registration: String(a.registration || ""),
873
+ altitudeFt: String(Math.round(a.altFt || 0)),
874
+ speedKt: String(Math.round(a.speedKt || 0)),
875
+ verticalRate: String(Math.round(a.verticalRate || 0)),
876
+ trackDeg: String(Math.round(a.trackDeg || 0)),
877
+ windowPositionSpeechText: display.windowPositionSpeechText || "",
878
+ specialDisplayText: display.specialDisplayText || ""
879
+ };
880
+ return String(template || "").replace(/\{([a-zA-Z0-9_]+)\}/g, (_match, key) => values[key] || "").replace(/\s+/g, " ").replace(/\s+\./g, ".").trim();
881
+ }
882
+ function cityOnly(name) {
883
+ const v = String(name || "").replace(/\bAirport\b/gi, "").replace(/\bInternational\b/gi, "").replace(/\bIntl\b/gi, "").replace(/\bFlughafen\b/gi, "").replace(/\bFort Worth\b/gi, "").replace(/\bMain\b/gi, "").replace(/\s+/g, " ").trim();
884
+ if (v === "Frankfurt am") {
885
+ return "Frankfurt";
886
+ }
887
+ return v;
888
+ }
889
+ function buildMessage(a) {
890
+ const lines = [];
891
+ const routeCallsign = String(a.routeCallsign || a.callsign || "").trim().toUpperCase();
892
+ lines.push("\u2708\uFE0F JetFrame");
893
+ lines.push("");
894
+ lines.push(`${a.icon || "\u2708\uFE0F"} ${modeText(a.mode || "")}`);
895
+ lines.push(`Flug: ${a.callsign || a.hex || "unbekannt"}`);
896
+ if (routeCallsign) {
897
+ lines.push(`Route \xFCber: ${routeCallsign}`);
898
+ }
899
+ if (a.airlineName) {
900
+ lines.push(`Airline: ${a.airlineName}`);
901
+ }
902
+ if (a.routeTextLong) {
903
+ lines.push(`Route: ${a.routeTextLong}`);
904
+ } else if (a.routeText) {
905
+ lines.push(`Route: ${a.routeText}`);
906
+ } else if (a.routeWarning) {
907
+ lines.push(`Route: ${a.routeWarning}`);
908
+ } else if (a.directionText) {
909
+ lines.push(`Richtung: ${a.directionText}`);
910
+ }
911
+ if (a.routeSource) {
912
+ lines.push(`Quelle: ${a.routeSource}`);
913
+ }
914
+ if (a.aircraftModel) {
915
+ lines.push(`Flugzeug: ${a.aircraftModel}`);
916
+ } else if (a.aircraftType || a.type) {
917
+ lines.push(`Typ: ${a.aircraftType || a.type}`);
918
+ }
919
+ if (a.registration) {
920
+ lines.push(`Kennz.: ${a.registration}`);
921
+ }
922
+ lines.push("");
923
+ lines.push(`H\xF6he: ${Math.round(a.altFt || 0)} ft`);
924
+ lines.push(`Speed: ${Math.round(a.speedKt || 0)} kt`);
925
+ lines.push(`Steigrate: ${Math.round(a.verticalRate || 0)} ft/min`);
926
+ lines.push(`Kurs: ${Math.round(a.trackDeg || 0)}\xB0`);
927
+ const specialDisplayText = a.specialLiveryVisText || a.specialLiveryFull || a.specialText || "";
928
+ if (specialDisplayText) {
929
+ lines.push("");
930
+ lines.push(`${a.isSpecial ? "\u2B50 Besonderheit: " : "\u2139\uFE0F Info: "}${specialDisplayText}`);
931
+ }
932
+ return lines.join("\n");
933
+ }
934
+ function modeText(mode) {
935
+ if (mode === "LANDING") {
936
+ return "Landung";
937
+ }
938
+ if (mode === "TAKEOFF") {
939
+ return "Start";
940
+ }
941
+ if (mode === "OVERFLIGHT") {
942
+ return "\xDCberflug";
943
+ }
944
+ return "Flug";
945
+ }
946
+ async function ensureStates(adapter, config) {
947
+ await ensureBaseStates(adapter, config);
948
+ }
949
+ async function keepExistingStringState(adapter, id, value) {
950
+ const next = String(value || "").trim();
951
+ if (next) {
952
+ return next;
953
+ }
954
+ try {
955
+ const oldState = await adapter.getForeignStateAsync(id);
956
+ return String((oldState == null ? void 0 : oldState.val) || "").trim();
957
+ } catch {
958
+ return "";
959
+ }
960
+ }
961
+ // Annotate the CommonJS export names for ESM import in node:
962
+ 0 && (module.exports = {
963
+ clearFlight,
964
+ ensureBaseStates,
965
+ ensureFlightStates,
966
+ ensureState,
967
+ ensureStates,
968
+ trackDirectionText,
969
+ writeFlight
970
+ });
971
+ //# sourceMappingURL=states.js.map