homebridge-navilink 0.1.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.
Files changed (82) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE +202 -0
  3. package/README.md +161 -0
  4. package/SECURITY.md +73 -0
  5. package/config.schema.json +138 -0
  6. package/dist/api/channel.d.ts +94 -0
  7. package/dist/api/channel.js +334 -0
  8. package/dist/api/http.d.ts +68 -0
  9. package/dist/api/http.js +205 -0
  10. package/dist/api/identity.d.ts +51 -0
  11. package/dist/api/identity.js +80 -0
  12. package/dist/api/index.d.ts +17 -0
  13. package/dist/api/index.js +33 -0
  14. package/dist/api/mqtt-codec.d.ts +181 -0
  15. package/dist/api/mqtt-codec.js +377 -0
  16. package/dist/api/mqtt.d.ts +178 -0
  17. package/dist/api/mqtt.js +450 -0
  18. package/dist/api/protocol.d.ts +212 -0
  19. package/dist/api/protocol.js +286 -0
  20. package/dist/api/rest.d.ts +139 -0
  21. package/dist/api/rest.js +317 -0
  22. package/dist/api/sigv4.d.ts +70 -0
  23. package/dist/api/sigv4.js +123 -0
  24. package/dist/api/topics.d.ts +75 -0
  25. package/dist/api/topics.js +90 -0
  26. package/dist/devices/base-accessory.d.ts +127 -0
  27. package/dist/devices/base-accessory.js +232 -0
  28. package/dist/devices/dhw-accessory.d.ts +62 -0
  29. package/dist/devices/dhw-accessory.js +100 -0
  30. package/dist/devices/fault-accessory.d.ts +31 -0
  31. package/dist/devices/fault-accessory.js +73 -0
  32. package/dist/devices/heating-accessory.d.ts +63 -0
  33. package/dist/devices/heating-accessory.js +128 -0
  34. package/dist/devices/host.d.ts +77 -0
  35. package/dist/devices/host.js +23 -0
  36. package/dist/devices/index.d.ts +17 -0
  37. package/dist/devices/index.js +33 -0
  38. package/dist/devices/power-accessory.d.ts +32 -0
  39. package/dist/devices/power-accessory.js +86 -0
  40. package/dist/devices/probe-accessory.d.ts +45 -0
  41. package/dist/devices/probe-accessory.js +108 -0
  42. package/dist/devices/recirculation-accessory.d.ts +47 -0
  43. package/dist/devices/recirculation-accessory.js +122 -0
  44. package/dist/devices/thermostat-accessory.d.ts +129 -0
  45. package/dist/devices/thermostat-accessory.js +372 -0
  46. package/dist/discovery.d.ts +99 -0
  47. package/dist/discovery.js +423 -0
  48. package/dist/index.d.ts +11 -0
  49. package/dist/index.js +15 -0
  50. package/dist/platform.d.ts +120 -0
  51. package/dist/platform.js +425 -0
  52. package/dist/session.d.ts +243 -0
  53. package/dist/session.js +717 -0
  54. package/dist/settings.d.ts +218 -0
  55. package/dist/settings.js +240 -0
  56. package/dist/types/index.d.ts +265 -0
  57. package/dist/types/index.js +58 -0
  58. package/dist/ui-api.d.ts +27 -0
  59. package/dist/ui-api.js +39 -0
  60. package/dist/utils/context.d.ts +32 -0
  61. package/dist/utils/context.js +74 -0
  62. package/dist/utils/errors.d.ts +69 -0
  63. package/dist/utils/errors.js +118 -0
  64. package/dist/utils/index.d.ts +15 -0
  65. package/dist/utils/index.js +31 -0
  66. package/dist/utils/redact.d.ts +85 -0
  67. package/dist/utils/redact.js +210 -0
  68. package/dist/utils/serial.d.ts +18 -0
  69. package/dist/utils/serial.js +24 -0
  70. package/dist/utils/temperature.d.ts +114 -0
  71. package/dist/utils/temperature.js +150 -0
  72. package/dist/utils/timing.d.ts +68 -0
  73. package/dist/utils/timing.js +91 -0
  74. package/dist/utils/validators.d.ts +96 -0
  75. package/dist/utils/validators.js +353 -0
  76. package/docs/FEATURES.md +80 -0
  77. package/docs/PROTOCOL.md +200 -0
  78. package/docs/README-DETAILED.md +312 -0
  79. package/homebridge-ui/public/index.html +123 -0
  80. package/homebridge-ui/public/index.js +503 -0
  81. package/homebridge-ui/server.js +174 -0
  82. package/package.json +87 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. This file is generated by
