Appearance
Position and time
Everything muxen-sextant publishes is a function of two numbers and a clock: latitude, longitude, and the instant you are asking about. This chapter is about where those come from, how often the daemon acts on them, and the ways that can go wrong quietly.
For the crew, the short version is: the environment pages follow the GPS, and they update every quarter of an hour, not every second. A sunrise time that does not tick is not a frozen screen; it is a number that only changes when the boat has moved a long way or fifteen minutes have passed.
The two inputs
The daemon subscribes to exactly two topics at QoS 0, both published by muxen-nmea2000:
| Topic | Field read | Used for |
|---|---|---|
nmea/navigation | data.position.latitude, data.position.longitude | the observer position |
nmea/datetime | data.now | nothing but a readiness flag |
The topic prefix is nmea by default and is set with --mqtt-nmea-prefix.
A nmea/navigation message whose data.position object is missing — which is what no GPS fix looks like — is discarded without changing anything. The daemon does not clear the last known position; it keeps it.
nmea/datetime is a gate, not a clock
This is the single most surprising thing about the daemon, and it matters operationally.
data.now is parsed, copied into memory, and never used for any computation. Its only effect is that the daemon refuses to compute anything until it has seen one — the guard is "have I got a latitude, a longitude, and at least one datetime message?".
Every actual computation then reads the Brain's system clock:
- the sun and moon positions and rise/set times,
- the decimal year the magnetic model is evaluated at,
- the Julian date at the centre of the tide curve,
- the sidereal rotation of the sky map.
So a Brain whose clock is wrong produces a complete, well-formed, confidently wrong set of reports, and the NMEA time on the same screens is right. If sunrise is out by exactly an hour, look at timedatectl before looking at anything in this manual.
The practical consequence: the GPS time discipline that keeps the Brain's clock right is a dependency of this daemon, even though nothing in the code says so.
The recompute rule
Position messages arrive at 1 Hz. Recomputing five reports at 1 Hz would be pointless — a sunrise time does not move — and expensive, so the daemon computes only when one of three conditions holds:
| Trigger | Condition | Flag |
|---|---|---|
| First fix | no position has ever been recorded | — |
| Position drift | ` | Δlatitude |
| Interval elapsed | --recompute-interval-min since the last recompute | default 15 |
All enabled reports are fed together from the same trigger, so the five topics always describe the same instant and the same position. There are no per-report timers.
Two details of the drift test are worth knowing:
- It compares latitude and longitude independently, not a distance. 1.25° of latitude is 75 nautical miles anywhere; 1.25° of longitude is 75 NM at the equator and about 37 NM at 60° north. A fast passage eastwards therefore triggers a recompute sooner than the same distance sailed north.
- The default of 1.25° is chosen to bound the error in the derived times: 1.25° of longitude is five minutes of solar time.
With the defaults, a boat at anchor recomputes four times an hour, and a boat under way recomputes whenever it crosses a drift threshold in between.
Turning on --verbose-recompute prints the reason for every recompute, which is the fastest way to confirm the rule is doing what you think:
Recompute: first GPS fix (48.3833, -4.4950)
Recompute: interval elapsed (15 min)
Recompute: position drift (48.3833,-4.4950)->(48.3901,-6.1200)
Recompute: position drift (48.3901,-6.1200)->(48.4102,-7.9910) + interval elapsedWhat the fifteen-minute cadence means for each field
Most published fields are predictions for the day and do not care: sunrise, sunset, the twilight bounds, the next high water, the moon phase. Three groups are snapshots of now and are as stale as the last recompute:
| Field | Staleness at the default interval |
|---|---|
sextant/sun altitude, azimuth | the sun moves about 3.75° of hour angle in 15 minutes |
sextant/moon altitude, azimuth | similar |
sextant/skymap star and planet positions | the whole sky rotates about 3.75° in 15 minutes |
sextant/tides height | up to 30 minutes old, because of the tides throttle |
If a screen draws a sun-position dial or a live planisphere, lower --recompute-interval-min. The cost is entirely in the tides and sky map computations; the sun, moon and magnetic reports are cheap.
Losing the GPS fix
This behaves differently from what "no fix, no data" would suggest, and the difference shows up on the screens.
When the fix is lost, nmea/navigation stops carrying a position object, so nothing updates the daemon's idea of where it is. But the daemon calls its scheduler from both input handlers, and nmea/datetime keeps arriving. So:
- The last known position is retained, indefinitely.
- Recomputes keep happening every
--recompute-interval-min, driven by the datetime messages, at that stale position. - The payloads keep their
metadata.rxDateadvancing and theirexpireAfterSecof 3600, so a consumer looking only at freshness sees perfectly healthy data.
In practice that is usually the behaviour you want — a boat that loses its fix in a marina has not moved, and the sunrise time stays correct. It is not what you want after a long passage with a dead GPS: the sun report will describe where the boat was.
There is no "position is stale" flag in any payload. The way to tell is to compare the tide stations' distanceNm, or the position echoed by muxen-nmea2000, against where the boat actually is.
Whether nmea/datetime continues to be published when the GPS fix is lost is a property of muxen-nmea2000, not of this daemon; if it stops too, recomputes stop and the retained payloads simply stand still.
Restarting
The daemon holds nothing across a restart. On start it has no position, so it publishes nothing until the first nmea/navigation message with a position — normally within a second on a boat with a fix.
The retained payloads from the previous run stay on the broker in the meantime, so screens do not blank. That also means a stopped daemon looks exactly like a running one to any consumer that does not check metadata.rxDate.
Altitude is ignored
nmea/navigation carries data.position.altitude. muxen-sextant never reads it. The magnetic model is evaluated at 0 km above the WGS-84 ellipsoid, which is the right choice on a boat and would need changing for an aircraft. It has no effect on the astronomical or tidal computations, which use position only.
