argos.core.session¶
Session layer — device ownership + acquisition orchestration (WS5).
DeviceSession owns the Alpaca device handles, discovery, the
pollers and the Stellarium server; the acquisition engine owns the camera
ownership state machine and the capture/solve/photometry workers. Both are
UI-thread QObjects; the ImagingPage is a view over them.
- class argos.core.session.CameraCapabilities(gain_min: int, gain_max: int, exposure_min: float, exposure_max: float, offset_min: int | None, offset_max: int | None, offset: int | None, max_bin: int, binning: int)[source]¶
Bases:
objectDriver-derived camera limits + optional parameters, read at connect.
Sourced from the fields
argos.core.alpaca.camera.Camera.connect()populates.offset/offset_min/offset_maxareNonewhen the driver doesn’t support offset;max_binis 1 when binning is fixed.
- class argos.core.session.FilterWheelState(names: tuple[str, ...], position: int, position_name: str)[source]¶
Bases:
objectFilter wheel snapshot at connect: slot names + current position.
- class argos.core.session.FocuserState(name: str, position: int, max_step: int, max_increment: int, absolute: bool)[source]¶
Bases:
objectFocuser snapshot at connect: capabilities + current position.
- class argos.core.session.LiveFrame(preview: ndarray, full: ndarray, start: datetime | None, end: datetime | None, decimated: bool)[source]¶
Bases:
objectOne acquired frame, as published by the AcquisitionEngine.
previewis the (possibly stride-decimated) display array;fullis always the full-resolution readout.decimatedis True when the two differ — plate-solve/photometry must skip such frames (their plate scale is wrong).start/endare the exposure UTC timestamps (Nonefor sequence frames, which are timestamped by their worker).
- class argos.core.session.PhotometryPoint(key: str, name: str, jd: float, mag: float, mag_err: float, saturated: bool, role: str = 'target', relative_flux: float | None = None, relative_flux_err: float | None = None)[source]¶
Bases:
objectOne differential-photometry light-curve point for a measured star.
Typed signal payloads for the session layer.
Frozen dataclasses carried by DeviceSession / AcquisitionEngine signals,
replacing the loose pyqtSignal(object, ...) tuples the ImagingPage used
internally. Modeled on argos.workers.preview_processor.ProcessedFrame.
- class argos.core.session.types.CameraCapabilities(gain_min: int, gain_max: int, exposure_min: float, exposure_max: float, offset_min: int | None, offset_max: int | None, offset: int | None, max_bin: int, binning: int)[source]¶
Bases:
objectDriver-derived camera limits + optional parameters, read at connect.
Sourced from the fields
argos.core.alpaca.camera.Camera.connect()populates.offset/offset_min/offset_maxareNonewhen the driver doesn’t support offset;max_binis 1 when binning is fixed.
- class argos.core.session.types.FilterWheelState(names: tuple[str, ...], position: int, position_name: str)[source]¶
Bases:
objectFilter wheel snapshot at connect: slot names + current position.
- class argos.core.session.types.FocuserState(name: str, position: int, max_step: int, max_increment: int, absolute: bool)[source]¶
Bases:
objectFocuser snapshot at connect: capabilities + current position.
- class argos.core.session.types.LiveFrame(preview: ndarray, full: ndarray, start: datetime | None, end: datetime | None, decimated: bool)[source]¶
Bases:
objectOne acquired frame, as published by the AcquisitionEngine.
previewis the (possibly stride-decimated) display array;fullis always the full-resolution readout.decimatedis True when the two differ — plate-solve/photometry must skip such frames (their plate scale is wrong).start/endare the exposure UTC timestamps (Nonefor sequence frames, which are timestamped by their worker).
- class argos.core.session.types.PhotometryPoint(key: str, name: str, jd: float, mag: float, mag_err: float, saturated: bool, role: str = 'target', relative_flux: float | None = None, relative_flux_err: float | None = None)[source]¶
Bases:
objectOne differential-photometry light-curve point for a measured star.
DeviceSession — owns the Alpaca device handles and their pollers.
Extracted from the ImagingPage (WS5): the session is a plain QObject
living on the UI thread (never moveToThread it — every worker→UI
connection relies on the receiver’s thread affinity for queued delivery).
It owns:
the four device handles (Telescope, Camera, Focuser, FilterWheel) and their connect/disconnect lifecycles;
Alpaca UDP discovery;
the mount-position poller and both temperature pollers;
the pointing intent (
target_radec, set on goto) and the cachedlast_position;the Stellarium telescope-control server worker (fed the mount position directly — no Shell-level signal plumbing).
The UI consumes typed signals (capabilities_ready carries a frozen
CameraCapabilities, …); device use (exposures, sweeps, sequences)
belongs to the AcquisitionEngine, which coordinates with the session through
the camera_will_disconnect / focuser_will_disconnect hooks.
AcquisitionEngine — camera ownership + capture/solve/photometry workers.
Extracted from the ImagingPage (WS5). A UI-thread QObject (never
moveToThread it) that owns everything that uses the devices:
the
CameraServiceownership state machine (WS3) and its preview hooks;the LivePreview / Sequence / Autofocus workers;
the
AstrometryController(live plate-solve lifecycle) and the VSX/VSP catalog cache;the persistent target set and the live photometry state (light curves, per-target CSVs, FITS saves).
The ImagingPage is a view: it forwards dock intents into these methods and
renders the typed signals (frame_ready carries a frozen
LiveFrame, photometry_point a PhotometryPoint, …).
Capture parameters are read through injected providers
(set_providers()) so the engine never touches a widget.
Coordination with the DeviceSession happens through its
camera_will_disconnect / focuser_will_disconnect hooks — the engine
stops using a device before the session drops the handle.
Read a finished Argos session for the offline Review workspace.
The reader is deliberately Qt-free: a session is useful after a crash, on a
different computer, or before any hardware is connected. It consumes the
durable session.json truth and only reads FITS headers for telemetry that
is not part of that log (currently CCD temperature).
- class argos.core.session.review.ReviewFrame(filename: 'str', image_type: 'str', filter_name: 'str', exposure_s: 'float', gain: 'int', timestamp: 'datetime | None', hfd: 'float | None' = None, fwhm: 'float | None' = None, star_count: 'int | None' = None, sky_adu: 'float | None' = None, peak_adu: 'float | None' = None, eccentricity: 'float | None' = None, ccd_temp: 'float | None' = None)[source]¶
Bases:
object
- class argos.core.session.review.ReviewedSession(root: 'Path', object_name: 'str', started_utc: 'str', software: 'str', observer: 'str', frames: 'list[ReviewFrame]' = <factory>, metadata: 'dict[str, Any]'=<factory>, comparison_quality: 'dict[str, Any] | None'=None, warnings: 'list[str]' = <factory>)[source]¶
Bases:
object- frame_path(frame: ReviewFrame) Path | None[source]¶
Find the stored FITS for a logged frame without modifying the session.
- frames: list[ReviewFrame]¶
- property light_frames: list[ReviewFrame]¶
- metric_samples() list[tuple[float, ReviewFrame]][source]¶
Return light-frame elapsed seconds and frames with a valid timestamp.
- nearest_light_frame(jd_utc: float) ReviewFrame | None[source]¶
Match a preview-photometry JD to its closest recorded light frame.
- exception argos.core.session.review.SessionReviewError[source]¶
Bases:
ValueErrorThe selected folder does not contain a readable Argos session.
- argos.core.session.review.load_session(path: Path | str, *, read_temperature: bool = True) ReviewedSession[source]¶
Load a session folder or its
session.jsonfile.Bad individual frame rows are skipped and reported so a partial night can still be reviewed. This function never writes or alters the session.
- argos.core.session.review.load_session_curves(review: ReviewedSession) dict[str, LightCurve][source]¶
Load all per-star curves with their scientific roles and identities.
Per-star CSVs deliberately contain only measurement columns so they remain simple inputs for external tools. Their filename and the session’s
targets.jsontherefore provide the missing role/identity at Review time. Older Review incorrectly treated every such file as a target, making calibration stars appear in the source-light-curve panel.
Session flight recorder — machine-readable per-frame diagnostics (JSONL).
One line of JSON per record, one file per run, next to the session outputs.
Postprod loads it with pandas.read_json(path, lines=True) and can audit
what Argos measured and decided on every frame: each comparison star’s raw
behaviour, the ensemble zero-point health, the aperture tracker’s state, and
sparse session events. The human-oriented log tells the story; this file is
the evidence.
Record shape: {"t": iso8601-utc, "kind": ..., ["frame": n,] **fields}.
Kinds in use: star, ensemble, tracking, frame, event
(see notes/photometry_hardening_plan.md §P11).
Failure-safe by design: the recorder must never take a session down. Any write error disables it with a single warning; every method is a no-op when disabled. Qt-free.
- class argos.core.session.diagnostics.SessionDiagnostics(path: Path | str, enabled: bool = True)[source]¶
Bases:
objectAppend-only JSONL writer for one run (live session or batch re-run).
The file is opened lazily on the first record so an enabled-but-unused recorder leaves nothing behind. It is an opt-in local diagnostic file and has no network transport.
enabled=False(configdiagnostics.enabled) makes every call a no-op.- record(kind: str, frame: int | None = None, **fields: Any) None[source]¶
Write one record; drops None-valued fields, rounds floats.
- star(frame: int, star, phot, x: float, y: float) None[source]¶
One measured star on one frame — target, comparison or check.
staris a TargetStar,photan AperturePhot or None (aperture off-frame). Recording every comparison’s raw instrumental behaviour is the point: a drifting or clouded comp is invisible in the calibrated target curve but obvious here.