From 42f0488fa2119c816fb3cba8e922812abacc3cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrik=20Mint=C4=9Bl?= Date: Mon, 2 Mar 2026 20:39:30 +0100 Subject: [PATCH 1/3] feat: include exposure time --- src/lib/server/nina.ts | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/lib/server/nina.ts b/src/lib/server/nina.ts index e7775fc..3e889ea 100644 --- a/src/lib/server/nina.ts +++ b/src/lib/server/nina.ts @@ -30,6 +30,12 @@ interface SequenceItem { Triggers?: SequenceItem[]; TargetTime?: string; Delay?: number; + ExposureTime?: number; +} + +interface CameraInfo { + ExposureEndTime: string; + IsExposing: boolean; } export type LiveStatus = { @@ -83,7 +89,7 @@ export class NinaClient { } } - private mapRunningAction(item: SequenceItem): string { + private async mapRunningAction(item: SequenceItem): Promise { const name = item.Name || ''; const map: Record = { 'Meridian Flip_Trigger': 'Meridian flip', @@ -109,6 +115,22 @@ export class NinaClient { } } else if (name === 'Wait for Time Span' && item.Delay) { action += ` for ${item.Delay}s`; + } else if (name === 'Smart Exposure' && item.ExposureTime) { + const time = item.ExposureTime; + + //fetch camera end time: + const info = await this.fetch>( + 'api/equipment/camera/info' + ); + + //calculate XXs/XXs (calc/time) + if (info?.Success && info.Response.ExposureEndTime) { + const endTime = new Date(info.Response.ExposureEndTime).getTime(); + const now = Date.now(); + const elapsed = (now - (endTime - time * 1000)) / 1000; + const total = time; + action += ` (${elapsed.toFixed(0)}s/${total}s)`; + } } return action; @@ -205,7 +227,7 @@ export class NinaClient { this.lastUpdate = now; } - const currentAction = this.mapRunningAction(deepestItem!); + const currentAction = await this.mapRunningAction(deepestItem!); const hiddenActions = [ 'Meridian flip', 'Waiting', From 262bc0b70e0ad457cd81acd227f22829efb157ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrik=20Mint=C4=9Bl?= Date: Mon, 2 Mar 2026 20:45:36 +0100 Subject: [PATCH 2/3] feat: added guiding info --- src/lib/lang/_template.ts | 1 + src/lib/lang/czech.ts | 1 + src/lib/lang/english.ts | 1 + src/lib/server/nina.ts | 38 +++++++++++++++++++++++++++++++++++++- 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/lib/lang/_template.ts b/src/lib/lang/_template.ts index 35701e0..6461e03 100644 --- a/src/lib/lang/_template.ts +++ b/src/lib/lang/_template.ts @@ -58,6 +58,7 @@ export default o({ current_status: _, mount: _, image: _, + guide: _, labels: o({ temp: _, exposure: _, diff --git a/src/lib/lang/czech.ts b/src/lib/lang/czech.ts index 6a8aaea..d19df98 100644 --- a/src/lib/lang/czech.ts +++ b/src/lib/lang/czech.ts @@ -37,6 +37,7 @@ export default lang.parse({ current_status: 'Aktuální stav', mount: 'Montáž', image: 'Poslední obrázek', + guide: 'Navádění', labels: { temp: 'Teplota', exposure: 'Expozice', diff --git a/src/lib/lang/english.ts b/src/lib/lang/english.ts index e42240d..afbe89b 100644 --- a/src/lib/lang/english.ts +++ b/src/lib/lang/english.ts @@ -37,6 +37,7 @@ export default lang.parse({ current_status: 'Current Status', mount: 'Mount', image: 'Latest Image', + guide: 'Guiding', labels: { temp: 'Temperature', exposure: 'Exposure', diff --git a/src/lib/server/nina.ts b/src/lib/server/nina.ts index 3e889ea..2754dd4 100644 --- a/src/lib/server/nina.ts +++ b/src/lib/server/nina.ts @@ -38,10 +38,35 @@ interface CameraInfo { IsExposing: boolean; } +//{"Response":{"Connected":true,"Name":"PHD2","DisplayName":"PHD2","Description":"PHD2 Guider","DriverInfo":"PHD2 Guider","DriverVersion":"1.0","DeviceId":"PHD2_Single","CanClearCalibration":true,"CanSetShiftRate":true,"CanGetLockPosition":true,"SupportedActions":[],"RMSError":{"RA":{"Pixel":0.1670851110717076,"Arcseconds":0.5743968405867628},"Dec":{"Pixel":0.14570647415145718,"Arcseconds":0.5009024315141719},"Total":{"Pixel":0.22169305571328599,"Arcseconds":0.7621253022783488},"PeakRA":{"Pixel":0.52,"Arcseconds":1.78763},"PeakDec":{"Pixel":1.21,"Arcseconds":4.1596775}},"PixelScale":3.43775,"LastGuideStep":{"RADistanceRaw":0.12,"DECDistanceRaw":-0.088,"RADuration":1,"DECDuration":0},"State":"Guiding"},"Error":"","StatusCode":200,"Success":true,"Type":"API"} +interface GuideResponse { + RMSError: { + RA: { + Pixel: number; + Arcseconds: number; + }; + Dec: { + Pixel: number; + Arcseconds: number; + }; + Total: { + Pixel: number; + Arcseconds: number; + }; + }; +} + +interface GuideInfo { + ra: number; + dec: number; + total: number; +} + export type LiveStatus = { active: boolean; imageInfo?: ImageHistoryItem; mountInfo?: MountInfo; + guideInfo?: GuideInfo; currentAction?: string; showImage?: boolean; }; @@ -246,12 +271,23 @@ export class NinaClient { showImage = false; } + const guideData = await this.fetch>( + 'api/equipment/guider/info' + ); + this.cachedLiveStatus = { active: true, mountInfo: mountData?.Response, imageInfo, currentAction, - showImage + showImage, + guideInfo: guideData?.Success + ? { + ra: guideData.Response.RMSError.RA.Arcseconds, + dec: guideData.Response.RMSError.Dec.Arcseconds, + total: guideData.Response.RMSError.Total.Arcseconds + } + : undefined }; return this.cachedLiveStatus; From c8fb27412235d3e5ebb49beaad4fed22c375db8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrik=20Mint=C4=9Bl?= Date: Mon, 2 Mar 2026 20:45:58 +0100 Subject: [PATCH 3/3] fix: move text behind image + guiding --- .../[[lang=lang]]/live-photo/+page.svelte | 167 ++++++++++-------- 1 file changed, 98 insertions(+), 69 deletions(-) diff --git a/src/routes/[[lang=lang]]/live-photo/+page.svelte b/src/routes/[[lang=lang]]/live-photo/+page.svelte index 6efa57b..bced77b 100644 --- a/src/routes/[[lang=lang]]/live-photo/+page.svelte +++ b/src/routes/[[lang=lang]]/live-photo/+page.svelte @@ -46,21 +46,22 @@
- {#if liveData?.active && liveData?.showImage} - Live view - {:else} -
+
+ {liveData?.active ? liveData?.currentAction || appState.lang.live_photo.inactive : appState.lang.live_photo.inactive} -
- {/if} + + {#if liveData?.active && liveData?.showImage} + Live view + {/if} +
- +

- {appState.lang.live_photo.image} + {appState.lang.live_photo.guide} (PHD2)

-
- - {appState.lang.live_photo.labels.target}: - - {liveData?.imageInfo?.TargetName || 'No info'} - - - {appState.lang.live_photo.labels.date}: - - {liveData?.imageInfo?.Date - ? new Date(liveData.imageInfo.Date).toLocaleTimeString() - : '-'} - - - {appState.lang.live_photo.labels.exposure}: - - {liveData?.imageInfo?.ExposureTime - ? `${liveData.imageInfo.ExposureTime}s` - : '-'} - - - {appState.lang.live_photo.labels.temp}: - - {liveData?.imageInfo?.Temperature - ? `${liveData.imageInfo.Temperature}°C` - : '-'} + RA Error: + + {liveData?.guideInfo ? `${liveData.guideInfo.ra.toFixed(2)}″"` : '-'} - - {appState.lang.live_photo.labels.gain}: Dec Error: + + {liveData?.guideInfo ? `${liveData.guideInfo.dec.toFixed(2)}″"` : '-'} - {liveData?.imageInfo?.Gain ?? '-'} - - {appState.lang.live_photo.labels.focal_length}: - - {liveData?.imageInfo?.FocalLength - ? `${liveData.imageInfo.FocalLength}mm` + Total Error: + + {liveData?.guideInfo + ? `${liveData.guideInfo.total.toFixed(2)}″"` : '-'} +
- - {appState.lang.live_photo.labels.telescope}: - - {liveData?.imageInfo?.TelescopeName || 'No info'} - - - {appState.lang.live_photo.labels.camera}: - - {liveData?.imageInfo?.CameraName || 'No info'} + +
+

+ {appState.lang.live_photo.image} +

+
+ + {appState.lang.live_photo.labels.target}: + + {liveData?.imageInfo?.TargetName || 'No info'} + + + {appState.lang.live_photo.labels.date}: + + {liveData?.imageInfo?.Date + ? new Date(liveData.imageInfo.Date).toLocaleTimeString() + : '-'} + + + {appState.lang.live_photo.labels.exposure}: + + {liveData?.imageInfo?.ExposureTime + ? `${liveData.imageInfo.ExposureTime}s` + : '-'} + + + {appState.lang.live_photo.labels.temp}: + + {liveData?.imageInfo?.Temperature + ? `${liveData.imageInfo.Temperature}°C` + : '-'} + + + {appState.lang.live_photo.labels.gain}: + {liveData?.imageInfo?.Gain ?? '-'} + + + {appState.lang.live_photo.labels.focal_length}: + + {liveData?.imageInfo?.FocalLength + ? `${liveData.imageInfo.FocalLength}mm` + : '-'} + + + {appState.lang.live_photo.labels.telescope}: + + {liveData?.imageInfo?.TelescopeName || 'No info'} + + + {appState.lang.live_photo.labels.camera}: + + {liveData?.imageInfo?.CameraName || 'No info'} +