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 e7775fc..2754dd4 100644 --- a/src/lib/server/nina.ts +++ b/src/lib/server/nina.ts @@ -30,12 +30,43 @@ interface SequenceItem { Triggers?: SequenceItem[]; TargetTime?: string; Delay?: number; + ExposureTime?: number; +} + +interface CameraInfo { + ExposureEndTime: string; + 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; }; @@ -83,7 +114,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 +140,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 +252,7 @@ export class NinaClient { this.lastUpdate = now; } - const currentAction = this.mapRunningAction(deepestItem!); + const currentAction = await this.mapRunningAction(deepestItem!); const hiddenActions = [ 'Meridian flip', 'Waiting', @@ -224,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; 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'} +