@mxtommy/kip 4.8.0-beta.1 → 4.8.1
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 +32 -0
- package/LICENSE +3 -0
- package/README.md +56 -49
- package/package.json +24 -21
- package/plugin/history-series.service.js +108 -30
- package/plugin/index.js +157 -115
- package/plugin/kip-series-contract.js +12 -3
- package/plugin/openApi.json +64 -13
- package/plugin/sqlite-history-storage.service.js +4 -2
- package/plugin/src/history-series.service.js +634 -0
- package/plugin/src/index.js +1322 -0
- package/plugin/src/kip-series-contract.js +31 -0
- package/plugin/src/openApi.json +855 -0
- package/plugin/src/sqlite-history-storage.service.js +1122 -0
- package/public/3rdpartylicenses.txt +569 -727
- package/public/assets/help-docs/chartplotter.md +1 -1
- package/public/assets/help-docs/contributing-widgets.md +40 -0
- package/public/assets/help-docs/dashboards.md +6 -0
- package/public/assets/help-docs/history-api.md +69 -71
- package/public/assets/help-docs/menu.json +27 -7
- package/public/assets/help-docs/time-series.md +81 -0
- package/public/assets/help-docs/welcome.md +1 -1
- package/public/assets/svg/icons.svg +36 -1
- package/public/chunk-00hwknVI.js +1 -0
- package/public/chunk-5U8d2Ygo.js +14 -0
- package/public/chunk-AANk-NXH.js +1015 -0
- package/public/chunk-B6bEhzNR.js +1 -0
- package/public/chunk-B82ADJSs.js +1 -0
- package/public/chunk-BJz7Ij9E.js +1 -0
- package/public/chunk-BKj60jdq.js +1 -0
- package/public/chunk-BOAD0N2a.js +2 -0
- package/public/chunk-BQr-tSkv.js +1 -0
- package/public/chunk-BX6skw5k.js +1 -0
- package/public/chunk-BdokyhBM.js +1 -0
- package/public/chunk-Blokg6Ds.js +1 -0
- package/public/chunk-BoNDCNGE.js +1 -0
- package/public/chunk-Bp0MQwPM.js +1 -0
- package/public/chunk-BwOIef42.js +1 -0
- package/public/chunk-By8ZVvDx.js +2 -0
- package/public/chunk-C2VQxCXa.js +1 -0
- package/public/chunk-C6UXF7BI.js +1 -0
- package/public/chunk-CA6RRaxd.js +1 -0
- package/public/chunk-CIlfzV9R.js +1 -0
- package/public/chunk-CL2xiH57.js +1 -0
- package/public/chunk-CNMFlw_H.js +1 -0
- package/public/chunk-CNNTuNlM.js +1 -0
- package/public/chunk-CQNVyz8q.js +1 -0
- package/public/chunk-CXvG8mMq.js +1 -0
- package/public/chunk-CaD3zVfK.js +1 -0
- package/public/chunk-CkXTl3su.js +1 -0
- package/public/chunk-CpMCBDvH.js +1 -0
- package/public/chunk-CpuB_ZZz.js +2 -0
- package/public/chunk-CrBxxZCe.js +1 -0
- package/public/chunk-CwSa_BNV.js +1 -0
- package/public/chunk-D4xZ2tGB.js +39 -0
- package/public/chunk-DDqeRiB0.js +1 -0
- package/public/chunk-DE4ylhpq.js +1 -0
- package/public/chunk-DNS-qsFC.js +1 -0
- package/public/chunk-DQnoPLyC.js +1 -0
- package/public/chunk-DWLISAZi.js +1 -0
- package/public/chunk-DXkKj21H.js +1 -0
- package/public/chunk-DchvLV_Y.js +1 -0
- package/public/chunk-DjZgzSiH.js +1 -0
- package/public/chunk-DumLX5k_.js +1 -0
- package/public/chunk-Dxlia2NE.js +1 -0
- package/public/chunk-DzTTqoF_.js +1 -0
- package/public/chunk-H9_eqTYx.js +1 -0
- package/public/chunk-Ii9n-oiL.js +1 -0
- package/public/chunk-JbEkcxJm.js +2 -0
- package/public/chunk-MjWuPUhu.js +1 -0
- package/public/chunk-PheXEqie.js +1 -0
- package/public/chunk-TakPRI3t.js +2 -0
- package/public/chunk-VgxMqRPk.js +3 -0
- package/public/chunk-dgaOX1wC.js +382 -0
- package/public/chunk-hd2_AKwt.js +1 -0
- package/public/chunk-nu4vZg-z.js +1 -0
- package/public/chunk-sNakMDHi.js +1 -0
- package/public/chunk-tAiV3ARh.js +1 -0
- package/public/chunk-y1imvaA-.js +1 -0
- package/public/index.html +4 -4
- package/public/main-BAV5VDOD.js +7109 -0
- package/public/polyfills-5MJXXCNC.js +1 -0
- package/public/styles-JZSMCSRO.css +1 -0
- package/public/assets/help-docs/widget-historical-series.md +0 -110
- package/public/chunk-2TP7C66X.js +0 -5
- package/public/chunk-4KHUCTYN.js +0 -3
- package/public/chunk-6ISGIPNP.js +0 -1
- package/public/chunk-7JGTAL26.js +0 -10
- package/public/chunk-C23GLDFH.js +0 -62
- package/public/chunk-CB4E7PPA.js +0 -4
- package/public/chunk-DNM5XUIF.js +0 -1
- package/public/chunk-HF7V6XFA.js +0 -2
- package/public/chunk-HXR2BKDL.js +0 -4
- package/public/chunk-ILQQCGMJ.js +0 -5
- package/public/chunk-IXUKD73N.js +0 -5
- package/public/chunk-JMZYPL54.js +0 -2
- package/public/chunk-KJCBQE6W.js +0 -6
- package/public/chunk-LEY6MANN.js +0 -16
- package/public/chunk-O5BTKN5D.js +0 -1
- package/public/chunk-OH5KNIQ7.js +0 -50
- package/public/chunk-Q32FSCUX.js +0 -1
- package/public/chunk-RIX4VQJ2.js +0 -1
- package/public/chunk-SHJMXSDM.js +0 -1
- package/public/chunk-T4VTC6GW.js +0 -1
- package/public/chunk-VFJD3XKT.js +0 -1
- package/public/chunk-VFZSH4TC.js +0 -1
- package/public/chunk-W6MCE3GH.js +0 -6
- package/public/chunk-WAOG456B.js +0 -2
- package/public/chunk-XBOM6DMF.js +0 -9
- package/public/main-BECMST5R.js +0 -1
- package/public/polyfills-BWA36QKG.js +0 -1
- package/public/scripts-M6PHZBML.js +0 -14
- package/public/styles-DYEO23GZ.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,35 @@
|
|
|
1
|
+
# v4.9.0
|
|
2
|
+
## New Contributors
|
|
3
|
+
* Special thanks to @dillan for their first of many contributions.
|
|
4
|
+
* Special thanks to @macjl for their first of many contributions.
|
|
5
|
+
## Improvements
|
|
6
|
+
* Enhanced switch panel control states and sizing for clearer status visibility and easier interaction.
|
|
7
|
+
* Simplified and clarified Time-Series documentation for faster onboarding and fewer setup mistakes.
|
|
8
|
+
* Made the V2 autopilot mode menu provider-agnostic for broader compatibility.
|
|
9
|
+
* Hid the Action Sidebar Fullscreen button when hosted in AppDock for a cleaner, context-aware UI and to prevent browsers from being stuck in fullscreen. Fixes #1062.
|
|
10
|
+
* Multiple performance improvements increasing responsiveness and providing a smoother experience on low powered devices.
|
|
11
|
+
* Reduced startup bundle size to deliver faster app startup.
|
|
12
|
+
## Fixes
|
|
13
|
+
* Restored TTL reset to "--" after data timeouts to keep stale-state feedback accurate. Fixes #1069.
|
|
14
|
+
* Corrected layering so the autopilot SVG menu now appears above widget overlays. Fixes #1071.
|
|
15
|
+
* Fixed the autopilot static standby button label for clearer control feedback. Fixes #1072.
|
|
16
|
+
* Corrected the autopilot key map. Fixes #1073.
|
|
17
|
+
* Fixed Help image 404 errors when KIP is served under a base href. Fixes #1056.
|
|
18
|
+
* Resolved a test suite issue. Fixes #1074.
|
|
19
|
+
* Fixed remote storage request handling. Fixes #1075.
|
|
20
|
+
* Corrected Windsteer simple mode's True Wind Angle offset and simplified the interface to better match familiar, classic wind gauge features. Fixes #1066, #1063.
|
|
21
|
+
* Added circular directional angle support in the Data Charts widget using the Advancedwind wind shift path. Fixes #1070.
|
|
22
|
+
# v4.8.0
|
|
23
|
+
## New Features
|
|
24
|
+
* Solar Charger Widget: Get instant clarity on your solar system with a compact, purpose-built Solar Charger Widget. Track individual panels or full arrays in real time, including State of Charge, remaining capacity, remaining time, voltage, current, power flow, and temperature. Device discovery is automatic, and Zones support keeps warnings and alarms state highly visible.
|
|
25
|
+
* AC/DC Charger Widget: Monitor charging performance at a glance with a compact AC/DC Charger Widget. View single or multiple chargers with charge mode, voltage, current, power and temperature. Chargers are discovered automatically.
|
|
26
|
+
## Improvements
|
|
27
|
+
* Battery Monitor Widget visual cleanup for better readability and tighter consistency with the electrical widget family.
|
|
28
|
+
* Framework upgrades and core refactoring to improve long-term maintainability and runtime performance.
|
|
29
|
+
* New Display Testing option allowing widgets with invalid paths to be saved.
|
|
30
|
+
## Fixes
|
|
31
|
+
* Improved Battery Monitor text contrast when color state is Alert (yellow), making critical values easier to read. Fixes #1027
|
|
32
|
+
* Restored Countdown Timer visibility in Add Widgets.
|
|
1
33
|
# v4.7.0
|
|
2
34
|
## New Features
|
|
3
35
|
* Battery Monitor Widget: Stay on top of your vessel’s power system with a dedicated compact Battery Monitor Widget. Instantly view individual batteries or whole banks, including State of Charge, remaining capacity, remaining time, voltage, current, power flow, and temperature. Batteries are detected automatically, with Signal K Zones support for clear warning and alarm visibility at a glance.
|
package/LICENSE
CHANGED
|
@@ -19,3 +19,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
This repository may not be used to train machine learning or AI models
|
|
24
|
+
without explicit permission from the author.
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ KIP is designed for sailors and boaters who want:
|
|
|
18
18
|
|
|
19
19
|
With KIP, you get the **familiar feel of professional Multi-Function Displays** combined with the flexibility of Signal K. It’s simple, reliable, and highly usable — the ultimate ready-to-go, modern, touch-first, Multi-Function Display for [Signal K](https://signalk.org) vessels.
|
|
20
20
|
|
|
21
|
-

|
|
22
22
|
|
|
23
23
|
## Table of Content
|
|
24
24
|
- [Installations Showcase](#installations-showcase)
|
|
@@ -35,7 +35,7 @@ With KIP, you get the **familiar feel of professional Multi-Function Displays**
|
|
|
35
35
|
- [Connect, Share, and Support](#connect-share-and-support) & [Features, Ideas, Bugs](#features-ideas-bugs)
|
|
36
36
|
|
|
37
37
|
## Installations Showcase
|
|
38
|
-

|
|
39
39
|
In addition to the obvious navstation, wall mounted instrument panel and autopilot remote control usecases using PCs, tablets and phones, users have taken KIP into the elements using Raspberry Pi, Pi Zero, rugged tablets and all kinds of low cost AliExpress screens and industry leading, high quality, sunlight readable marine touch screens. KIP's native remote control feature opens up all kinds of possibilities.
|
|
40
40
|
|
|
41
41
|
## Read the Help Introduction How-To
|
|
@@ -50,7 +50,7 @@ The goal is to replicate and enhance the functionality of modern marine instrume
|
|
|
50
50
|
- **Cross-Device Compatibility**: Guarantee a consistent and responsive experience across phones, tablets, computers, and other devices.
|
|
51
51
|
- **Modern Browser Support**: Include support for the latest versions of Chromium and other modern web browsers to ensure optimal performance and compatibility.
|
|
52
52
|
|
|
53
|
-

|
|
54
54
|
|
|
55
55
|
## User Experience
|
|
56
56
|
|
|
@@ -67,10 +67,10 @@ The goal is to replicate and enhance the functionality of modern marine instrume
|
|
|
67
67
|
- Easily switch between multiple user and device configurations profiles for different roles, formfactors or use cases.
|
|
68
68
|
|
|
69
69
|
Sidenav for quick access to all important features.
|
|
70
|
-

|
|
71
71
|
|
|
72
72
|
Chartplotter Mode with dashboards
|
|
73
|
-

|
|
74
74
|
|
|
75
75
|
## Dashboards and Configuration
|
|
76
76
|
|
|
@@ -80,75 +80,68 @@ Meant to build purposeful dashboards with however many widgets you want, whereve
|
|
|
80
80
|
Add, resize, and position the widgets of your choosing. Need more? Add as many additional dashboards as you wish to keep your display purposeful. Simply swipe up and down to quickly cycle through dashboards or effortlessly jump between dashboards with a single tap in the action sidenav, always knowing exactly where you are thanks to clear highlighting of your current dashboard.
|
|
81
81
|
|
|
82
82
|
Widget lists are sorted by category.
|
|
83
|
-

|
|
84
84
|
|
|
85
85
|
Intuitive widget configuration.
|
|
86
|
-

|
|
87
87
|
|
|
88
88
|
See what Signal K has to offer that you can leverage with widgets. Select it and tweak the display options to suit your purpose.
|
|
89
|
-

|
|
90
90
|
|
|
91
91
|
Many units are supported. Choose your preferred app defaults, then tweak them widget-by-widget as necessary. KIP will automatically convert the units for you.
|
|
92
|
-

|
|
93
93
|
|
|
94
94
|
Organize your dashboards and access tools.
|
|
95
|
-

|
|
96
96
|
|
|
97
97
|
## Widget Library
|
|
98
98
|
All KIP widgets are visual presentation controls that are very versatile, with multiple advanced configuration options available to suit your needs:
|
|
99
|
-
- **
|
|
100
|
-
- **
|
|
101
|
-
- **
|
|
102
|
-
- **
|
|
103
|
-
- **
|
|
104
|
-
- **
|
|
105
|
-
- **
|
|
106
|
-
- **
|
|
107
|
-
- **
|
|
108
|
-
- **
|
|
109
|
-
- **
|
|
110
|
-
- **
|
|
111
|
-
- **
|
|
112
|
-
- **
|
|
113
|
-
- **
|
|
114
|
-
- **Countdown Timer**: A simple start sequences timer.
|
|
115
|
-
- **Racer Start Timer**: Advanced race countdown timer with OCS (On Course Side) detection and automatic dashboard switching.
|
|
116
|
-
- **Start Line Insight**: Analyze and visualize the start line for tactical racing advantage, including favored end and distance-to-line.
|
|
117
|
-
- **Boolean Control Panel**: A digital switchboard to configure and operate remote devices: lights, bilge pumps, solenoids, or any Signal K compatible device that supports On/Off operations.
|
|
118
|
-
- **Slider**: A versatile control that allows users to adjust values within a defined range by sliding. Commonly used for settings like light intensity, volume control, or any parameter requiring fine-tuned adjustments.
|
|
119
|
-
- **Multi State Switch**: Lists all available device modes/states (e.g., On, Off, Charge Only, Invert Only), highlights the current state, and lets you select a new state to send to the device and see the result.
|
|
120
|
-
- **Zones State Panel**: Monitor the health/state of multiple sensors and devices at a glance. Configure multiple paths per panel; each control uses KIP’s zone severity colors and status messages so warnings and alarms stand out immediately.
|
|
121
|
-
- **Freeboard-SK Chart Plotter**: High-quality Signal K chartplotter integration widget.
|
|
122
|
-
- **Autopilot Head**: Operate your autopilot from any device remotely.
|
|
99
|
+
- **Compact Linear** – Simple horizontal linear gauge with a large value label and modern look.
|
|
100
|
+
- **Linear** – Horizontal or vertical linear gauge with zone highlighting.
|
|
101
|
+
- **Radial** – Radial gauge with configurable dials and zone highlighting.
|
|
102
|
+
- **Compass** – Rotating compass gauge with multiple cardinal indicator options.
|
|
103
|
+
- **Level Gauge** – Dual-scale heel angle indicator for trim tuning and sea-state monitoring.
|
|
104
|
+
- **Pitch & Roll** – Horizon-style attitude indicator showing live pitch and roll degrees.
|
|
105
|
+
- **Classic Steel** – Traditional steel-look linear & radial gauges with range sizes and zone highlights.
|
|
106
|
+
- **Windsteer** – Combines wind, wind sectors, heading, COG, and waypoint info for wind steering.
|
|
107
|
+
- **Wind Trends** – Real-time True Wind trends with dual axes for direction and speed, live values, and averages.
|
|
108
|
+
- **Battery Monitor** - Display batteries or whole banks state State of Charge, remaining capacity, remaining time, voltage, current, power flow, and temperature.
|
|
109
|
+
- **Solar Charger**- Track solar generation and charging performance at a glance with live panel output, battery-side metrics, and clear charger and relay status indicators.
|
|
110
|
+
- **AC/DC Charger**- Monitor charging performance at a glance with a compact AC/DC Charger Widget. View single or multiple chargers with charge mode, voltage, current, power and temperature. Chargers are discovered automatically.
|
|
111
|
+
- **Freeboard-SK** – Adds the Freeboard-SK chart plotter as a widget with automatic sign-in.
|
|
112
|
+
- **Autopilot Head** – Typical autopilot controls for compatible Signal K Autopilot devices.
|
|
113
|
+
- **Realtime Data Chart** – Visualizes data on a real-time chart with actuals, averages, and min/max.
|
|
123
114
|
- **AIS Radar**: Display AIS targets with range rings, interactive target details, and quick zoom and filtering controls.
|
|
124
|
-
- **
|
|
125
|
-
- **
|
|
126
|
-
- **
|
|
115
|
+
- **Embed Webpage Viewer** – Embeds external web apps (Grafana, Node-RED, etc.) into your dashboard.
|
|
116
|
+
- **Racesteer** – Race steering display fusing polar performance data with live conditions for optimal tactics.
|
|
117
|
+
- **Racer - Start Line Insight** – Set and adjust start line ends, see distance, favored end, and line bias; integrates with Freeboard SK.
|
|
118
|
+
- **Racer - Start Timer** – Advanced racing countdown timer with OCS status and auto dashboard switching.
|
|
119
|
+
- **Countdown Timer** – Simple race start countdown timer with start, pause, sync, and reset options.
|
|
127
120
|
|
|
128
121
|
Get the latest version of KIP to see what's new!
|
|
129
122
|
|
|
130
123
|
### Widget Samples
|
|
131
124
|
Gauges sample
|
|
132
|
-

|
|
133
126
|
|
|
134
127
|
Various other types of widgets
|
|
135
|
-

|
|
136
129
|
|
|
137
130
|
Freeboard-SK Chartplotter integration with Autopilot widget
|
|
138
|
-

|
|
139
132
|
|
|
140
133
|
Grafana integration with other widgets
|
|
141
|
-

|
|
142
135
|
|
|
143
136
|
## Historical Data
|
|
144
|
-
Experience effortless insight into your vessel’s past with KIP’s Widget Historical Charts—automatically track, store, and visualize key data, unlocking instant access charts showing up to the last full day of performance. Whether you’re sailing or docked, simply tap or right-click widgets to reveal a seamless history dialog—no setup, no clutter, just the trends you need.
|
|
137
|
+
Experience effortless insight into your vessel’s past with KIP’s Widget Historical Charts—automatically track, store, and visualize key data, unlocking instant access charts showing up to the last full day of performance. Whether you’re sailing or docked, simply two-finger tap or right-click widgets to reveal a seamless history dialog—no setup, no clutter, just the trends you need. When combining data visualisation using Data Driven widgets, live-to-history transitions, KIP puts your boat’s story at your fingertips—so you can make smarter decisions, spot patterns, and sail with confidence.
|
|
145
138
|
|
|
146
139
|
## Night Modes
|
|
147
140
|
Keep your night vision with automatic or manual day and night switching to a color preserving dim mode or an all Red theme. The images below look very dark, but at night... they are perfect!
|
|
148
141
|
|
|
149
|
-

|
|
150
143
|
|
|
151
|
-

|
|
152
145
|
|
|
153
146
|
## Chartplotter Mode
|
|
154
147
|
Keep a live Freeboard‑SK chart visible while switching dashboards for an MFD‑style workflow. The chart persists (no reload or flicker), you can choose its side, collapse it per‑dashboard for full data pages, and drag resize the split. Layout auto‑stacks in portrait / narrow screens. See the dedicated Chartplotter Mode help page for setup, performance tips, and troubleshooting.
|
|
@@ -188,7 +181,9 @@ Stay informed with notifications about the state of the data you are interested
|
|
|
188
181
|
For example, Signal K will notify KIP when a water depth or temperature sensor reaches certain levels. In addition to KIP's centralized notification menu, individual widgets offer tailored visual representations appropriate to their design objectives, providing an optimal user experience.
|
|
189
182
|
|
|
190
183
|
# How To Contribute
|
|
191
|
-
KIP is under the MIT license and is built with Node and Angular using various open-source assets. All free!
|
|
184
|
+
KIP is under the MIT license and is built with Node and Angular using various open-source assets. All free! The project want's to insure your time is well invested by favouring discussion before submitting bug fixes and new features.
|
|
185
|
+
|
|
186
|
+
Please ensure you submit an issue (bug/feature) before submitting a pull request.
|
|
192
187
|
|
|
193
188
|
## Project Scope
|
|
194
189
|
What KIP IS about:
|
|
@@ -265,17 +260,26 @@ Once done with your work, from your fork's working branch, make a GitHub pull re
|
|
|
265
260
|
For comprehensive development guidance, please refer to these instruction files:
|
|
266
261
|
|
|
267
262
|
### Primary Instructions
|
|
268
|
-
- **[
|
|
263
|
+
- **[Project Instructions](./.github/instructions/project.instructions.md)**: KIP policy owner for architecture/domain rules, including widget creation and Host2 contracts.
|
|
264
|
+
- **[COPILOT.md](./COPILOT.md)**: Architecture context, rationale, and evolution notes (non-policy).
|
|
269
265
|
- **[Angular Instructions](./.github/instructions/angular.instructions.md)**: Modern Angular v21+ coding standards, component patterns, and framework best practices.
|
|
270
266
|
- **[Copilot Agent Instructions](./.github/copilot-instructions.md)**: Architecture details and coding-agent guardrails for this repository.
|
|
271
267
|
|
|
272
268
|
### Development Workflow
|
|
273
|
-
1. **Start Here**: Read
|
|
269
|
+
1. **Start Here**: Read `.github/instructions/project.instructions.md` for KIP policy contracts.
|
|
274
270
|
2. **Angular Standards**: Follow `.github/instructions/angular.instructions.md` for modern Angular development.
|
|
275
|
-
3. **
|
|
271
|
+
3. **Architecture Context**: Use `COPILOT.md` for rationale and dated architecture notes.
|
|
272
|
+
4. **Setup & Build**: Use this README for project setup and build commands.
|
|
273
|
+
|
|
274
|
+
### Widget Creation Workflow
|
|
275
|
+
1. Scaffold with `npm run generate:widget` (Host2 schematic-first path).
|
|
276
|
+
2. Use `docs/widget-schematic.md` for CLI flags, prompting behavior, and troubleshooting.
|
|
277
|
+
3. Follow Host2 runtime/stream patterns in `.agents/skills/kip-host2-widget/SKILL.md`.
|
|
278
|
+
4. Apply widget creation implementation checklist from `.agents/skills/kip-widget-creation/SKILL.md`.
|
|
279
|
+
5. Keep enforceable behavior aligned with `.github/instructions/project.instructions.md` (`Widget Creation Domain Rules`).
|
|
276
280
|
|
|
277
281
|
### Key Priorities
|
|
278
|
-
- **Widget Development**: Use
|
|
282
|
+
- **Widget Development**: Use Host2 patterns and scaffold with the `create-host2-widget` schematic (see `docs/widget-schematic.md`).
|
|
279
283
|
- **Angular Patterns**: Use signals, standalone components, and modern control flow.
|
|
280
284
|
- **Theming**: Follow KIP's theme system for consistent UI.
|
|
281
285
|
- **Code Quality**: Run `npm run lint` before commits.
|
|
@@ -288,3 +292,6 @@ KIP has its own Discord Signal K channel for getting in touch. Join us at https:
|
|
|
288
292
|
# Features, Ideas, Bugs
|
|
289
293
|
See KIP's GitHub project for the latest feature requests:
|
|
290
294
|
https://github.com/mxtommy/Kip/issues
|
|
295
|
+
|
|
296
|
+
This repository may not be used to train machine learning or AI models
|
|
297
|
+
without explicit permission from the author.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mxtommy/kip",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.1",
|
|
4
4
|
"description": "An advanced and versatile marine instrumentation package to display Signal K data.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -65,48 +65,51 @@
|
|
|
65
65
|
},
|
|
66
66
|
"schematics": "tools/schematics/collection.json",
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@angular-devkit/build-angular": "^21.2.3",
|
|
69
68
|
"@angular-devkit/schematics-cli": "^20.1.6",
|
|
70
|
-
"@angular/animations": "
|
|
71
|
-
"@angular/build": "^
|
|
72
|
-
"@angular/cdk": "
|
|
73
|
-
"@angular/cli": "^
|
|
74
|
-
"@angular/common": "
|
|
75
|
-
"@angular/compiler": "
|
|
76
|
-
"@angular/compiler-cli": "
|
|
77
|
-
"@angular/core": "
|
|
78
|
-
"@angular/forms": "
|
|
79
|
-
"@angular/language-service": "
|
|
80
|
-
"@angular/material": "
|
|
81
|
-
"@angular/platform-browser": "
|
|
82
|
-
"@angular/platform-browser-dynamic": "
|
|
83
|
-
"@angular/router": "
|
|
69
|
+
"@angular/animations": "22.0.5",
|
|
70
|
+
"@angular/build": "^22.0.5",
|
|
71
|
+
"@angular/cdk": "22.0.3",
|
|
72
|
+
"@angular/cli": "^22.0.5",
|
|
73
|
+
"@angular/common": "22.0.5",
|
|
74
|
+
"@angular/compiler": "22.0.5",
|
|
75
|
+
"@angular/compiler-cli": "22.0.5",
|
|
76
|
+
"@angular/core": "22.0.5",
|
|
77
|
+
"@angular/forms": "22.0.5",
|
|
78
|
+
"@angular/language-service": "22.0.5",
|
|
79
|
+
"@angular/material": "22.0.3",
|
|
80
|
+
"@angular/platform-browser": "22.0.5",
|
|
81
|
+
"@angular/platform-browser-dynamic": "22.0.5",
|
|
82
|
+
"@angular/router": "22.0.5",
|
|
84
83
|
"@aziham/chartjs-plugin-streaming": "^3.5.1",
|
|
85
84
|
"@godind/ng-canvas-gauges": "^6.2.1",
|
|
86
85
|
"@types/canvas-gauges": "^2.1.8",
|
|
87
86
|
"@types/d3": "^7.4.3",
|
|
87
|
+
"@types/d3-selection": "^3.0.11",
|
|
88
|
+
"@types/d3-shape": "^3.1.8",
|
|
89
|
+
"@types/express": "^5.0.6",
|
|
88
90
|
"@types/js-quantities": "^1.6.6",
|
|
89
91
|
"@types/lodash-es": "^4.17.9",
|
|
90
92
|
"@types/node": "^24.1.0",
|
|
91
93
|
"@vitest/coverage-v8": "^4.1.0",
|
|
92
94
|
"@zakj/no-sleep": "^0.13.5",
|
|
93
|
-
"angular-eslint": "
|
|
95
|
+
"angular-eslint": "^22.0.0",
|
|
94
96
|
"chart.js": "^4.5.1",
|
|
95
97
|
"chartjs-adapter-date-fns": "^3.0.0",
|
|
96
98
|
"chartjs-plugin-annotation": "^3.0.1",
|
|
97
99
|
"clipboard": "^2.0.11",
|
|
98
|
-
"codelyzer": "^6.0.0",
|
|
99
100
|
"compare-versions": "^6.1.1",
|
|
100
101
|
"core-js": "^3.13.1",
|
|
101
102
|
"d3": "^7.9.0",
|
|
103
|
+
"d3-selection": "^3.0.0",
|
|
104
|
+
"d3-shape": "^3.2.0",
|
|
102
105
|
"date-fns": "^2.30.0",
|
|
103
106
|
"eslint": "^9.29.0",
|
|
104
107
|
"gridstack": "^12.3.3",
|
|
105
108
|
"js-quantities": "^1.8.0",
|
|
106
109
|
"jsdom": "^26.1.0",
|
|
107
110
|
"lodash-es": "^4.17.23",
|
|
108
|
-
"ng-packagr": "^
|
|
109
|
-
"ngx-markdown": "^
|
|
111
|
+
"ng-packagr": "^22.0.1",
|
|
112
|
+
"ngx-markdown": "^22.0.0",
|
|
110
113
|
"prismjs": "^1.30.0",
|
|
111
114
|
"pwa-asset-generator": "^8.1.1",
|
|
112
115
|
"rxjs": "^7.8.2",
|
|
@@ -116,7 +119,7 @@
|
|
|
116
119
|
"steelseries": "^2.0.9",
|
|
117
120
|
"ts-node": "^10.9.2",
|
|
118
121
|
"tslib": "^2.6.2",
|
|
119
|
-
"typescript": "^
|
|
122
|
+
"typescript": "^6.0.3",
|
|
120
123
|
"vitest": "^4.1.0"
|
|
121
124
|
},
|
|
122
125
|
"dependencies": {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HistorySeriesService = exports.isKipTemplateSeriesDefinition = exports.isKipSolarTemplateSeriesDefinition = exports.isKipSeriesEnabled = exports.isKipConcreteSeriesDefinition = exports.isKipBmsTemplateSeriesDefinition = void 0;
|
|
3
|
+
exports.HistorySeriesService = exports.isKipTemplateSeriesDefinition = exports.isKipSolarTemplateSeriesDefinition = exports.isKipSeriesEnabled = exports.isKipElectricalTemplateSeriesDefinition = exports.isKipConcreteSeriesDefinition = exports.isKipBmsTemplateSeriesDefinition = void 0;
|
|
4
4
|
const kip_series_contract_1 = require("./kip-series-contract");
|
|
5
|
+
Object.defineProperty(exports, "isKipElectricalTemplateSeriesDefinition", { enumerable: true, get: function () { return kip_series_contract_1.isKipElectricalTemplateSeriesDefinition; } });
|
|
5
6
|
Object.defineProperty(exports, "isKipBmsTemplateSeriesDefinition", { enumerable: true, get: function () { return kip_series_contract_1.isKipBmsTemplateSeriesDefinition; } });
|
|
6
7
|
Object.defineProperty(exports, "isKipConcreteSeriesDefinition", { enumerable: true, get: function () { return kip_series_contract_1.isKipConcreteSeriesDefinition; } });
|
|
7
8
|
Object.defineProperty(exports, "isKipSeriesEnabled", { enumerable: true, get: function () { return kip_series_contract_1.isKipSeriesEnabled; } });
|
|
@@ -227,6 +228,18 @@ class HistorySeriesService {
|
|
|
227
228
|
if (!seriesKeys || seriesKeys.length === 0) {
|
|
228
229
|
return;
|
|
229
230
|
}
|
|
231
|
+
const hasSpecificSourceMatch = seriesKeys.some(seriesKey => {
|
|
232
|
+
const series = this.seriesById.get(seriesKey);
|
|
233
|
+
if (!series) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
const seriesContext = series.context ?? 'vessels.self';
|
|
237
|
+
if (!this.isContextMatch(seriesContext, context)) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
const seriesSource = series.source ?? 'default';
|
|
241
|
+
return seriesSource !== 'default' && seriesSource === source;
|
|
242
|
+
});
|
|
230
243
|
seriesKeys.forEach(seriesKey => {
|
|
231
244
|
const series = this.seriesById.get(seriesKey);
|
|
232
245
|
if (!series) {
|
|
@@ -240,6 +253,9 @@ class HistorySeriesService {
|
|
|
240
253
|
if (!this.isSourceMatch(seriesSource, source)) {
|
|
241
254
|
return;
|
|
242
255
|
}
|
|
256
|
+
if (seriesSource === 'default' && source !== 'default' && hasSpecificSourceMatch) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
243
259
|
if (this.recordSampleByKey(seriesKey, leaf.value, ts)) {
|
|
244
260
|
recorded += 1;
|
|
245
261
|
}
|
|
@@ -328,8 +344,9 @@ class HistorySeriesService {
|
|
|
328
344
|
&& leftComparable.ownerWidgetSelector === rightComparable.ownerWidgetSelector
|
|
329
345
|
&& leftComparable.path === rightComparable.path
|
|
330
346
|
&& leftComparable.expansionMode === rightComparable.expansionMode
|
|
331
|
-
&&
|
|
332
|
-
&& this.areStringArraysEquivalent(leftComparable.
|
|
347
|
+
&& leftComparable.familyKey === rightComparable.familyKey
|
|
348
|
+
&& this.areStringArraysEquivalent(leftComparable.allowedIds, rightComparable.allowedIds)
|
|
349
|
+
&& this.areTrackedDevicesEquivalent(leftComparable.trackedDevices, rightComparable.trackedDevices)
|
|
333
350
|
&& leftComparable.source === rightComparable.source
|
|
334
351
|
&& leftComparable.context === rightComparable.context
|
|
335
352
|
&& leftComparable.timeScale === rightComparable.timeScale
|
|
@@ -344,11 +361,22 @@ class HistorySeriesService {
|
|
|
344
361
|
void reconcileTs;
|
|
345
362
|
return {
|
|
346
363
|
...comparable,
|
|
347
|
-
|
|
348
|
-
|
|
364
|
+
allowedIds: this.normalizeComparableStringArray(comparable.allowedIds),
|
|
365
|
+
trackedDevices: this.normalizeComparableTrackedDevices(comparable.trackedDevices),
|
|
349
366
|
methods: this.normalizeComparableStringArray(comparable.methods)
|
|
350
367
|
};
|
|
351
368
|
}
|
|
369
|
+
areTrackedDevicesEquivalent(left, right) {
|
|
370
|
+
const normalizedLeft = this.normalizeComparableTrackedDevices(left) ?? [];
|
|
371
|
+
const normalizedRight = this.normalizeComparableTrackedDevices(right) ?? [];
|
|
372
|
+
if (normalizedLeft.length !== normalizedRight.length) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
return normalizedLeft.every((value, index) => {
|
|
376
|
+
const candidate = normalizedRight[index];
|
|
377
|
+
return value.id === candidate?.id && value.source === candidate?.source;
|
|
378
|
+
});
|
|
379
|
+
}
|
|
352
380
|
areStringArraysEquivalent(left, right) {
|
|
353
381
|
const normalizedLeft = this.normalizeComparableStringArray(left) ?? [];
|
|
354
382
|
const normalizedRight = this.normalizeComparableStringArray(right) ?? [];
|
|
@@ -365,6 +393,31 @@ class HistorySeriesService {
|
|
|
365
393
|
.filter((value) => typeof value === 'string')
|
|
366
394
|
.sort((left, right) => left.localeCompare(right));
|
|
367
395
|
}
|
|
396
|
+
normalizeComparableTrackedDevices(values) {
|
|
397
|
+
if (!Array.isArray(values) || values.length === 0) {
|
|
398
|
+
return undefined;
|
|
399
|
+
}
|
|
400
|
+
const normalizedByKey = new Map();
|
|
401
|
+
values.forEach(value => {
|
|
402
|
+
if (!value || typeof value !== 'object') {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
const id = typeof value.id === 'string' ? value.id.trim() : '';
|
|
406
|
+
const sourceText = typeof value.source === 'string' ? value.source.trim() : '';
|
|
407
|
+
const source = sourceText.length > 0 ? sourceText : 'default';
|
|
408
|
+
if (!id) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
normalizedByKey.set(`${id}||${source}`, { id, source });
|
|
412
|
+
});
|
|
413
|
+
if (normalizedByKey.size === 0) {
|
|
414
|
+
return undefined;
|
|
415
|
+
}
|
|
416
|
+
return Array.from(normalizedByKey.values()).sort((left, right) => {
|
|
417
|
+
const idCompare = left.id.localeCompare(right.id);
|
|
418
|
+
return idCompare !== 0 ? idCompare : left.source.localeCompare(right.source);
|
|
419
|
+
});
|
|
420
|
+
}
|
|
368
421
|
isChartWidget(ownerWidgetSelector, ownerWidgetUuid) {
|
|
369
422
|
if (ownerWidgetSelector === 'widget-data-chart' || ownerWidgetSelector === 'widget-windtrends-chart') {
|
|
370
423
|
return true;
|
|
@@ -391,18 +444,29 @@ class HistorySeriesService {
|
|
|
391
444
|
}
|
|
392
445
|
const ownerWidgetSelector = typeof input.ownerWidgetSelector === 'string' ? input.ownerWidgetSelector.trim() : null;
|
|
393
446
|
const expansionMode = input.expansionMode ?? null;
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
447
|
+
const familyKey = expansionMode ? this.expansionModeToFamilyKey(expansionMode) : null;
|
|
448
|
+
let normalizedTemplateSelector = null;
|
|
449
|
+
if (expansionMode) {
|
|
450
|
+
const selectorByMode = {
|
|
451
|
+
'bms-battery-tree': 'widget-bms',
|
|
452
|
+
'solar-tree': 'widget-solar-charger',
|
|
453
|
+
'charger-tree': 'widget-charger',
|
|
454
|
+
'inverter-tree': 'widget-inverter',
|
|
455
|
+
'alternator-tree': 'widget-alternator',
|
|
456
|
+
'ac-tree': 'widget-ac'
|
|
457
|
+
};
|
|
458
|
+
const requiredSelector = selectorByMode[expansionMode];
|
|
459
|
+
if (ownerWidgetSelector !== requiredSelector) {
|
|
460
|
+
throw new Error(`Template series mode "${expansionMode}" must use ownerWidgetSelector "${requiredSelector}"`);
|
|
461
|
+
}
|
|
462
|
+
normalizedTemplateSelector = requiredSelector;
|
|
399
463
|
}
|
|
400
464
|
const normalizedMethods = this.normalizeComparableStringArray(input.methods);
|
|
401
|
-
const
|
|
402
|
-
? this.normalizeComparableStringArray(input.
|
|
465
|
+
const normalizedAllowedIds = expansionMode
|
|
466
|
+
? this.normalizeComparableStringArray(input.allowedIds)
|
|
403
467
|
: undefined;
|
|
404
|
-
const
|
|
405
|
-
? this.
|
|
468
|
+
const normalizedTrackedDevices = expansionMode
|
|
469
|
+
? this.normalizeComparableTrackedDevices(input.trackedDevices)
|
|
406
470
|
: undefined;
|
|
407
471
|
const isDataWidget = this.isChartWidget(ownerWidgetSelector, ownerWidgetUuid);
|
|
408
472
|
const retentionMs = this.resolveRetentionMs(input);
|
|
@@ -423,6 +487,7 @@ class HistorySeriesService {
|
|
|
423
487
|
ownerWidgetUuid,
|
|
424
488
|
ownerWidgetSelector,
|
|
425
489
|
path,
|
|
490
|
+
familyKey,
|
|
426
491
|
source: input.source ?? 'default',
|
|
427
492
|
context: input.context ?? 'vessels.self',
|
|
428
493
|
timeScale: input.timeScale ?? null,
|
|
@@ -433,34 +498,47 @@ class HistorySeriesService {
|
|
|
433
498
|
methods: normalizedMethods,
|
|
434
499
|
reconcileTs: input.reconcileTs
|
|
435
500
|
};
|
|
436
|
-
if (expansionMode
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
expansionMode,
|
|
441
|
-
allowedBatteryIds: normalizedAllowedBatteryIds ?? null,
|
|
442
|
-
allowedSolarIds: null
|
|
443
|
-
};
|
|
444
|
-
return templateSeries;
|
|
445
|
-
}
|
|
446
|
-
if (expansionMode === 'solar-tree') {
|
|
501
|
+
if (expansionMode) {
|
|
502
|
+
if (!normalizedTemplateSelector) {
|
|
503
|
+
throw new Error(`Template series mode \"${expansionMode}\" must resolve a non-null ownerWidgetSelector`);
|
|
504
|
+
}
|
|
447
505
|
const templateSeries = {
|
|
448
506
|
...normalizedBase,
|
|
449
|
-
ownerWidgetSelector:
|
|
507
|
+
ownerWidgetSelector: normalizedTemplateSelector,
|
|
450
508
|
expansionMode,
|
|
451
|
-
|
|
452
|
-
|
|
509
|
+
familyKey,
|
|
510
|
+
allowedIds: normalizedAllowedIds ?? null,
|
|
511
|
+
trackedDevices: normalizedTrackedDevices ?? null
|
|
453
512
|
};
|
|
454
513
|
return templateSeries;
|
|
455
514
|
}
|
|
456
515
|
const concreteSeries = {
|
|
457
516
|
...normalizedBase,
|
|
458
517
|
expansionMode: null,
|
|
459
|
-
|
|
460
|
-
|
|
518
|
+
familyKey: null,
|
|
519
|
+
allowedIds: null,
|
|
520
|
+
trackedDevices: null
|
|
461
521
|
};
|
|
462
522
|
return concreteSeries;
|
|
463
523
|
}
|
|
524
|
+
expansionModeToFamilyKey(mode) {
|
|
525
|
+
switch (mode) {
|
|
526
|
+
case 'bms-battery-tree':
|
|
527
|
+
return 'batteries';
|
|
528
|
+
case 'solar-tree':
|
|
529
|
+
return 'solar';
|
|
530
|
+
case 'charger-tree':
|
|
531
|
+
return 'chargers';
|
|
532
|
+
case 'inverter-tree':
|
|
533
|
+
return 'inverters';
|
|
534
|
+
case 'alternator-tree':
|
|
535
|
+
return 'alternators';
|
|
536
|
+
case 'ac-tree':
|
|
537
|
+
return 'ac';
|
|
538
|
+
default:
|
|
539
|
+
throw new Error(`Unsupported expansion mode: ${String(mode)}`);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
464
542
|
resolveRetentionMs(series) {
|
|
465
543
|
if (Number.isFinite(series.retentionDurationMs) && series.retentionDurationMs > 0) {
|
|
466
544
|
return series.retentionDurationMs;
|