Expand description
A mariner’s own display units, as signalk-server’s unitpreferences
feature states them.
Signal K itself is SI on the wire and says nothing about how a value
should be shown – that is what unitpreferences is for, a
signalk-server feature (not part of the core specification, the same
already-observed-convention standing this crate already gives
crate::AisTargetStatus and crate::NotificationSeverity) that
lets a mariner pick nautical miles, kilometres or statute miles for
distance, once, on the server, for every client to honour alike.
§Why this does not read the server’s own conversion formula
GET /signalk/v1/unitpreferences/active answers with a formula and
inverseFormula per category – a short expression, "value * 1.94384",
meant to be evaluated. This crate deliberately never evaluates it: doing
so needs a small expression interpreter, which is new conversion math of
exactly the kind this workspace exists to avoid growing twice. Instead,
conversions below is a table of (scale, offset) pairs – one row
per target = value * scale + offset – computed once, by hand, from
every formula string GET /signalk/v1/unitpreferences/definitions
answered on a real signalk-server (confirmed live; see
crates/signalk/testdata/unitpreferences.json, the fixture this table
is checked against, and this module’s own tests). What is read from a
server at runtime is only which row a mariner’s preference names –
never a formula to evaluate.
§What is not covered
Every target unit signalk-server ships is in conversions, with two
exceptions, both left unread the same way an unrecognised path is
anywhere else in this crate – skipped, not refused:
- Beaufort (
m/s->Bf), the one target in the entire catalogue whose own formula is not affine –(value / 0.836)^(2/3), a power law. Modelling it would mean either a second kind of table entry for one row, or the interpreter this module exists to avoid; a mariner who picks Beaufort for wind speed gets the same “not a reading this crate understands”Preferences::convertalready gives any other unrecognised target. - Duration formatters (
s->HH:MM:SSand six siblings), which are not a numeric scale at all –formatDurationHMS(value)turns a seconds count into a clock-formatted string, which is a formatting concern, not a unit conversion, and not this module’s to grow into. The plain decimal ones (s->hour,minute,day, …) are ordinary affine conversions and are covered.
Three base units are themselves formats rather than physical
quantities – RFC 3339 (UTC) and Epoch Seconds (the dateTime/
epoch categories’ own timestamp representations) and bool (the
boolean category) – each with exactly one target, itself. The
target-equals-base rule Preferences::convert applies before ever
consulting conversions already answers that trivially and
correctly (the value passes through unchanged), without this module
needing to know or care that a category is not really a measurement.
§The target-equals-base rule
A preference whose targetUnit is exactly the category’s own Signal K
base unit ("m" for length, "K" for temperature, …) means “no
conversion” – confirmed live: signalk-server sends that literal
string, not the differently-spelled identity row its own
conversions table happens to carry for some base units (m’s own
identity entry is named "meter", never "m"; several base units –
V, A, bool, tr, the two timestamp formats – carry no entry
but their own name at all). Preferences::convert checks this
before ever looking a target up in conversions, so every category
has a correct identity regardless of which, if either, spelling the
table itself happens to carry.
Structs§
- Preferences
- What a server’s
unitpreferencesstates, as far as this crate reads it – every categorycategory_base_unitnames a Signal K base unit for, present once the server has stated a target unit this crate converts (see this module’s own top doc for the two kinds of target that leaves out), absent otherwise.Defaultis every category absent, which is exactly the state a caller should fall back to its own default unit for – the same valueSelf::parsereturns for an unreadable answer.
Functions§
- localized_
symbol symbolinlang’s own words, when this crate knows one –symbolunchanged otherwise, the same “unrecognised passes through” disciplinePreferences::parseitself already keeps.signalk-serverstates every symbol in English regardless of who is reading it (confirmed live: a mariner’s own distance preference set to nautical miles comes back with"symbol":"nmi"whatever locale the request was made under) – this is the one place that turns it into something else.