4
+ [release-please](https://github.com/googleapis/release-please) from Conventional Commit
5
+ messages; do not edit it by hand. See [RELEASING.md](RELEASING.md).
package/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # homebridge-navilink
2
+
3
+ [![Tests](https://github.com/tbaur/homebridge-navilink/actions/workflows/test.yml/badge.svg)](https://github.com/tbaur/homebridge-navilink/actions/workflows/test.yml) [![npm version](https://img.shields.io/npm/v/homebridge-navilink?style=flat-square)](https://www.npmjs.com/package/homebridge-navilink) [![npm downloads](https://img.shields.io/npm/dt/homebridge-navilink?label=downloads&style=flat-square)](https://www.npmjs.com/package/homebridge-navilink) [![Node.js](https://img.shields.io/badge/node-22%20%7C%7C%2024%20%7C%7C%2026-green)](https://nodejs.org) [![Homebridge](https://img.shields.io/badge/homebridge-2.x-purple)](https://homebridge.io) [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
4
+
5
+ **Navien combi boilers and water heaters in Apple HomeKit.** Hot water and space-heating thermostats, recirculation, faults and temperature probes, with changes arriving as they happen rather than on a polling loop. Verified against an NCB-240E (firmware 4352).
6
+
7
+ Scheduling, weekly programmes and commissioning stay in the NaviLink app, which does them properly. This plugin adds the tile, the scene, the automation and the spoken command. It also adds a fault sensor that tells you the boiler has stopped before the shower does.
8
+
9
+ > **This plugin talks to Navien's cloud, not to your boiler.** There is no local API on a NaviLink gateway. It needs your NaviLink account. See [Supported devices](#supported-devices) and [Security](#security) before you install it.
10
+
11
+ ## Features
12
+
13
+ ### Per appliance
14
+
15
+ - **Hot water thermostat:** the domestic hot water setpoint, reading the actual outlet temperature. Respects the range your installer set
16
+ - **Heating thermostat:** the space-heating flow temperature. This is the boiler's water temperature, not a room thermostat. Your room thermostat still decides when heat is called for
17
+ - **Power switch:** on and off, with switching *off* refused by default because it stops central heating too
18
+ - **Recirculation switch:** starts the on-demand pump, so hot water reaches the tap without running it first. Only offered where a pump is fitted. The appliance runs the pump for a fixed period and then stops; the tile turns itself off when that happens
19
+ - **Fault sensor:** a contact sensor that opens on an error code, so HomeKit can notify you. The code goes to the log
20
+ - **Temperature sensors:** hot water in and out, heating flow and return, and the outdoor probe if one is fitted. Each disables itself if the appliance does not report it
21
+
22
+ ### Reliability
23
+
24
+ - **Push, not polling.** The gateway sends changes as they happen, so a setpoint changed at the wall controller or in the NaviLink app reaches HomeKit in about a second. The poll is only a backstop
25
+ - **A rejected password is never retried.** Repeating a wrong password at a cloud is how an account gets locked. The plugin stops, says so once, and waits for you
26
+ - **Credentials are renewed on a clock,** a few minutes before they expire, so the connection is not already dead in the middle of the night
27
+ - **A connected socket is not a live appliance.** Readings carry the time they were taken, and a stale one becomes No Response instead of yesterday's setpoint
28
+ - **Honest state:** No Response until the appliance has actually been read, never a value it cannot confirm
29
+ - **Never loses your rooms:** a broken config disables the platform without unregistering anything
30
+
31
+ ### Quality
32
+
33
+ - **Strict TypeScript,** with `noUncheckedIndexedAccess` and type-aware lint
34
+ - **Tested:** a behavioural Jest suite against fixtures recorded from real hardware, with a guard that fails the build if anything identifying reaches them
35
+ - **No analytics:** nothing is sent anywhere except Navien's own service
36
+ - **One runtime dependency,** Homebridge's own UI helper. The MQTT client is a small in-repo codec, not a `mqtt.js` dependency tree
37
+
38
+ Every accessory, field and log line is documented in [Detailed documentation](docs/README-DETAILED.md).
39
+
40
+ ## Quick Start
41
+
42
+ ### 1. Install
43
+
44
+ **Homebridge UI** (recommended): Plugins → Search `homebridge-navilink` → Install
45
+
46
+ ```bash
47
+ npm install -g homebridge-navilink
48
+ ```
49
+
50
+ ### 2. Prepare your appliance
51
+
52
+ Your NaviLink gateway must be connected and showing as online in the NaviLink app. Nothing needs enabling: the plugin uses the same service the app does. If the app cannot see the appliance, neither can this.
53
+
54
+ ### 3. Configure
55
+
56
+ **Homebridge UI** (recommended): open the plugin settings, enter your NaviLink email and password, and press **Sign in**. Every appliance on the account is listed, along with the accessories it can actually support. A recirculation switch is only offered where a pump is fitted. Tick what you want and press the Homebridge Save button.
57
+
58
+ Or in `config.json`:
59
+
60
+ ```json
61
+ {
62
+ "platforms": [
63
+ {
64
+ "platform": "NaviLink",
65
+ "name": "NaviLink",
66
+ "email": "you@example.com",
67
+ "password": "your-navilink-password",
68
+ "devices": [
69
+ {
70
+ "id": "a1b2c3d4e5f6:1",
71
+ "name": "Boiler",
72
+ "dhw": true,
73
+ "heating": true,
74
+ "fault": true
75
+ }
76
+ ]
77
+ }
78
+ ]
79
+ }
80
+ ```
81
+
82
+ The `id` is your gateway's MAC address and the channel. The settings page writes it for you; finding it by hand is not worth the effort.
83
+
84
+ See the [full configuration reference](docs/README-DETAILED.md#full-configuration-reference) for every option.
85
+
86
+ ### 4. Restart Homebridge
87
+
88
+ Accessories appear in the Home app after restart, showing No Response for the few seconds it takes to sign in and read the first status frame.
89
+
90
+ ## Supported Devices
91
+
92
+ Any Navien appliance that the NaviLink app controls. The cloud interface is the same for all of them; what differs is which capabilities an appliance reports.
93
+
94
+ | Verified against | Notes |
95
+ |---|---|
96
+ | **NCB-240E (NG)** | Combi: hot water and space heating, firmware 4352 |
97
+
98
+ Other families are decoded from the same table the NaviLink app uses and are expected to work, but nobody has confirmed them here:
99
+
100
+ | Family | Expected |
101
+ |---|---|
102
+ | **NPE, NPE2, NPN** | Tankless water heaters. Hot water only; the heating thermostat disables itself |
103
+ | **NCB-H** | Combi with a buffer tank |
104
+ | **NHB** | Boiler. Space heating only |
105
+ | **NFB, NFC** | Boilers with hot water and space heating |
106
+ | **NVW** | Water heater with a tank |
107
+
108
+ If yours is not listed, it will most likely work. Please open an issue with the output of `node scripts/capture-fixture.js --redact` either way, so the table can say so with confidence.
109
+
110
+ ## Configuration Options
111
+
112
+ Only one `NaviLink` platform block is supported. It can hold as many appliances as the account owns.
113
+
114
+ | Option | Required to run | Description |
115
+ |---|:-:|---|
116
+ | `name` | ✓ | Plugin instance name shown in Homebridge logs |
117
+ | `email` | ✓ | Your NaviLink account address. Needed before the plugin signs in |
118
+ | `password` | ✓ | Your NaviLink password. Needed before the plugin signs in |
119
+ | `devices` | ✓ | List of appliances. Needed before the plugin signs in |
120
+ | `options.statusIntervalSec` | | Backstop refresh, 30–3600 seconds (default 120) |
121
+ | `options.readOnly` | | Report everything, change nothing (default false) |
122
+ | `options.allowPowerOff` | | Let HomeKit switch the appliance off (default false) |
123
+
124
+ Each entry in `devices[]` takes `id` and `name`, plus an optional `channel` and one flag per accessory: `dhw`, `heating`, `power`, `recirculation`, `fault`, `temperatureSensors` and `outdoorSensor`. The [detailed documentation](docs/README-DETAILED.md#devices-entries) describes each one.
125
+
126
+ ## Not Working?
127
+
128
+ 1. **"NaviLink rejected the email address or password."** Sign in to the NaviLink app with the same credentials. The plugin has stopped trying on purpose, so fix the password and restart Homebridge
129
+ 2. **Everything shows No Response.** Check the log for `the NaviLink platform is disabled`, which means the configuration could not be read
130
+ 3. **The heating thermostat says it has no loop.** Your appliance reports no space-heating circuit. Turn the accessory off in the settings
131
+ 4. **A recirculation switch that is not offered.** No pump is fitted, or it is not commissioned. Check the NaviLink app
132
+ 5. **"The appliance refused a command for arriving too soon."** The cloud rate-limits control. The plugin pauses and retries on your next press
133
+
134
+ The [full troubleshooting list](docs/README-DETAILED.md#troubleshooting) covers more, including what Off on the hot water tile does once you allow power-off.
135
+
136
+ ## Security
137
+
138
+ This plugin needs your NaviLink password, stores it in the Homebridge configuration file as every Homebridge credential is stored, and sends it to Navien to sign in. It is never written to the Homebridge log, never put into an accessory's cache, and redacted from anything the plugin prints. That is the honest summary; [SECURITY.md](SECURITY.md) has the detail, including what a capture contains and why the fixtures in this repository are pseudonymised.
139
+
140
+ ## Requirements
141
+
142
+ - Homebridge 2.x
143
+ - Node.js 22, 24 or 26, matching what Homebridge 2.x itself supports
144
+ - A North American NaviLink account (`nlus`). Other Navien regions use different hosts and will look like a rejected password
145
+ - A NaviLink account with at least one gateway online
146
+ - A working internet connection
147
+
148
+ ## More Info
149
+
150
+ - [Detailed documentation](docs/README-DETAILED.md)
151
+ - [Features](docs/FEATURES.md)
152
+ - [Protocol reference](docs/PROTOCOL.md): what the NaviLink cloud actually does
153
+ - [Development](DEVELOPMENT.md)
154
+ - [Report Issues](https://github.com/tbaur/homebridge-navilink/issues)
155
+ - [Changelog](CHANGELOG.md)
156
+
157
+ ## License
158
+
159
+ Copyright 2026 tbaur
160
+
161
+ Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) file for details.
package/SECURITY.md ADDED
@@ -0,0 +1,73 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ | ------- | ------------------ |
7
+ | 0.x.x | ✅ Active support |
8
+
9
+ ## Reporting a Vulnerability
10
+
11
+ Do not open a public issue. Use GitHub's [private vulnerability reporting](https://github.com/tbaur/homebridge-navilink/security/advisories/new), and include a description, how to reproduce it, and the impact.
12
+
13
+ ## The honest summary
14
+
15
+ **This plugin needs your NaviLink password and stores it in plain text in the Homebridge configuration file.** That is how every Homebridge plugin that talks to a cloud service works, because Homebridge offers no secret store. It deserves saying plainly.
16
+
17
+ What follows from that:
18
+
19
+ - Anyone who can read your Homebridge config can sign in to your NaviLink account, which controls your boiler.
20
+ - The plugin uses an interface Navien has never published. Navien can change or withdraw it at any time, without notice, and would be within their rights to.
21
+ - There is no local fallback. A NaviLink gateway has no LAN interface, so this stops working when your internet does.
22
+
23
+ If those are not acceptable, this plugin is not for you, and that is a reasonable conclusion.
24
+
25
+ ## Security Measures
26
+
27
+ - **Credentials in one place.** The password is read from configuration, used to sign in, and held only in memory. It is never written to a log, never placed in an accessory's cache, never sent anywhere except Navien's sign-in endpoint over HTTPS, and never passed to a script as a command-line argument.
28
+ - **Redaction by shape, not by name.** `src/utils/redact.ts` matches JWTs, AWS key ids, signed-URL parameters and credential-shaped JSON fields by their *form*. A field name list would miss a token in a response shape nobody anticipated; this does not.
29
+ - **Masked identifiers in the log.** The account address appears as `s…e@example.com` and a gateway MAC as `…E5F6`. Both identify you, and a Homebridge log gets pasted into issues.
30
+ - **The accessory cache holds identity, not credentials.** Homebridge persists `{mac}:{channel}` as `deviceId` so a restart adopts the same tile. That file is plain JSON and is included in diagnostic bundles, so it must never hold the password, a token or a signed AWS URL. The MAC is the appliance's address in every MQTT topic. HomeKit serial numbers are opaque generated values, not the MAC.
31
+ - **HomeKit serial numbers are opaque generated values,** not the gateway MAC. The Home app displays them, so they reach screenshots.
32
+ - **Input validation.** Config is checked at startup. A missing account, or a `devices` value that is not a list, disables the platform without unregistering accessories. A bad appliance entry is skipped. Names are stripped of control characters and length-capped before they reach a log line or a characteristic.
33
+ - **Bounded I/O.** Separate connect and total timeouts on every request, a capped HTTP response size, and a capped MQTT packet size, so a hostile or broken response cannot exhaust memory.
34
+ - **A rejected credential stops the session.** Retrying a wrong password is how an account gets locked; the plugin declines to do it.
35
+ - **Minimal dependencies.** One at runtime: Homebridge's own UI helper. The MQTT client is in this repository, for a protocol reason ([PROTOCOL.md](docs/PROTOCOL.md)) that also reduces supply-chain surface.
36
+ - **Dependencies audited.** CI runs `npm audit` on the runtime tree and OSV-Scanner on the full tree.
37
+ - **A CI step rejects credential-shaped strings** in the published docs, fixtures, schema and issue templates, so a token cannot be committed by accident. Unit tests that hold fake JWTs are outside that scan on purpose.
38
+
39
+ ## The settings page
40
+
41
+ The configuration UI runs in its own short-lived process and is the one place that handles a typed password.
42
+
43
+ - The password is used for the sign-in of the request that carried it. It is not cached between requests and not written to a file by that process.
44
+ - Nothing from a sign-in response reaches the browser. The page receives appliances; the tokens and AWS credentials stay in the UI process and die with the request.
45
+ - Diagnostic output handed back on failure is the plugin's own redacted log, filtered a second time on the way out, because a line that reaches a browser can end up in a screenshot in a public issue.
46
+
47
+ ## Captures and fixtures
48
+
49
+ A raw frame from the NaviLink cloud carries your gateway's MAC address and your account's sequence numbers. The `device/info` endpoint also returns your installation's **street address and coordinates**, which is why the plugin reads only the firmware version from it and nothing else is available to callers.
50
+
51
+ - Raw captures go to `tests/fixtures/raw/`, which is git-ignored.
52
+ - `scripts/pseudonymise.js` rewrites them and then audits its own output. It reports every identifier that remains. It does not trust a list of field names. A MAC appears twice in two spellings in these frames, and a name-driven rewrite misses the second.
53
+ - `tests/unit/fixtures.test.ts` fails the build if a MAC, email address, JWT or AWS key that is not the documented example appears in `tests/fixtures/`.
54
+ - `scripts/capture-fixture.js --redact` is the form to paste into a bug report. Read it before you paste it: the redaction is good, and it is not a promise.
55
+
56
+ ## Best Practices for Users
57
+
58
+ 1. Keep Homebridge and this plugin updated.
59
+ 2. Run Homebridge with minimal privileges, and do not expose it to the internet.
60
+ 3. Protect the Homebridge configuration file and any backup of it as you would a password file, because it contains one.
61
+ 4. Use `options.readOnly` if you want the readings without the plugin being able to change anything.
62
+ 5. Leave `options.allowPowerOff` off unless you have thought about what "turn everything off" means in February.
63
+ 6. Consider a NaviLink account used only for this, if you would rather not have your primary one in a config file.
64
+
65
+ ## Response Timeline
66
+
67
+ - **Acknowledgment**: Within 48 hours
68
+ - **Initial assessment**: Within 1 week
69
+ - **Fix timeline**: Depends on severity
70
+ - Critical: 24-48 hours
71
+ - High: 1 week
72
+ - Medium: 2 weeks
73
+ - Low: Next release
@@ -0,0 +1,138 @@
1
+ {
2
+ "pluginAlias": "NaviLink",
3
+ "pluginType": "platform",
4
+ "singular": true,
5
+ "customUi": true,
6
+ "customUiPath": "./homebridge-ui",
7
+ "headerDisplay": "Exposes Navien combi boilers and water heaters to HomeKit through the North American NaviLink cloud (`nlus`): hot water and space-heating thermostats, a power switch, recirculation, a fault sensor and temperature probes. Verified on an NCB-240E. Press **Sign in** to list the appliances on your account; every field below can also be edited by hand.",
8
+ "footerDisplay": "Your NaviLink password is stored in the Homebridge configuration file, because the plugin has to sign in again after a restart and Navien offers no other credential. See the [documentation](https://github.com/tbaur/homebridge-navilink#readme) for what this plugin does and does not do.",
9
+ "schema": {
10
+ "type": "object",
11
+ "required": ["name"],
12
+ "properties": {
13
+ "name": {
14
+ "title": "Platform Name",
15
+ "type": "string",
16
+ "default": "NaviLink",
17
+ "description": "Shown in the Homebridge log."
18
+ },
19
+ "email": {
20
+ "title": "NaviLink Email",
21
+ "type": "string",
22
+ "format": "email",
23
+ "maxLength": 254,
24
+ "description": "The email address for your NaviLink account, the same one you use in the NaviLink app."
25
+ },
26
+ "password": {
27
+ "title": "NaviLink Password",
28
+ "type": "string",
29
+ "maxLength": 256,
30
+ "x-schema-form": { "type": "password" },
31
+ "description": "Stored in plain text in the Homebridge configuration file, as every Homebridge credential is. It is never written to the Homebridge log."
32
+ },
33
+ "options": {
34
+ "title": "Options",
35
+ "type": "object",
36
+ "properties": {
37
+ "statusIntervalSec": {
38
+ "title": "Status Refresh (seconds)",
39
+ "type": "integer",
40
+ "default": 120,
41
+ "minimum": 30,
42
+ "maximum": 3600,
43
+ "description": "A floor on how stale a reading can be. The appliance pushes changes as they happen, so this is not how state normally arrives; it is the backstop for a push that was missed."
44
+ },
45
+ "readOnly": {
46
+ "title": "Read-only",
47
+ "type": "boolean",
48
+ "default": false,
49
+ "description": "Report everything, change nothing. Every accessory still shows state, and a HomeKit write is declined with one explanatory line in the log."
50
+ },
51
+ "allowPowerOff": {
52
+ "title": "Allow HomeKit to Switch the Appliance Off",
53
+ "type": "boolean",
54
+ "default": false,
55
+ "description": "Off by default, and worth leaving off. On a combi appliance the power state governs central heating as well as hot water, so \"turn off the water heater\" said to Siri, or a scene that turns everything off, would stop the heating in a house that may be empty and freezing. With this off, a power-off request is declined and explained instead of obeyed."
56
+ }
57
+ }
58
+ },
59
+ "devices": {
60
+ "title": "Appliances",
61
+ "type": "array",
62
+ "items": {
63
+ "type": "object",
64
+ "title": "Appliance",
65
+ "required": ["id", "name"],
66
+ "properties": {
67
+ "id": {
68
+ "title": "Identity",
69
+ "type": "string",
70
+ "minLength": 3,
71
+ "maxLength": 20,
72
+ "pattern": "^[0-9a-fA-F]{12}:([1-9]|[12][0-9]|3[0-2])$",
73
+ "examples": ["a1b2c3d4e5f6:1"],
74
+ "description": "Stable identity: twelve hex digits and the channel, as the settings page writes it (lowercase, no separators). Changing it detaches the accessories from their HomeKit rooms and automations."
75
+ },
76
+ "name": {
77
+ "title": "Name",
78
+ "type": "string",
79
+ "maxLength": 64,
80
+ "examples": ["Zone One"],
81
+ "description": "The appliance's name. Accessories are named from it: \"Boiler\" gives \"Boiler Hot Water\", \"Boiler Heating\", \"Boiler Fault\" and so on."
82
+ },
83
+ "channel": {
84
+ "title": "Channel",
85
+ "type": "integer",
86
+ "default": 1,
87
+ "minimum": 1,
88
+ "maximum": 32,
89
+ "description": "1 for a single appliance. A cascade of several appliances behind one gateway uses a channel each."
90
+ },
91
+ "dhw": {
92
+ "title": "Hot Water Thermostat",
93
+ "type": "boolean",
94
+ "default": true,
95
+ "description": "The domestic hot water setpoint, as a HomeKit thermostat. Reads the outlet temperature. Switching it off does not switch the appliance off unless you also allow that above."
96
+ },
97
+ "heating": {
98
+ "title": "Heating Thermostat",
99
+ "type": "boolean",
100
+ "default": false,
101
+ "description": "The space-heating water setpoint, as a HomeKit thermostat. This is the boiler's flow temperature, not a room thermostat: it sets how hot the water going to your radiators is, and your existing room thermostat still decides when heat is called for. Only useful on a combi; an appliance with no heating loop disables it and says so in the log."
102
+ },
103
+ "power": {
104
+ "title": "Power Switch",
105
+ "type": "boolean",
106
+ "default": false,
107
+ "description": "A switch for the appliance's power state. Switching it off is refused unless \"Allow HomeKit to switch the appliance off\" is on."
108
+ },
109
+ "recirculation": {
110
+ "title": "Recirculation Switch",
111
+ "type": "boolean",
112
+ "default": false,
113
+ "description": "Starts the on-demand hot water recirculation pump, so hot water reaches the tap without running it first. The appliance runs the pump for a fixed period and then stops; the switch turns itself off when that happens. Only for appliances with a pump fitted and commissioned."
114
+ },
115
+ "fault": {
116
+ "title": "Fault Sensor",
117
+ "type": "boolean",
118
+ "default": false,
119
+ "description": "A contact sensor that opens when the appliance reports an error code, so HomeKit can notify you. The code itself is written to the log."
120
+ },
121
+ "temperatureSensors": {
122
+ "title": "Temperature Sensors",
123
+ "type": "boolean",
124
+ "default": false,
125
+ "description": "Four read-only sensors: hot water in and out, and heating flow and return. Each one disables itself if the appliance turns out not to report it."
126
+ },
127
+ "outdoorSensor": {
128
+ "title": "Outdoor Temperature",
129
+ "type": "boolean",
130
+ "default": false,
131
+ "description": "The outdoor probe, on an installation that has one fitted for weather compensation. Most do not."
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }