Skip to content

Reference ​

Everything muxen-sextant exposes, in tables. Every entry here is taken from the software as it ships: its own code, its systemd unit and its package.

Command line ​

muxen-sextant takes no positional arguments. Options are grouped; --help lists the groups and --help-report, --help-mqtt and --help-verbose expand them.

General ​

OptionShortTypeDefaultEffect
--version-vflag—print muxen-sextant: version <v> and exit 0
--data-dirDIRsee belowdirectory holding WMM.COF and tides.db

--data-dir is resolved at startup by trying, in order, /var/lib/muxen-sextant and ./data, taking the first that exists as a directory; if neither does, it falls back to /var/lib/muxen-sextant. That is what lets the binary run straight from a source checkout.

Report options ​

All reports are off by default. The shipped systemd unit passes --report-all.

OptionTypeDefaultEffect
--report-allflagoffenables all four report flags below
--report-astroflagoffpublish {prefix}/sun and {prefix}/moon
--report-magneticflagoffpublish {prefix}/magnetic
--report-tidesflagoffpublish {prefix}/tides
--report-skymapflagoffpublish {prefix}/skymap
--wmm-cof-pathPATH{data-dir}/WMM.COFWorld Magnetic Model coefficient file
--tides-db-pathPATH{data-dir}/tides.dbtidal harmonics database
--tide-radius-nmdouble50.0station search radius, nautical miles
--tide-recompute-minint30minimum minutes between tidal recomputations
--skymap-max-magdouble5.0faintest star magnitude included
--recompute-drift-degdouble1.25position drift, in degrees of latitude or longitude, that triggers a recompute
--recompute-interval-minint15minutes between periodic recomputes

--report-all is expanded immediately after parsing, so it can be combined with individual flags in any order.

MQTT options ​

OptionTypeDefaultEffect
--no-mqttreverse flagMQTT enableddisable all publishing and subscribing
--mqtt-hostHOST127.0.0.1broker host
--mqtt-portint1883broker port
--mqtt-usernameUSERunsetbroker username
--mqtt-passwordPASSunsetbroker password
--mqtt-client-idIDmuxen-sextantMQTT client identifier
--mqtt-topic-prefixPREFIXsextantprefix for published reports
--mqtt-nmea-prefixPREFIXnmeaprefix for the subscribed input topics

Verbose options ​

OptionEffect
--verbose-allenable all of the below
--verbose-astroone line per sun and moon publish
--verbose-magneticone line per magnetic publish
--verbose-tidestidal computation and station counts
--verbose-skymapstar, constellation and planet counts per publish
--verbose-mqttconnection, reconnection and message tracing
--verbose-recomputethe reason for every recompute trigger

Verbose output goes to stderr. The always-on Config:, Main: and per-report startup lines go through the GLib log handler, which timestamps them HH:MM:SS.mmm and sends informational messages to stdout and warnings to stderr.

MQTT interface ​

Subscribed ​

Both at QoS 0, subscribed from the connect callback so they are re-subscribed automatically after a reconnection.

TopicFields read
{nmea-prefix}/navigationdata.position.latitude, data.position.longitude
{nmea-prefix}/datetimedata.now — presence only; the value is never used in any computation

data.position.altitude is present in the input and is not read. The magnetic model is evaluated at 0 km above the WGS-84 ellipsoid.

Published ​

All five are published at QoS 0 with the retain flag set, in the MUXEN envelope { "data": {…}, "metadata": {…} }, serialised compactly (no pretty-printing).

TopicContentexpireAfterSec
{prefix}/sunsolar rise/set/transit, three twilights, current position3600
{prefix}/moonlunar rise/set/transit, phase, illumination, phase name, age, lit side and angle, days to new/full, track of one pass3600
{prefix}/magneticdeclination, inclination, total intensity3600
{prefix}/tidesarray of nearby stations with curves3600
{prefix}/skymapstars, constellation segments, planets3600

metadata.rxDate is an ISO-8601 UTC timestamp taken at publish time.

app/sextant/info — daemon info ​

Retained, QoS 1, on a fixed topic that --mqtt-topic-prefix does not change: every MUXEN daemon publishes the same shape on app/<daemon>/info, so a screen lists them all with one app/+/info subscription.

json
{"name":"muxen-sextant","version":"v2.3.0","hostname":"brain-3",
 "features":["sun","moon","magnetic","tides","skymap"],"online":true,
 "metadata":{"rxdate":"2026-09-22T07:58:15.659Z","rxTimestamp":1790063895,
             "expireAfterSec":3124137600}}
KeyMeaning
namemuxen-sextant
versionbuild version (git describe); for display only, never branch on it
hostnamehost the daemon runs on
onlinetrue on every (re)connect; false on a clean shutdown, and as the MQTT last will when the connection is lost
featuresthe report topics this instance publishes (below)
metadatarxdate (lowercase, unlike the reports' rxDate), rxTimestamp, and expireAfterSec ≈ 99 years: liveness is online, not age

A feature is listed only when its report is enabled and started: a tides report with no readable tide database, for instance, leaves tides out. Clients ignore features they do not know.

FeaturePublished topic
sun{prefix}/sun (astro report)
moon{prefix}/moon (astro report)
magnetic{prefix}/magnetic
tides{prefix}/tides
skymap{prefix}/skymap

{prefix}/sun — data ​

KeyTypeOptionalUnit
rise, set, transitstringyesISO-8601 UTC
riseTimestamp, setTimestamp, transitTimestampint64yesUnix epoch seconds
riseAzimuth, setAzimuthdoubleyesdegrees, 0 = North
transitAltitudedoubleyesdegrees
civilTwilightStart, civilTwilightEndstringyesISO-8601 UTC
nauticalTwilightStart, nauticalTwilightEndstringyesISO-8601 UTC
astronomicalTwilightStart, astronomicalTwilightEndstringyesISO-8601 UTC
…Timestamp for each twilight boundint64yesUnix epoch seconds
altitudedoublenodegrees
azimuthdoublenodegrees, 0 = North

A time string and its …Timestamp sibling are always present together or absent together. Each twilight bound is the next time the sun passes 6°, 12° or 18° below the horizon, upwards for a start and downwards for an end; it is absent when that does not happen within 48 hours.

{prefix}/moon — data ​

KeyTypeOptionalUnit
rise, set, transit (+ …Timestamp)string / int64yesISO-8601 UTC / epoch; the next moonrise, moonset and culmination
riseAzimuth, setAzimuthdoubleyesdegrees, 0 = North, at rise and at set
transitAltitudedoubleyesdegrees, at transit
altitude, azimuthdoublenodegrees
phasedoubleno0.0–1.0, synodic cycle position
illuminationdoubleno0.0–1.0, lit fraction
phaseNamestringnonew, waxing-crescent, first-quarter, waxing-gibbous, full, waning-gibbous, last-quarter or waning-crescent
waxingbooleannotrue from new moon to full moon (phase < 0.5)
agedoublenodays since the last new moon
litSidestringyesright or left; absent when the latitude is exactly 0
litAngledoublenodegrees, 0 (included) to 360 (excluded), clockwise from the vertical: 0 = lit side straight up, 90 = on the right
daysToNewMoon, daysToFullMoondoubleyesdays, half-day resolution
trackarrayyesthe moon's path for one pass above the horizon; absent when there is no pass
track[].time, track[].timestampstring / int64noISO-8601 UTC / Unix epoch seconds
track[].altitude, track[].azimuthdoublenodegrees to 0.01°, azimuth 0 = North

rise, set and transit are the next moonrise, the next moonset and the next culmination above the horizon after the report: never a past one, each a whole second that stays the same from report to report while the event is ahead, and each absent, with its bearing or altitude, when the event does not come within 48 hours.

A principal phase (new, first-quarter, full, last-quarter) is named within 20° of elongation of its exact position, that is within 20/360 of its position in the cycle (0.0, 0.25, 0.5, 0.75), lower bound included: about 3.3 days each, and about 4.1 days for each crescent or gibbous name between them. litSide is right for a waxing moon north of the equator and for a waning moon south of it, left otherwise: the hemisphere's convention. litAngle is the measured direction of the lit limb as the observer sees the moon. track is the pass in progress if the moon is up, the next one if it is down: points in time order, at most 20 minutes apart and 77 in all, from that pass's moonrise to its moonset, its culmination among them, each at the instant rise, transit or set gives when it names the same event. It is absent when the moon stays up for more than 25 hours or does not rise within 48. The rules, and how the fields relate, are set out in Sun and moon.

{prefix}/magnetic — data ​

KeyTypeUnit
declinationdoubledegrees, positive = east
inclinationdoubledegrees
totalIntensitydoublenanotesla

All three are always present. The whole message is omitted when the model cannot be evaluated.

{prefix}/tides — data.stations[] ​

KeyTypeOptionalUnit
namestringno—
countrystringyesISO alpha-3
latitude, longitudedoublenodegrees
distanceNmdoublenonautical miles
heightdoublenometres about local mean water
nextHighTidestringyesISO-8601 UTC
nextHighTideHeightdoubleyesmetres
nextLowTidestringyesISO-8601 UTC
nextLowTideHeightdoubleyesmetres
tidalCoefficientintyesrounded; clamped to 0…200
curvearrayno216 objects { "t": ISO-8601 UTC, "h": metres }

Stations are sorted by distanceNm, nearest first. When no station is within range, the message is not published at all.

There are no …Timestamp siblings in this report.

{prefix}/skymap — data ​

KeyTypeNotes
stars[]arrayid (int), altitude, azimuth (1 decimal), magnitude (2 decimals), optional name
constellations[]arrayname, segments = array of [id, id] pairs referring to stars[] of the same message
——id is an internal 1…1663 index into the built-in catalogue, not a Hipparcos or HD number, and is stable only for a given build
planets[]arrayname, altitude, azimuth, magnitude

Stars are included when brighter than --skymap-max-mag and above −5°. Planets are included when above 0°, with no magnitude filter.

Recompute triggers ​

TriggerCondition
First fixno position recorded yet
Position drift`
Interval--recompute-interval-min elapsed since the last recompute

All enabled reports are fed from the same trigger. The tides report applies an additional internal floor of --tide-recompute-min and skips triggers that arrive sooner.

Files ​

PathOwnerContent
/usr/bin/muxen-sextantmuxen-sextantthe daemon
/usr/lib/systemd/system/muxen-sextant.servicemuxen-sextantthe systemd unit
/etc/nginx/snippets/muxen-ws-sextant.confmuxen-sextantlocation = /ws/sextant proxying to http://127.0.0.1:1884/
/var/lib/muxen-sextant/WMM.COFmuxen-sextant-databaseWMM-2025 coefficients, epoch 2025.0
/var/lib/muxen-sextant/tides.dbmuxen-sextant-databaseSQLite tidal harmonics, 8117 stations

The daemon opens tides.db read-only and never writes to disk.

The nginx snippet does nothing until a server block includes it, and that block is not in this package: it is shipped by the boat's UI interface package (muxen-interface-*), one site file per boat, which is also where the map $http_upgrade $connection_upgrade block the proxy needs is defined. Interfaces that want /ws/sextant include the snippet with a trailing * — include /etc/nginx/snippets/muxen-ws-sextant.conf*; — which makes the include optional, so a Brain without muxen-sextant installed still starts nginx and simply has no /ws/sextant. Not every interface asks for it, so the endpoint exists only on the boats whose site file has that line.

systemd unit ​

DirectiveValue
DescriptionMUXEN Sextant Environment Daemon
Aftermosquitto.service
PartOfmuxen.target
WantedBymuxen.target
Typesimple
ExecStart/usr/bin/muxen-sextant --report-all
Restartalways
RestartSec10
TimeoutStopSec5
StartLimitIntervalSec / StartLimitBurst300 / 5
User / Groupmuxen / muxen
StateDirectorymuxen-sextant, mode 0750
RuntimeDirectorymuxen-sextant, mode 0755

Hardening: NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables, ProtectKernelModules, ProtectKernelLogs, ProtectControlGroups, ProtectClock, ProtectHostname, ProtectProc=invisible, ProcSubset=pid, RestrictRealtime, RestrictSUIDSGID, MemoryDenyWriteExecute, LockPersonality, RestrictNamespaces, SystemCallArchitectures=native, SystemCallFilter=@system-service, RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6, and an empty CapabilityBoundingSet and AmbientCapabilities.

ProtectClock=yes is worth noting: the daemon can read the clock but cannot set it, which is correct — it is a consumer of time, not a source.

Signals and exit status ​

SIGINT and SIGTERM are handled through the GLib main loop: the loop quits, every report and the MQTT client are freed, and the process exits 0. TimeoutStopSec=5 bounds that.

StatusMeaning
0normal shutdown on SIGINT/SIGTERM, or --version
1command-line option parsing failed — the message is Config: Option parsing failed: …

There is no other non-zero exit. A missing coefficient file, a missing tide database, an unreachable broker and an expired magnetic model are all logged and survived; the daemon keeps running and publishes whatever it still can.

MQTT client behaviour ​

PropertyValue
Client IDmuxen-sextant (--mqtt-client-id)
Keepalive60 s
Clean sessionyes
Connectasynchronous, integrated into the GLib main loop
Reconnectevery 5000 ms until it succeeds
Housekeeping timer100 ms
PublishQoS 0, retain set (daemon info: QoS 1, retain set)
Last willapp/sextant/info with online: false, retained, QoS 1, re-registered before every connect attempt
Clean shutdownpublishes the offline info and waits up to 1 s for its PUBACK before disconnecting
SubscribeQoS 0, re-issued on every successful connect

The daemon does not exit when the broker is unreachable at startup; it retries indefinitely and begins publishing once connected.

Packages ​

PackageArchDepends
muxen-sextantany${shlibs:Depends}, ${misc:Depends}, muxen-systemd, muxen-sextant-database
muxen-sextant-databaseall${misc:Depends}

muxen-sextant activates the muxen-restart-target dpkg trigger, and nginx-reload, so a running nginx reloads at the end of the transaction and serves a changed muxen-ws-sextant.conf at once.

Build dependencies: debhelper-compat (= 13), meson, ninja-build, pkg-config, libglib2.0-dev, libmosquitto-dev, libjson-c-dev, libnova-dev, libsqlite3-dev.

Third-party components ​

ComponentLicenceRole
libnovaLGPL-2.0linked; solar, lunar, planetary and coordinate computations
NOAA WMM reference librarypublic domainvendored in src/vendor/wmm/, built as a static library
json-c, libmosquitto, GLib, SQLitesystem packagesJSON, MQTT, main loop, database

libnova is a system library this daemon links against; its API is not part of the MUXEN interface and nothing in this manual documents it.

Runtime data volumes ​

QuantityValue
Tide stations in tides.db8117
Harmonic constants~205 000
Constituents per station2 to 34, 25 on average
Distinct constituents in the database34
Stations with a country code7988 of 8117
Stations without a mean spring range2
Curve points per station216, at 10-minute spacing, −12 h to +24 h
Built-in stars1663
Built-in constellation line segments695
Built-in constellations88
Planets computed7

Integration of multiplexed solutions
MUXEN and the MUXEN logo are trademarks of MUXEN SAS.