signalk-polar-performance-plugin 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,7 +4,40 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased]
7
+ ## Unreleased
8
+
9
+ ### Fixed
10
+ - Keep `performance.targetSpeed` and `performance.targetVelocityMadeGood` published in irons using the selected beat or run target; polar values and ratios based on the boat's current angle are still cleared.
11
+
12
+ ## [2.2.0] - 2026-11-02
13
+
14
+ ### Changed
15
+ - Polar calculations now come directly from signalk-polar-management's live calculation service: the plugin always follows the active polar, the sailplan selection and the performance factor chosen in the Polar Management webapp — including v2 polar sets, which could not be calculated before. The active polar's details shown in the webapp come from the same service. signalk-polar-management (with the calculation service, >=1.5.0) is now required for all polar outputs; the `polar-math` library is no longer bundled.
16
+ - The overview now shows the selected sailplan for v2 polar sets, and the active polar's details refresh automatically after selection changes or edits in the management webapp, without reloading the page.
17
+ - Smoothed-input outputs (damped TWA and boat speed) are now published even while no polar is active; polar-derived outputs are still cleared.
18
+ - The webapp now distinguishes between a missing calculation service (management plugin not installed or disabled) and no active polar being selected.
19
+
20
+ ### Fixed
21
+ - The polar selected in Polar Management is picked up automatically after a Signal K server restart, without reselecting it ([#41](https://github.com/htool/signalk-polar-performance-plugin/issues/41)).
22
+
23
+ ### Known limitations
24
+ - Sea state (wave) correction is not applied: the Signal K specification defines no paths for the required wave height, period and direction inputs. It can be added once such paths exist.
25
+
26
+ ## [2.1.0] - 2026-10-27
27
+
28
+ ### Changed
29
+ - Requires signalk-server >=2.35.0 for the upstream metadata-first subscription fix ([SignalK/signalk-server#3216](https://github.com/SignalK/signalk-server/pull/3216)).
30
+ - Requires signalkutilities >=3.2.0 (subscriptions without cached-value replay, smoothers cleared by `null`) and polar-math >=1.1.1 (in-irons cutoff relative to the 25° curve endpoint).
31
+ - Read-only Signal K users can now access live values, status, active-polar display metadata, and polar curve queries used by the plotter. Curve resolution is bounded to at most 181 samples per request; settings remain administrator-only.
32
+ - Clearer `meta` descriptions for `performance.optimumWindAngle` (where the optimal angle comes from, what zero means) and `performance.polarVelocityMadeGood` (the polar's prediction, not the actual VMG).
33
+
34
+ ### Fixed
35
+ - Removed idle-triggered input resubscriptions to avoid replaying cached values during sensor outages. Idle/stale warnings remain, and existing subscriptions receive data when the source resumes. Source changes and heading toggles still update subscriptions normally.
36
+ - Heading inputs enabled at runtime now use the same lifecycle-warning callbacks as heading inputs enabled at startup.
37
+ - When sailing in irons, all values taken from the polar (polar speed, target speed, target and polar VMG, beat/gybe angles and VMGs, max speed) and the percentages based on them are now cleared consistently. Previously some were cleared, some kept showing and VMG % froze on its last value. This also prevents spikes in the performance percentages while tacking. Steering advice (target angle, optimum wind angle, opposite tack heading) stays available so you can see how far to bear away. Everything returns as soon as you leave irons ([#38](https://github.com/htool/signalk-polar-performance-plugin/issues/38)).
38
+ - When pinching (between the in-irons cutoff and the beat angle), all outputs keep being published.
39
+ - Actual VMG keeps updating in irons instead of freezing on its last value.
40
+ - Performance outputs whose inputs become unavailable (for example missing boat speed, heading or polar targets) are now cleared instead of showing a stale value.
8
41
 
9
42
  ## [2.0.0] - 2026-09-09
10
43
 
package/README.md CHANGED
@@ -7,8 +7,8 @@ Polar Performance calculates live sailing performance metrics — target boat sp
7
7
  **Polar Performance works together with a polar provider plugin** (such as [signalk-polar-management](https://github.com/Asw1n/signalk-polar-management)).
8
8
 
9
9
  Starting in version 2.0.0, polar file storage, file format conversion, ORC imports, and polar selection are decoupled from this compute plugin:
10
- - **Polar Provider (`signalk-polar-management`):** Stores polar files, imports ORC/CSV/text polar files, manages polar metadata, and publishes the selected active polar to Signal K (`polars.activePolar`) along with any performance factor (`polars.performanceFactor`).
11
- - **Performance Plugin (`signalk-polar-performance-plugin`):** Subscribes to the active polar and boat instrument data (TWS, TWA, STW/SOG), calculates real-time performance values using the [`polar-math`](https://github.com/Asw1n/polar-math) engine, and publishes the resulting performance metrics back to the Signal K delta stream.
10
+ - **Polar Provider (`signalk-polar-management`):** Stores polar files, imports ORC/CSV/text polar files, manages polar metadata, publishes the selected active polar to Signal K (`polars.activePolar`) along with the shared performance factor (`polars.performanceFactor`), and provides an in-process polar calculation service to other plugins.
11
+ - **Performance Plugin (`signalk-polar-performance-plugin`):** Subscribes to boat instrument data (TWS, TWA, STW/SOG), calculates real-time performance values through the management plugin's live *active polar* calculation handle, and publishes the resulting performance metrics back to the Signal K delta stream. The handle automatically follows the active polar, the sailplan selection, and the performance factor chosen in the Polar Management webapp — including v2 polar sets.
12
12
 
13
13
  When a polar lookup cannot be completed or required instrument data is missing/stale, output paths are cleanly set to `null` and the webapp status indicates the exact cause.
14
14
 
@@ -16,6 +16,8 @@ When a polar lookup cannot be completed or required instrument data is missing/s
16
16
 
17
17
  ## Installation
18
18
 
19
+ Requires signalk-server >=2.35.0 for reliable metadata-first input subscriptions. Idle/stale warnings do not trigger resubscriptions; existing subscriptions receive data when the source resumes. Requires signalk-polar-management >=1.5.0, which provides the in-process polar calculation service.
20
+
19
21
  Install both plugins from the Signal K App Store, or via npm:
20
22
 
21
23
  ```sh
@@ -23,7 +25,13 @@ cd ~/.signalk
23
25
  npm install signalk-polar-performance-plugin signalk-polar-management
24
26
  ```
25
27
 
26
- Then restart Signal K and enable both plugins in **Server → Plugin Config**. Without a polar resource provider installed and enabled, Polar Performance will wait for an active polar to be published and indicate this in its status.
28
+ Then restart Signal K and enable both plugins in **Server → Plugin Config**. This plugin requires signalk-polar-management for all polar calculations: without it (or with it disabled), Polar Performance runs but publishes nothing and reports the missing calculation service in its status.
29
+
30
+ ---
31
+
32
+ ## HTTP endpoint access
33
+
34
+ Signal K read-only users can view live values, status, active-polar display metadata, and polar curves used by the plotter. Plugin settings, including settings reads, require administrator access. Anonymous access remains controlled by the server's security configuration and is not enabled by this plugin. See the [developer reference](./docs/developer-reference.md#rest-api) for the endpoint list and access policies.
27
35
 
28
36
  ---
29
37
 
@@ -60,7 +68,7 @@ Most configuration is done through the webapp.
60
68
 
61
69
  ### Active polar and performance factor
62
70
 
63
- These are **not** configured here. Select the active polar and set the performance factor in the polar management webapp (e.g. signalk-polar-management); this plugin reads them from the `polars.activePolar` and `polars.performanceFactor` Signal K paths. If no polar is active, the plugin runs but publishes nothing; any previously published values are nullified immediately.
71
+ These are **not** configured here. Select the active polar (and, for v2 polar sets, a sailplan) and set the performance factor in the polar management webapp (signalk-polar-management); this plugin's calculation handle follows those selections automatically on every calculation. If no polar is active, the plugin runs but publishes nothing; any previously published values are nullified immediately.
64
72
 
65
73
  ### Smoother
66
74
 
@@ -156,11 +164,29 @@ Requires `navigation.headingTrue` to be available.
156
164
 
157
165
  Useful when you want downstream instruments to use the same smoothed values that drive the performance calculation.
158
166
 
167
+ ### Output handling when pinching and in irons
168
+
169
+ The polar defines two zones above the beat angle:
170
+
171
+ - **Pinching** — TWA is between the in-irons cutoff and the beat angle. The boat is still sailing, and the polar curve is extended smoothly towards zero speed. **All outputs are published.**
172
+ - **In irons** — TWA is below the cutoff, which lies 80 % of the way from 25° to the beat angle (for example ~38.6° for a 42° beat angle). The polar has no sailing state here, so the outputs are handled per kind:
173
+
174
+ | Kind | Outputs | In irons |
175
+ |------|---------|----------|
176
+ | Measured | `velocityMadeGood`, `angleTrueWaterDamped`, `boatSpeedDamped` | Published |
177
+ | Steering advice | `targetAngle`, `optimumWindAngle`, `tackTrue` | Published, so you can see how far to bear away |
178
+ | Selected target performance | `targetSpeed`, `targetVelocityMadeGood` | Published from the selected beat or run target |
179
+ | Polar values and ratios based on them | `polarSpeed`, `polarSpeedRatio`, `polarVelocityMadeGood`, `polarVelocityMadeGoodRatio`, `beatAngle`, `gybeAngle`, `beatAngleVelocityMadeGood`, `gybeAngleVelocityMadeGood`, `maxSpeed`, `maxSpeedAngle` | Set to `null` |
180
+
181
+ The selected target speed and VMG remain available in irons because they describe the optimal beat or run target for the current TWS, rather than the boat's current angle. Clearing values based on the boat's current polar state prevents spikes in performance ratios while tacking. Through a tack the boat carries its speed head-to-wind while the polar speed falls towards zero, which would briefly drive the ratios to meaningless values. As soon as you bear away out of irons, all other polar values return on the next wind update.
182
+
183
+ A value is set to `null` once when it becomes unavailable and is not repeated until it returns.
184
+
159
185
  ---
160
186
 
161
187
  ## Managing polars
162
188
 
163
- Polar storage, import (ORC, text formats), and active-polar/performance-factor selection are handled by a separate 'polars' resource-provider plugin, such as [signalk-polar-management](https://github.com/Asw1n/signalk-polar-management). See that plugin's documentation for import formats, the ORC certificate search, and extrapolation behaviour of the underlying `polar-math` library.
189
+ Polar storage, import (ORC, text formats), and active-polar/sailplan/performance-factor selection are handled by [signalk-polar-management](https://github.com/Asw1n/signalk-polar-management), which also performs all polar calculations for this plugin through its in-process calculation service. See that plugin's documentation for import formats, the ORC certificate search, and extrapolation behaviour of the underlying `polar-math` library.
164
190
 
165
191
  ---
166
192
 
@@ -221,9 +247,10 @@ The webapp shows warnings whenever something prevents accurate calculation:
221
247
  | *True wind speed — no data* | `environment.wind.speedTrue` is not arriving from Signal K. |
222
248
  | *True wind angle — no data* | `environment.wind.angleTrueWater` is not arriving. |
223
249
  | *Boat speed — no data* | `navigation.speedThroughWater` (or SOG) is not arriving. |
224
- | *No active polar* | No `polars.activePolar` is published. Select an active polar in the polar management webapp. |
225
- | *Sailing in irons* | TWA is below the minimum angle in the polar. No output is produced. |
226
- | *Pinching* | TWA is between the minimum polar angle and the beat angle. Values come from the extrapolated beat zone. |
250
+ | *No active polar* | No active polar is selected. Select one in the polar management webapp. |
251
+ | *Polar calculation service not available* | signalk-polar-management is not installed, not enabled, or too old to provide the in-process calculation service. |
252
+ | *Sailing in irons* | TWA is below the in-irons cutoff. Polar values and the ratios based on them are set to `null`; measured values and steering advice keep updating. See [Output handling when pinching and in irons](#output-handling-when-pinching-and-in-irons). |
253
+ | *Pinching* | TWA is between the in-irons cutoff and the beat angle. All outputs are published; values come from the extrapolated beat zone. |
227
254
  | *Extrapolated beyond run angle* | TWA is deeper than the run angle. Values come from the cosine-VMG extrapolation model. |
228
255
  | *Wind speed below/above polar range* | TWS is outside the range covered by the polar. Values are extrapolated from the nearest TWS entry. |
229
256
 
@@ -245,11 +272,12 @@ If you want to consume this plugin's live performance queries, use the developer
245
272
 
246
273
  - [Developer reference](docs/developer-reference.md) for the plugin REST API.
247
274
  - [openApi.json](openApi.json) for the authoritative machine-readable contract.
248
- - For the canonical `polarTable` structure, polar storage, and import, see [signalk-polar-management](https://github.com/Asw1n/signalk-polar-management) and the [polar-format](https://github.com/Asw1n/polar-format) / [polar-math](https://github.com/Asw1n/polar-math) packages it depends on.
275
+ - For the canonical `polarTable` / `polarSet` structures, polar storage, import, and the in-process calculation service, see [signalk-polar-management](https://github.com/Asw1n/signalk-polar-management) and the [polar-format](https://github.com/Asw1n/polar-format) / [polar-math](https://github.com/Asw1n/polar-math) packages it depends on.
249
276
 
250
277
  ---
251
278
 
252
279
  ## Known limitations
253
280
 
254
281
  - Heel angle is not taken into account in the polar lookup. Most ORC polars are upright polars.
255
- - Requires a 'polars' resource-provider plugin (e.g. `signalk-polar-management`) to be installed and running for polar storage, import, and active polar selection.
282
+ - Requires `signalk-polar-management` to be installed and running: it stores and imports polars, owns the active selection, and performs all polar calculations for this plugin.
283
+ - Sea state (wave) correction is not applied, even when the active v2 polar set carries a wave-correction table. The Signal K specification currently defines no paths for the required inputs (significant wave height, wave period, wave direction), so this plugin has nothing to feed the correction with. Support can be added once such paths exist in the specification.
@@ -1,40 +1,64 @@
1
1
  # Polar Performance Developer Reference
2
2
 
3
3
  This document covers the REST API this plugin still exposes. It no longer stores, imports,
4
- or manages polar files — that is handled by a separate 'polars' resource-provider plugin
5
- (e.g. [signalk-polar-management](https://github.com/Asw1n/signalk-polar-management)). For the
6
- canonical `polarTable` format and its management API, see that plugin's documentation and the
7
- [polar-format](https://github.com/Asw1n/polar-format) / [polar-math](https://github.com/Asw1n/polar-math)
8
- packages it depends on.
4
+ or manages polar files — that is handled by
5
+ [signalk-polar-management](https://github.com/Asw1n/signalk-polar-management), which also
6
+ provides the in-process polar calculation service this plugin uses. For the canonical
7
+ `polarTable` / `polarSet` formats and the management API, see that plugin's documentation
8
+ and the [polar-format](https://github.com/Asw1n/polar-format) package; the underlying
9
+ calculation engine, [polar-math](https://github.com/Asw1n/polar-math), is a dependency of
10
+ the management plugin, not of this one.
9
11
 
10
12
  For installation, day-to-day use, and webapp workflow, start with [../README.md](../README.md).
11
13
 
12
14
  ## How the active polar is resolved
13
15
 
14
- This plugin subscribes to two Signal K paths published by the 'polars' resource provider:
16
+ All polar calculations and all active-polar metadata go through the in-process
17
+ calculation service announced by signalk-polar-management via the `polarManagement`
18
+ PropertyValue. At startup this plugin subscribes with
19
+ `app.onPropertyValues('polarManagement', …)` and acquires an **active-polar handle**
20
+ (`service.activePolar()`). Every calculation call on that handle automatically follows
21
+ the shared active polar, the shared sailplan selection (for v2 polar sets), the shared
22
+ performance factor, and the shared wave-correction toggle — this plugin applies none of
23
+ them itself. When the management plugin is missing or stopped, calculations are
24
+ unavailable and the plugin reports this in its status; results then carry
25
+ `state.available: false` with a reason such as `no_active_polar`.
15
26
 
16
- - `polars.activePolar` — `{ href: '/resources/polars/<id>' }`, or absent if no polar is active.
17
- - `polars.performanceFactor` — a number applied as a multiplier to all polar speeds.
27
+ Descriptive metadata comes from the same handle: `handle.describe()` returns the active
28
+ document's name, boat details, selected sailplan, the applied performance factor, and the
29
+ selected table's TWS axis. The plugin refreshes this snapshot on `handle.onChange`
30
+ notifications and serves it through `/meta` and `/polar/axes/tws`. It does not subscribe
31
+ to the `polars.*` Signal K paths and performs no resource lookups; those paths remain
32
+ published by signalk-polar-management for other consumers.
18
33
 
19
- On a change to `polars.activePolar`, the plugin resolves `<id>` via the in-process
20
- `app.resourcesApi.getResource('polars', id)` call and builds a `polar-math` `Polar` instance
21
- from the returned canonical document. If the resource provider or the active polar becomes
22
- unavailable, the last successfully loaded polar is kept until a valid update arrives.
34
+ ### Sea state / wave correction
35
+
36
+ v2 polar sets can carry a wave-correction table, and active handles accept per-call
37
+ `seaState` input. This plugin does not supply `seaState`, because the Signal K
38
+ specification currently defines no paths for the required inputs (significant wave height,
39
+ wave period, wave direction). Wave correction therefore has no effect on this plugin's
40
+ outputs. If the specification gains such paths, sea state can be wired into the existing
41
+ handle calls without restructuring.
23
42
 
24
43
  ## REST API
25
44
 
26
45
  The plugin exposes a REST API under `/plugins/signalk-polar-performance-plugin/`. Authentication
27
46
  follows Signal K server rules; the same session cookie used by the webapp works for direct API calls.
47
+ The endpoints marked **Read-only** are available to users with Signal K read-only permission.
48
+ Anonymous access is controlled only by the server's `allow_readonly` setting and is not enabled by
49
+ the plugin. Curve queries are capped at 181 sample angles per request (minimum step 1°).
50
+ `/meta` includes the active polar's boat type, sail number, source, and free-text notes, so those
51
+ fields are also available to read-only users.
28
52
 
29
- | Method | Path | Description |
30
- |--------|------|-------------|
31
- | `GET` | `/live` | Current smoothed TWS, TWA, BSP, polar speed, and polar state. |
32
- | `GET` | `/status` | Full snapshot: raw inputs, smoothed inputs, and all enabled output values. |
33
- | `GET` | `/meta` | Display unit metadata for all fields, plus a read-only summary of the active polar (name, boatType, sailnumber, year, source) and performance factor. |
34
- | `GET` | `/settings` | Current plugin settings (smoother, output toggles, speed source — no polar selection). |
35
- | `PUT` | `/settings` | Update settings. Body: JSON object with changed keys only. |
36
- | `GET` | `/polar/axes/tws` | TWS axis of the currently active polar. 404 if none is active. |
37
- | `GET` | `/polar/queries/curve?tws=&step=` | Interpolated curve for the active polar at the given TWS, with beat/run markers, performance factor already applied. |
53
+ | Method | Path | Description | Access |
54
+ |--------|------|-------------|--------|
55
+ | `GET` | `/live` | Current smoothed TWS, TWA, BSP, polar speed, and polar state. | Read-only |
56
+ | `GET` | `/status` | Full snapshot: raw inputs, smoothed inputs, and all enabled output values. | Read-only |
57
+ | `GET` | `/meta` | Display unit metadata for all fields, plus a read-only summary of the active polar (name, boatType, sailnumber, year, source, notes, selected sailplan) and the applied performance factor. | Read-only |
58
+ | `GET` | `/settings` | Current plugin settings (smoother, output toggles, speed source — no polar selection). | Administrator |
59
+ | `PUT` | `/settings` | Update settings. Body: JSON object with changed keys only. | Administrator |
60
+ | `GET` | `/polar/axes/tws` | TWS axis of the currently active polar. 404 if none is active. | Read-only |
61
+ | `GET` | `/polar/queries/curve?tws=&step=` | Interpolated curve for the active polar at the given TWS, with beat/run markers, performance factor already applied. `step` must be at least 1° and at most π/2 radians. | Read-only |
38
62
 
39
63
  The authoritative machine-readable schema for the two `/polar/*` endpoints is in
40
64
  [../openApi.json](../openApi.json).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signalk-polar-performance-plugin",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "Calculates live sailing performance from the active polar selected in a polar management plugin (e.g. signalk-polar-management).",
5
5
  "main": "plugin/index.js",
6
6
  "exports": {
@@ -19,23 +19,17 @@
19
19
  ],
20
20
  "engines": {
21
21
  "node": ">=20",
22
- "signalk-server": ">=2.28.0"
22
+ "signalk-server": ">=2.35.0"
23
23
  },
24
24
  "scripts": {
25
25
  "test": "node --test test/**/*.test.js",
26
26
  "prepublishOnly": "npm test"
27
27
  },
28
28
  "dependencies": {
29
- "polar-math": "^1.0.0",
30
- "signalkutilities": "^3.1.3"
29
+ "signalkutilities": "^3.2.0"
31
30
  },
32
- "peerDependencies": {
33
- "signalk-polar-management": ">=1.0.0"
34
- },
35
- "peerDependenciesMeta": {
36
- "signalk-polar-management": {
37
- "optional": true
38
- }
31
+ "devDependencies": {
32
+ "polar-math": "^1.1.1"
39
33
  },
40
34
  "repository": {
41
35
  "type": "git",
@@ -51,6 +45,9 @@
51
45
  "signalk": {
52
46
  "appIcon": "./icon.png",
53
47
  "displayName": "Polar Performance",
48
+ "requires": [
49
+ "signalk-polar-management"
50
+ ],
54
51
  "screenshots": [
55
52
  "./docs/plotter.png",
56
53
  "./docs/overview.png",