Documentation Index
Fetch the complete documentation index at: https://mintlify.com/skyrobot804/node_v1/llms.txt
Use this file to discover all available pages before exploring further.
SafetyManager is a daemon thread component that monitors telescope connectivity and automatically parks the mount at dawn or on heartbeat loss. It runs as a background watchdog: the dashboard poll cycle sends a heartbeat on each tick, and if disconnect_timeout seconds pass without a heartbeat the manager attempts a configurable number of reconnection retries before issuing an emergency park command. It also computes the local astronomical, nautical, or civil dawn time and parks the telescope when that threshold is crossed. All pipeline and dashboard code should gate observations on _safety_mgr.is_safe() to ensure the system halts safely under adverse conditions.
Constructor
SafetyManager from config["safety"]. No threads are started at construction time — call start() to activate the watchdog.
Master enable switch. When
false, is_safe() always returns True and the watchdog thread exits immediately after start() — useful for bench testing without a connected telescope.Number of seconds without a heartbeat before the manager considers the connection lost and begins reconnection attempts.
Expected interval in seconds between heartbeat signals from the dashboard poll cycle. Used to set watchdog timer granularity.
Maximum number of reconnection attempts before the manager gives up and issues an emergency park command.
Delay in seconds between successive reconnection attempts.
When
true, the telescope is automatically parked once the configured dawn_type threshold is reached. When false, dawn monitoring is still computed and reported in status() but no park command is sent.Determines which solar elevation defines dawn. One of
"astronomical" (sun at −18°), "nautical" (sun at −12°), or "civil" (sun at −6°). See Dawn Parking for details.Observer latitude in decimal degrees (positive = North). Required for dawn time computation; if zero or absent, dawn parking is skipped.
Observer longitude in decimal degrees (positive = East). Required alongside
latitude for dawn time computation.Lifecycle
attach_telescope()
Telescope object or equivalent) that the SafetyManager will use to issue park commands. Should be called before start(). If no telescope is attached, the watchdog still monitors heartbeat and dawn but cannot issue a park command on trigger.
start()
heartbeat_interval granularity, checking elapsed time since the last heartbeat and comparing the current UTC time against the computed dawn time. Safe to call multiple times — subsequent calls after the thread is already running are no-ops.
stop()
stop() returns, is_safe() continues to return the last computed state; start() may be called again to restart monitoring.
is_safe()
True if the system is in a safe state to continue observing; False if the system should halt. A False result is returned when any of the following conditions holds:
- More than
disconnect_timeoutseconds have elapsed since the last heartbeat (telescope connectivity lost). - The current UTC time is past the computed dawn threshold for today (
dawn_type).
safety.enabled is false, always returns True.
status()
Current result of
is_safe() — True if observing may continue, False if the system has triggered a safety halt.Human-readable description of the safety state. Examples:
"OK", "heartbeat timeout", "past astronomical dawn", "safety disabled".Unix timestamp (from
time.monotonic() or time.time()) of the most recent heartbeat received from the dashboard poll cycle. 0.0 if no heartbeat has been received since start().ISO 8601 UTC string of today’s computed dawn time for the configured
dawn_type and observer coordinates. Example: "2025-06-01T02:47:00+00:00". "unknown" if lat/lon are not configured or the computation fails.Heartbeat Watchdog
The dashboard poll cycle (typically driven by a scheduler or a UI refresh loop) is expected to call an internal heartbeat method on each tick. The watchdog thread monitors the elapsed time since the last heartbeat:- If
elapsed > disconnect_timeout, the manager logs a warning and begins a reconnection sequence. - Reconnection is attempted up to
reconnect_attemptstimes, withreconnect_delayseconds between each attempt. - If all reconnection attempts fail, the manager calls
telescope.Park()via the attached device handle (emergency park) and setsis_safe()to returnFalse. - If a heartbeat is received at any point during the reconnection sequence, the sequence is aborted and normal monitoring resumes.
daemon=True) so it does not prevent process exit.
Dawn Parking
Whensafety.park_at_dawn is true, the watchdog computes the time at which the sun crosses the elevation threshold corresponding to dawn_type for the configured observer location:
dawn_type | Solar Elevation | Description |
|---|---|---|
astronomical | −18° | Standard end-of-night for deep-sky photometry; sky background rises significantly above this point |
nautical | −12° | Useful for bright targets or when a slightly shorter night is acceptable |
civil | −6° | Latest safe limit; horizon glow is already visible |
start() call (and recomputed each calendar day by the watchdog loop). If observer.latitude and observer.longitude are both zero or absent, dawn computation is skipped and dawn_time is reported as "unknown" in status().
When the current UTC time crosses the dawn threshold, the manager:
- Logs the event at
WARNINGlevel. - Calls
telescope.Park()if a telescope handle is attached. - Sets the internal state so
is_safe()returnsFalsefor the remainder of the night.
Extending SafetyManager
Custom safety checks can be added by subclassingSafetyManager. Override the internal watchdog loop body to add domain-specific checks — weather station humidity, cloud sensor readings, mount limit switches, etc. Always gate any observing operation on _safety_mgr.is_safe():
