lightman-agent 1.0.21 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cms-agent.js +39 -60
- package/package.json +1 -1
- package/scripts/guardian.ps1 +25 -6
- package/scripts/install-linux.sh +4 -4
- package/scripts/install-windows.ps1 +159 -51
- package/scripts/launch-kiosk.vbs +23 -7
- package/scripts/lightman-shell.bat +30 -9
- package/scripts/setup.ps1 +25 -9
- package/scripts/setup.sh +4 -4
- package/src/index.ts +142 -142
- package/src/lib/screenMap.ts +135 -135
- package/src/services/multiScreenKiosk.ts +356 -356
package/scripts/setup.ps1
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
# Generates agent.config.json for this specific device.
|
|
3
3
|
#
|
|
4
4
|
# Usage (run from agent directory or scripts directory):
|
|
5
|
-
# powershell -ExecutionPolicy Bypass -File setup.ps1 -Slug "f-av01" -Server "http://192.168.
|
|
6
|
-
# powershell -ExecutionPolicy Bypass -File setup.ps1 -Slug "f-av01" -Server "http://192.168.
|
|
5
|
+
# powershell -ExecutionPolicy Bypass -File setup.ps1 -Slug "f-av01" -Server "http://192.168.10.100:3401"
|
|
6
|
+
# powershell -ExecutionPolicy Bypass -File setup.ps1 -Slug "f-av01" -Server "http://192.168.10.100:3401" -Timezone "Asia/Kolkata"
|
|
7
7
|
#
|
|
8
8
|
# This script MUST be run once on every new device installation.
|
|
9
9
|
# It clears any cached identity so the device provisions fresh.
|
|
@@ -42,6 +42,23 @@ Write-Host " Install dir: $InstallDir"
|
|
|
42
42
|
Write-Host " Timezone: $Timezone"
|
|
43
43
|
Write-Host ""
|
|
44
44
|
|
|
45
|
+
function Get-KioskBrowserPath {
|
|
46
|
+
$candidates = @(
|
|
47
|
+
"C:\Program Files\Google\Chrome\Application\chrome.exe",
|
|
48
|
+
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe",
|
|
49
|
+
(Join-Path $env:LOCALAPPDATA "Google\Chrome\Application\chrome.exe"),
|
|
50
|
+
"C:\Program Files\Microsoft\Edge\Application\msedge.exe",
|
|
51
|
+
"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
|
|
52
|
+
(Join-Path $env:LOCALAPPDATA "Microsoft\Edge\Application\msedge.exe")
|
|
53
|
+
) | Where-Object { $_ -and (Test-Path $_) }
|
|
54
|
+
|
|
55
|
+
if ($candidates.Count -gt 0) {
|
|
56
|
+
return $candidates[0]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
throw "Neither Google Chrome nor Microsoft Edge was found. Install one of them and re-run setup."
|
|
60
|
+
}
|
|
61
|
+
|
|
45
62
|
# 1. Clear cached identity (CRITICAL - prevents old device credentials leaking)
|
|
46
63
|
$IdentityFile = Join-Path $InstallDir ".lightman-identity.json"
|
|
47
64
|
if (Test-Path $IdentityFile) {
|
|
@@ -55,13 +72,12 @@ if (Test-Path $IdentityFile) {
|
|
|
55
72
|
$KioskUrl = "http://localhost:3403/display/$Slug"
|
|
56
73
|
|
|
57
74
|
# 3. Detect browser path
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
$BrowserPath
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
Write-Host "[WARN] Chrome not found - using 'chromium-browser'" -ForegroundColor Yellow
|
|
75
|
+
try {
|
|
76
|
+
$BrowserPath = Get-KioskBrowserPath
|
|
77
|
+
Write-Host "[OK] Using kiosk browser: $BrowserPath" -ForegroundColor Green
|
|
78
|
+
} catch {
|
|
79
|
+
Write-Host "[ERROR] $($_.Exception.Message)" -ForegroundColor Red
|
|
80
|
+
exit 1
|
|
65
81
|
}
|
|
66
82
|
|
|
67
83
|
$ChromeDataDir = "C:\ProgramData\Lightman\chrome-kiosk"
|
package/scripts/setup.sh
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
# Generates agent.config.json for this specific device.
|
|
4
4
|
#
|
|
5
5
|
# Usage:
|
|
6
|
-
# sudo bash setup.sh --slug f-av01 --server http://192.168.
|
|
7
|
-
# sudo bash setup.sh --slug f-av01 --server http://192.168.
|
|
6
|
+
# sudo bash setup.sh --slug f-av01 --server http://192.168.10.100:3401
|
|
7
|
+
# sudo bash setup.sh --slug f-av01 --server http://192.168.10.100:3401 --timezone Asia/Kolkata --dir /opt/lightman/agent
|
|
8
8
|
#
|
|
9
9
|
# This script MUST be run once on every new device installation.
|
|
10
10
|
# It clears any cached identity so the device provisions fresh.
|
|
@@ -37,13 +37,13 @@ done
|
|
|
37
37
|
|
|
38
38
|
if [[ -z "$SLUG" ]]; then
|
|
39
39
|
echo "Error: --slug is required"
|
|
40
|
-
echo "Usage: bash setup.sh --slug f-av01 --server http://192.168.
|
|
40
|
+
echo "Usage: bash setup.sh --slug f-av01 --server http://192.168.10.100:3401"
|
|
41
41
|
exit 1
|
|
42
42
|
fi
|
|
43
43
|
|
|
44
44
|
if [[ -z "$SERVER" ]]; then
|
|
45
45
|
echo "Error: --server is required"
|
|
46
|
-
echo "Usage: bash setup.sh --slug f-av01 --server http://192.168.
|
|
46
|
+
echo "Usage: bash setup.sh --slug f-av01 --server http://192.168.10.100:3401"
|
|
47
47
|
exit 1
|
|
48
48
|
fi
|
|
49
49
|
|
package/src/index.ts
CHANGED
|
@@ -10,11 +10,11 @@ import { KioskManager } from './services/kiosk.js';
|
|
|
10
10
|
import { registerPowerCommands } from './commands/power.js';
|
|
11
11
|
import { registerKioskCommands, registerMultiScreenKioskCommands } from './commands/kiosk.js';
|
|
12
12
|
import { registerScreenshotCommands } from './commands/screenshot.js';
|
|
13
|
-
import { MultiScreenKioskManager } from './services/multiScreenKiosk.js';
|
|
14
|
-
import { detectScreens } from './lib/screens.js';
|
|
15
|
-
import type { DetectedScreen } from './lib/screens.js';
|
|
16
|
-
import { resolveScreenMap } from './lib/screenMap.js';
|
|
17
|
-
import { registerDisplayCommands } from './commands/display.js';
|
|
13
|
+
import { MultiScreenKioskManager } from './services/multiScreenKiosk.js';
|
|
14
|
+
import { detectScreens } from './lib/screens.js';
|
|
15
|
+
import type { DetectedScreen } from './lib/screens.js';
|
|
16
|
+
import { resolveScreenMap } from './lib/screenMap.js';
|
|
17
|
+
import { registerDisplayCommands } from './commands/display.js';
|
|
18
18
|
import { registerNetworkCommands } from './commands/network.js';
|
|
19
19
|
import { Updater } from './services/updater.js';
|
|
20
20
|
import { registerUpdateCommands } from './commands/update.js';
|
|
@@ -32,7 +32,7 @@ import { SerialBridge } from './services/serialBridge.js';
|
|
|
32
32
|
import { OscBridge } from './services/oscBridge.js';
|
|
33
33
|
import { LocalEventServer } from './services/localEvents.js';
|
|
34
34
|
import { PresenceSensor } from './services/presenceSensor.js';
|
|
35
|
-
import type { WsMessage, KioskConfig, PowerScheduleConfig, Identity, ScreenMapping } from './lib/types.js';
|
|
35
|
+
import type { WsMessage, KioskConfig, PowerScheduleConfig, Identity, ScreenMapping } from './lib/types.js';
|
|
36
36
|
|
|
37
37
|
function getAgentVersion(): string {
|
|
38
38
|
try {
|
|
@@ -168,60 +168,60 @@ async function main(): Promise<void> {
|
|
|
168
168
|
const getIdentity = () => identity!;
|
|
169
169
|
registerMultiScreenKioskCommands(commandExecutor.register.bind(commandExecutor), multiScreenKiosk, getIdentity, logger);
|
|
170
170
|
|
|
171
|
-
// Detect physical screens and keep them fresh (multi-display setups can change after boot).
|
|
172
|
-
let detectedScreens = detectScreens(logger);
|
|
173
|
-
multiScreenKiosk.setDetectedScreens(detectedScreens);
|
|
174
|
-
|
|
175
|
-
const toScreenPayload = (screens: DetectedScreen[]) => (
|
|
176
|
-
screens.map((s) => ({
|
|
177
|
-
hardwareId: s.hardwareId,
|
|
178
|
-
name: s.name,
|
|
179
|
-
index: s.index,
|
|
180
|
-
width: s.width,
|
|
181
|
-
height: s.height,
|
|
182
|
-
x: s.x,
|
|
183
|
-
y: s.y,
|
|
184
|
-
primary: s.primary,
|
|
185
|
-
}))
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
const sendAgentRegister = () => {
|
|
189
|
-
wsClient.send({
|
|
190
|
-
type: 'agent:register',
|
|
191
|
-
payload: {
|
|
192
|
-
agentVersion: getAgentVersion(),
|
|
193
|
-
screens: toScreenPayload(detectedScreens),
|
|
194
|
-
},
|
|
195
|
-
timestamp: Date.now(),
|
|
196
|
-
});
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
const refreshDetectedScreens = async (reason: string) => {
|
|
200
|
-
const latest = detectScreens(logger);
|
|
201
|
-
if (!haveScreensChanged(detectedScreens, latest)) return;
|
|
202
|
-
|
|
203
|
-
logger.info(`[Screens] Topology changed (${reason}): ${detectedScreens.length} -> ${latest.length}`);
|
|
204
|
-
detectedScreens = latest;
|
|
205
|
-
multiScreenKiosk.setDetectedScreens(detectedScreens);
|
|
206
|
-
|
|
207
|
-
if (wsClient.isConnected()) {
|
|
208
|
-
sendAgentRegister();
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (multiScreenKiosk.hasDesiredScreenMap()) {
|
|
212
|
-
try {
|
|
213
|
-
await multiScreenKiosk.reapplyDesiredMap(identity);
|
|
214
|
-
} catch (err) {
|
|
215
|
-
logger.error('[MultiKiosk] Failed to reapply desired screen map after topology change:', err);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
const screenRefreshInterval = setInterval(() => {
|
|
221
|
-
refreshDetectedScreens('periodic-refresh').catch((err) => {
|
|
222
|
-
logger.error('[Screens] Periodic refresh failed:', err);
|
|
223
|
-
});
|
|
224
|
-
}, 20_000);
|
|
171
|
+
// Detect physical screens and keep them fresh (multi-display setups can change after boot).
|
|
172
|
+
let detectedScreens = detectScreens(logger);
|
|
173
|
+
multiScreenKiosk.setDetectedScreens(detectedScreens);
|
|
174
|
+
|
|
175
|
+
const toScreenPayload = (screens: DetectedScreen[]) => (
|
|
176
|
+
screens.map((s) => ({
|
|
177
|
+
hardwareId: s.hardwareId,
|
|
178
|
+
name: s.name,
|
|
179
|
+
index: s.index,
|
|
180
|
+
width: s.width,
|
|
181
|
+
height: s.height,
|
|
182
|
+
x: s.x,
|
|
183
|
+
y: s.y,
|
|
184
|
+
primary: s.primary,
|
|
185
|
+
}))
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const sendAgentRegister = () => {
|
|
189
|
+
wsClient.send({
|
|
190
|
+
type: 'agent:register',
|
|
191
|
+
payload: {
|
|
192
|
+
agentVersion: getAgentVersion(),
|
|
193
|
+
screens: toScreenPayload(detectedScreens),
|
|
194
|
+
},
|
|
195
|
+
timestamp: Date.now(),
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const refreshDetectedScreens = async (reason: string) => {
|
|
200
|
+
const latest = detectScreens(logger);
|
|
201
|
+
if (!haveScreensChanged(detectedScreens, latest)) return;
|
|
202
|
+
|
|
203
|
+
logger.info(`[Screens] Topology changed (${reason}): ${detectedScreens.length} -> ${latest.length}`);
|
|
204
|
+
detectedScreens = latest;
|
|
205
|
+
multiScreenKiosk.setDetectedScreens(detectedScreens);
|
|
206
|
+
|
|
207
|
+
if (wsClient.isConnected()) {
|
|
208
|
+
sendAgentRegister();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (multiScreenKiosk.hasDesiredScreenMap()) {
|
|
212
|
+
try {
|
|
213
|
+
await multiScreenKiosk.reapplyDesiredMap(identity);
|
|
214
|
+
} catch (err) {
|
|
215
|
+
logger.error('[MultiKiosk] Failed to reapply desired screen map after topology change:', err);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const screenRefreshInterval = setInterval(() => {
|
|
221
|
+
refreshDetectedScreens('periodic-refresh').catch((err) => {
|
|
222
|
+
logger.error('[Screens] Periodic refresh failed:', err);
|
|
223
|
+
});
|
|
224
|
+
}, 20_000);
|
|
225
225
|
|
|
226
226
|
// Create Watchdog (Phase 20)
|
|
227
227
|
const watchdog = new Watchdog(
|
|
@@ -464,11 +464,11 @@ async function main(): Promise<void> {
|
|
|
464
464
|
watchdog.start();
|
|
465
465
|
powerScheduler.start();
|
|
466
466
|
|
|
467
|
-
// Send registration message once connected, then auto-launch kiosk
|
|
468
|
-
const registerInterval = setInterval(() => {
|
|
469
|
-
if (wsClient.isConnected()) {
|
|
470
|
-
sendAgentRegister();
|
|
471
|
-
clearInterval(registerInterval);
|
|
467
|
+
// Send registration message once connected, then auto-launch kiosk
|
|
468
|
+
const registerInterval = setInterval(() => {
|
|
469
|
+
if (wsClient.isConnected()) {
|
|
470
|
+
sendAgentRegister();
|
|
471
|
+
clearInterval(registerInterval);
|
|
472
472
|
|
|
473
473
|
// Fetch device config first to decide single vs multi-screen kiosk
|
|
474
474
|
fetchDeviceConfig(config.serverUrl, identity, logger).then((deviceCfg) => {
|
|
@@ -499,31 +499,31 @@ async function main(): Promise<void> {
|
|
|
499
499
|
} else {
|
|
500
500
|
logger.info('[Presence] Template is not presence-enabled — sensor not started');
|
|
501
501
|
}
|
|
502
|
-
// Multi-screen handling:
|
|
503
|
-
// 1) Use explicit screenMap when present.
|
|
504
|
-
// 2) For multi-screen apps without a saved map, auto-create placeholders.
|
|
505
|
-
const requestedScreenMap = deviceCfg?.screenMap || [];
|
|
506
|
-
const isMultiScreenApp = !!deviceCfg && deviceCfg.totalScreens > 1;
|
|
507
|
-
const effectiveRequestedMap = requestedScreenMap.length > 0
|
|
508
|
-
? requestedScreenMap
|
|
509
|
-
: (isMultiScreenApp ? createPlaceholderScreenMap(deviceCfg.totalScreens) : []);
|
|
510
|
-
|
|
511
|
-
if (effectiveRequestedMap.length > 0) {
|
|
512
|
-
const resolved = resolveScreenMap({
|
|
513
|
-
requestedScreenMap: effectiveRequestedMap,
|
|
514
|
-
detectedScreens,
|
|
515
|
-
totalScreens: Math.max(deviceCfg?.totalScreens || 0, effectiveRequestedMap.length),
|
|
516
|
-
});
|
|
517
|
-
logger.info(
|
|
518
|
-
`[MultiKiosk] Effective map ready: requested=${effectiveRequestedMap.length}, mode=${resolved.mode}, totalScreens=${deviceCfg?.totalScreens || 0}`
|
|
519
|
-
);
|
|
520
|
-
watchdog.setMultiScreenActive(true);
|
|
521
|
-
multiScreenKiosk.applyScreenMap(effectiveRequestedMap, identity).catch((err) => {
|
|
522
|
-
logger.error('[MultiKiosk] Failed to apply effective screenMap from config:', err);
|
|
523
|
-
});
|
|
524
|
-
return;
|
|
525
|
-
}
|
|
526
|
-
|
|
502
|
+
// Multi-screen handling:
|
|
503
|
+
// 1) Use explicit screenMap when present.
|
|
504
|
+
// 2) For multi-screen apps without a saved map, auto-create placeholders.
|
|
505
|
+
const requestedScreenMap = deviceCfg?.screenMap || [];
|
|
506
|
+
const isMultiScreenApp = !!deviceCfg && deviceCfg.totalScreens > 1;
|
|
507
|
+
const effectiveRequestedMap = requestedScreenMap.length > 0
|
|
508
|
+
? requestedScreenMap
|
|
509
|
+
: (isMultiScreenApp ? createPlaceholderScreenMap(deviceCfg.totalScreens) : []);
|
|
510
|
+
|
|
511
|
+
if (effectiveRequestedMap.length > 0) {
|
|
512
|
+
const resolved = resolveScreenMap({
|
|
513
|
+
requestedScreenMap: effectiveRequestedMap,
|
|
514
|
+
detectedScreens,
|
|
515
|
+
totalScreens: Math.max(deviceCfg?.totalScreens || 0, effectiveRequestedMap.length),
|
|
516
|
+
});
|
|
517
|
+
logger.info(
|
|
518
|
+
`[MultiKiosk] Effective map ready: requested=${effectiveRequestedMap.length}, mode=${resolved.mode}, totalScreens=${deviceCfg?.totalScreens || 0}`
|
|
519
|
+
);
|
|
520
|
+
watchdog.setMultiScreenActive(true);
|
|
521
|
+
multiScreenKiosk.applyScreenMap(effectiveRequestedMap, identity).catch((err) => {
|
|
522
|
+
logger.error('[MultiKiosk] Failed to apply effective screenMap from config:', err);
|
|
523
|
+
});
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
527
|
// No effective multi-screen map - launch single-screen kiosk as before
|
|
528
528
|
if (config.kiosk) {
|
|
529
529
|
if (config.kiosk.shellMode) {
|
|
@@ -552,10 +552,10 @@ async function main(): Promise<void> {
|
|
|
552
552
|
}, 1000);
|
|
553
553
|
|
|
554
554
|
// 7. Graceful shutdown
|
|
555
|
-
const shutdown = async (signal: string): Promise<void> => {
|
|
556
|
-
logger.info(`${signal} received. Shutting down...`);
|
|
557
|
-
clearInterval(registerInterval);
|
|
558
|
-
clearInterval(screenRefreshInterval);
|
|
555
|
+
const shutdown = async (signal: string): Promise<void> => {
|
|
556
|
+
logger.info(`${signal} received. Shutting down...`);
|
|
557
|
+
clearInterval(registerInterval);
|
|
558
|
+
clearInterval(screenRefreshInterval);
|
|
559
559
|
|
|
560
560
|
// Wait for updater to finish if it's busy (max 60s)
|
|
561
561
|
if (updater.isBusy()) {
|
|
@@ -603,36 +603,36 @@ async function main(): Promise<void> {
|
|
|
603
603
|
process.exit(1);
|
|
604
604
|
});
|
|
605
605
|
|
|
606
|
-
logger.info('LIGHTMAN Agent running.');
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
function createPlaceholderScreenMap(totalScreens: number): ScreenMapping[] {
|
|
610
|
-
const count = Math.max(0, Math.floor(totalScreens || 0));
|
|
611
|
-
return Array.from({ length: count }, () => ({ hardwareId: '', url: '' }));
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
function haveScreensChanged(prev: DetectedScreen[], next: DetectedScreen[]): boolean {
|
|
615
|
-
if (prev.length !== next.length) return true;
|
|
616
|
-
for (let i = 0; i < prev.length; i++) {
|
|
617
|
-
const a = prev[i];
|
|
618
|
-
const b = next[i];
|
|
619
|
-
if (
|
|
620
|
-
a.hardwareId !== b.hardwareId
|
|
621
|
-
|| a.index !== b.index
|
|
622
|
-
|| a.x !== b.x
|
|
623
|
-
|| a.y !== b.y
|
|
624
|
-
|| a.width !== b.width
|
|
625
|
-
|| a.height !== b.height
|
|
626
|
-
|| a.primary !== b.primary
|
|
627
|
-
) {
|
|
628
|
-
return true;
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
return false;
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
function handleServerMessage(
|
|
635
|
-
msg: WsMessage,
|
|
606
|
+
logger.info('LIGHTMAN Agent running.');
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
function createPlaceholderScreenMap(totalScreens: number): ScreenMapping[] {
|
|
610
|
+
const count = Math.max(0, Math.floor(totalScreens || 0));
|
|
611
|
+
return Array.from({ length: count }, () => ({ hardwareId: '', url: '' }));
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
function haveScreensChanged(prev: DetectedScreen[], next: DetectedScreen[]): boolean {
|
|
615
|
+
if (prev.length !== next.length) return true;
|
|
616
|
+
for (let i = 0; i < prev.length; i++) {
|
|
617
|
+
const a = prev[i];
|
|
618
|
+
const b = next[i];
|
|
619
|
+
if (
|
|
620
|
+
a.hardwareId !== b.hardwareId
|
|
621
|
+
|| a.index !== b.index
|
|
622
|
+
|| a.x !== b.x
|
|
623
|
+
|| a.y !== b.y
|
|
624
|
+
|| a.width !== b.width
|
|
625
|
+
|| a.height !== b.height
|
|
626
|
+
|| a.primary !== b.primary
|
|
627
|
+
) {
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function handleServerMessage(
|
|
635
|
+
msg: WsMessage,
|
|
636
636
|
commandExecutor: CommandExecutor,
|
|
637
637
|
logger: Logger,
|
|
638
638
|
powerScheduler?: PowerScheduler,
|
|
@@ -756,17 +756,17 @@ async function fetchDeviceConfig(
|
|
|
756
756
|
serverUrl: string,
|
|
757
757
|
identity: Identity,
|
|
758
758
|
logger: Logger
|
|
759
|
-
): Promise<{
|
|
760
|
-
comPort: string;
|
|
761
|
-
controllerId: string;
|
|
762
|
-
baudRate: number;
|
|
763
|
-
screenMap: ScreenMapping[];
|
|
764
|
-
totalScreens: number;
|
|
765
|
-
oscPort: number;
|
|
766
|
-
oscAddress: string;
|
|
767
|
-
oscHost: string;
|
|
768
|
-
templateType: string;
|
|
769
|
-
} | null> {
|
|
759
|
+
): Promise<{
|
|
760
|
+
comPort: string;
|
|
761
|
+
controllerId: string;
|
|
762
|
+
baudRate: number;
|
|
763
|
+
screenMap: ScreenMapping[];
|
|
764
|
+
totalScreens: number;
|
|
765
|
+
oscPort: number;
|
|
766
|
+
oscAddress: string;
|
|
767
|
+
oscHost: string;
|
|
768
|
+
templateType: string;
|
|
769
|
+
} | null> {
|
|
770
770
|
try {
|
|
771
771
|
const url = `${serverUrl}/api/devices/${identity.deviceId}/config`;
|
|
772
772
|
const res = await fetch(url, {
|
|
@@ -788,12 +788,12 @@ async function fetchDeviceConfig(
|
|
|
788
788
|
const controllerId = (appConfig.controllerId as string) || comPort;
|
|
789
789
|
const baudRate = (device?.baud_rate as number) || 115200;
|
|
790
790
|
|
|
791
|
-
// Screen map from device config (set by admin)
|
|
792
|
-
const screenMap = (device?.screenMap as ScreenMapping[]) || [];
|
|
793
|
-
const appScreens = (appConfig.screens as Array<Record<string, unknown>>) || [];
|
|
794
|
-
const totalScreens = appScreens.length > 0
|
|
795
|
-
? appScreens.length
|
|
796
|
-
: ((appConfig.totalScreens as number) || 0);
|
|
791
|
+
// Screen map from device config (set by admin)
|
|
792
|
+
const screenMap = (device?.screenMap as ScreenMapping[]) || [];
|
|
793
|
+
const appScreens = (appConfig.screens as Array<Record<string, unknown>>) || [];
|
|
794
|
+
const totalScreens = appScreens.length > 0
|
|
795
|
+
? appScreens.length
|
|
796
|
+
: ((appConfig.totalScreens as number) || 0);
|
|
797
797
|
|
|
798
798
|
// OSC settings from app config (custom07-osc template)
|
|
799
799
|
const inputSource = appConfig.inputSource as string;
|
|
@@ -803,7 +803,7 @@ async function fetchDeviceConfig(
|
|
|
803
803
|
|
|
804
804
|
const templateType = (assignedApp?.templateType as string) || '';
|
|
805
805
|
|
|
806
|
-
return { comPort, controllerId, baudRate, screenMap, totalScreens, oscPort, oscAddress, oscHost, templateType };
|
|
806
|
+
return { comPort, controllerId, baudRate, screenMap, totalScreens, oscPort, oscAddress, oscHost, templateType };
|
|
807
807
|
} catch (err) {
|
|
808
808
|
logger.debug('Failed to fetch device config:', err);
|
|
809
809
|
return null;
|